Skip to content

gix: negotiate and adopt sha256 object format#2642

Merged
Sebastian Thiel (Byron) merged 10 commits into
GitoxideLabs:mainfrom
10ne1:dev/aratiu/sha256-transport
Jun 22, 2026
Merged

gix: negotiate and adopt sha256 object format#2642
Sebastian Thiel (Byron) merged 10 commits into
GitoxideLabs:mainfrom
10ne1:dev/aratiu/sha256-transport

Conversation

@10ne1

@10ne1 Adrian Ratiu (10ne1) commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

What

This teaches the v2 protocol fetch client to negotiate object-format with sha256 remotes and to adopt the remote object format when cloning. Before this, gix assumed sha1 during protocol negotiation and hit an unimplemented panic when a clone target turned out to use sha256.

This addresses the gix-protocol line item of Batch 3 in #281:

Accept and preserve SHA256 object-format negotiation end to end.

Testing

These tests were suggested by Sebastian Thiel (@Byron), so I also added their equivalent to the justfile:

GIX_TEST_FIXTURE_HASH=sha256 cargo nextest run -p gix --features async-network-client --no-fail-fast
GIX_TEST_FIXTURE_HASH=sha256 cargo nextest run -p gix --features blocking-network-client --no-fail-fast

AI disclosure
This PR was written with the help of Claude Code, but was not vibe-coded. I'm not a fan of vibe-coding. I used AI to better understand the codebase myself (asked it a lot of questions), review both my code and the code generated by AI, used it especially to detect bugs and corner-cases and suggest fixes, however I very carefully reviewed & edited each code/comment lines, the commit messages and so on, until I was satisfied with the result.


Byron's Tasks

  • initial refackiew
  • see if Attempt can be removed, as it does affect callers apparently (*progress).
  • journey tests maybe?

Copilot AI review requested due to automatic review settings June 11, 2026 17:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR adds SHA-256 object-format awareness to fetch/clone flows (notably protocol v2), including automatically adopting a remote’s object format during a fresh clone, and extends the test suite/fixtures to cover SHA-256 scenarios.

Changes:

  • Echo object-format in protocol v2 commands and parse server-advertised object-format into the fetch ref-map.
  • Teach clone::fetch_only to adopt a remote’s object hash (SHA-256) during initial clone by reinitializing/reopening the empty repo and retrying.
  • Add fixtures and tests (including nextest matrix updates) to validate SHA-256 behavior across protocol/refmap/clone.

Reviewed changes

Copilot reviewed 12 out of 16 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
justfile Runs gix-protocol tests with additional sha256 feature combinations.
gix/tests/gix/util.rs Extends SHA1↔SHA256 fixture hash mapping for tests.
gix/tests/gix/clone.rs Stabilizes shallow ID comparisons; adds SHA-256 clone adoption test.
gix/tests/fixtures/make_sha256_remote.sh Adds a deterministic SHA-256 remote fixture generator.
gix/src/remote/connection/fetch/update_refs/tests.rs Makes tests hash-kind agnostic; fixes NULL handling for SHA-256.
gix/src/clone/fetch/util.rs Adds repo reinitialization helper to adopt remote object format.
gix/src/clone/fetch/mod.rs Implements adopt-and-retry on object-format mismatch during fetch_only.
gix-worktree-stream/tests/fixtures/generated-archives/.gitignore Ignores a new SHA-256 generated fixture archive.
gix-protocol/tests/protocol/fetch/v2.rs Updates v2 request expectations; adds SHA-256 v2 test.
gix-protocol/tests/protocol/fetch/ref_map.rs Adds unit tests for object-format capability parsing.
gix-protocol/src/fetch/refmap/init.rs Parses object-format into gix_hash::Kind and uses hash-specific null IDs.
gix-protocol/src/command.rs Echoes server object-format in all v2 commands; validates it as an allowed feature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread gix/src/clone/fetch/util.rs Outdated
Comment thread gix/src/clone/fetch/util.rs Outdated
Comment thread gix/src/clone/fetch/util.rs
Comment thread gix/tests/fixtures/make_sha256_remote.sh Outdated
Comment thread justfile
Comment thread gix-protocol/tests/protocol/fetch/v2.rs
Comment thread gix/src/clone/fetch/mod.rs
@10ne1
Adrian Ratiu (10ne1) force-pushed the dev/aratiu/sha256-transport branch from 51c5f0e to 73c1cdf Compare June 12, 2026 16:46
Copilot AI review requested due to automatic review settings June 12, 2026 17:07
@10ne1
Adrian Ratiu (10ne1) force-pushed the dev/aratiu/sha256-transport branch from 73c1cdf to 8cb8290 Compare June 12, 2026 17:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 16 changed files in this pull request and generated 6 comments.

