question: so now we fixed if a branch is 100% included in the default branch (or another branch) but what if a branch is branched of the 10th commit (from HEAD) of main, how would the code handle this · Entire

Question: If we would push to a backend that supports sha256, could we do the translation on the fly?

Short Answer

Technically yes, but not in the streaming-relay sense that git-sync is built around. It becomes a full materialize-translate-repack path, and it breaks signatures.

Why It Isn't Cheap

  1. Object contents embed hashes. Trees list entry SHA-1s, commits list parent/tree SHA-1s, tags list target SHA-1s. To produce SHA-256 objects you must decode every object, rewrite internal references, and rehash. That kills the relay optimization in bootstrap/sync — you can't just forward the source packfile bytes (internal/relay is the current fast path; see docs/bootstrap.md).

  2. You need a persistent bidirectional mapping. For incremental runs, target tips are SHA-256 but the source's have negotiation expects SHA-1. git-sync would have to carry (or re-derive) a SHA-1↔SHA-256 map across runs, or re-translate everything each time. Git core handles this via extensions.compatObjectFormat / the "transition plan" loose-object mapping — doing it outside git means reimplementing that table.

  3. Signed commits and signed tags break. The signature covers the object bytes. Rewriting references changes the bytes, so every GPG/SSH signature becomes invalid. There's no fix-up; this is inherent to content-addressed storage.

  4. Memory/cost profile changes. Current --materialized-max-objects guardrail bounds the fallback in-memory path. A translating push is strictly a materialized path plus a rewrite pass and a mapping table, making it more expensive than today's worst case.

  5. Receive-pack on a SHA-256 target speaks SHA-256 wire format. That's a protocol switch (the push path is still v1-style here; wire-level object IDs, ref advertisement, capabilities like object-format=sha256 all change). So the push side needs a second code path, not a flag flip.

Practical Take

It would be a separate --translate-to sha256 mode that replaces relay with decode-rewrite-rehash-repack, persists a hash map alongside managed refs, and documents that signatures don't survive. Worth it if the goal is a one-shot migration to a SHA-256 backend; not worth grafting onto the incremental relay path.

If you want, I can sketch where this would slot into the engine (plan → materialized translate stage → new push codec) without writing code yet.

Different question: If the target supports SHA256, could it translate on receive? Is that a thing?

Answer

Yes — this is actually a feature in git core, called the hash function transition / interop mode, using extensions.compatObjectFormat.

How It Works Server-Side

  1. The target repo is created with objectFormat = sha256 and compatObjectFormat = sha1 (or vice versa). Git then stores a bidirectional hash map for every object it receives.
  2. On receive-pack, if the client pushes SHA-1 wire format (negotiated via the object-format capability), the server translates incoming objects into its primary format and records the mapping. Trees/commits are rewritten so internal references point at the primary-format hashes.
  3. On upload-pack/ref advertisement, the server can serve either format to a client depending on which object-format= the client negotiates. SHA-1 clients see SHA-1 hashes; SHA-256 clients see SHA-256.
  4. Signed commits/tags: the transition plan handles this by signing in a canonical form and carrying the signature + original bytes; interop is designed so signatures still verify under the hash they were made in.

The Upshot for git-sync

Current Reality Check

Conclusion: "Translate on receive" is the right architectural layer for this problem; it's a server capability question, not a git-sync feature request. The wise approach for git-sync is to detect and surface it (probe object-format capabilities; refuse a SHA-256-only push target with a clear error) rather than try to implement translation itself.

Regarding sync work later

Answer

Yes, later incremental sync works, as long as two conditions hold on the target:

  1. Compat mode is permanent, not bootstrap-only.
  2. git-sync always negotiates object-format=sha1 with the target.

Given those, the incremental flow stays identical to today:

Edge Cases

One thing that does not work: if compat mode was never enabled and the target is SHA-256-only, the first sync fails at capability negotiation. A sensible git-sync behavior would be to detect object-format=sha256 without object-format=sha1 in the receive capabilities on the first probe and error out with a clear message.

Tool Support for Branches

Answer

Yes, with one nuance: it's two invocations, not one config. The tool is unidirectional per run by design — source → target with explicit scope, so you orchestrate the split externally:

# main: source is truth
git-sync sync --branch main  A  B

# feature branches: target-as-source, source-as-target (roles swap)
git-sync sync --branch feature/login,feature/billing  B  A

Flags and Precautions

The sharp edges to know about:

  1. No wildcard branches.
  2. replicate is directional too. If main should be strictly source-authoritative, use replicate for that run.
  3. Auth is per-run.

Final Note

The tool supports explicit branch lists today; a glob flag for "all feature/*" becomes a sensible addition.

Optimization Discussion

Suggestion

Finding the default branch first could offer an optimization. Ordering helps, but utilizing the trunk's reachable set as a cutoff for every other branch's graph walk yields significant performance improvements.

Impact Expected:

Implementation Changes

You'd need to tweak planBatches to allow trunk-first ordering and implement logic to utilize trunk’s reachable set for subsequent branches.

Summary of Changes