[Git瘦身] 使用cherry-pick挑出並保留只有master的節點

當一個專案運行了幾年後Git逐漸開始肥大,因為它記錄了每個分支的每個commit歷史。但對於已經併進master上線運行好幾年的code來說,有沒有辦法只保留master的hotfix commit及merge記錄就好,將其他支幹的commit都拿掉,幫Git瘦身呢?

(這是我主管某天突然丟出的疑問)

於是在我回去研究了一下後,發現可以將這個問題拆成兩個步驟解決。

  • 列出所有master的commit (一般節點及合併的節點)

  • 用cherry-pick的方式挑出剛剛列出的commit

為了模擬這樣的情境,我們開一個新的repository,並隨意commit一下,製造一些偽開發記錄,如下圖。反白的部份是我們希望最後cherry-pick出來保留的節點。

 

列出所有master的commit

我們首先切回至master分枝,用git log來幫助我們印出歷年來master分枝的commit hash(從舊至新)。雖然上圖中的master節點不多直接印出來沒關係,但如果像我公司的專案一樣已經有點年紀的話,還是把它先導至檔案存起來比較好。

git log --first-parent --pretty=format:"%h" --reverse > git.txt
  • --first-parent:這個參數設定了如果今天找到的是merge commit,因為它會有兩個父節點(兩個爸爸?咦),一個指向前一個master、另一個指向被併進來的分支,那我們自動選擇first parent的節點繼續往回追蹤。

  • --pretty=format:"%h:只印出commit hash

  • --reverse:由於git log是以新至舊的方式排序,跟我們想要的方向相反,所以也加上

好了之後打開git.txt就會看到我們已經完整列出從舊至新歷代所有的master commit了。

6c31839
902a0e2
6420525
96865c8
84c4cf0
4a70984
0a05e68

 

用cherry-pick的方式挑出剛剛列出的commit

有了歷代所有的master commit hash後,我們首先checkout至整個專案的第一個commit,也就是6c31839(Init.)。

git checkout -b Tidy 6c31839

好了後6c31839這個commit hash已經不需要了,我們將它從清單裡拿掉。接著用編輯器的全取代功能把換行替換成空格,這就是我們最終cherry-pick要依序pick的東西。

902a0e2 6420525 96865c8 84c4cf0 4a70984 0a05e68

下一步,將大家熟悉的cherry-pick語法加在剛剛的commit hash串前面。那個-m 1參數的全名是parent-number,也就是指定一樣當遇到了merge commit則採用第一個父節點為主。

git cherry-pick -m 1 902a0e2 6420525 96865c8 84c4cf0 4a70984 0a05e68

按下Enter後如果像我們公司的專案一樣已經肥了好幾年了就需要等它跑一下。當跑完後就會有如下圖一樣,一個名叫Tidy乾淨只有master記錄的branch了。最後一步只要把master指過來,並且呼叫Git的gc把垃圾清一清,整個repository就瘦身成功了。


發佈留言