When running git mv A B while A has unstaged working-tree modifications (e.g., a script wrote new content to A then immediately git-mv’d), the staged rename uses A’s HEAD content, NOT A’s working-tree content. The working-tree file ends up at B with the modified content intact — but unstaged. A subsequent git commit will commit the rename of HEAD-content + leave the modifications unstaged + omit them from the commit.
Why: Result of git mv A B ≡ mv A B && git rm --cached A && git add B. The git add B step, when there’s an existing rename relationship, registers B with whatever content is at B in the working tree at the moment of git mv — but on the index path B is tracked as a rename-from-A with A’s index content (which is HEAD content if A wasn’t staged). The reconciliation can vary by git version + by whether the working-tree write happened before or after the index update.
Why: Caught empirically 2026-05-23 during BATCH improvement 22 Phase A retirement of richard-tasks-tt.md → richard-tasks-tt-historical.md. Sequence: (1) script read file content + computed v1.26 + FROZEN banner; (2) script wrote new content to original path; (3) script invoked git mv to register rename. Commit landed but git show origin/main:richard-tasks-tt-historical.md returned the v1.21 HEAD content with no banner; local file had v1.26 + banner. rename ... (100%) in commit output was the smoking gun — 100% similarity means rename-without-modification. Required a follow-up commit (git add richard-tasks-tt-historical.md && git commit) to stage and land the modifications.
How to apply:
-
Pattern that works (used successfully by the BATCH 22 phase-1-5 retirement script): write new content to NEW path →
git mv OLD NEW→ re-write new content to NEW path AFTER git mv. The post-mv re-write ensures the working tree has modifications that show ingit statusso they get staged ongit add. -
Pattern that fails (used by the BATCH 22 docs-personal retirement script): write new content to OLD path →
git mv OLD NEW. The git mv catches the rename but doesn’t carry forward the working-tree modifications into the index. -
Verification: after
git mvof a file you intended to modify, ALWAYS rungit status— if you seeMnext to the renamed file, the modifications are unstaged. Rungit add <new-path>before committing. Alternatively, checkgit diff --cached <new-path>— if it shows only the rename (no content changes), modifications are unstaged. -
Companion verification:
git log --stat origin/main -1after push — if the rename line shows(100%)similarity but you expected substantive content changes, the staging defect occurred.
Companion: batch-imp-22-phase-a-native-tasks-migration (the originating session); §13.6 post-commit grep-verify discipline (would have caught this earlier had grep run before declaring done).