Skip to content

Commit 23af41a

Browse files
authored
Merge pull request #2543 from cruessler/run-gix-worktree-stream-tests-with-sha-256
Use `GIX_TEST_FIXTURE_HASH` for `gix-worktree-stream`
2 parents fbb2e6e + b358d31 commit 23af41a

64 files changed

Lines changed: 300 additions & 236 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

etc/plan/sha256-support.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Source issue: [GitoxideLabs/gitoxide#281](https://github.com/GitoxideLabs/gitoxide/issues/281)
44
Imported on: 2026-04-22
5+
Last reconciled: 2026-04-30
56
Working assumption: checkboxes in this file reflect current checkout, not only historical issue state.
67

78
## Mission
@@ -20,9 +21,11 @@ Make object-hash kind first-class across config, protocol, storage, tests, and c
2021
- [ ] Remove hash-type specific methods from `gix-hash` and lean on `gix_hash::Kind`-parametric usage.
2122
Evidence: `gix-hash` still contains `new_sha1`, `new_sha256`, `from_20_bytes`, `from_32_bytes`, `null_sha1`, `null_sha256`.
2223
- [ ] Remove len-20 assumptions from all relevant code paths.
23-
Evidence: big progress exists, but 73 `Kind::Sha1.null()` call sites still remain, plus a few explicit 20-byte comments and helpers.
24+
Evidence: big progress exists, but 69 non-plan/non-changelog `Kind::Sha1.null()` call sites still remain, plus a few explicit 20-byte comments and helpers.
2425
- [ ] Provide visible CLI path for choosing object hash kind.
2526
Evidence: current tree has 0 `--object-hash` matches.
27+
- [ ] Propagate `sha256` feature support through crates that participate in object traversal, object parsing, and object-id storage.
28+
Evidence: only `gix-hash`, `gix-ref`, `gix-worktree-stream`, and top-level `gix` define a `sha256` feature today; `gix-traverse` only exposes `sha1`, while `justfile` compile-guards it for missing hash selection and only checks `--features sha1`.
2629
- [x] Remove default `sha1` feature from `gix-hash` and deal with fallout.
2730
Evidence: `gix-hash` has `default = []`, docs.rs explicitly enables `sha1`, root `gitoxide` chooses SHA1 via features, and `justfile` contains 31 compile-guard checks for missing hash selection.
2831
- [x] Remove SHA1 mention from `gix-features` feature toggles.
@@ -45,28 +48,35 @@ Make object-hash kind first-class across config, protocol, storage, tests, and c
4548

4649
## Current Snapshot
4750

48-
Workspace signals on 2026-04-22:
51+
Workspace signals on 2026-04-30:
4952

5053
- `gix-hash` default hash feature: removed
5154
- compile-guard checks for missing hash selection in `justfile`: 31
52-
- `Kind::Sha1.null()` occurrences: 73
55+
- crates with explicit `sha256 = ...` feature declarations: 4 (`gix-hash`, `gix-ref`, `gix-worktree-stream`, `gix`)
56+
- `gix-traverse` hash feature declarations: `sha1` only
57+
- `Kind::Sha1.null()` occurrences outside this plan and changelogs: 69
5358
- `object-format=sha1` fixture occurrences: 10
5459
- clone path `unimplemented!()` for hash mismatch: 1
5560
- `--object-hash` CLI flag matches: 0
5661

5762
Dual-hash test hooks already exist in `justfile` for at least:
5863

5964
- `gix-filter`
65+
- `gix-diff`
6066
- `gix-commitgraph`
6167
- `gix-object`
68+
- `gix-ref-tests`
6269
- `gix-pack`
70+
- `gix-diff-tests`
71+
- `gix-blame`
6372
- `gix-refspec`
73+
- `gix-worktree-stream`
6474
- `gix-hash`
6575

6676
## Confirmed Done
6777

6878
- [x] `gix-commitgraph`
69-
Evidence: issue marked it complete, crate depends on `gix-hash` with `sha1` and `sha256`, and `justfile` runs it with `GIX_TEST_FIXTURE_HASH=sha1` and `sha256`.
79+
Evidence: issue marked it complete, dev-dependencies enable `gix-hash` with `sha1` and `sha256`, and `justfile` runs it with `GIX_TEST_FIXTURE_HASH=sha1` and `sha256`.
7080

7181
## Remaining Hotspots
7282

@@ -78,13 +88,21 @@ Dual-hash test hooks already exist in `justfile` for at least:
7888
repository object hash still falls back to SHA1 when config does not say otherwise.
7989
- `gix/src/clone/fetch/mod.rs`
8090
clone still aborts on remote hash mismatch instead of configuring repo state.
91+
- `gix-traverse/Cargo.toml`
92+
only defines a `sha1` feature and docs.rs/dev-dependencies use `sha1`; there is no `sha256` feature despite traversal code carrying `ObjectId` and `object_hash` state.
93+
- `gix/Cargo.toml`
94+
top-level `sha256` currently forwards only to `gix-hash/sha256`, unlike `sha1`, which fans out to the stack including `gix-traverse/sha1`.
95+
- `gix-worktree-stream/Cargo.toml`
96+
has a `sha256` feature, but it forwards only `gix-hash/sha256`; its `sha1` feature forwards into `gix-filter`, `gix-object`, and `gix-traverse`.
8197

8298
## Execution Order
8399

84100
### Batch 1: hash API and explicit selection
85101

86102
- [ ] `gix-hash`
87103
Remove remaining SHA1/SHA256-shaped helper APIs where `Kind`-based forms can replace them.
104+
- [ ] feature propagation
105+
Add and forward `sha256` features where crates already have hash-sensitive APIs or compile guards, starting with `gix-traverse`, then the dependent stack that needs to run under SHA256.
88106
- [ ] `gitoxide` CLI surface
89107
Decide whether to restore a flag like `--object-hash` or bless config-only selection and document it clearly.
90108
- [ ] `gix-refspec`
@@ -100,6 +118,8 @@ Dual-hash test hooks already exist in `justfile` for at least:
100118
Expand refs and reflog read/write coverage to both hash lengths.
101119
- [ ] `gix-index`
102120
Extend checksum and extension tests to SHA256-sized object ids.
121+
- [ ] `gix-traverse`
122+
Add `sha256` feature support and traversal tests that parse SHA256 commit parents and tree ids instead of relying on SHA1-shaped fixtures.
103123

104124
### Batch 3: protocol and transport
105125

@@ -123,6 +143,8 @@ Dual-hash test hooks already exist in `justfile` for at least:
123143
Remove SHA1-only sentinel assumptions where caller hash kind should drive impossible ids.
124144
- [ ] `gix-blame`
125145
Same sentinel cleanup where SHA1 null ids are only placeholders.
146+
- [ ] `gix-traverse`
147+
Replace remaining SHA1 defaults in traversal state with caller/repository hash kind where traversal starts from generic object ids.
126148
- [ ] broad repo sweep
127149
Review remaining `Kind::Sha1.null()` occurrences one by one and separate acceptable sentinels from real SHA1 assumptions.
128150

@@ -136,6 +158,7 @@ Dual-hash test hooks already exist in `justfile` for at least:
136158
## Immediate Next Moves
137159

138160
- [ ] Decide whether `--object-hash` is still required as CLI UX, or whether config plus API is enough.
161+
- [ ] Add `sha256` feature support to `gix-traverse` and forward it from dependent crates.
139162
- [ ] Make `extensions.objectFormat=sha256` parse successfully.
140163
- [ ] Make fetch negotiation accept `object-format=sha256`.
141164
- [ ] Remove clone-time `unimplemented!()` for remote hash mismatch.

gitoxide-core/src/hours/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ fn parse_trailer_identity(trailer: gix::objs::commit::message::body::TrailerRef<
8383
/// Return `(commit_author, [commit_author, co_authors...])`. Use the `commit_author` for easy access to the commit author itself.
8484
fn commit_author_identities(
8585
commit_data: &[u8],
86-
hash_kind: gix::hash::Kind,
86+
object_hash: gix::hash::Kind,
8787
) -> Result<(gix::actor::SignatureRef<'_>, SmallVec<[ParsedIdentity<'_>; 2]>), gix::objs::decode::Error> {
88-
let commit = gix::objs::CommitRef::from_bytes(commit_data, hash_kind)?;
88+
let commit = gix::objs::CommitRef::from_bytes(commit_data, object_hash)?;
8989
let author = commit.author()?.trim();
9090
let mut authors = smallvec![ParsedIdentity::Borrowed(gix::actor::IdentityRef::from(author))];
9191
authors.extend(commit.co_authored_by_trailers().filter_map(parse_trailer_identity));

gitoxide-core/src/index/checkout.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ where
192192
// …but write nothing
193193
Ok(Some(gix::objs::Data {
194194
kind,
195-
hash_kind: id.kind(),
195+
object_hash: id.kind(),
196196
data: buf,
197197
}))
198198
} else {
@@ -209,7 +209,7 @@ impl gix::objs::Find for Empty {
209209
buffer.clear();
210210
Ok(Some(gix::objs::Data {
211211
kind: gix::object::Kind::Blob,
212-
hash_kind: id.kind(),
212+
object_hash: id.kind(),
213213
data: buffer,
214214
}))
215215
}

gitoxide-core/src/query/engine/update.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ pub fn update(
395395
self.progress.inc();
396396
if self.known_commits.binary_search(&id.to_owned()).is_err() {
397397
let res = {
398-
let mut parents = gix::objs::CommitRefIter::from_bytes(obj.data, obj.hash_kind).parent_ids();
398+
let mut parents = gix::objs::CommitRefIter::from_bytes(obj.data, obj.object_hash).parent_ids();
399399
let res = parents.next().map(|first_parent| (Some(first_parent), id.to_owned()));
400400
match parents.next() {
401401
Some(_) => None,

gitoxide-core/src/repository/archive.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn stream(
3434
.ok_or_else(|| anyhow!("Adding files requires a worktree directory that contains them"))?,
3535
)?;
3636
for path in add_paths {
37-
stream.add_entry_from_path(&root, &gix::path::realpath(&path)?)?;
37+
stream.add_entry_from_path(&root, &gix::path::realpath(&path)?, repo.object_hash())?;
3838
}
3939
}
4040
for (path, content) in files {

gix-archive/tests/archive.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,12 @@ mod from_tree {
240240
.map(|_| ())
241241
},
242242
);
243+
let object_hash = gix_testtools::object_hash();
243244
stream
244-
.add_entry_from_path(&dir, &dir.join("extra-file"))?
245-
.add_entry_from_path(&dir, &dir.join("extra-exe"))?
246-
.add_entry_from_path(&dir, &dir.join("extra-dir-empty"))?
247-
.add_entry_from_path(&dir, &dir.join("extra-dir").join("symlink-to-extra"))?;
245+
.add_entry_from_path(&dir, &dir.join("extra-file"), object_hash)?
246+
.add_entry_from_path(&dir, &dir.join("extra-exe"), object_hash)?
247+
.add_entry_from_path(&dir, &dir.join("extra-dir-empty"), object_hash)?
248+
.add_entry_from_path(&dir, &dir.join("extra-dir").join("symlink-to-extra"), object_hash)?;
248249

249250
let mut buf = Vec::new();
250251
if format == Format::InternalTransientNonPersistable {

gix-blame/tests/blame.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use gix_hash::ObjectId;
55
use gix_object::bstr;
66

77
fn fixture_hash_kind() -> gix_hash::Kind {
8-
gix_testtools::hash_kind_from_env().unwrap_or_default()
8+
gix_testtools::object_hash()
99
}
1010

1111
struct Baseline<'a> {

gix-diff/src/tree/function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ mod tests {
425425

426426
#[test]
427427
fn compare_select_samples() {
428-
let null = gix_testtools::hash_kind_from_env().unwrap_or_default().null();
428+
let null = gix_testtools::object_hash().null();
429429
let actual = compare(
430430
&EntryRef {
431431
mode: EntryKind::Blob.into(),

gix-diff/tests/diff/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ use gix_testtools::Result;
22
use std::collections::HashMap;
33

44
fn hex_to_id(hex_sha1: &str, hex_sha256: &str) -> gix_hash::ObjectId {
5-
match gix_testtools::hash_kind_from_env().unwrap_or_default() {
5+
match gix_testtools::object_hash() {
66
gix_hash::Kind::Sha1 => gix_hash::ObjectId::from_hex(hex_sha1.as_bytes()).expect("40 bytes hex"),
77
gix_hash::Kind::Sha256 => gix_hash::ObjectId::from_hex(hex_sha256.as_bytes()).expect("64 bytes hex"),
88
_ => unimplemented!(),
99
}
1010
}
1111

1212
fn fixture_hash_kind() -> gix_hash::Kind {
13-
gix_testtools::hash_kind_from_env().unwrap_or_default()
13+
gix_testtools::object_hash()
1414
}
1515

1616
fn open_odb(objects_dir: impl Into<std::path::PathBuf>) -> std::io::Result<gix_odb::Handle> {
@@ -162,7 +162,7 @@ mod util {
162162
buffer.extend_from_slice(data);
163163
Ok(Some(gix_object::Data {
164164
kind: gix_object::Kind::Blob,
165-
hash_kind: id.kind(),
165+
object_hash: id.kind(),
166166
data: buffer.as_slice(),
167167
}))
168168
}

gix-diff/tests/diff/tree_with_rewrites.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ fn empty_to_new_tree_without_rename_tracking() -> crate::Result {
107107
{
108108
let (lhs, rhs, mut cache, odb) = repo_with_trees(None, "c1 - initial")?;
109109
let err = gix_diff::tree_with_rewrites(
110-
TreeRefIter::from_bytes(&lhs, gix_testtools::hash_kind_from_env().unwrap_or_default()),
111-
TreeRefIter::from_bytes(&rhs, gix_testtools::hash_kind_from_env().unwrap_or_default()),
110+
TreeRefIter::from_bytes(&lhs, gix_testtools::object_hash()),
111+
TreeRefIter::from_bytes(&rhs, gix_testtools::object_hash()),
112112
&mut cache,
113113
&mut Default::default(),
114114
&odb,
@@ -1960,7 +1960,7 @@ mod util {
19601960
}
19611961

19621962
pub fn fixture_hash_kind() -> gix_hash::Kind {
1963-
gix_testtools::hash_kind_from_env().unwrap_or_default()
1963+
gix_testtools::object_hash()
19641964
}
19651965

19661966
pub fn repo_with_trees(

0 commit comments

Comments
 (0)