fix(segment): resolve a relative gitdir: pointer against its .git file's folder - #7801
Merged
JanDeDobbeleer merged 9 commits intoAug 25, 2026
Conversation
📦 Release binary size reportCompares this PR's release-equivalent build against the latest published release, per OS (amd64).
🎉 Binary size shrank on at least one platform. |
This was referenced Aug 13, 2026
JanDeDobbeleer
approved these changes
Aug 25, 2026
JanDeDobbeleer
changed the base branch from
main
to
claude/msix-appinstaller-auto-update-4893ry
August 25, 2026 09:34
Define and test a normalized worktrees/<name> shape check before discovery starts using it. This isolates classification from filesystem probing and covers Unix and Windows separator styles.
The old fixture conflates gitfile contents with the directory discovery must probe and models worktree back-references inconsistently. Separate those roles so later fixes detect the wrong resolution base without pinning directory ownership reserved for D3.
Path components named worktrees are not sufficient evidence of a linked worktree. Normalize the admin path and require its gitdir metadata to resolve back to the discovered checkout before setting IsWorkTree.
Git resolves relative gitdir pointers from the directory containing the .git file, not from the process working directory. Convert first, resolve every pointer, and retain the raw value for submodule detection.
filepath.Join concatenates absolute gitdir pointers and can poison the memoized config read. Initialize WSL command state first, then convert and resolve the pointer before reading core.bare.
A .git pointer whose spelling merely contains a modules path component took the submodule branch, so `git init --separate-git-dir` aimed at /srv/modules/project.git had repoRootDir set to the git dir instead of the working tree root and rendered .RepoName as "project.git". The shape rule that classifies /worktrees/ does not transfer: a submodule's name is its path, so it may contain separators, it may nest, and the folder in front of modules is only called .git when the superproject has no --separate-git-dir of its own. What does hold is that git records core.worktree in a submodule's git dir and never in a --separate-git-dir target, so resolving it back to the checkout is the same kind of proof the worktree branch takes from its gitdir metadata. Detection stays on the raw pointer. Testing the resolved path instead would pull every genuine worktree below a folder named modules into this branch, which is the regression the /worktrees/ ordering already avoids. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The parameter was called path, shadowing the runtime/path package that git.go imports, which gocritic's importShadow flags. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Go 1.26 lets new take an expression, which the modernize check in CI flags the helper and all 26 of its call sites for. The module already requires go 1.26.0, so the builtin is available. This step never ran in CI on this branch: the Fieldalignment step above it failed first and aborted the job, so the finding only surfaced locally. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TestEnabledInBareLayout and TestIsBareRepoResolvesPointer hardcoded
"/repo" instead of following the platform-aware TestRootPath convention
every other test in the file uses, which failed the windows-latest run.
filepath.IsAbs is the real one, not the mocked GOOS, so on a Windows
runner "/repo/.bare" has no volume name and IsAbs returns false. Checked
against go1.26.5 internal/filepathlite: volumeNameLen("/repo/.bare") is 0,
while "C:/repo/.bare" gives 2 and the remainder starts with a separator,
so both asserted fields are absolute on either platform now.
TestIsBareRepoResolvesPointer did not fail, but only by accident:
"/repo/.bare" took the Windows disk-relative branch of resolveGitPath and
landed on the same string, so its "absolute pointer" case never exercised
the absolute branch it names. Its expected config path and the path the
old filepath.Join produced are now derived from the pointer instead of
written out, so they cannot drift apart per platform.
Field order in the case struct follows fieldalignment, which CI runs
separately from golangci-lint. Its -fix pass drops comments, so the field
documentation is restored by hand.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JanDeDobbeleer
force-pushed
the
fix/git-relative-gitdir
branch
from
August 25, 2026 09:34
831f28d to
2f9ea29
Compare
JanDeDobbeleer
merged commit Aug 25, 2026
a9a2d8a
into
JanDeDobbeleer:claude/msix-appinstaller-auto-update-4893ry
13 checks passed
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7797.
Prerequisites
Description
hasWorktreestored a relativegitdir:pointer raw and only made it absolute when it started with.., so any other relative spelling (./.bare,.bare,subdir/git) resolved against the process'sworking directory instead of the directory holding the
.gitfile — the segment simply vanishedoutside that one directory, with no error.
isBareRepohad the same class of bug through a barefilepath.Joinon an already-absolute second argument.This PR:
hasWorktreeandisBareRepo,strings.LastIndex(mainSCMDir, "/worktrees/")substring test with a structuralclassifier (
worktreeAdminIndex) that validates the match is a genuine worktree administrativedirectory rather than any path merely containing the word,
/modules/submodule classifier, which had an equivalentfalse-positive: a
--separate-git-diror bare pointer under a path containing amodulescomponentwas misclassified as a submodule. The new
isModuleAdminDirverifies acore.worktreeback-referenceto the checkout instead of testing the raw string.
None of this changes behaviour for any layout that resolves correctly today — verified with new tests
covering plain clones, linked worktrees, submodules, submodule worktrees, bare repositories via a
.gitfile, and
--separate-git-dir, from multiple process working directories.This is part of a stacked series
This branch is the bottom of a four-part stack fixing related defects in the git segment's directory
handling, all opened against
main:Each of the other three branches is rebased/merged on top of this one, so their diffs will include
this PR's commits until it merges — that's expected for a stack on plain GitHub (no base-branch
retargeting available across forks). This PR itself has no dependency and can be reviewed and merged
on its own.