SHA256 / Object-Hash Transition Plan
Source issue: GitoxideLabs/gitoxide#281
Imported on: 2026-04-22
Last reconciled: 2026-05-08
Working assumption: checkboxes in this file reflect current checkout, not only historical issue state.
Mission
Make object-hash kind first-class across config, protocol, storage, tests, and clone flow so SHA1 and SHA256 are both deliberate runtime choices instead of SHA1 being hidden fallback everywhere.
Constraints
- Use current workspace as source of truth.
- Treat old issue checkmarks as historical context only.
- Prefer end-to-end correctness over isolated enum or parser support.
- Keep scope on actual supported transition path, not abandoned pack-index-v3 speculation.
Reconciled Status
- Remove hash-type specific methods from
gix-hashand lean ongix_hash::Kind-parametric usage. Evidence:gix-hashstill containsnew_sha1,new_sha256,from_20_bytes,from_32_bytes,null_sha1,null_sha256. - Remove len-20 assumptions from all relevant code paths.
Evidence: big progress exists, but 79 non-plan/non-changelog
Kind::Sha1.null()/ObjectId::null(...Sha1)call sites still remain, plus a few explicit 20-byte comments and helpers. - Provide visible CLI path for choosing object hash kind.
Evidence:
src/plumbing/options/mod.rsandsrc/plumbing/options/free.rsexpose clapobject_hashfields, which produce--object-hash. - Propagate
sha256feature support through crates that participate in object traversal, object parsing, and object-id storage. Evidence: 31 workspace packages now define asha256feature, includinggix-object,gix-index,gix-protocol,gix-ref,gix-refspec,gix-traverse, and top-levelgix. - Make SHA256-only builds compile where supported by feature flags.
Evidence:
cargo check -p gix --no-default-features --features sha256fails becausegix/src/config/cache/incubate.rsandgix/src/config/tree/sections/core.rsstill namegix_hash::Kind::Sha1unconditionally. - Remove default
sha1feature fromgix-hashand deal with fallout. Evidence:gix-hashhasdefault = [], docs.rs explicitly enablessha1, rootgitoxidechooses SHA1 via features, andjustfilecontains compile-guard checks for missing hash selection. - Remove SHA1 mention from
gix-featuresfeature toggles. Evidence:gix-features/Cargo.tomlhas no SHA1/SHA256 feature toggles anymore. - Parameterize hash length when decoding non-blob objects.
Evidence:
gix-objecttree decoding hotspot useshash_kind.len_in_bytes(). - Add
Sha256enum variant and hasher support. Evidence:gix_hash::Kind::Sha256,ObjectId::Sha256, andHasher::Sha256exist. - Add broad dual-hash test hooks for reading refs and objects of different lengths.
Evidence:
justfileruns SHA256 fixture suites forgix-object,gix-ref-tests,gix-traverse-tests, and top-levelgix. - Add write/read roundtrip coverage for different hash lengths, ideally with stronger repo-level verification. Evidence: targeted tests exist, but no obvious repo-conversion or full transition verifier is present.
- Handle remote object-hash mismatch during clone by configuring repository accordingly.
Evidence:
gix/src/clone/fetch/mod.rsstill hasunimplemented!("configure repository to expect a different object hash as advertised by the server").
Deferred / Out Of Scope
- Pack index v3 transition work stays deferred unless Git actually relies on it. Rationale: issue itself already demoted this from active task to decision point.
Current Snapshot
Workspace signals on 2026-05-08:
gix-hashdefault hash feature: removed- compile-guard checks for missing hash selection in
justfile: 8 - crates/packages with explicit
sha256 = ...feature declarations: 31 gix-traversehash feature declarations:sha1andsha256Kind::Sha1.null()/ObjectId::null(...Sha1)occurrences outside this plan and changelogs: 79object-format=sha1fixture occurrences outside this plan: 10object-format=sha256fixture occurrences outside this plan: 0- clone path
unimplemented!()for hash mismatch: 1 - visible object-hash CLI fields: present in repo and no-repo plumbing options
cargo check -p gix --no-default-features --features sha256: fails on unconditionalKind::Sha1references ingix
Dual-hash test hooks already exist in justfile for at least:
gixgix-filtergix-diffgix-status-testsgix-commitgraphgix-objectgix-ref-testsgix-packgix-diff-testsgix-traverse-testsgix-blamegix-refspecgix-worktree-streamgix-hash
Confirmed Done
-
gix-commitgraphEvidence: issue marked it complete, dev-dependencies enablegix-hashwithsha1andsha256, andjustfileruns it withGIX_TEST_FIXTURE_HASH=sha1andsha256. -
gix-traversefeature declaration Evidence:gix-traverse/Cargo.tomlnow defines bothsha1andsha256. -
extensions.objectFormat=sha256parsing Evidence:gix/src/config/tree/sections/extensions.rsacceptssha256behind the feature, andgix/tests/gix/config/tree.rscovers lowercase and uppercase SHA256.
Remaining Hotspots
gix/src/config/cache/incubate.rsRepository object hash still falls back to SHA1 when config does not say otherwise, and the unconditionalKind::Sha1references break SHA256-onlygixbuilds.gix/src/config/tree/sections/core.rscore.abbrevvalidation still passesKind::Sha1unconditionally for a context that may compile without SHA1.gix-protocol/src/fetch/refmap/init.rsobject-formatcapability parsing still rejects anything exceptsha1.gix/src/clone/fetch/mod.rsClone still aborts on remote hash mismatch instead of configuring repo state.gix/Cargo.tomlTop-levelsha256currently forwards togix-hash,gix-pack, and optionalgix-worktree-stream, but not to all direct dependencies that define their own hash features; confirm whether this is intentional feature unification or an under-forwarding gap.gix-worktree-stream/Cargo.tomlItssha256feature forwards onlygix-hash/sha256. This may be acceptable because dependencies currently avoid SHA-specific cfgs, but it should be verified against feature-isolated builds.
Execution Order
Batch 1: hash API, features, and explicit selection
-
gix-hashRemove remaining SHA1/SHA256-shaped helper APIs whereKind-based forms can replace them. - feature propagation
Add and forward
sha256features where crates already have hash-sensitive APIs or compile guards, includinggix-traverse. -
gitoxideCLI surface Keep the clap-derived--object-hashselection on plumbing commands. - SHA256-only compile
Replace unconditional
Kind::Sha1fallbacks ingixconfig/cache paths with feature-aware defaults or required configuration. -
gix-refspecKeep object-hash-looking refspec parsing honest under SHA256-heavy inputs.
Batch 2: config and object parsing
-
gixTeachextensions.objectFormatconfig parsing to acceptsha256. -
gixDecide the correct default/fallback behavior when noextensions.objectFormatexists and SHA1 is not compiled in. -
gix-objectKeep object parsers hash-length aware and extend tests around non-SHA1 trees and related decode paths. -
gix-refExpand refs and reflog read/write coverage to both hash lengths. -
gix-indexExtend checksum and extension tests to SHA256-sized object ids. -
gix-traverseAddsha256feature support and a SHA256 fixture run injustfile.
Batch 3: protocol and transport
-
gix-transportAdd negotiation fixtures that advertiseobject-format=sha256. -
gix-protocolAccept and preserve SHA256 object-format negotiation end to end.
Batch 4: storage layer
-
gix-odbStrengthen loose/packed lookup and prefix behavior under SHA256. -
gix-packFinish pack data, index, multi-index, and verification assumptions that still lean on SHA1-shaped fixtures or sentinels.
Batch 5: porcelain behavior and sentinel cleanup
-
gixReplace clone hash-mismatchunimplemented!()with real repo initialization/configuration. -
gix-diffRemove SHA1-only sentinel assumptions where caller hash kind should drive impossible ids. -
gix-blameSame sentinel cleanup where SHA1 null ids are only placeholders. -
gix-traverseReplace remaining SHA1 defaults in traversal state with caller/repository hash kind where traversal starts from generic object ids. - broad repo sweep
Review remaining
Kind::Sha1.null()occurrences one by one and separate acceptable sentinels from real SHA1 assumptions.
Batch 6: acceptance coverage
- dual-hash refs/object read suite
- dual-hash write/read suite
- repo-level transition or conversion verification
- CI gating for SHA1 and SHA256 critical paths
Immediate Next Moves
- Fix SHA256-only
gixcompilation by removing unconditionalKind::Sha1references from config/cache code paths. - Make fetch negotiation accept
object-format=sha256. - Remove clone-time
unimplemented!()for remote hash mismatch. - Turn current scattered dual-hash tests into named acceptance criteria.
Exit Criteria
- SHA256 repository format parses through config without immediate rejection.
- SHA256-only top-level
gixbuild compiles when requested by features. - protocol negotiation can roundtrip
object-format=sha256. - clone/fetch can initialize repo state for non-SHA1 remotes without panicking or aborting.
- no important code path relies on implicit SHA1-only object-id shape.
- CI and local test entrypoints exercise both SHA1 and SHA256 where behavior differs.