# Git 小教室「在 Merge 之前想試試看有沒有衝突？」

> 在 Git 中，當要合併分支時，如果希望在合併之前檢查是否會有衝突，可以使用 git merge --no-commit --no-ff 命令。這個命令允許模擬合併的過程，但不會產生新的提交，讓您有機會檢查和調整合併結果。如果合併順利完成，則可使用 git merge --abort 來回到合併之前的狀態。這些選項有助於更好地管理合併過程，特別是在需要處理可能的衝突時。

Published: 2018-07-20
URL: https://kaochenlong.com/git-merge-dry-run

---

當你開了一個新的 branch，然後做了幾個 commit，進度做得差不多之後，下一步就是準備使用 `git merge` 指令來進行合併。但你手邊的專案可能有好一陣子沒跟線上的同步，這個 merge 執行下去可能噴一堆的衝突要解決。

不久前在社群分享就有朋友問到，有沒有辦法可以在進行 merge 之前先看看會不會發生衝突發生？

&lt;!--more--&gt;

除了直接合併下去，衝突再解掉或是再 `git reset` 回來就好的方法之外， `git merge` 指令目前並沒有類似 `git commit --dry-run` 的乾跑參數。

假設想要合併分支 `cat`，想做到乾跑效果可以這樣做：

    $ git merge cat --no-commit --no-ff

根據 Git 的說明手冊，對於 `--no-commit` 參數的說明如下：

&gt; 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 是怎麼回事，歡迎參閱「[為什麼我的分支都沒有『小耳朵』](https://gitbook.tw/chapters/branch/merge-commit.html)」章節。

那，就讓我們實際來操作一次：

目前專案裡有 `master` 跟 `cat` 兩個分支，`cat` 分支是從 `master` 分出去的，狀態如下：

![Git Merge Dryrun](/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBWHM9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--b43a06bb5f0267b66bc845da52f231d7c25e3427/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFJQUJXa0NBQVE9IiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--578d6799c87a604ca574298502ba874c9075e929/git-merge-dryrun1.png)

    $ 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 &quot;git commit&quot; to conclude merge)

    Changes to be committed:

      new file:   cat1.html
      new file:   cat2.html

的確就停在 Commit 之前的狀態，`cat1.html` 跟 `cat2.html` 都被放到暫存區了。

要注意的是，這個地方如果沒有加上 `--no-ff` 的話，雖然不會產生 Commit，但還是因為 Fast forward 而完成合併。

剛剛這個例子太順利的，沒有每天在過年的，讓我們再來看一個會衝突的例子：

![Git Merge Dryrun](/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBWHc9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3d7974ad464c88a456364361708c0877a8e3fd93/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFJQUJXa0NBQVE9IiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--578d6799c87a604ca574298502ba874c9075e929/git-merge-dryrun2.png)

在這個例子裡，`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 &quot;git commit&quot;)
      (use &quot;git merge --abort&quot; to abort the merge)

    Changes to be committed:

      new file:   member.html

    Unmerged paths:
      (use &quot;git add &lt;file&gt;...&quot; 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` 參數的手冊說明：

&gt; The second syntax (&quot;git merge --abort&quot;) 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 有關的疑難雜症或是應用情境，都歡迎來信或留言，如果討論的篇幅夠多就會另外整理一篇文章供大家參考。


