利用 Git fixup 和 autosquash 整理 commit
最近在找資料的時候,偶然發現了兩個有趣的 git 指令:git commit --fixup
和 git rebase -i <sha> --autosquash
。
研究了下發現對於像我這種每次 commit 都要斤斤計較,盡可能完美的人來說非常好用,因此寫一篇筆記記錄一下用法。
說明
簡單來說,之前的我如果在 commit 之後,發現有問題的話,通常會採取下面幾種做法之一:
- 直接修改、add、commit,然後使用
rebase
來 squash commit git reset HEAD~ --soft
修改後重新 commit
上述兩種做法都可以在 local 整理好 commit log 再推出去,就會乾淨漂亮。缺點就是會比較麻煩,尤其是在改完其他東西 commit 後才發現,就要在 rebase 的時候調換順序來 squash,有時一個不小心可能會出現意外情況(我自己是沒碰過,畢竟 rebase 本身就有風險,使用時都要特別小心)。
而本文這次重點的 fixup 和 autosquash 就可以避免這個問題:在進行修補的時候,直接按照一般方式修改後,使用 git commit --fixup <被修補的 commit sha>
,然後 push 之前使用 git rebase -i <本次操作之前沒問題的 commit sha> --autosquash
就可以了。
聽起來好像非常美好,實際使用如何呢?接著就是動手嘗試的時間了!
動手試試看
連續提交
首先開一個資料夾,然後初始化一下:
接著新增一個文字檔 a.txt
:
讓我們來寫一下裡面的內容:
1 |
|
此時我們完成了 commit 但是發現打錯了,並沒有 git fixup
這個指令,因此要修正一下內容:
1 |
|
不過 commit 之前,先看一下我們 patch 對象 commit sha,並且加在這次 commit 指令上:
1 |
|
如果有實際動手操作的話,應該會發現當執行 fixup commit 的時候,不會跳出編輯器,commit message 直接帶入 fixup! <patch 對象的 commit message>
。
接著來試試 autosquash 吧:
1 |
|
此時會跳出編輯器,就和一般的互動式 rebase 一樣,唯一不同的是他在 fixup commit 那邊自動改為 fixup
:
直接儲存,來看看差異:
看起來不錯,commit log 整理的乾乾淨淨,而且還少了一次寫多餘的 commit message 的工。
跨提交
那如果是跨越一個或以上的提交,也能這樣玩嗎?我們用現在這個測試用的 repo 繼續試試看!
首先把剛剛 rebase 的指令也加上去:
接著回頭再修正一開始 fixup 指令中少的 =
:
1 |
|
OK 現在我們再來執行一次相同的 rebase 指令試試看:
可以發現 commit 的順序被自動的調換了!所以我們也不需要做什麼變更,直接儲存並執行 rebase:
居然有衝突?原先預期應該是直接完成變基才對啊?好吧來看看發生什麼事:
微妙……反正修一下就好對吧,還算簡單:
結果還是衝突= =
總之依樣畫葫蘆,再改一下就對了。
但是注意一點,雖然對後面 fixup! commit 來說,rebase 那行已經存在(文字檔第二行),可是在第一次解衝突的時候,那行是不該存在的!因為後面才會由第三個 commit 新增,所以記得只保留第一行(fixup 那行)就好。
由於會調換 commit 順序,解衝突時需注意 commit 在調換順序後當下內容的合理性。
結語
指令一覽:
1 |
|
如果問我的話,因為常常使用 rebase 來壓縮 commit 或直接 reset 來整理 commit history,所以理解這項功能的使用並不難。不過如果是跨提交的情況下,對 rebase 操作不熟悉的人,使用上就比較危險一點。但這個東西確實能加快速度,省掉 patch commit message 的時間,之後有機會再來用用(但希望仍是可以盡量確認後再提交是最好的)。
最後提醒大家一點,這東西很明顯的就是 rebase 的應用,代表 commit sha 是會被變更的。如果已經推出去了,除非是只有自己在使用的分支,否則建議還是走一般的 commit 方式修正,避免其他人 pull 下來整個亂七八糟。
因為 commit sha 會變動,建議 rebase 指令那段使用最後一個 remote sha,避免修改到遠端 commit 影響他人。