Comment thread gix/src/remote/connection/fetch/update_refs/tests.rs Outdated
Comment thread gix/src/remote/connection/fetch/update_refs/tests.rs
Comment thread gix/src/remote/connection/fetch/update_refs/tests.rs
Comment thread gix/src/clone/fetch/util.rs
Comment thread gix/src/clone/fetch/util.rs Outdated
Comment thread gix/src/clone/fetch/mod.rs
@10ne1

Copy link
Copy Markdown
Contributor Author

I reworded the commit message subject prefixes to follow the Gitoxide conventions (added fix: to a few commits). No code changes.

Adrian Ratiu (10ne1) and others added 6 commits June 21, 2026 19:22
RefMap::from_refs only recognized sha1, so it refused to talk to
sha256 remotes even with the sha256 feature on.

Parse the server's object-format instead, accepting any hash the
build supports. When the server omits the capability, default to
Sha1 if available, otherwise report UnknownObjectFormat.

This also replaces a hardcoded `Kind::Sha1` null placeholder, which
did not compile in sha256-only builds, with the resolved hash.

Tests cover the sha1, sha256, unknown, and missing cases.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>
A v2 client must report its object format to the server, otherwise the
server assumes SHA-1 and aborts the request with a "mismatched object
format" error when talking to a SHA-256 repository.

This affects both ls-refs and fetch. A persistent connection retains the
object format negotiated during ls-refs, but a stateless transport like
HTTP sends each command as its own request, so every v2 command must echo
the object-format the server advertised.

So add the echo to `Command::default_features` so it applies to every v2
command and permit object-format during v2 feature validation.

Also add v2 wire-format sha256 tests for ls-refs and ref-in-want.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>
A clone into a freshly initialized repository hit an `unimplemented!`
panic when the remote used sha256, since the local repository defaults
to sha1.

Reconfigure the still-empty local repository to the remote's object
format and retry the fetch, matching git's behavior of inheriting
the remote's hash on clone.

Without the sha256 feature gix_hash::Kind has a single variant, so the
local and remote hashes can never differ; the mismatch check is compiled
out entirely in that case.

Co-Authored-By: Claude Fable 5 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>
The clone fetch loop adopts the remote's object format and retries when
it differs from the freshly initialized local repository. Adoption makes
the next iteration's hashes match, but if the reopened repository somehow
still disagrees the loop would re-handshake forever. Track whether we
already retried and fail with IncompatibleObjectHash on a second mismatch
instead. The error variant is introduced here, as this is its only user.

Also silence clippy::never_loop on default (sha1) features, where the
sha256-gated `continue` is absent and the loop always returns first pass.

Co-Authored-By: Claude Fable 5 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>
Add a dedicated test for the clone-time object-format adoption.

Basically a fixture remote created with --object-format=sha256
independent of GIX_TEST_FIXTURE_HASH gets cloned into a fresh
SHA-1-default repository which must adopt the remote format.

The test asserts the adopted format both in memory and as
persisted on disk, and that the remote is written exactly once
despite the adoption retry.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>
Derive expected object ids from the fixture repo instead of hardcoding
SHA-1 hex, so the update_refs tests pass under both SHA-1 and SHA-256
fixtures (GIX_TEST_FIXTURE_HASH).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>
@Byron
Sebastian Thiel (Byron) force-pushed the dev/aratiu/sha256-transport branch from 9758eff to b439eaa Compare June 21, 2026 11:27
Copilot AI review requested due to automatic review settings June 21, 2026 11:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 16 changed files in this pull request and generated 2 comments.

Comment thread gix-protocol/tests/protocol/fetch/v2.rs
Comment thread gix/src/clone/fetch/util.rs Outdated
The fetch_pack tests assert on pack data and index checksums, which are
hash-algorithm dependent. Add the SHA-256 equivalents so the tests pass
under GIX_TEST_FIXTURE_HASH=sha256.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>

compare shallow boundary commits order-independently

The on-disk order of shallow boundary commits is hash-dependent. This
means that inside a hash alorithm the commit order is deterministic and
it reshuffless across hashes.

E.g. a commit which sorts 1st under sha1 might sort 3rd under sha256.

This is the reason why the clone shallow/unshallow tests fail under
sha256 when comparing against the sha1-ordered expectations, due to the
hex_to_id() calls preserving the sha1-ordering even when converting the
hashes to sha256.

Thus we sort the expected side before comparing.

Note: only the expected side needs sorting, as the actual side already
comes sorted by gix_shallow::read.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>

add generated sha256 archive for symlink-prefix-reuse fixture

Adds the SHA-256 variant of the make_symlink_prefix_reuse_advisory
fixture archive, matching its committed SHA-1 sibling. Contains no
host-absolute paths, so it is safe to track.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>

do not track the sha256 basic fixture archive

This mirrors the existing basic.tar file exclusion.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Adrian Ratiu <[email protected]>
@Byron
Sebastian Thiel (Byron) force-pushed the dev/aratiu/sha256-transport branch from b439eaa to 0ed353f Compare June 21, 2026 16:03
@Byron

Sebastian Thiel (Byron) commented Jun 21, 2026

