1. 程式人生 > >git整理commit的基本方法(拆分、合併、修改commit)

git整理commit的基本方法(拆分、合併、修改commit)

覺得整理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>: 只比較某個檔案的改動。