Imported from marcostomatti/template-agentic-research (
.claude/skills/git-add-partial-failure/SKILL.md). Install upstream withnpx skills add marcostomatti/template-agentic-research --skill git-add-partial-failure. Copyright stays with the author.
git add Aborts Entirely On Any Missing Pathspec
git add A B C treats the file list atomically. If any of A/B/C does not exist as a pathspec (typo, stale expectation, wrong lockfile extension), the whole git add fails and nothing gets staged — not even the files that DO exist. If you're piping stderr to /dev/null and chaining with a bare newline (not &&), the shell keeps going and the next git commit finds an empty index. The commit reports "no changes added to commit" and lists the still-modified files, which reads like the modifications weren't detected.
The specific bug
Ran in a bash loop iterating over multiple repos, adding + committing dep-pin changes:
for repo in ...; do
cd "$repo"
git status --short
git add package.json bun.lock bun.lockb 2>/dev/null # bun.lockb doesn't exist in modern bun
git -c commit.gpgsign=false commit -m "..."
done
bun.lockb (legacy binary lockfile) does not exist post-migration to text bun.lock. Every iteration:
git addfailed withfatal: pathspec 'bun.lockb' did not match any files(silenced by2>/dev/null).- Nothing was staged.
git commitreportedno changes added to commitwith the modified files listed.
Looked like a mysterious "changes not being detected" symptom. Real cause: silent partial-add failure.
Fixes (any one is sufficient)
- Drop
2>/dev/nullfromgit add. The stderr messages are the diagnostic. - Add files individually, ignore per-file failures:
This preserves the "add whatever exists" behavior without atomic abort.for f in package.json bun.lock bun.lockb; do git add "$f" 2>/dev/null || true done - Use
git add --ignore-errors A B C(best-of-both — atomic-ish behavior but skips non-existent paths). - Use
git add -Ascoped to a directory if you actually want "everything modified here":git add -A .in the target dir. Loses the file-list intent but is bulletproof. - Test each pathspec with
[ -f "$f" ]before including it in thegit addlist — verbose but explicit.
Related failure mode
git rm A B C has the same behavior. If any pathspec doesn't match tracked files, the whole command fails. Same fixes apply.
When to Use
- A
git commitin a scripted loop reports "no changes added to commit" for files that clearly show as modified ingit status. - Writing a shell loop that batches
git addacross multiple files, especially with2>/dev/nullor when file existence is uncertain (lockfile format transitions, optional dotfiles). - Debugging why a chained
git add && git commitproduced an empty commit.
Anti-pattern
Assuming git add is a for-each-file operation. It isn't — it's a single atomic operation over the pathspec list. Modeling it as for-each leads to silent staging losses.