冷知識 - Git 的搬檔更名跟你想的不一樣
0 |
昨天 Git 資料夾搬家一文發表後,讀者 Danny Lin 於小站留言提到一則重要觀念:
事實上 Git 並沒有記錄所謂的「搬檔/更名」動作,在 Git 眼中,不管搬檔案或檔案改名,都一律被視為刪除舊檔外加新增檔案,差別在於若刪除檔案與新增檔案的內容相似度達一定門檻(預設為50%),Git 就會將這組刪除加新增動作解讀為更名。而且,相似度門檻是活的,可以任意調整。
我做了幾點實驗驗證這點。
實驗一,git status 的新增加刪除,commit 後視為 rename
- 直接用 DOS 指令將 src/ExampleForDummy.sln 移到上一層目錄
- git status 查看為一個刪除動作
- 加一個新增動作
- 將刪除與新增動作 Commit 進版控
- delete + add 動作被解讀成 rename,數字 100% 表示刪除與新增內容完全相同
實驗二,同時搬移多個內容相同檔案
- 建立 a.txt
- 將 a.txt 複製成 b.txt,二者內容應完全相同
- 將 a.txt 與 b.txt Commit 進去
- 將 a.txt 與 b.txt 移到上一層目錄
- Commit 搬家後的結果,Git 沒被 a.txt 與 b.txt 內容相同混淆,成功判讀二者的搬家前後關聯(應該是用檔名輔助判別)
- R100 的 R 表示 Rename,100 代表 100% 相同
實驗三,更改檔名並且改掉部分內容,動態指定更名門檻
- 建立 a.txt,內容為 12345678 共 8 Bytes
- Commit a.txt 進 Git
- 將 a.txt 更名為 b.txt
- 在 b.txt 後方加上 ABC 三個字元
- Commit b.txt,Git 判定這算是更名,內容相似度 66%
- git diff 也判定這次修改是 src/a.txt 更名 src/b.txt (預設門檻 50%,相似度 66% 視為更名)
- git diff 加上 -M80% 參數,將更名門檻提高到 80%,則同一個 Commit 修改變成一刪一增
結論
由以上實驗可知,對 Git 而言,更名或搬檔只是一組刪除與新增相似內容的動作,git status 顯示 renamed 或 deleted + untracked 並不影響 Commit 後的判別,而相似度門檻預設為 50%,但門檻是活的,每次 git diff、git log 時可透過 -M 參數指定。所以前一篇提到使用 git mv 確保 status 呈現 renamed 狀態並絕對必要性,只要確保該次 Commit 只有搬檔或更名動作,不要摻入其他修改,Git 都可正確判讀。
覺得這算是一則冷知識的理由是,網站上真有不少用 git mv 搬檔避免 git status 出現 deleted + untracked files 討論,足見還有蠻多人不知道的,多虧 Danny Lin 補充。而這也更讓我覺得 Git 要上手不簡單,想精通更難,呵。
Explanation of how Git decide the delete + add actions are a rename or move action.
Comments
Be the first to post a comment