Git merge时使用--no-ff参数
/1、Git:Git-merge的–ff和–no-ff。
前言
Git merge最容易糊涂的地方就是這個--ff參數和--no-ff 參數,通過本文,把這個整理清楚。
其實官網講的非常清楚,不過可能因為是英文的,所以大家閱讀起來會有一些障礙。(PS:其實還是應該逐步逐步提高自己閱讀英文文檔的能力,想達到一個更高的高度,是需要客服自己本身很多的弱點的)
實例
假設合并前的分支是這樣,這個一個非常常見的場景,如果不明白,可以參考另外一篇文章Git Flow工作流:
這是一個很常見的用例,功能開發分支是iss53,在開發新功能,master分支是線上分支,出現了問題,開辟了hotfix分支進行修復,修復完成,進行合并,需要把hotfix合并回master。
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
?index.html | 2 ++
?1 file changed, 2 insertions(+)
步驟如下:
切換回master分支。
將hotfix分支合并會master分支。
然后看到了Fast-forward 的字樣,這個詞組的意思就是快進,播放電影的時候,可以注意一下,快進按鈕上面就是這個詞組。
那么實際變成了什么樣呢?
僅僅是master指針指向了這個提交C4。這樣是一種比較快的合并方式,輕量級,簡單。
這個時候,我們往往會刪掉hotfix分支,因為它的歷史作用已經結束,這個時候,我們的iss53這個功能又向前開發,進行了一次提交,到了C5,那么變成了這樣:
然后,我們要把iss53 這個分支合并回master,就變成了這樣:
這個時候生成了一個新的commit號,這種提交就不是fast-forward(這個時候也無法生成fast-forward提交,因為要將兩個版本的內容進行合并,只有在沒有需要合并內容的時候,會有這個fast-forward 方式的提交)。
如果我們對第一次合并,使用了--no-ff參數,那么也會產生這樣的結果,生成一個新的提交,實際上等于是對C4 進行一次復制,創建一個新的commit,這就是--no-ff的作用。
?
?
2、在很多介紹GItFlow工作流的文章里面,都會推薦在合并分支的時候加上--no-ff參數, 而我們在合并的時候,有時git也會提示 使用了 fast-forward, 這里我將介紹一下merge的三種狀態及 git merge 和 git merge --no-ff 的區別
Git merge的時候,有幾種合并方式可以選擇
--ff When the merge resolves as a fast-forward, only update the branch pointer, without creating a merge commit. This is the default behavior.--no-ff Create a merge commit even when the merge resolves as a fast-forward. This is the default behaviour when merging an annotated (and possibly signed) tag.--squash --no-squash Produce the working tree and index state as if a real merge happened (except for the merge information), but do not actually make a commit, move the HEAD, or record $GIT_DIR/MERGE_HEAD (to cause the next git commit command to create a merge commit). This allows you to create a single commit on top of the current branch whose effect is the same as merging another branch (or more in case of an octopus).With --no-squash perform the merge and commit the result. This option can be used to override --squash.而我們平常什么都不加的時候,則使用默認的 --ff , 即 fast-forward 方式
看過官方注釋后,我們用一張圖來簡單描畫一下相應的行為
?
image.png
?
fast-forward
Git 合并兩個分支時,如果順著一個分支走下去可以到達另一個分支的話,那么 Git 在合并兩者時,只會簡單地把指針右移,叫做“快進”(fast-forward)不過這種情況如果刪除分支,則會丟失merge分支信息。
–squash
把一些不必要commit進行壓縮,比如說,你的feature在開發的時候寫的commit很亂,那么我們合并的時候不希望把這些歷史commit帶過來,于是使用–squash進行合并,此時文件已經同合并后一樣了,但不移動HEAD,不提交。需要進行一次額外的commit來“總結”一下,然后完成最終的合并。
–no-ff
關閉fast-forward模式,在提交的時候,會創建一個merge的commit信息,然后合并的和master分支
merge的不同行為,向后看,其實最終都會將代碼合并到master分支,而區別僅僅只是分支上的簡潔清晰的問題,然后,向前看,也就是我們使用reset 的時候,就會發現,不同的行為就帶來了不同的影響
?
https://github-1253518569.cos.ap-shanghai.myqcloud.com/2018-09-18_201744.png
?
上圖是使用 merge --no-ff的時候的效果,此時git reset HEAD^ --hard 的時候,整個分支會回退到 dev2-commit-2
?
dev3-commit-1
?
上圖是使用 fast-forward 模式的時候,即 git merge ,這時候 git reset HEAD^ --hard,整個分支會回退到 dev1-commit-3
通常我們把 master 作為主分支,上面存放的都是比較穩定的代碼,提交頻率也很低,而 develop 是用來開發特性的,上面會存在許多零碎的提交,快進式合并會把 develop 的提交歷史混入到 master 中,攪亂 master 的提交歷史。所以如果你根本不在意提交歷史,也不愛管 master 干不干凈,那么 –no-ff 其實沒什么用。不過,如果某一次 master 出現了問題,你需要回退到上個版本的時候,比如上例,你就會發現退一個版本到了 commint-3,而不是想要的 commit-2,因為 feature 的歷史合并進了 master 里。這也就是很多人都會推薦 –no-ff 的原因了吧
3、
通常,合并分支時,如果可能,Git會用Fast forward模式,但這種模式下,刪除分支后,會丟掉分支信息。
如果要強制禁用Fast forward模式,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就可以看出分支信息。
下面我們實戰一下--no-ff方式的git merge:
Administrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (master) $ git checkout -b dev Switched to a new branch 'dev'Administrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (dev) $ ls abc.txt dd ddd.txt READMYFILEAdministrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (dev) $ vi abc.txtAdministrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (dev) $ git add abc.txt warning: LF will be replaced by CRLF in abc.txt. The file will have its original line endings in your working directory.Administrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (dev) $ git commit -m 'add merge' [dev 4fe2eaf] add merge1 file changed, 1 insertion(+)Administrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (dev) $ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'.Administrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (master) $ git merge --no-ff -m 'merge with no-ff' dev Merge made by the 'recursive' strategy.abc.txt | 1 +1 file changed, 1 insertion(+)Administrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (master) $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits.(use "git push" to publish your local commits) nothing to commit, working tree cleanAdministrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (master) $ git log --graph --pretty=oneline --abbrev-commit * 0b655f8 (HEAD -> master) merge with no-ff |\ | * 4fe2eaf (dev) add merge |/ * d2ac9a9 (origin/master, origin/HEAD) merge |\ | * 62feb86 feature * | a1d0ee6 master |/ * 2360738 conflict fixed |\ | * 22f91d7 READ * | 4518e6a by master |/ * c01f0f2 Merge branch 'master' of github.com:ZhuBaker/learngit |\ | * 6af3724 abc | * ed9c88d dddd | * 0fefcee dd | * 1c508f7 Merge branch 'master' of github.com:ZhuBaker/learngit | |\ | | * 78b85de abc | * 7e13181 abc :Administrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (master) $ git branch -d dev Deleted branch dev (was 4fe2eaf).Administrator@EZ-20170513RQHH MINGW32 /d/workspace/learngit/learn2 (master) $ git log --graph --pretty=oneline --abbrev-commit * 0b655f8 (HEAD -> master) merge with no-ff |\ | * 4fe2eaf add merge |/ * d2ac9a9 (origin/master, origin/HEAD) merge |\ | * 62feb86 feature * | a1d0ee6 master |/ * 2360738 conflict fixed |\ | * 22f91d7 READ * | 4518e6a by master |/ * c01f0f2 Merge branch 'master' of github.com:ZhuBaker/learngit |\ | * 6af3724 abc | * ed9c88d dddd | * 0fefcee dd | * 1c508f7 Merge branch 'master' of github.com:ZhuBaker/learngit | |\ | | * 78b85de abc | * 7e13181 abc :分支策略
在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,比如1.0版本發布時,再把dev分支合并到master上,在master分支發布1.0版本;
你和你的小伙伴們每個人都在dev分支上干活,每個人都有自己的分支,時不時地往dev分支上合并就可以了。
所以,團隊合作的分支看起來就像這樣:
小結
Git分支十分強大,在團隊開發中應該充分應用。
合并分支時,加上--no-ff參數就可以用普通模式合并,合并后的歷史有分支,能看出來曾經做過合并,而fast forward合并就看不出來曾經做過合并。
?
總結
以上是生活随笔為你收集整理的Git merge时使用--no-ff参数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Markdown入门学习小结
- 下一篇: 阿里 delphi java_Delph