Skip to content

chore(worktree): keep Claude Code worktrees out of the working tree - #9

Merged
anilcancakir merged 3 commits into
developfrom
chore/worktree-layout
Sep 3, 2026
Merged

chore(worktree): keep Claude Code worktrees out of the working tree#9
anilcancakir merged 3 commits into
developfrom
chore/worktree-layout

Conversation

@anilcancakir

Copy link
Copy Markdown
Contributor

What

.gitignore: ignore .claude/worktrees/ (only that subdirectory; the rules under .claude/ stay tracked).

Why

Worktrees were opened beside the checkout as <repo>-<slug>, so they landed in the workspace directory next to the real repositories, and Claude Code's EnterWorktree could not be used at all: it writes to a fixed .claude/worktrees/<slug>. With them inside the repository, git has to be told to ignore them.

No .worktreeinclude here, because this repository keeps no pubspec_overrides.yaml; there is nothing gitignored that a worktree would need. Sibling repositories that do carry one get that file too, see fluttersdk/magic_starter#124.

Testing

Config only. No Dart, YAML or lib/ file is touched, so analyze, format and test have nothing to say about this diff.

Worktrees used to sit beside the checkout as <repo>-<slug>, which put them in the workspace directory next to the real repositories and left EnterWorktree unusable, since that tool writes to a fixed .claude/worktrees/<slug>. Pattern proven on fluttersdk/magic_starter#124.
@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kodizm

kodizm Bot commented Sep 3, 2026

Copy link
Copy Markdown

Note

Kodizm (AI-generated). May contain mistakes; verify before acting.

A five-line .gitignore addition that does exactly what it says; the ignore rule is correctly scoped and nothing downstream is affected.

Minor

.gitignore:41-42 — The comment says "the rest of .claude/ is tracked, because the rules under it are part of the repository", but this repository tracks nothing under .claude/ today (git ls-files .claude returns 0 files). The rule itself is right; the justification describes a sibling repository's state, not this one. Maintainability only. (Also worth knowing: .pubignore:52 already excludes all of .claude/, so nothing needs adding there for publishing.)

Tests

Config-only change with no test surface, which matches the description. Verified behaviourally instead, see below.

Checks I ran

  • git check-ignore -v .claude/worktrees/foo.gitignore:43:.claude/worktrees/, so the pattern matches, and .claude/rules/x is not matched: the scoping is correct.
  • git ls-files .claude | wc -l0, the basis for the Minor above.
  • git status --porcelain → clean, no tracked file becomes ignored by this change.
  • Simulated a worktree at .claude/worktrees/slug/ (with its own pubspec.yaml, as a real git worktree of this repo would have) and ran dart analyze and dart format --output=none --set-exit-if-changed . at the root: neither reported a single path under worktrees/, because the nested pubspec makes it a separate analysis context. So placing worktrees inside the checkout does not pollute local analyze or format runs. CI is unaffected regardless, since .github/workflows/ci.yml:27,30 scopes both to lib/ test/.
  • The diff also removes the missing trailing newline on the old last line, which is a tidy-up rather than a behaviour change.

@anilcancakir

Copy link
Copy Markdown
Contributor Author

Fixed. git ls-files .claude returns nothing here, so the comment described a sibling repository rather than this one. It now says only that subdirectory is ignored, so anything else landing under .claude/ stays visible to git, and that nothing is tracked there today.

Also noted your .pubignore:52 point: nothing needed adding there.

@kodizm

kodizm Bot commented Sep 3, 2026

Copy link
Copy Markdown

Note

Kodizm (AI-generated). May contain mistakes; verify before acting.

Since my last review the ignore rule itself is unchanged and still correct; the new commit only rewrites the comment above it, and two things in that new prose are off.

The .claude tracking claim I raised is fixed, thanks. Reviewing only the comment rewrite in 6e4a5ba.

Minor

