1161 字
6 分鐘

git diff 沒有輸出卻有修改?檢查暫存區與 HEAD 的差異

執行 git add 後,git diff 突然沒有輸出,但編輯器仍顯示修改,先看 git diff --cached。不帶參數的 diff 比較暫存區與工作檔案;stage 完成後,這兩份內容相同就會空白。 已暫存的修改仍可進入一般 commit。

還有一種更容易誤判的情況:stage 後在編輯器把內容改回原樣,git diff HEAD 也是空白,但暫存區仍保存先前的修改。要確認下次提交內容,必須看對比較的兩端。

先用唯讀命令找出是哪份快照#

在專案目錄執行:

Terminal window
git status --short
git diff --name-status
git diff --cached --name-status
git diff HEAD --name-status

依 Git diff 文件,這三個比較回答不同問題:

命令比較的兩端用途
git diff暫存區 → 工作檔案stage 後又改了什麼
git diff --cachedHEAD → 暫存區一般 commit 準備提交什麼
git diff HEADHEAD → 工作檔案磁碟上的檔案相對上次 commit 改了什麼

--staged 和 --cached 是同義選項。要看某個檔案的內容差異,把確切路徑放在 -- 後面,例如 git diff --cached -- settings.txt。

暫存區(index)保存的是 stage 當時的內容,並不會持續追蹤編輯器的新版本。Pro Git 的記錄變更章節 說明了「stage 後再編輯」為何會同時出現兩份修改。

status 的兩欄各看一個比較#

對已有追蹤、沒有未解 merge 的一般檔案,short status 第一欄描述 index 相對 HEAD,第二欄描述工作檔案相對 index:

M settings.txt
M settings.txt
MM settings.txt
?? notes.txt

這是四種不同情境,不是同一個檔案同時列出四次。M 是已 stage; M 是尚未 stage;MM 表示兩端都有修改,要分別看 cached 與一般 diff。?? 是未追蹤檔案,上面三種一般 diff 不會自動列出其內容。

如果 MM 搭配空白的 git diff HEAD,可能是磁碟內容回到 HEAD,而 index 還在另一個版本。不能據此說「Git 狀態壞掉」,也不需要先 reset 或刪除 .git。

重現工作檔案改回去,暫存區仍保留修改#

以下用 Bash 執行,只在 mktemp 建立的獨立目錄操作,沒有 remote。本文維護流程於 2026-10-10 在 macOS、Git 2.54.0(Apple Git-157)執行;斷言涵蓋一般文字檔,不包含衝突、submodule 或自訂 diff driver。

Terminal window
set -eu
fixture_dir="$(mktemp -d)"
git init -q -b main "$fixture_dir"
cd "$fixture_dir"
git config user.name Fixture
git config user.email [email protected]
printf 'theme=light\n' > settings.txt
git add -- settings.txt
git -c commit.gpgsign=false commit -qm Baseline
printf 'theme=dark\n' > settings.txt
git add -- settings.txt
git diff --quiet -- settings.txt
if git diff --cached --quiet -- settings.txt; then
echo '預期暫存區應有修改' >&2
exit 1
else
test "$?" -eq 1
fi
printf 'theme=light\n' > settings.txt
git diff HEAD --quiet -- settings.txt
test "$(git status --short)" = 'MM settings.txt'
test "$(git show :settings.txt)" = 'theme=dark'
git -c commit.gpgsign=false commit -qm 'Commit staged content'
test "$(git show HEAD:settings.txt)" = 'theme=dark'
test "$(cat settings.txt)" = 'theme=light'
test "$(git status --short)" = ' M settings.txt'
printf '暫存快照檢查通過:%s\n' "$fixture_dir"

git diff --quiet 的狀態碼 0 代表沒有差異,1 代表有差異;其他非零狀態要當錯誤處理。這裡第一個比較成功,接著確認 cached 比較並非空白。

工作檔案改回 light 後,三個位置是:HEAD 為 light、index 為 dark、工作檔案為 light。兩端相同,所以 git diff HEAD 空白;一般 commit 仍提交 index 的 dark,磁碟內容則維持 light。

測試不會清掉暫存 repository,最後一行會顯示路徑,方便查看。不要把這些初始化與提交命令換成正式專案路徑。

決定要交哪個版本,再改暫存區#

先確認目前暫存的內容:

Terminal window
git diff --cached -- settings.txt
git show :settings.txt

如果準備提交的就是這一版,可以保留後續未 stage 的編輯。若應提交的是磁碟上的新版本,才再次 stage 該確切檔案:

Terminal window
git add -- settings.txt
git diff --cached -- settings.txt
git status --short

在上面 fixture 的提交前狀態,重新 stage light 會讓 index 回到 HEAD,該檔案的修改消失;這是選擇了目前工作內容,不是 Git 遺失資料。

cached diff 的預覽適用於一般、沒有路徑參數或 -a 的 commit。Git commit 文件 說明 -a 會先納入已追蹤檔案的修改與刪除,帶路徑的提交則有不同的內容選擇規則。不要看完 cached diff,卻換用另一種提交方式後仍假設結果相同。

多個 Agent 在同一專案工作時,先用 Git worktree 隔離工作目錄,再各自確認 HEAD、index 與工作檔案。即使只剩一位操作者,也應在 commit 前看暫存版本,而不是用空白的 git diff HEAD 代替驗收。

參考資料:

Git:git diff

Git:git status

Git:git commit

Pro Git:Recording Changes to the Repository

git diff 沒有輸出卻有修改?檢查暫存區與 HEAD 的差異
https://laplusda.com/posts/git-diff-empty-staged-changes/
作者
Zero
發佈於
2026-10-10
許可協議
CC BY-NC-SA 4.0