在使用 Git 的進行代碼版本控制的時候,往往會發現在 log 中出現 "Merge branch 'master' of ..." 這句話,如下圖所示。日志中記錄的一般為開發過程中對代碼的改動信息,如果出現過多例如上述描述的信息會造成日志的污染。

閱讀了一些外文的博客,下面就來一探究竟。
產生原因分析
當多人合作開發一個項目時,本地倉庫落后於遠程倉庫是一個非常正常的事情,可參考下圖。
A-B-C(master)
\
D(origin/master)
具體情境如下:
- 我當前拉取的遠端版本為
B,此時修改了代碼,並在本地倉庫 commit 一次,但並未 push 到遠端倉庫。 - 另一位開發者在
B的基礎上,同樣 commit 了一次並 push 到遠端倉庫。那么這個時候,我再 push 自己的代碼就會發生錯誤,如下。
To github.com:maoqyhz/usegit.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:maoqyhz/usegit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
這個時候我們會選擇,先 pull,再 push。Ok,push 成功,但是此時我們查看 log 就會發現除了我們自己提交的那條日志之外,會多出一條 "Merge branch 'master' of ..."。
那么,為什么會出現這種現象呢?其實是與 Git 的工作原理有關,對 Git 比較了解的人應該會知道,無論是 pull、push 亦或是 merge 操作,其實背后都是有很多的不同的模式的。
在進行 pull 操作的同時,其實就是 fetch+merge 的一個過程。我們從 remote 分支中拉取新的更新,然后再合並到本地分支中去。
- 如果 remote 分支超前於本地分支,並且本地分支沒有任何 commit 的,直接從 remote 進行 pull 操作,默認會采用
fast-forward模式,這種模式下,並不會產生合並節點,也就是說不會產生多余的那條 log 信息 - 如果想之前那樣,本地先 commit 后再去 pull,那么此時,remote 分支和本地會分支會出現分叉,這個時候使用 pull 操作拉取更新時,就會進行分支合並,產生合並節點和 log 信息。這兩種狀態分別如下圖所示:
# fast-forword
A-B-D(origin/master)
\
C'(master)
# merge
A-B-C-E(master)
\ /
D(origin/master)
如何避免
為了去除自動生成的 log 信息,有以下幾種解決方案:
- 如果你使用的是 Git Bash,直接使用
git pull --rebase。如果拉取不產生沖突,會直接 rebase,不會產生分支合並操作,如果有沖突則需要手動 fix 后,自行合並。 - 如果使用的是 GUI,例如 TortoiseGit,可以先 fetch,再手動 rebase 就可以了。
關於 rebase 和 merge
關於什么時候使用 rebase,什么時候使用 merge,開發者總結了幾條規則:
- 從 remote 分支拉取更新到本地時,使用 rebase。
- 當完成 bug 修復或新功能時,使用 merge 將子分支合並到主分支。
- 沒有人應該 rebase 一根共享的分支。
有關這兩者具體的操作,可以參考我在文章最后列出的博客。
