Skip to content

fix(core): resolve git rerun paths so worktree builds stay fresh - #4947

Merged
pimlock merged 1 commit into
mainfrom
fix-worktree-build-rerun/pimlock
Oct 30, 2026
Merged

pimlock merged 1 commit into
mainfrom
fix-worktree-build-rerun/pimlock

Conversation

@pimlock

@pimlock pimlock commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Every cargo command in a git worktree rebuilt openshell-core and everything that depends on it, even with no changes. mise run rust:lint re-clippied the whole workspace on each run, which made the pre-commit hook take minutes.

The cause is in openshell-core/build.rs. It tells cargo to watch ../../.git/HEAD and a few other files under ../../.git/. In a worktree .git is a small file, not a directory, so those paths don't exist. Cargo treats a missing watched path as changed and reruns the build script every time. The fingerprint log shows it as MissingFile { path: ".../crates/openshell-core/../../.git/HEAD" }.

This PR asks git where those files really are.

Background

The build script bakes a version like 0.1.6-dev.51+g5aea12245 into the binaries. It derives it from git: the last release tag, the number of commits since, and the short SHA. The watched paths make cargo recompute it after a commit or a new tag. Without them the version would go stale.

History of the watched paths:

All of them assume .git is a directory at the repo root. That's only true for the main checkout. Linked worktrees (including ones made from a bare repo), submodules, and --separate-git-dir clones all have a .git file like this one:

gitdir: /home/me/OpenShell/.git/worktrees/<name>

That directory holds the worktree's own HEAD and logs/HEAD. Branches, tags and packed-refs stay in the main .git, which git calls the common dir. git rev-parse --git-dir and git rev-parse --git-common-dir return the right directory in every layout. In a normal clone both return the same .git as before, so rebuild behavior there doesn't change.

Related Issue

No issue required. This is a small build-script fix.

Changes

  • Watch HEAD and logs/HEAD in the directory from git rev-parse --git-dir.
  • Watch refs/tags, packed-refs and the checked-out branch ref in the directory from git rev-parse --git-common-dir.
  • Watch the branch ref because a new worktree has no logs/HEAD until its first commit, and the HEAD file doesn't change when you commit on a branch.
  • Emit only paths that exist. Without git (Docker builds, source tarballs) the script watches nothing and the version falls back as before. The version logic itself is unchanged.

Testing

  • mise run pre-commit passes
  • Unit tests added/updated
  • E2E tests added/updated (if applicable)

I ran cargo clippy -p openshell-core --all-targets -- -D warnings in a worktree:

  • A second run right after the first finished in 0.17 s and didn't rebuild openshell-core.
  • A new commit triggered a rebuild, and the version went from 0.1.6-dev.50+gc4688aa87 to 0.1.6-dev.51+g5aea12245.
  • Creating a tag triggered a rebuild, and so did deleting it.

I also timed mise run rust:lint in a worktree, with a shared sccache dir. Each run touched one file first, or none for the first row. Each build.rs version got one warm-up run.

Touched file Before After openshell crates re-checked (before → after)
None 44 s 3.3 s 49 → 0
openshell-cli/src/main.rs 44.1 s 4.3 s 49 → 1
openshell-server/src/lib.rs 44.9 s 20.6 s 49 → 3
openshell-policy/src/lib.rs 46.1 s 25.6 s 49 → 19
openshell-core/src/lib.rs 44.8 s 41.0 s 49 → 49

The last column is summed over the 7 clippy commands in rust:lint. Before the fix every run re-checked the whole workspace, whatever changed. After it, only the touched crate and the crates that depend on it are re-checked. sccache doesn't help here because it doesn't cache clippy: every run reported 0 cache hits.

The main checkout was never affected, since the old ../../.git paths exist there.

In the main checkout I confirmed both git commands point at the same .git paths the old code used. I didn't build there.

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)

In a git worktree .git is a file, so the hard-coded ../../.git/* rerun-if-changed
paths never exist and cargo rebuilds openshell-core and every dependent crate
on each invocation. Resolve HEAD and logs/HEAD from the git dir and tag refs,
packed-refs, and the checked-out branch ref from the common git dir, and only
emit paths that exist.

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
@pimlock
pimlock added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit c2311ad Oct 30, 2026
86 checks passed
@pimlock
pimlock deleted the fix-worktree-build-rerun/pimlock branch October 30, 2026 22:22
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.

2 participants