git整理commit的基本方法(拆分、合併、修改commit)
阿新 • • 發佈:2019-02-17
覺得整理commit還是非常重要的一種技能,看到有人已經很好地整理過了,也搬運到自己的部落格中,以備不時之需。本文轉載自:Git整理Patch的一些經驗。
U-Boot升級到了最後,需要將之前比較雜亂的commit重新整理,有的需要整合,有的需要拆分。在這個過程中深刻的體會到了git的強大和靈活性。這裡總結一下大的步驟和中間用到的各種小技巧。
步驟
commands | usage |
---|---|
git checkout –b | 新建一個branch來做整理的工作,保持原來的branch作為工作記錄 |
git rebase –i | 在新建的branch上,用rebase -i接squash的方法,將所有零碎的commit合成一個 |
git reset –soft HEAD~1 | 這一步只將object store還原到working_base上。所有需要整理的改動都留在index上,以備下一步做stash |
git stash save “stash message” | 將所有的改動放進stash中 |
至此,我們有了一個工作的基礎,所有雜亂的commit被合成一個,並被放進stash中,以備後面一點點的commit進去。
接下來,最好過一遍所有的改動。記錄下每個檔案的改動包含了那些內容。以備後一步的按照不同的改動內容來合併commit。
git diff stash
舉個簡單的例子,假如總共有5個改動的檔案a~e,分析它們的改動內容包含了四個不同的目的I~IV,如下所示:
檔案a --- 目的I
檔案b --- 目的II
檔案c --- 目的II, 目的III
檔案d --- 目的II, 目的IV
檔案e --- 目的III
現在考慮按照不同的目的來組織不同的commit:
commit 1 - 目的I - 檔案a
commit 2 - 目的II - 檔案b,檔案c和檔案d的一部分
commit 3 - 目的III - 檔案c的一部分,檔案e
commit 4 - 目的IV - 檔案d的一部分
commit 1
commands | usage |
---|---|
git checkout stash | 將stash中的檔案a checkout出來,此時改動已放入index,我們可以直接commit |
git commit –s | 完成commit 1 |
commit 2
commands | usage |
---|---|
git checkout stash . | 將stash中的所有檔案checkout出來。這裡不能用git stash pop,因為一旦pop了,stash也就消失了,也就無法進行後續的工作。也不能用git stash apply,因為apply是嘗試merge,有時候反而會引起conflict,這不是我們想要的結果 |
git reset HEAD | 將所有改動移出index,但保留在working目錄中 |
git add b | 將b的所有改動放入index |
git add -p c | 以interactive的方式,將c的部分改動放進index |
git add -p d | 同前 |
git commit -s | 完成commit 2 |
git clean -dfx | 由於工作目錄是dirty的,所以這一步用以清空空座目錄,與object store保持嚴格一致,用來進行測試。很容易想到git reset –hard HEAD,但是這個命令不會將add的檔案清空,比如這個例子中的檔案e,所以用clean -dfx是最徹底的,但執行前請確保目錄中沒有需要儲存而未儲存的檔案。 |
git add -p的用法
* add -p 會逐個顯示檔案中的每組改動,並詢問是否要加入index
– y : 放入index
– n : 不要放入index
– e : 手動編輯需要加入index的部分,常用來拆分一個改動塊
– “+”行,增加
– “-”行,刪除
– “ “行,保持原樣
第三個commit和第二個類似。不贅述。到第四個commit時,只剩下檔案d,並且雖說d只有一部分與commit 4的目的相關,但由於d的其他部分在之前的commit已經放入object store了,所以又退化成和第一個commit類似的情況。
錯誤及補救措施
1. Commit到某個點以後,需要增減。
git rebase -i <targetCommit>~1
: 對出錯的commit,用e來表示需要更改修改:
這裡常用的git命令有
git checkout stash <file> 增加一個檔案
git diff stash <file> 某個檔案需要改動
git reset HEAD~1 <file> 將某個檔案移出這次commit
無論如何,保證最後index中是修改過的正確改動。
git rebase –continue
: 結束脩改。
2. Commit到某個點後,發現前面某個commit需要拆分。
git rebase -i <targetCommit>~1
: 回到拆分點,用e來表示需要更改git reset –mixed HEAD~1
: 將這個targetCommit的改動放回working directory,object store和index都還原成這個commit尚未放入的狀態。- 拆分進行commit: 將這些改動拆分的進行commit。
git rebase –continue
: 結束脩改。
3. rebase -i遇到conflict。
- 手動修改: 通常是先改成A,後改成B,此時改成B。也有先加上A,後加上B,這時需要取並集。有時A和B有相同的程式碼段時,這個程式碼段會被吃掉,修改的時候需要重新加上。
git add <file>
: 將修改完的檔案放入index。git rebase –continue
: 繼續rebase。
4. 在git command中的運用。
git log <path>
: 只顯示修改了某個檔案commits。git log -p <path>
: 同上,並且顯示這個檔案被修改的內容。commit中其他檔案的修改則不被顯示。git diff … <path>
: 只比較某個檔案的改動。