比如當我們Git revert的時候,
git revert
Git會抱怨:
is a merge but no -m option was given
這是因為你revert的那個commit是一個merge commit,它有兩個parent, Git不知道base是選哪個parent,就沒法diff,所以就抱怨了,所以你要顯示告訴Git用哪一個parent。
git revert sidsad8 -m 1
這樣就選parent 1,那么parent 1又是哪一個呢?
一般來說,如果你在master上mergezhc_branch,那么parent 1就是master,parent 2就是zhc_branch.
Often this will be parent number one, for example if you were on master and did git merge unwanted and then decided to revert the merge of unwanted. The first parent would be your pre-merge master branch and the second parent would be the tip of unwanted.
Git 撤銷 merge
在使用Git開發過程中偶爾會遇到合並(merge)錯代碼的情形。此時需要撤銷已經合並的分支(branch)。
Merge Commit
在描述 merge commit 之前,先來簡短地描述一下常規的 commit。每當你做了一批操作(增加、修改、或刪除)之后,你執行 git commit
便會得到一個常規的 Commit。執行 git show <commit>
將會輸出詳細的增刪情況。
Merge commit 則不是這樣。每當你使用 git merge
合並兩個分支,你將會得到一個新的 merge commit。執行 git show <commit>
之后,會有類似的輸出:
commit 83281a8e9aa1ede58d51a6dd78d5414dd9bc8548//本人實際git信息,這里對應git演進圖中的 g
Merge: 312a518 fa87415 //312a518和fa87415 可以在git log中找到對應的提交信息(只是commit一長串字符的頭部分)
Author:XXX
Date: Wed May 28 10:02:10 2014 +0800
Merge branch 'dev' into master
Merge branch 'dev' into master
Conflicts:
gitRevert.rtf
其中,Merge 這一行代表的是這個合並 parents,它可以用來表明 merge 操作的線索。
舉個例子,通常,我們的穩定代碼都在 master 分支,而開發過程使用 dev 分支,當開發完成后,再把 dev 分支 merge 進 master 分支:
a -> b -> c -> f -- g -> h (master) \ / d -> e (dev)
上圖中,g
是 merge commit,其他的都是常規 commit。g
的兩個 parent 分別是 f
和 e
。
Revert a Merge Commit
當你使用 git revert
撤銷一個 merge commit 時,如果除了 commit 號而不加任何其他參數,git 將會提示錯誤:
$ git revert 83281a8e9aa1ede58d51a6dd78d5414dd9bc8548 //本人實際git信息,這里對應git演進圖中的 g
error: Commit g is a merge but no -m option was given.
fatal: revert failed
在你合並兩個分支並試圖撤銷時,Git 並不知道你到底需要保留哪一個分支上所做的修改。從 Git 的角度來看,master
分支和 dev
在地位上是完全平等的,只是在 workflow 中,master
被人為約定成了「主分支」。
於是 Git 需要你通過 m
或 mainline
參數來指定「主線」。merge commit 的 parents 一定是在兩個不同的線索上,因此可以通過 parent 來表示「主線」。m
參數的值可以是 1 或者 2,對應着 parent 在 merge commit 信息中的順序。
以上面那張圖為例,我們查看 commit g
的內容:
$ git show 83281a8e9aa1ede58d51a6dd78d5414dd9bc8548 //本人實際git信息,這里對應git演進圖中的 g
commit 83281a8e9aa1ede58d51a6dd78d5414dd9bc8548
Merge: 312a518 fa87415 //312a518和fa87415 可以在git log中找到對應的提交信息(只是commit一長串字符的頭部分)
......
那么,$ git revert -m 1 g
將會保留 master 分支上的修改,撤銷 dev 分支上的修改。//(1就是1,表示312a518對應的父來源,2表示fa87415對應的父來源)撤銷成功之后,Git 將會生成一個新的 Commit,提交歷史就成了這樣:
a -> b -> c -> f -- g -> h -> G (master)
\ /
d -> e (dev)
其中 G
是撤銷 g
生成的 commit。通過 $ git show G
之后,我們會發現 G
是一個常規提交,內容就是撤銷 merge 時被丟棄的那條線索的所有 commit 的「反操作」的合集。
請注意紅色注釋部分。