Copy link
Copy Markdown
Member

Thanks!

I couldn't believe my eyes when I couldn't find these lines in the justfile, I genuinely thought I accidentally removed them.

GIX_TEST_FIXTURE_HASH=sha256 cargo nextest run -p gix --features async-network-client --no-fail-fast
GIX_TEST_FIXTURE_HASH=sha256 cargo nextest run -p gix --features blocking-network-client --no-fail-fast

After all, they are needed to run the changes introduced to gix.

@10ne1

Adrian Ratiu (10ne1) commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

I couldn't believe my eyes when I couldn't find these lines in the justfile, I genuinely thought I accidentally removed them.

GIX_TEST_FIXTURE_HASH=sha256 cargo nextest run -p gix --features async-network-client --no-fail-fast
GIX_TEST_FIXTURE_HASH=sha256 cargo nextest run -p gix --features blocking-network-client --no-fail-fast

After all, they are needed to run the changes introduced to gix.

Sebastian Thiel (@Byron) Yes, I added them in this commit (right at the end): 9067bcb

Perhaps I should have explicitly added them in a separate commit. 🙂

Edit: They seem to be present in your latest push: 0ed353f

@Byron

Sebastian Thiel (Byron) commented Jun 21, 2026

Copy link
Copy Markdown
Member

Adrian Ratiu (@10ne1) 9067bcb just adds them for gix-protocol, gix was missing. The review commit (which somehow has an extra file curtesy of my editor) adds these test-runs.

In any case, I'd expect this to PR to merge soon.

@Byron
Sebastian Thiel (Byron) force-pushed the dev/aratiu/sha256-transport branch from 0ed353f to e9445c7 Compare June 21, 2026 23:26
Copilot AI review requested due to automatic review settings June 21, 2026 23:26
@Byron
Sebastian Thiel (Byron) force-pushed the dev/aratiu/sha256-transport branch from e9445c7 to 3262d99 Compare June 21, 2026 23:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 21 changed files in this pull request and generated 1 comment.

Comment thread justfile Outdated
Copilot AI review requested due to automatic review settings June 21, 2026 23:34
@Byron
Sebastian Thiel (Byron) force-pushed the dev/aratiu/sha256-transport branch from 3262d99 to ea0f627 Compare June 21, 2026 23:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 21 changed files in this pull request and generated 1 comment.

Comment thread gix/src/clone/fetch/util.rs
The major change is to actually run the `gix` tests for the affected code.

Co-authored-by: Sebastian Thiel <[email protected]>
@Byron
Sebastian Thiel (Byron) force-pushed the dev/aratiu/sha256-transport branch 2 times, most recently from b866ed3 to c6789d3 Compare June 22, 2026 06:49
Copilot AI review requested due to automatic review settings June 22, 2026 06:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 32 changed files in this pull request and generated 6 comments.

Comment thread gix/src/clone/fetch/mod.rs
Comment thread gix/src/clone/fetch/mod.rs Outdated
Comment thread justfile
Comment thread tests/fixtures/generated-archives/.gitignore
Comment thread gix/tests/fixtures/generated-archives/.gitignore
Comment thread gix/src/clone/fetch/util.rs
@Byron
Sebastian Thiel (Byron) force-pushed the dev/aratiu/sha256-transport branch from c6789d3 to 2bf6a59 Compare June 22, 2026 07:22
Sebastian Thiel (Byron) and others added 2 commits June 22, 2026 15:42
…olled hash kind.

Connections can now be created from detached remotes, internally,
which makes them independent of the underlying repository.

This is breaking as it comes with a cleanup of `Connection` lifetimes,
which will break anyone who stores them in a struct. So hopefully
nobody is affected.

Co-authored-by: Sebastian Thiel <[email protected]>

address auto-review
Copilot AI review requested due to automatic review settings June 22, 2026 07:42
@Byron
Sebastian Thiel (Byron) force-pushed the dev/aratiu/sha256-transport branch from 2bf6a59 to 3927d70 Compare June 22, 2026 07:42

@Byron Sebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that's it 🎉!

The Attempt workaround was removed in favor of the refactoring that was needed to be able to change/reopen the repository in place. In future, that's even more important as it will also have to deal with reftable.
Due to not using Attempt, it will be avoiding to redo the entire fetch operation.
And as a side-effect, a long-standing Connection lifetime bug was also fixed.

Journey tests were added as well, proving that SHA-256 transport and protocol parts now work. I also validated that manually, awing at the SHA-256 references provided by the remote.

Will merge soon.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 33 changed files in this pull request and generated 2 comments.

Comment thread gix-protocol/tests/protocol/fetch/ref_map.rs
Comment thread gix/src/remote/connection/mod.rs
@Byron
Sebastian Thiel (Byron) merged commit da6b267 into GitoxideLabs:main Jun 22, 2026
32 checks passed
@10ne1
Adrian Ratiu (10ne1) deleted the dev/aratiu/sha256-transport branch June 25, 2026 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants