pub fn tracked(path: &Path) -> TrackedExpand description
Ask git whether it tracks path.
Asked as git -C <parent> ls-files --error-unmatch -- <file-name>, and the
two halves of that are both deliberate.
The BASENAME, not the absolute path. git normalises a pathspec
LEXICALLY, but resolves its working directory PHYSICALLY. When .git/hooks
is a symlink into the working tree — the setup at the centre of both
incidents — handing git the absolute path <repo>/.git/hooks/pre-commit
gets exit 1, pathspec did not match, because no such path exists in the
index under that spelling. Handing it pre-commit from -C <repo>/.git/hooks resolves through the link to <repo>/devhooks/pre-commit
and gets exit 0. Same file, same question, opposite answers: the
absolute-path form silently reports every hook reached through a symlinked
directory as untracked. (amont-fleet’s own fix::is_tracked still asks
the absolute-path way, and has this hole.)
The exit code, not status.success(). git distinguishes them and the
distinction is the whole point:
0— tracked.1— the pathspec matched nothing in the index. Untracked. This is also what a hook under a plain.git/hooksreturns, since.gitis outside the working tree.128+ “not a git repository” — no repository at all. Treated as untracked: the test fixtures throughout this suite build hook directories in bare temp dirs, and refusing those would make every one of them fail for a reason unrelated to what it tests.- anything else — spawn failure,
detected dubious ownership, a broken.git, a permissions error.Tracked::Unknown, which refuses.
The dubious ownership case is the one worth naming out loud, because it is
common (a repo owned by another uid, which is every repo inside a container
bind mount) and because it produces a fatal: that a success() check reads
as a clean “no”. Under the old predicate, that meant install --force was
free to write over tracked files in exactly the environments where the user
cannot see what happened. The refusal message names
git config --global --add safe.directory <path> because that is the fix,
and a refusal without one is just an obstacle.