高見龍

Git/Ruby/Rails/iOS app Developer & Instructor, 喜愛非主流的新玩具 :)

Git 小說連載系列之「在 Merge 之前想試試看有沒有衝突?」

Git 小說連載系列」系列主要是針對在大家學習或使用 Git 的過程遇到的的一些有趣或微妙的情境而寫的短文,希望可以藉由這一系列的短文幫大家更容易的了解到底 Git 是怎麼回事。

當你開了一個新的 branch,然後做了幾個 commit,進度做得差不多之後,下一步就是準備使用 git merge 指令來進行合併。但你手邊的專案可能有好一陣子沒跟線上的同步,這個 merge 執行下去可能噴一堆的衝突要解決。

不久前在社群分享就有朋友問到,有沒有辦法可以在進行 merge 之前先看看會不會發生衝突發生?

除了直接合併下去,衝突再解掉或是再 git reset 回來就好的方法之外, git merge 指令目前並沒有類似 git commit --dry-run 的乾跑參數。

假設想要合併分支 cat,想做到乾跑效果可以這樣做:

$ git merge cat --no-commit --no-ff

根據 Git 的說明手冊,對於 --no-commit 參數的說明如下:

With –no-commit perform the merge but pretend the merge failed and do not autocommit, to give the user a chance to inspect and further tweak the merge result before committing.

這個參數會假裝這次的合併失敗,並且不會產生新的 commit,讓使用者有機會可以在 commit 前再做一些事。

而後面再加上 --no-ff 參數則是不希望 Git 使用 Fast Forward 方式合併,如果想了解 Fast Forward 是怎麼回事,歡迎參閱「為什麼我的分支都沒有『小耳朵』」章節。

那,就讓我們實際來操作一次:

目前專案裡有 mastercat 兩個分支,cat 分支是從 master 分出去的,狀態如下:

image

$ git merge cat --no-commit --no-ff
Automatic merge went well; stopped before committing as requested

Good! 沒發生衝突,但也沒產生 Commit 或 Fast Forward。看一下目前的 Git 狀態:

$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

  new file:   cat1.html
  new file:   cat2.html

的確就停在 Commit 之前的狀態,cat1.htmlcat2.html 都被放到暫存區了。

要注意的是,這個地方如果沒有加上 --no-ff 的話,雖然不會產生 Commit,但還是因為 Fast forward 而完成合併。

剛剛這個例子太順利的,沒有每天在過年的,讓我們再來看一個會衝突的例子:

image

在這個例子裡,payment 分支跟 member 因為剛好改到同一個檔案,所以 merge 應該會發生衝突:

$ git merge member --no-commit --no-ff
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

果然發生衝突了。看一下狀態:

$ git status
On branch payment
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:

  new file:   member.html

Unmerged paths:
  (use "git add <file>..." to mark resolution)

  both modified:   index.html

回到過去

在上面這兩個範例中,git reset --merge 指令來回到合併之前的狀態,而在 Git 1.7.4 版本之後,可使用 git merge --abort 也可以跟上面這個指令一樣的效果:

$ git merge --abort

再看一下狀態:

$ git status
On branch payment
nothing to commit, working tree clean

這樣就回到合併之前的狀態了。

來看一下這個 --abort 參數的手冊說明:

The second syntax (“git merge –abort”) can only be run after the merge has resulted in conflicts. git merge –abort will abort the merge process and try to reconstruct the pre-merge state.

簡單的說,如果合併沒有順利完成的話,這個參數可以讓專案會回到合併之前的狀態。

歡迎來聊聊

有任何跟 Git 有關的疑難雜症或是應用情境,都歡迎來信或留言,如果討論的篇幅夠多就會另外整理一篇文章供大家參考 :)

Comments