Skip to content

fix: make the init-repo test fixture collision-proof under parallel threads - #25

Merged
ashproto merged 2 commits into
nextfrom
fix/flaky-init-repo-tempdir
Aug 8, 2026
Merged

fix: make the init-repo test fixture collision-proof under parallel threads#25
ashproto merged 2 commits into
nextfrom
fix/flaky-init-repo-tempdir

Conversation

@ashproto

@ashproto ashproto commented Aug 8, 2026

Copy link
Copy Markdown
Owner

What

cargo test intermittently failed one of the four git_ops::tests::initialize_repository_* tests. Pre-existing flake, unrelated to any feature work.

Cause

TempFolder::new() built its path as git-it-init-test-{pid}-{nanos} and then called fs::create_dir(&path).unwrap(). All four tests run on parallel threads in one process, so the pid is shared and two threads can read the same nanosecond; create_dir then fails with AlreadyExists and the unwrap() panics. A different one of the four failed on each run, which is what made it look random.

Fix

Replace the wall-clock stamp with a process-wide AtomicU32 counter — the pattern the TempRepo fixtures in ops.rs and ops_worktree.rs already use. pid + counter cannot collide by construction.

Kept create_dir over create_dir_all deliberately: a collision is now impossible, so if one ever happens it should panic loudly rather than be absorbed. The now-unused SystemTime/UNIX_EPOCH import is removed.

Test plan

  • cargo test -p git-core initialize_repository -- --test-threads=1 — 4/4 pass
  • Five consecutive full cargo test runs, all green (the flake needed repetition to surface)
  • Rebuild produces no new warnings; the two that appear (git_may_fail, read_file) are pre-existing dead test helpers in other files

Note

Other TempRepo fixtures (ops_rewrite.rs, ops_remote.rs, graph.rs, ops_merge.rs) each define their own. Any that derive uniqueness from a timestamp rather than a counter could flake the same way under enough parallelism — not touched here since none are currently failing.

🤖 Generated with Claude Code

…hreads

TempFolder::new() named its directory git-it-init-test-{pid}-{nanos}. The
four initialize_repository tests run on parallel threads in one process, so
the pid is shared and two threads could read the same nanosecond; fs::create_dir
then failed with AlreadyExists and the unwrap() panicked. A different one of
the four failed on each run, which is what made it look random.

Replace the wall-clock stamp with a process-wide AtomicU32 counter, matching
the TempRepo fixtures in ops.rs and ops_worktree.rs. pid + counter cannot
collide by construction, so create_dir is kept over create_dir_all: a
collision should now be impossible, and would be a real bug worth panicking on.

Verified with five consecutive full cargo test runs, all green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4480001d54

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/git-core/src/git_ops.rs Outdated
The previous commit claimed pid + counter "cannot collide by construction"
and kept `create_dir` over `create_dir_all` on that basis. That reasoning
only holds among LIVE processes. The counter restarts at zero every run, so
uniqueness rests entirely on the pid never repeating — and a pid is unique
only while its process is alive. A run killed before `Drop` (Ctrl-C on
cargo test, or a panic=abort) leaves its directories behind; once the OS
recycles that pid, a fresh process counting from zero reproduces the exact
same path and `create_dir(...).unwrap()` panics with AlreadyExists.

Not hypothetical: this machine currently holds 36 orphaned `gte-*` fixture
directories spanning 18 distinct pids.

Remove any leftover first, then `create_dir_all` — the same two lines the
TempRepo fixtures in ops.rs, ops_worktree.rs, ops_merge.rs, ops_rewrite.rs
and graph.rs already use. Those fixtures were right and this one was the
outlier; the extra line is the point, not redundancy.

Reported by Codex review on #25. cargo test -p git-core: 183 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ashproto ashproto added the skip-build Infra/bootstrap PR: skip release build; may target main directly label Aug 8, 2026
@ashproto
ashproto merged commit 67db4c7 into next Aug 8, 2026
2 checks passed
ashproto added a commit that referenced this pull request Aug 9, 2026
`chmod +x` plus an edited line is one diff with one file header, and git puts
`old mode`/`new mode` in that header. Discard reverse-applies the header to the
working tree, and `git apply` honours a mode pair — so "Discard 1 line" also
took the executable bit off. Not in the confirmation, not in the line count,
and not undoable.

Verified against real git: reverse-applying the header with the mode pair took
f.sh from 755 to 644 while reverting the text; dropping the two mode lines left
755 and reverted the text just the same.

Codex flagged `discard_lines`. `discard_hunk` reverse-applies the same header
and loses the bit identically, so both destructive ops now build a content-only
header. Stage and unstage keep the mode deliberately: there it belongs to the
same index entry the caller is moving, and the result is recoverable either way.

cargo test -p git-core: 222 passed (the one failure in a full run is the
`git_ops.rs` init-repo flake, fixed on `next` by #25 and merged in next commit).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ashproto added a commit that referenced this pull request Aug 9, 2026
Picks up #25's init-repo fixture fix so this branch's CI stops rolling the
`git_ops::tests::initialize_repository_*` dice.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-build Infra/bootstrap PR: skip release build; may target main directly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant