git里面的每一個commit都有一個parent commit脊框,所有的commit構(gòu)成一個commit樹(tree)
- 對于multiple parent commit的場景
普通commit只有一個parent commit浇雹,而merge commit會有多個parent commit屿讽,取決于從多少個分支進(jìn)行merge昭灵,如果從兩個分支merge則有兩個parent commit,如果從三個分支merge則有三個parent commit诵棵,抠蚣。。履澳。
舉例來說:
- 主干分支master有A嘶窄,B,C三個commit
- 拉出一個開發(fā)分支developer距贷,并且在開發(fā)分支上產(chǎn)生D柄冲,E兩個commit。
- 同時主干分支上又有了F忠蝗,G现横,H三個commit。
此時我們要把開發(fā)分支developer合并回主干master分支:
- 產(chǎn)生一個新的merge commit: M
- M包含兩個parent commit阁最,即E长赞,和H
很多人會有疑問,為什么要生成merge commit闽撤,它其實沒有任何實效的代碼變化得哆,為什么不把分支developer和master拉直,比如:
或者
這樣做是需要更改歷史commit的哟旗,或者把commit D的parent commit的改掉贩据,或者把commit F的parent commit改掉栋操,這都是不被允許的,即修改歷史信息饱亮。所以只能添加一個新的commit M矾芙,它包含兩個parent commit分別指向E和H,那么以后的commit也只需要一個parent commit即M就可以了近上。
git cherry-pick -m的使用
還是從前面的例子繼續(xù)來說剔宪。
假設(shè)之前還有一個分支feature從G拉出,并且已經(jīng)生成提交G1壹无,G2兩次提交:
此時發(fā)現(xiàn)需要把分支developer的改動(D和E)合并進(jìn)來葱绒,怎么辦呢:
- 分支developer已經(jīng)刪除了。
- 不能從master分支merge斗锭,因為不要commit H地淀。
可以把commit D和E一個一個cherry-pick進(jìn)來;但是如果developer上的commit數(shù)目很多岖是,就會很麻煩帮毁,那么能不能通過把commit M合并進(jìn)來了,是可以的豺撑,但是必須指定-m <parent>選項烈疚。
查看master分支的提交歷史:
$ git checkout master
$ git log --oneline
<hash M> Merge pull request # in <repo> from developer to master
<hash E> Comment of commit E
<hash D> Comment of commit D
<hash H> Comment of commit H
...
再查看merge commit M的信息:
$ git cat-file -p <hash M>
tree <hash tree>
parent <hash E>
parent <hash H>
author ...
committer ..
Merge pull request #4 in <repo> from <developer> to <master>
* commit '<hash E>':
...
或者使用git show
$ git show <hash M>
commit <hash M>
Merge: <hash E> <hash H>
author ...
committer ..
Merge pull request #4 in <repo> from <developer> to <master>
* commit '<hash E>':
...
很清楚的看到commit M有兩個parent commit,即H和E聪轿,(是誰排先誰排后胞得,還不清除呢,待研究)
此時使用使用git cherry-pick -m 1 <hash M>
就會把commit D和E的內(nèi)容復(fù)制到分支feature上面來屹电。(注意parent 的序號從1開始)
另外需要特別說明的是阶剑,用這種產(chǎn)出的commit會抹去之前的提交歷史,我們看命令輸出:
$ git checkout feature
$ git log --oneline
dc54985 Merge pull request #4 in <repo> from <developer> to <master>
...
$ git cat-file -p dc54985
tree <hash>
parent <hash G2>
author ...
committer ...
Merge pull request #4 in <repo> from <developer> to <master>
* commit 'Hash E':
...
也就是說cherry-pick之后生成了一個新的commit N ‘hash=dc54985’危号,這個新的commit包含之前D和E的改動牧愁,但是D和E的提交歷史并沒有帶進(jìn)分支feature,用git log并不能看到D和E的提交過程外莲,而且新commit E并不是作為一個merge commit而存在猪半,它只有parent commit G2,只是左右一個普通commit存在偷线。
總結(jié)一下:
- cherry-pickup如果指定的是一個merge commit磨确,那么必須指定-m用來標(biāo)識哪一個parent commit.
-
之后會把parent commit這條線上的所有commits都merge過來。
2.1 這里要注意是merge commit提到的所有commits声邦,和此merge commit無關(guān)的commit不會被merge進(jìn)來乏奥,例如。
- 假設(shè) B5是 branchC到branchB的一個merge commit
- 此時在分支A上的C點做從merge commit B5的cherry-pickup操作:
- git cherry-pickup -m 1 <hashB5>:則包括B2, B3和B4
- git cherry-pickup -m 2 <hashB5>:則包括C1和C2
- 注意不管’-m 1‘還是’-m 2‘亥曹,commit B1都不會被merge進(jìn)來邓了,因為B1不在B5的范圍內(nèi)恨诱。
- 這些所有的commits會被squash成一個commit提交,也就是之前的commits history無法查找了骗炉。
- 最后照宝,不建議使用cherry-pickup一個merge commit。