Git show讀取commit:file快照

想確認上週提交的設定檔究竟寫了什麼,不必先切換分支,也不用把目前修改暫存起來。Git可以直接讀取某個提交裡的檔案快照。關鍵在冒號:git show COMMIT:path讀的是那個提交保存的檔案內容;git show COMMIT — path通常顯示提交資訊及該路徑的變更。兩個指令很像,回答的問題卻不同。

先分清完整內容與變更片段

假設page.txt有兩行,第一次提交是old title和footer,第二次只把第一行改成new title。現在工作目錄又改成dirty title,尚未提交。此時至少有三份內容:較早提交、目前HEAD提交,以及磁碟上正在編輯的檔案。查歷史前先決定要讀哪一份,避免看完補丁就誤以為那是整個檔案。

git status --short
git log --oneline -- page.txt
git show HEAD -- page.txt
git show HEAD:page.txt

第三行的雙減號把提交與路徑分開,結果包含diff標頭與加減行,適合回答「這次改了哪裡」。第四行的冒號把提交和樹內路徑接起來,結果只有檔案內容,適合回答「提交當時整份檔案是什麼」。完整快照包含沒有變動的footer;補丁裡看到footer,可能只是差異的上下文,不應據此判斷檔案只剩那幾行。

用提交雜湊指定真正要查的版本

HEAD代表目前檢出的提交,會隨切換分支或新提交而改變。要在問題紀錄或修復筆記中重現同一份檔案,先從git log找到目標提交,記下雜湊,再把範例中的OLD_COMMIT換成那個值。這裡的OLD_COMMIT只是占位文字,不能原樣執行。

git show OLD_COMMIT:page.txt
git show HEAD:page.txt

本地隔離案例使用Git 2.47.1.windows.1,建立兩個提交後故意保留未提交修改。第一個提交的快照輸出old title與footer,HEAD快照輸出new title與footer,而工作目錄仍是dirty title與footer。三份內容同時存在,讀取歷史不會把較早版本套到工作目錄,也不會建立新提交。案例沒有遠端,沒有測試推送或正式站設定檔。

# OLD_COMMIT:page.txt
old title
footer

# HEAD:page.txt
new title
footer

# working tree page.txt
dirty title
footer

冒號後的路徑屬於該提交的目錄樹

使用COMMIT:path時,最容易出錯的是路徑。一般直接寫儲存庫根目錄下的相對路徑,例如HEAD:config/site.json。不要拿電腦的絕對路徑放在冒號後,也不要把網址當成Git路徑。若目前人在子目錄,仍以根目錄相對路徑寫法整理查詢,讓指令放在筆記裡也能讀懂。路徑包含空白時,可以把整個提交與路徑參數用引號包起來。

git show "HEAD:docs/site notes.txt"
git ls-tree -r --name-only OLD_COMMIT

第二行列出目標提交中的檔案名稱,適合在記不清舊路徑時先查目錄樹。檔案可能後來才新增,也可能曾經改名。今天的檔名不一定存在於昨天的提交,git show也不會替這個冒號查詢自動追蹤改名。先確認目標提交裡的實際路徑,再取內容,比反覆更換雜湊猜測更可靠。這一步只讀取樹與物件,不改索引。

查不到檔案時先處理版本與路徑

隔離案例另執行git show HEAD:missing.txt,因HEAD裡沒有這個檔案,指令回傳非零退出狀態並顯示路徑不存在的錯誤。這不是空檔案,也不代表歷史被刪掉。若把這種失敗當成成功取到空內容,後續比較或匯出就會得到錯誤結論。先看退出狀態與錯誤訊息,接著用ls-tree確認檔名,必要時重新選擇提交。

提交識別本身也可能錯誤。從別人的問題描述複製短雜湊時,先確認自己的儲存庫具有該提交;不同儲存庫的短雜湊不能當成相同版本的保證。若目標物件未在本地,這篇只讀查詢不會自行補齊遠端資料。需要另行取得資料時,應按自己的遠端與權限處理,不能拿查詢失敗推論正式站版本不存在。

把查到的內容放回問題脈絡

例如網站的設定在某次發布後出現異常,先查那次發布實際使用的提交,不要只因主分支現在沒有問題就認定當時也相同。讀取設定檔快照只能證明儲存庫記錄的內容;它不會證明部署機當時載入了哪個環境變數,也不會證明程式重新啟動過。若問題涉及部署,還要另核發布紀錄與執行環境。這些資訊不能從一份Git快照推算出來。

另一種情況是檔案在兩個提交之間改名。你可以先看兩次提交各自的目錄樹,找出新舊名稱,再分別讀取快照。這樣做回答的是兩個明確版本的內容差異;若要研究整條改名歷史,才進一步使用log的路徑追蹤工具。不要因為HEAD的新路徑讀得到,就假設相同路徑在所有舊提交都有效。目錄樹本身才是指定版本的依據。

讀到完整檔案後,仍要注意設定值是否屬於該環境。測試站與正式站可能使用不同設定,提交中的範例值也可能只供文件說明。可以在自己的問題筆記記下提交雜湊、根目錄相對路徑和觀察到的欄位,方便日後重查;若檔案含敏感內容,分享時只摘與問題有關的部分。查詢不會遮蔽檔案內容,終端輸出與你另外保存的副本都應按該檔案原有的使用範圍處理。

保持目前修改,再決定是否另存

本地案例在讀取快照與補丁前後各執行一次git status –short,兩次都顯示page.txt有未提交修改;讀回磁碟內容也仍是dirty title。這是本案例對「查詢沒有改工作目錄」的具體核對。查歷史時即使工作目錄不乾淨,仍可以先讀取內容;若接著要還原、切換或合併,那已經是另一種操作,必須另外考慮目前修改。

若要把快照留作比較,可以選一個新的輸出檔名,確認不會覆蓋正在使用的檔案,再依所用shell的重導向方式處理。本案例只在終端讀取,沒有測試跨shell輸出編碼;因此不要把範例延伸成所有shell都會保留同樣位元組。尤其不要直接把歷史內容重導向到正在編輯的page.txt,否則改檔的是重導向動作,已經不是單純git show。

日常查錯時,可以把流程固定成三步:先用log選提交,再用ls-tree確認那時的路徑,最後用COMMIT:path讀完整快照。需要知道變更原因時,再看同一提交的補丁。筆記裡同時保留查詢指令與提交雜湊,日後即使HEAD移動,也能重新取得同一版本。把版本、路徑與目前工作目錄分開,你就能在保留手邊修改的同時,回答歷史設定究竟長什麼樣子。

參考資料

原文鏈接:https://wntheme.com/git-show-commit-file-snapshot/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?