git merge/rebaseでconflictした時、git checkout --ours/--theirs
が何を指しているのかを整理する。
準備
mkdir test
cd test
git init
touch file
git add file
git commit -am 'init'
git checkout -b alice master
echo 'alice 1' >> file
git commit -am 'alice 1'
echo 'alice 2' >> file
git commit -am 'alice 2'
echo 'alice 3' >> file
git commit -am 'alice 3'
git checkout -b bob master
echo 'bob 1' >> file
git commit -am 'bob 1'
echo 'bob 2' >> file
git commit -am 'bob 2'
echo 'bob 3' >> file
git commit -am 'bob 3'
次のようなツリーになるので、ここから色々操作してみる。
* <49acc5b> [TTouka] (HEAD, bob) bob 3
* <a3bce11> [TTouka] bob 2
* <971d689> [TTouka] bob 1
| * <1596bc6> [TTouka] (alice) alice 3
| * <4c13261> [TTouka] alice 2
| * <e361716> [TTouka] alice 1
|/
* <93ce8a8> [TTouka] (master) init
例
merge
git checkout -b m-alice-bob alice
git merge bob
# Auto-merging file
# CONFLICT (content): Merge conflict in file
# Automatic merge failed; fix conflicts and then commit the result.
<<<<<<< HEAD
alice 1
alice 2
alice 3
=======
bob 1
bob 2
bob 3
>>>>>>> bob
- ours: m-alice-bob
- theirs: bob
m-alice-bobがbobをmergeするので、 Branch 'm-alice-bob' merges branch 'bob' into itself となる。
ours
git checkout --ours file
alice 1
alice 2
alice 3
theirs
git checkout --theirs file
bob 1
bob 2
bob 3
rebase
git checkout -b r-alice-bob alice
git rebase bob
# First, rewinding head to replay your work on top of it...
# Applying: alice 1
# Using index info to reconstruct a base tree...
# M file
# Falling back to patching base and 3-way merge...
# Auto-merging file
# CONFLICT (content): Merge conflict in file
# Failed to merge in the changes.
# Patch failed at 0001 alice 1
# The copy of the patch that failed is found in:
# /Users/TTouka/test/.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".
- ours: bobの先頭
- theirs: r-alice-bobのcommit
まずbobの先頭commitをcheckoutし、r−alice-bobのcommitを順番にmergeしていくので、 HEAD merges branch 'r-alice-bob' into itself となる。
ours
git checkout --ours file
bob 1
bob 2
bob 3
theirs
git checkout --theirs file
alice 1
git merge後のgit rebase -i
この記事の主目的。このパターンで混乱している人が目の前にいたので、整理してみる。
たとえば、先のmergeで発生したconflictを次のように修正してcommitする:
alice 1
bob 1
alice 2
bob 2
alice 3
bob 3
* <a5e4462> [TTouka] (HEAD, m-alice-bob) Merge branch 'bob' into m-alice-bob
|\
| * <49acc5b> [TTouka] (bob) bob 3
| * <a3bce11> [TTouka] bob 2
| * <971d689> [TTouka] bob 1
* | <1596bc6> [TTouka] (alice) alice 3
* | <4c13261> [TTouka] alice 2
* | <e361716> [TTouka] alice 1
|/
* <93ce8a8> [TTouka] (master) init
ここから git rebase -i
でsquashしてみる:
git checkout -b s-alice-bob m-alice-bob
git rebase -i HEAD~1
pick 971d689 bob 1
pick a3bce11 bob 2
pick 49acc5b bob 3
HEAD~1
という指定に対し、3つのcommitが表示された。
(merge commitの中身 (bob 1からbob 3) が1段階としてカウントされている。)
ここで、bob 2とbob 3をbob 1にsquashしてみる:
pick 971d689 bob 1
s a3bce11 bob 2
s 49acc5b bob 3
(save)
error: could not apply 971d689... bob 1
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".
Could not apply 971d689c3a8f3130660a22a8c4cbb46097eb4bdb... bob 1
* <a5e4462> [TTouka] (s-alice-bob, m-alice-bob) Merge branch 'bob' into m-alice-bob
|\
| * <49acc5b> [TTouka] (bob) bob 3
| * <a3bce11> [TTouka] bob 2
| * <971d689> [TTouka] bob 1
* | <1596bc6> [TTouka] (HEAD, alice) alice 3
* | <4c13261> [TTouka] alice 2
* | <e361716> [TTouka] alice 1
|/
* <93ce8a8> [TTouka] (master) init
s-alice-bobに属するコミットとしてbob 1からbob 3をrebaseするので、まずalice 3にbob 1が後続するためのrebaseが実行される。
Commit 'alice 3' merges commit 'bob 1' into itself なので
- ours: alice 3
- theirs: bob 1
conflictを修正し git rebase --continue
する
* <163a666> [TTouka] (HEAD) bob 1
| * <a5e4462> [TTouka] (s-alice-bob, m-alice-bob) Merge branch 'bob' into m-alice-bob
| |\
|/ /
| * <49acc5b> [TTouka] (bob) bob 3
| * <a3bce11> [TTouka] bob 2
| * <971d689> [TTouka] bob 1
* | <1596bc6> [TTouka] (alice) alice 3
* | <4c13261> [TTouka] alice 2
* | <e361716> [TTouka] alice 1
|/
* <93ce8a8> [TTouka] (master) init
順次修正、continueする
* <af8b869> [TTouka] (HEAD) bob 1 and bob 2
| * <a5e4462> [TTouka] (s-alice-bob, m-alice-bob) Merge branch 'bob' into m-alice-bob
| |\
|/ /
| * <49acc5b> [TTouka] (bob) bob 3
| * <a3bce11> [TTouka] bob 2
| * <971d689> [TTouka] bob 1
* | <1596bc6> [TTouka] (alice) alice 3
* | <4c13261> [TTouka] alice 2
* | <e361716> [TTouka] alice 1
|/
* <93ce8a8> [TTouka] (master) init
最終的にこうなる。
* <4eb944c> [TTouka] (HEAD, s-alice-bob) bob 1, bob 2, and bob 3
| * <a5e4462> [TTouka] (m-alice-bob) Merge branch 'bob' into m-alice-bob
| |\
|/ /
| * <49acc5b> [TTouka] (bob) bob 3
| * <a3bce11> [TTouka] bob 2
| * <971d689> [TTouka] bob 1
* | <1596bc6> [TTouka] (alice) alice 3
* | <4c13261> [TTouka] alice 2
* | <e361716> [TTouka] alice 1
|/
* <93ce8a8> [TTouka] (master) init
まとめ
merge/rebaseいずれの場合も A merges B into itself ととらえれば、
- ours: A (主語)
- theirs: B (目的語)
となって混乱しないと思う。