當持續在改檔案內容,容易發生當初為這個檔案取的名字已經不適合描述目前內容的情況,所以會對檔案名稱做修改。
最好的例子就是重構,當重構的時候很容易發生class名稱變換,這個時候會一起調整class的檔案檔名避免未來不好找。
不過當有天需要追蹤那個檔案的變更歷史的時候,會突然發現,只有 從新檔名那段開始有記錄,而舊檔名的記錄則看不到。這個對於從svn轉過來的使用者來說是無法理解的。
在這篇將會針對這個常見的問題來談到解決的方式和為什麼git會是這樣運作。
問題重現
基本上我們可以用以下的方式來重現這個問題:
- 先建立一個檔案
file.txt
- 把這個檔案commit上去
- 把檔案改名字
change.txt
- 這個時候看狀態會變成
file.txt
在被刪除狀態,而change.txt
則是untrack的狀態
- 用 add 加入到index (注意到這邊狀態變成了 renamed)
- 這個時候用小烏龜對那個檔案做看 log - 會發現歷史不見了
解決方式
如果今天只是要看到包含改檔名前的日誌,下面是做法 - 如果對於為什麼會發生和git重命名的做法有興趣在往下看。
指令的方式
其實在git裡面針對某個檔案看日誌的時候,可以使用指令follow
來包含變更名稱前的日誌:
git log -follow filex.txt
在各個ui裡面也有類似的設可以啟用:
TortoiseGit log 啟用方式
選取要檢查的檔案(以我們例子是change.txt
),呼叫log的部分並且在最下面第3個按鈕 Walk Behaviour -> Follow Renames就可以看到。下面截圖就是有開啟的狀態,可以看到最早file.txt
的建立也有看到了:
TortoiseGit blame啟用方式
如果對一個檔案做blame - 下面的log清單也需要開啟在 View -> Folle Rename才會看到
SourceTree log 啟用方式
在log裡面選change.txt
,點右鍵,選擇 Log Selected,在左下角有個Follow renamed file
發生原因 - git如何處理檔名變更
大部分第一次遇到這種情況都是在想,會不會是rename方式錯誤,是不是需要透過git的指令來rename就沒問題?
如果深入在研究,會發現git有提供一個指令叫做git mv
(TortoiseGit也有一個對應的刪除功能)- 但是如果你用那個指令來刪除,會發現其實還是看不到日誌。
要了解這個,首先有件事情一定要記得的是,git和其他版控不同在於,git記錄的是內容變更,而不是檔案變更。
所以其實git不在乎檔名有沒有變更,他看的是檔案內容的變更。所以在上面我們沒有透過git指令改名的時候,一開始在status顯示的是有個檔案被delete,然後有個檔案屬於untrack,但是當我們加到staging之後 (透過 git add)自動切換變成renamed
狀態。
會有這種混搖是因為git觸發檢查的時間點不同,當status的時候還沒比對過資料,而在add等於進入準備建立commit,所以一比對,發現只是檔名不同(在git來說就是在不同的tree),因此它自動識別原來這是一個檔名變更。
這個時候有些gui就容易誤導使用者
以TortoiseGit來說,他沒有staging概念(應該說有,但是commit的那個畫面沒有這種感覺)會造成使用者擔心為什麼不是顯示重改檔名,造成他們不敢commit:
在git裡面重新命名怎麼做才正確
- 當檔案內容沒有修改或者少量修改的時候,就依照喜歡的方式改檔名就好
- 如果檔案內容有大幅度修改,建議改檔名和修改內容分兩個commit(一個改檔案內容,一個改檔名)
有沒有必要呼叫 git mv
答案是:不需要
git mv
= 改完檔名然後呼叫 git add
因為Windows使用者習慣直接透過檔案總管改檔名,因此專門為了省一個git add的指令而特意去呼叫git mv
有點不方便,只是要知道顯示一個delete和一個untrack是正常即可。
當檔案內容和檔案名稱都有修改的情況下是否會不同?
假設檔案內容只改了一些 - git會夠聰明的知道,其實這是一個修改檔名+修改檔案內容。
但是當修改檔案內容很多也有修改檔名,git add
還是會顯示一個delete和一個untrack。
如果進入那種狀態,會有以下壞處:
- 未來在看commit的時候,不那麼直覺能夠看出是一個檔名修改+檔案內容修改
-follow
的參數就沒有用了 - 所以換檔名前的log沒法一次顯示當有檔案修改又有檔名修改無法用follow和網上說法有點不同
以我解git是記錄檔案內容變更,理論上來說就算變成 一個delete一個untrack也應該要能夠用
follow
追蹤的到才對,但是實際上我測試的時候不行。這個和網路上的一些說法不一致,因此為了未來看起來方便和容易追蹤,建議還是分兩個commit,一個改檔名,一個改檔案內容。
假設commit已經是一個delete和一個untrack,可以用
rebase
把它拆開成為兩個commit,一個改檔名,一個改檔案內容。
結語
在第一次接觸到git的rename的時候容易進入到以前以檔案修改為記錄的版控思維影響,因此希望這篇能夠讓了解發生的原因,並且記得:
- 如果
log
和blame
需要看到包含改檔名前的記錄,記得找找和follow
有關的關鍵字做切換
- 改檔名不用擔心,可以直接用檔案總管修改然後add、commit即可
- 如果檔案有大改,然後又要改檔名,建議分成兩個commit
對剛接觸的新手實用性很大阿,之前就有遇過別的組員說要整理一下名稱後,就找不到自己檔案的情況呢
回覆刪除很高興對您有幫助,持續關注,最近還會在放一些git相關內容。
回覆刪除