今天研究了一下git merge命令經常使用參數,並分別用簡單的例子實驗了一下,整理以下:git
輸入命令git merge -h能夠查看相關參數:工具
--ff 快速合併,這個是默認的參數。若是合併過程出現衝突,Git會顯示出衝突並等待手動解決spa
--ff-only 只有能快速合併的狀況才合併。若是合併過程出現衝突,Git會自動abort這次merge對象
--no-ff 不使用快速合併。會生成一次新的提交記錄,這個記錄只是標識在這裏進行了一次merge操做(目前還沒想到應用場景)ip
--squash 壓縮合並。將待合併的分支的內容壓縮成一個新的提交合並進來it
接下來分別模擬幾種應用場景來舉例說明,C表明一次提交,合併時都是將dev分支合併到master。ast
第一種狀況:master分支切出dev分支後沒有新的提交,也就是說只有dev分支有更新,能夠快速合併的狀況:cli
eg:master:C1 ← C2date
↑blob
dev: C3 ← C4
1.執行:git merge --ff dev
master:C1 ← C2 ← C3 ← C4
dev:C1 ← C2 ← C3 ←C4
結果:查看git log時master分支會看到dev分支上的全部提交,此時master和dev是同樣的
2.執行:git merge --ff-only dev
結果同上。
3.執行:git merge --no-ff dev
git會提示讓你輸入這次合併的信息,而後生成一個特殊的commit。
master:C1 ← C2 ← C3 ← C4 ← C5 (Merge branch 'dev')
dev:C1 ← C2 ← C3 ←C4
結果:master分支會比dev分支多一條提交記錄,也就是剛纔輸入犯人合併信息
4.執行:git merge --squash dev
master:C1 ← C2 ← C5 (Merge branch 'dev')
dev:C1 ← C2 ← C3 ←C4
結果:這裏的C5實際上是C3和C4的合併,若是隻想合併dev的內容可是不須要它的提交記錄就能夠用這個參數
第二種狀況,切出後master和dev分支均有更新,這種狀況是最多見的。這裏爲了演示衝突,在C4和C5分別對一個文件進行了修改。
eg:master:C1 ← C2 ← C4
↑
dev: C3 ← C5
1.執行:git merge --ff dev
這時Git會告訴你產生了衝突並列出衝突的文件,查看文件時會列出具體衝突內容,這時要先解決衝突(若是使用Intellij Idea或Eclipse等工具,能夠直接選擇use ours/theirs,ours表明被合併分支即master,theirs表明合併分支即dev),而後將這些修改的部分提交,再執行merge操做。
master:C1 ← C2 ← C3 ← C5 ← C4 ← C6 (解決衝突的那次提交)
dev:C1 ← C2 ← C3 ←C5
那麼問題來了,Git是如何知道兩個文件有衝突呢?
這裏先說下結論,有時間再補一篇文章單獨說明說明。
你們都知道在Git裏每一個文件都是一個blob對象,這裏先無論合併時怎麼找到同一個文件在兩個分支上的blob(其實若是文件沒有更新,在兩個分支上是指向同一個blob),假設如今已經到了比較階段了,Git會拿兩個文件來逐行進行對比,可是斷定是否修改是經過相鄰行來肯定的。也就是說文件a的第三行修改了,Git是經過第2行和第4行的對比來斷定的,不信的能夠先本身作實驗驗證。因爲篇幅緣由,這裏再也不贅述。
2.執行:git merge --ff-only dev
這時Git會檢測到產生了衝突,因此提示:Not possible to fast-forward, aborting. 即取消此次merge操做。
3.執行:git merge --no-ff dev
結果同1,不過這裏在解決了衝突執行commit操做後不用再進行merge操做了。若是再執行merge操做,它會提示:Already up-to-date.
4.執行:git merge --squash dev
master:C1 ← C2 ← C4 ← C6 (解決衝突的那次提交)
dev:C1 ← C2 ← C3 ←C5
這裏解決了衝突並提交以後也不用再執行merge操做了。若是再執行merge操做會有兩種狀況:
a.剛纔解決衝突時選用了master分支的修改,那麼仍是會提示有衝突須要解決。
b.剛纔解決衝突時選用了dev分支的修改,那麼會提示Already up-to-date。
對比發現,使用--squash參數時,若是有衝突,解決完衝突後只要兩個分支不徹底同樣,再執行git merge --squash時仍是會進行merge。但--no-ff就不會。