綾小路龍之介の素人思考

[Git] git rebase で CONFLICT した時の対処は

git のコンフリクトが発生した場合の対処方法。

カレントブランチに対して上流開発ブランチからの rebase を行う際に、コンフリクトが生じ、以下のメッセージが出て処理が止まったとする。

$ git rebase @{upstream}
First, rewinding head to replay your work on top of it...
Applying: THIS_COMMIT_MESSAGE_TITLE0
Using index info to reconstruct a base tree...
M       relative/path/to/file.txt
Falling back to patching base and 3-way merge...
Auto-merging relative/path/to/file.txt
CONFLICT (content): Merge conflict in relative/path/to/file.txt
Failed to merge in the changes.
Patch failed at 0001 THIS_COMMIT_MESSAGE_TITLE0
The copy of the patch that failed is found in:
   /home/path/to/GIT_WORK_TREE/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

ここでするべきことは表示されたメッセージに書かれたとおりだが、この情報は git status で確認することも可能。

$ git status
rebase in progress; onto XXXXXXX
You are currently rebasing branch 'current/branch/name/at/starting/rebase' on 'XXXXXXX'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

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

        both modified:   relative/path/to/file.txt

no changes added to commit (use "git add" and/or "git commit -a")

また、diff コマンドを使えばコンフリクトが発生した場所を確認できる。

$ git diff
diff --cc relative/path/to/file.txt
index DDDDDDD,BBBBBBB..0000000
--- a/relative/path/to/file.txt
+++ b/relative/path/to/file.txt
@@@ -5,7 -5,7 +5,11 @@@ msgid "
  CCCCCCCCC
  CCCCCCCCCCCCCCCCCCCCCCCCC
  CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
++<<<<<<< HEAD
 +OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
++=======
+ TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
++>>>>>>> THIS_COMMIT_MESSAGE_TITLE0
  CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  CCCCCCCCCCCCCCCCCCC
@@@ -13,7 -13,7 +17,11 @@@
  CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
++<<<<<<< HEAD
 +OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
++=======
+ TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
++>>>>>>> THIS_COMMIT_MESSAGE_TITLE0

  CCCCCCCCCCCCCCCC
  CCCCCCCCCCCCCCCCC

ここでは @{upstream} の変更を優先してコンフリクトを解消する。つまり、HEAD からの行を残して、THIS_COMMIT_MESSAGE_TITLE0 からの行を削除する。ここで大事なのは、git checkout --ours を使うこと。git checkout --theirs は間違い。なぜなら、git rebase でコンフリクトが起きた場合、カレントブランチは rebase を実行したブランチではなく、新たに作られた rebase 作業用の無名ブランチにいて、この無名ブランチは @{upstream} と rebase 実行時のカレントブランチの共通の子孫から作られ、先に @{upstream} (ours) の変更が取り込まれ、そして今 rebase 実行時のカレントブランチ (theirs) の変更が取り込もうとした際にコンフリクトが起きたから。

$ git checkout --ours relative/path/to/file.txt
$ git branch
* (no branch, rebasing current/branch/name/at/starting/rebase)
  current/branch/name/at/starting/rebase
(snip)

コンフリクトの解決が済んだら git diff で確認。git は修正があったファイルを知っているので、diff を取ってくれるが、結局違いはない事がわかる。OK なので git add でワーキングツリーの内容をインデックスに登録。

$ git diff
diff --cc relative/path/to/file.txt
index DDDDDDD,BBBBBBB..0000000
--- a/relative/path/to/file.txt
+++ b/relative/path/to/file.txt
$ git add relative/path/to/file.txt

git rebase の再開を指令すると、rebase 実行時のカレントブランチの変更が全て破棄されているけど良いか聞かれる。

$ git rebase --continue
Applying: THIS_COMMIT_MESSAGE_TITLE0
No changes - did you forget to use 'git add'?
If there is nothing left to stage, chances are that something else
already introduced the same changes; you might want to skip this patch.

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

今回の場合問題ないので、git rebase --skip。新たにコンフリクト発生。先程と同様に @{upstream} の修正を優先して取り込む。コンフリクトが発生したファイルが複数個あって、@{upstream} の修正を取り込む方針で問題ないことがわかっているならば、 git rebase --skip を何回も実行してもOK。

$ git rebase --skip
Applying: THIS_COMMIT_MESSAGE_TITLE1
Using index info to reconstruct a base tree...
M       relative/path/to/file.txt
Falling back to patching base and 3-way merge...
Auto-merging relative/path/to/file.txt
CONFLICT (content): Merge conflict in relative/path/to/file.txt
Failed to merge in the changes.
Patch failed at 0002 THIS_COMMIT_MESSAGE_TITLE1
The copy of the patch that failed is found in:
   /home/path/to/GIT_WORK_TREE/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

リファレンス

  1. Git - git-checkout Documentation

ソーシャルブックマーク

  1. はてなブックマーク
  2. Google Bookmarks
  3. del.icio.us

ChangeLog

  1. Posted: 2007-11-06T13:31:49+09:00
  2. Modified: 2007-11-06T13:31:49+09:00
  3. Generated: 2019-01-02T23:09:09+09:00