-
場(chǎng)景復(fù)現(xiàn)
a. 原始A分支有一個(gè)file,里面有一行,"hello,world1"
b. 切出新的B分支享扔,此時(shí)B分支和A分支內(nèi)容一樣趟庄,都只有一行
c. 切回A分支括细,file增加一行伪很,“hello,world2”戚啥,此時(shí)A分支有兩行
d. 切回B分支,cherry-pick A分支剛才的commit锉试,此時(shí)B分支也有兩行
d. B分支將“hello,world2”這行刪除
e. A分支合并B分支
提問(wèn):
此時(shí)A分支file中應(yīng)該有幾行猫十??jī)?nèi)容是什么?
-
類似的一個(gè)場(chǎng)景
a. 原始A分支有一個(gè)file呆盖,里面有一行,"hello,world1"
b. 切出新的B分支拖云,此時(shí)B分支和A分支內(nèi)容一樣,都只有一行
c. 切回A分支应又,刪除這一行宙项,此時(shí)A分支的file一行都沒(méi)有
d. A分支合并B分支
提問(wèn):
此時(shí)A分支file中應(yīng)該有幾行??jī)?nèi)容是什么株扛?
-
先揭曉答案
-
第一個(gè)場(chǎng)景尤筐,A分支file最終的內(nèi)容是有2行
hello,world1 hello,world2
第二個(gè)場(chǎng)景,A分支file最終的內(nèi)容是1L都沒(méi)有
-
-
原因分析
- git的分支合并主要是采用三路合并洞就,通過(guò)比較共同的祖先盆繁,生成合并結(jié)果
- 對(duì)于第一個(gè)場(chǎng)景
- A分支相對(duì)于共同的祖先,是增加了一行旬蟋,變化了油昂,所以合并
- B分支做了一頓操作,但是最后結(jié)果是相對(duì)于祖先倾贰,沒(méi)有變化冕碟,所以不合并
- 所以最終合并結(jié)果就是2L
- 對(duì)于第二個(gè)場(chǎng)景
- A分支相對(duì)于共同的祖先,刪除了一行匆浙,變化了安寺,所以合并
- B分支相對(duì)共同的祖先,什么都沒(méi)變化吞彤,所以不合
- 所以最終合并結(jié)果就是0L
- 所以三路合并歸根是跟祖先的commit做對(duì)比我衬,雙方都有不同的變化則都會(huì)合進(jìn)來(lái),如果變化的是相同的文件則如可能出現(xiàn)沖突饰恕,交由用戶自行解決
-
繼續(xù)分析第一個(gè)場(chǎng)景
-
現(xiàn)實(shí)中這個(gè)場(chǎng)景
master分支是主干分支挠羔,是進(jìn)行最新版本的內(nèi)容開(kāi)發(fā),包含了許多新版本內(nèi)容
pre-release分支是預(yù)發(fā)布分支埋嵌,主要是當(dāng)前線上版本內(nèi)容
當(dāng)master分支發(fā)現(xiàn)了一個(gè)bug后破加,fix后,通常是通過(guò)cherry-pick到pre-release分支
但是pre-release分支發(fā)現(xiàn)bug沒(méi)有解決雹嗦,又繼續(xù)在pre-release修改范舀,如刪除
再merge回master合是,就可能出現(xiàn)場(chǎng)景中的問(wèn)題
但相對(duì)來(lái)說(shuō),這種情況出現(xiàn)的概率較低
但是確實(shí)潛在隱患
-
-
讓我們換一種思路解決
master分支file有一行"hello,world"
切pre-release分支
-
master發(fā)現(xiàn)bug
此時(shí)從master切一個(gè)bug_fix分支锭环,修復(fù)bug聪全,如增加"hello,fix bug"
-
將bug_fix分支分別合并到master和pre-release
注意:git merge --no-ff -m "merge from bug-fix" bug-fix,加上--no-ff參數(shù)
此時(shí)pre-release分支發(fā)現(xiàn)有問(wèn)題辅辩,直接再該分支修改难礼,刪除了"hello,fix bug"這一行
pre-release合回master
-
提問(wèn):此時(shí)master file的內(nèi)容是什么呢?
- 此時(shí)file的內(nèi)容就是"hello,world"
-
原因:
- 根據(jù)三路合并玫锋,在合并分支的時(shí)候,master和pre-release的祖先提交都是merge bug-fix那個(gè)commit
- 而對(duì)比后蛾茉,發(fā)現(xiàn)master沒(méi)有變化,而pre-release刪除了一行
- 則最終合并是把pre-relese的變化合并過(guò)來(lái)了
-
對(duì)比cherry-pick
- 最大的不同點(diǎn)是bug_fix合并的時(shí)候在master/pre-release生成了共同的有關(guān)聯(lián)的commit
- 而如果直接從master cherry-pick到pre-release撩鹿,是生成一個(gè)新的commit谦炬,而這個(gè)commit和原來(lái)之前master的commit沒(méi)有任何關(guān)系。所以三路合并的時(shí)候要繼續(xù)找祖先...
-
注意:
- 這只是一個(gè)sample节沦,因?yàn)閷?shí)際上應(yīng)該要在pre-release切分支键思,如果在mater切,則會(huì)把master的版本內(nèi)容merge到pre-release
-
其他的辦法
- 保證對(duì)于同一個(gè)bug的修改一定要在同一分支修改...
-
已經(jīng)有先例了
-
Stop cherry-picking, start merging: Index
- Part 1: The merge conflict
- Part 2: The merge conflict that never happened (but should have)
- Part 3: Avoiding problems by creating a new merge base
- Part 4: Exploiting the recursive merge algorithm
- Part 5: Exploiting the three-way merge
- Part 6: Replacing the temporary fix with the permanent fix
- Part 7: Preventing a change from leaving a branch
- Part 8: How to merge a partial cherry-pick
- Part 9: Chasing the commit
- Part 10: Web-based workflow for VSTS
- Stop merging if you need to cherry-pick
-
Intro to Cherry Picking with Git
Cherry picking is commonly discouraged in developer community. The main reason is because it creates a duplicate commit with the same changes and you lose the ability to track the history of the original commit. If you can merge, then you should use that instead of cherry picking. Use it with caution! 即不建議使用cherry pick稚机,因?yàn)樗鼊?chuàng)建了一個(gè)重復(fù)的提交,和原來(lái)的提交無(wú)法track...
-
-x When recording the commit, append a line that says "(cherry picked from commit …)" to the original commit message in order to indicate which commit this change was cherry-picked from. This is done only for cherry picks without conflicts. Do not use this option if you are cherry-picking from your private branch because the information is useless to the recipient. If on the other hand you are cherry-picking between two publicly visible branches (e.g. backporting a fix to a maintenance branch for an older release from a development branch), adding this information can be useful.
-
trunk based
-
解釋
1. If you’re lucky, you get a merge conflict. If you’re not lucky, your modification is simply ignored. - 即會(huì)出現(xiàn)沖突获搏,或者修改被忽略(ABA) 2. Okay, back to our original story. Creating the patch branch and merging it into both the master and feature branches preserves the connection between the two commits in the respective branches, and in particular identifies them as being two manifestations of the same underlying change (namely, commit P). The resulting merge of the two branches recognizes this relationship and doesn’t double-apply the change. - 這個(gè)也是上面6提到的赖条,創(chuàng)建一個(gè)patch分支,然后分別merge常熙,會(huì)讓兩個(gè)分支有共同的base - 即這個(gè)patch用于下次分支合并的base 3. If the two branches never merge, then there’s no need to get all fancy with your cherry-picking
-
初步結(jié)論
-
使用cherry-pick存在ABA問(wèn)題
-
如果在master發(fā)現(xiàn)線上的bug纬乍,則不直接在master修改
-
而是在pre-relese分支創(chuàng)建一個(gè)bug-fix分支,修改裸卫,然后分別合并到master/pre-release
如果可以在pre-release修改仿贬,就改完后直接合回master
注:正式線上會(huì)是online
-
或者說(shuō)
- master發(fā)現(xiàn)bug,fixed了一個(gè)commit
- cherry-pick到pre-release了
- 如果此時(shí)pre-release發(fā)現(xiàn)該bug還有問(wèn)題墓贿,需要繼續(xù)修改
- 那么先在pre-release切一個(gè)bug-fix分支茧泪,先分別合并一次
- 在bug-fix上繼續(xù)修改,修正后再合并
-
或者說(shuō)從master cherry pick到pre-release
- 加上-x選項(xiàng) 即git cherry-pick -x commitId
- (cherry picked from commit ...)
- 在pre-release分支向master分支合并的時(shí)候關(guān)注一下原始的commit是否出現(xiàn)ABA問(wèn)題聋袋,做一下相關(guān)檢查即可
-
2019.9.29 討論結(jié)果
- 遇到一個(gè)bug队伟,優(yōu)先在線上分支修改
- online切bug-fix分支
- pre-release根據(jù)選擇是切分支還是直接在pre-release修改
- pre-release可以直接合并回master
- 放棄在master修改bug,然后cherry-pick
- 因?yàn)閏herry-pick的ABA問(wèn)題
- 客戶端之前的做法是master和pre-release相互cherry-pick幽勒,不merge嗜侮,也沒(méi)問(wèn)題(只要cherry-pick和merge不一起)
- 如果一定要使用cherry-pick,一定要注意問(wèn)題(ABA問(wèn)題,不和merge一起锈颗,-x選項(xiàng)等)
- 一定要理解git的三路合并原理
- 遇到一個(gè)bug队伟,優(yōu)先在線上分支修改