Skip to content

fix(discover): honor info/exclude and core.excludesFile in linked worktrees#683

Open
Naam wants to merge 1 commit into
DeusData:mainfrom
Naam:fix/worktree-info-exclude
Open

fix(discover): honor info/exclude and core.excludesFile in linked worktrees#683
Naam wants to merge 1 commit into
DeusData:mainfrom
Naam:fix/worktree-info-exclude

Conversation

@Naam

@Naam Naam commented Jun 29, 2026

Copy link
Copy Markdown

What does this PR do?

Closes #682.

In a linked git worktree, <repo>/.git is a regular file containing gitdir: <path>, not a directory. cbm_discover_ex() gated every per-clone ignore source on .git being a directory:

bool is_git_repo = wide_stat(gi_path, &gi_stat) == 0 && S_ISDIR(gi_stat.st_mode);

So when you index a worktree directly, .git/info/exclude and the global core.excludesFile are skipped, and the walker descends into directories you excluded there (build/, twister-out/, and so on). The committed .gitignore still applies because the #510 path loads <repo>/.gitignore unconditionally, which is why only the non-committed excludes broke. This is the worktree side of #489 and #499, both of which fixed the ordinary-checkout case only.

The fix resolves the git common dir up front. When .git is a gitlink file, it parses gitdir:, then follows <gitdir>/commondir to the shared directory where git keeps info/exclude and config (falling back to the gitdir itself when there is no commondir file). info/exclude and config are read from that common dir, so a worktree behaves like an ordinary checkout. A plain .git directory resolves to itself, so ordinary repos are unaffected.

Reproduce-first test discover_worktree_info_exclude fails before the change (count==2, build/ leaks) and passes after. discover_worktree_committed_gitignore guards the committed-.gitignore-in-worktree path.

Checklist

  • Every commit is signed off (git commit -s), verified locally with scripts/check-dco.sh
  • Tests pass locally (make -f Makefile.cbm test): 5714 passed, 0 failed under ASan/UBSan; discover suite 84/84
  • Lint passes (lint-format, lint-no-suppress); lint-cppcheck not run locally (cppcheck not installed), left to CI
  • New behavior is covered by a test (reproduce-first for bug fixes)

In a linked worktree, <repo>/.git is a regular file ("gitdir: <path>")
rather than a directory. cbm_discover_ex gated all per-clone ignore
sources on .git being a directory, so inside a worktree it skipped
.git/info/exclude and the global core.excludesfile entirely and walked
into directories the user had excluded there (e.g. build/, twister-out/).
Committed .gitignore still applied via the issue DeusData#510 path, which is why
the gap was easy to miss.

Resolve the git common dir up front: when .git is a gitlink file, parse
'gitdir:', then follow <gitdir>/commondir to the shared dir where git
keeps info/exclude and config (falling back to the gitdir when no
commondir file is present). info/exclude and config are then read from
that common dir, so a worktree behaves like an ordinary checkout.

Adds discover_worktree_info_exclude (fails before this change) and
discover_worktree_committed_gitignore.

Signed-off-by: Nahim El Atmani <2959826+Naam@users.noreply.github.com>
@Naam Naam requested a review from DeusData as a code owner June 29, 2026 04:11
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.

index_repository ignores .git/info/exclude and core.excludesFile inside linked git worktrees

1 participant