Files
command-center/agent/managed-skills/gitignore-trailing-slash-symlink-contamination/SKILL.md
T

1.9 KiB

name, description
name description
gitignore-trailing-slash-symlink-contamination 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

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)

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:

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.