Skip to content

fix: resolve linked worktrees via git metadata instead of path names - #302

Open
delanym wants to merge 1 commit into
git-commit-id:masterfrom
delanym:fix/worktree-resolution
Open

fix: resolve linked worktrees via git metadata instead of path names#302
delanym wants to merge 1 commit into
git-commit-id:masterfrom
delanym:fix/worktree-resolution

Conversation

@delanym

@delanym delanym commented Sep 6, 2026

Copy link
Copy Markdown

resolveWorktree recognised a linked worktree by testing whether the resolved gitdir sat below a directory literally named .git, and then returned that main .git directory. Both halves are wrong:

  • Worktrees of a bare repository live in your-repository.git/worktrees/X (or .bare/worktrees/X), which the name test never matched. The administrative directory was then handed to the native git executable as a working directory and every build failed with fatal: this operation must be run in a work tree.

  • Where the test did match, resolution landed on the git directory shared by all worktrees. The native git executable therefore ran in the main checkout and stamped the build with that checkout's branch and commit rather than the ones of the worktree being built (#882).

Git records both locations explicitly in the administrative directory of every linked worktree: commondir points to the shared git directory and gitdir points back to the .git file inside the worktree. Reading those identifies a worktree without guessing from directory names, and works no matter what the repository directory is called.

resolveWorktree now returns the shared git directory from commondir, which keeps jgit on the location it resolved to before, and lookupGitDirectory treats a linked worktree like a submodule for the native git executable: it falls back to the unresolved .git file, whose parent is the working tree that is actually being built.

Since resolution now reads the files git wrote, a gitdir path that does not point at an existing worktree administrative directory is no longer rewritten -- the a/.git/worktrees/b noop cases in the test cover that. Relative gitdir values (worktree.useRelativePaths, git 2.48+) are resolved against the file that holds them, which the previous code only did for submodules.

jgit still reports the shared git directory for a worktree; that is #215 and unchanged here.

Fixes #301

Context

Contributor Checklist

  • Added relevant integration or unit tests to verify the changes
  • Update the Readme or any other documentation (including relevant Javadoc)
  • Ensured that tests pass locally: mvn clean package
  • Ensured that the code meets the current checkstyle coding style definition: mvn clean verify -Pcheckstyle -Dmaven.test.skip=true -B

`resolveWorktree` recognised a linked worktree by testing whether the
resolved gitdir sat below a directory literally named `.git`, and then
returned that main `.git` directory. Both halves are wrong:

* Worktrees of a bare repository live in `your-repository.git/worktrees/X`
  (or `.bare/worktrees/X`), which the name test never matched. The
  administrative directory was then handed to the native git executable as
  a working directory and every build failed with
  `fatal: this operation must be run in a work tree`.

* Where the test did match, resolution landed on the git directory shared
  by all worktrees. The native git executable therefore ran in the main
  checkout and stamped the build with that checkout's branch and commit
  rather than the ones of the worktree being built (#882).

Git records both locations explicitly in the administrative directory of
every linked worktree: `commondir` points to the shared git directory and
`gitdir` points back to the `.git` file inside the worktree. Reading those
identifies a worktree without guessing from directory names, and works no
matter what the repository directory is called.

`resolveWorktree` now returns the shared git directory from `commondir`,
which keeps jgit on the location it resolved to before, and
`lookupGitDirectory` treats a linked worktree like a submodule for the
native git executable: it falls back to the unresolved `.git` file, whose
parent is the working tree that is actually being built.

Since resolution now reads the files git wrote, a gitdir path that does not
point at an existing worktree administrative directory is no longer
rewritten -- the `a/.git/worktrees/b` noop cases in the test cover that.
Relative `gitdir` values (`worktree.useRelativePaths`, git 2.48+) are
resolved against the file that holds them, which the previous code only did
for submodules.

jgit still reports the shared git directory for a worktree; that is git-commit-id#215
and unchanged here.

Fixes git-commit-id#301
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

resolveWorktree only matches a parent named .git, so worktrees of a bare repository fail

1 participant