42 lines
1.9 KiB
Markdown
42 lines
1.9 KiB
Markdown
---
|
|
name: gitignore-trailing-slash-symlink-contamination
|
|
description: "Trailing-slash gitignore rules don't match symlinks, so worktree dependency symlinks get committed; detect with git ls-tree mode 120000, fix with git rm --cached."
|
|
---
|
|
|
|
A `.gitignore` entry written with a **trailing slash matches directories only**. A symlink of the same name is not a directory, so it slips past the rule, and `git add -A` in a `git worktree` checkout silently **tracks** it. Cost measured 2026-10-19: a machine-specific symlink (`node_modules -> /home/blank/Projects/dankvoice/node_modules`) landed in `main` with a merged PR.
|
|
|
|
Why worktrees are the trigger: a worktree has no `node_modules` (or other installed-deps dir) of its own, so the cheap way to make build/test work there is a symlink into the primary checkout. With `node_modules/` ignored, nothing complains.
|
|
|
|
## Detect
|
|
|
|
```bash
|
|
git ls-tree HEAD -- node_modules # mode 120000 == tracked symlink
|
|
git ls-files -s | awk '$1==120000' # every tracked symlink in the index
|
|
```
|
|
|
|
## Fix (branch, never on main directly)
|
|
|
|
```bash
|
|
git rm -q --cached node_modules # untrack; leaves the file on disk
|
|
```
|
|
|
|
plus relax the ignore rule to the slash-free form, with the reason inline so nobody re-adds the slash:
|
|
|
|
```
|
|
# Trailing slash would only match directories: a node_modules symlink (the
|
|
# shape `git worktree` checkouts end up with) slips past it and gets tracked.
|
|
node_modules
|
|
```
|
|
|
|
Then `git check-ignore -v node_modules` must print the rule, and the suite runs after (the symlink still resolves, it is just ignored).
|
|
|
|
## Prevent
|
|
|
|
In a fresh worktree, create the deps symlink **after** confirming the ignore rule has no trailing slash:
|
|
|
|
```bash
|
|
git check-ignore -v node_modules || sed -i 's|^node_modules/$|node_modules|' .gitignore
|
|
```
|
|
|
|
Same class for any ignored-by-convention dir that a worktree might provide as a link: `node_modules`, `vendor`, `.venv`, `target`, `dist` when built artifacts are ignored.
|