.gitignore:42 — Stray # glued to the end of Nothing is tracked there today.#. It looks like an intended blank comment separator that lost its newline; harmless to git, but it reads as a typo in a file whose whole purpose here is explanation. (maintainability)

.gitignore:45-46 — The claim "A worktree's .git is a file rather than a directory, so git's nested-repo guard does not stop it" is the wrong way round: git's guard resolves gitfiles too, so plain git clean -xdf does skip a nested worktree and leaves it intact. The hazard the comment describes only appears at -xdff. As written it warns about the wrong command, so someone reasoning from it would draw the wrong conclusion about which invocation is safe. (maintainability)

Tests

Comment-only change, no test surface. Verified the claim behaviourally instead, below.

Checks I ran

  • Built a throwaway repo with a worktree at .claude/worktrees/slug (git 2.43.0) and ran git clean -xdfSkipping repository .claude/worktrees/slug, and the worktree checkout plus .git/worktrees/slug both survived. Re-running with git clean -xdffRemoving .claude/, which does destroy it. That pair is the basis for the second finding.
  • git check-ignore -v .claude/worktrees/foo.gitignore:47:.claude/worktrees/; .claude/rules/x still not matched, so the scoping is unchanged and correct.
  • git status --porcelain → clean; git ls-files .claude0, consistent with the new comment's "nothing is tracked there today".

The comment claimed plain -xdf wipes a live worktree because its .git is a file rather than a directory. Measured on a scratch repo: the dry run prints "Skipping repository .claude/worktrees/slug", the worktree survives -xdf with its untracked files intact, and only -xdff removes it and leaves the registration prunable. The guard keys on the gitlink, not on the form of .git. Also splits the stray # that joined the two comment blocks.
@anilcancakir

Copy link
Copy Markdown
Contributor Author

You are right and I had it backwards. Reproduced your probe independently before changing anything:

$ git clean -xdf --dry-run
Skipping repository .claude/worktrees/slug

$ git clean -xdf        # worktree intact, its untracked scratch file too
$ ls .claude/worktrees/slug/
untracked.txt

$ git clean -xdff       # gone
$ git worktree list --porcelain | grep -c prunable
1

So the guard keys on the gitlink, exactly as you said, and my stated reason (that a file-form .git slips past it) was wrong as well as the command. The comment now says -xdf leaves them alone and names -xdff as the one that does not, with the "Skipping repository" line quoted so the next reader can recognise it.

The stray # is fixed in the same commit; it came from joining two comment blocks without the separating newline, and it went out to every repository in this sweep, so the fix did too.

@kodizm

kodizm Bot commented Sep 3, 2026

Copy link
Copy Markdown

Note

Kodizm (AI-generated). May contain mistakes; verify before acting.

Both findings from my last review are fixed and the new comment now matches the behaviour I measured; nothing else to raise.

Since 6e4a5ba the only change is the comment block above the ignore rule. The stray # is gone, and the git clean prose is now the right way round: -xdf skips a nested worktree with "Skipping repository ...", -xdff is the one that wipes it and leaves a registration for git worktree prune. That matches the reproduction in my previous review and yours. The ignore pattern itself is untouched.

Tests

Comment-only change on a config file, so no test surface, as the description says.

Checks I ran

  • git check-ignore -v .claude/worktrees/foo.gitignore:49:.claude/worktrees/; .claude/rules/x still not matched, so the scoping is unchanged and correct.
  • git status --porcelain → clean; git ls-files .claude0, consistent with "Nothing is tracked there today."
  • tail -c 1 .gitignore | od -c\n, so the file still ends with a newline.
  • I did not re-run the git clean -xdf / -xdff probe this round (the sandbox declined the temp-repo command); I am relying on the run from my previous review, which produced exactly the "Skipping repository" line the new comment quotes.

@anilcancakir
anilcancakir merged commit e30a8ed into develop Sep 3, 2026
4 checks passed
@anilcancakir
anilcancakir deleted the chore/worktree-layout branch September 3, 2026 18:04
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.

1 participant