カテゴリー
コンピューター

【Git】コンフリクトが発生する3つのブランチのマージをしたときの記録とポイント

概要

共通の祖先をもつ3つのブランチをマージしたい

  • origin/feature1
  • origin/feature2
  • origin/feature3

  • feature1-2-3

へとマージしたいですわ。

なお feature1-2-3 は master からチェックアウトしたマージ専用のブランチですの。

マージ手順概要

  1. master ブランチで feature1-2-3 ブランチでを作成
  2. feature1-2-3 ブランチにチェックアウト
  3. origin/fiature1 をマージコミットを作成してマージ
  4. origin/feature2 を –no-commit 指定でマージ
  5. コンフリクトを解消してコミット
  6. origin/feature3 を –no-commit 指定でマージ
  7. コンフリクトを解消してコミット

気がついたこと

  • ローカルブランチを改めて作成する必要は無い。リモートリポジトリの追跡ブランチ (fetch した状態) からマージ可能だった。
  • マージするときは、origin/feature1 といったリモートリポジトリのつ追跡ブランチを直接指定すればよい。
  • コンフリクトの解消は、Atom の merge-conflicts を使用した。過度に自動的にならず、Git のマーカーのハイライトとそのカウントに特化していて使いやすかった。

使用したコマンドまとめ

# ログ確認
git log --all --decorate --graph --oneline

# ブランチを作成し、そこにチェックアウト
git checkout -b feature

# マージコミットを作成してマージ実行
git merge --no-ff feature
# コミットをしないでマージ実行
git merge --no-commit feature
# もう一度チェックアウトし、コンフリクトマーカーを書き直す。
# 通常のマーカーである "ours" と "theirs" に加え、"base" も表示
# 自分たちの分 (ours)、相手側 (マージしようとしているブランチ) の分 (theirs)、
# 共通 (両方のブランチの共通の祖先) の分 (base) の3つのバージョンを表示
git checkout --conflict=diff3 .
# マージ中止。マージを実行する前の状態に戻る。
git merge --abort

# 作業ディレクトリ、インデックスの状態確認
# s: 簡潔に表示
# b: 現在のブランチを表示
git status -sb

# HEAD とインデックスの差分をファイル名のみ表示
git diff --cached --name-only
# HEAD とインデックスの差分を表示
git diff --cached

実践記録

  • controllers/code1.php でコンフリクトが発生
  • feature1 でも 2 でも 3 でも controllers/code1.php を編集している。
$ # 作業前の状態を確認
$ git log --all --decorate --graph --oneline
* a2e47a0 (origin/feature2) feature2完成
* 6386bbb (feature2) feature2途中
| * 3e9c40f (origin/feature3) feature3完成
|/
| * 640e7c9 (origin/feature1, feature1) feature1完成
|/
* clell8f (HEAD -> master, origin/master) 最初のコミット
$
$ # マージ用ブランチの作成・チェックアウト
$ git checkout -b feature1-2-3
Switched to a new branch 'feature1-2-3'
$
$ # 1回目のマージ(マージコミットを作成)
$ git merge --no-ff origin/feature1
Merge made by the 'recursive' stategy.
 controllers/cod1.php    | 266 ++++++++------
 .../models/code2.php    | 395 +++++++++++++++++++++++
 views/code3.php        |   8 +-
 views/code4.php        |   2 +-
 views/code5.php        |  43 ++-
 5 files chnged, 579 insertions(+), 135 deletions(-)
 create mode 100644 models/code2.php
$
$ # マージ結果確認
$ git log --all --decorate --graph --oneline
*   8ed3e0a (HEAD -> feature1-2-3) Merge remote-tracking branch 'origin/feature1' into feature1-2-3
|\
| * 640e7c9 (origin/feature1, feature1) feature1完成
|/
| * a2e47a0 (origin/feature2) feature2完成
| * 6386bbb (feature2) feature2途中
|/
| * 3e9c40f (origin/feature3) feature3完成
|/
* clell8f (HEAD -> featrure1-2-3, origin/master, master) 最初のコミット
$
$ # 2回目のマージ。コンフリクト発生
$ git merge --no-commit origin/feature2
Auto-merging controllers/code1.php
CONFLICT (content): Merge conflict in controllers/code1.php
Automatic merge failed; fix conflicts and then commit the result.
$
$ # 作業ディレクトリ、インデックスの状態を確認
$ # UU: コンフリクトが発生しているファイル。作業ディレクトリにある。
$ # M : コンフリクトが発生していないファイル。ステージングにある。
$ git status -sb
## feature1-2-3
UU controllers/code1.php
M  models/code6.php
$
$ # 差分を確認したが、自分と相手だけでは何をマージすべきかがわからなかった。
$ git diff
$
$ # もう一度チェックアウトし、コンフリクトマーカーを書き直す。
$ # 自分たちの分 (ours)、相手側 (マージしようとしているブランチ) の分 (theirs)、
$ # 共通 (両方のブランチの共通の祖先) の分 (base) の3つのバージョンを表示
$ git checkout --conflict=diff3 .
$
$ # ours: origin/feature1 をマージして取り込んだ feature1-2-3
$ # base: 共通の祖先である master 
$ # theirs: これから取り込む origin/feature2
$ # エディタでコンフリクトを解消し、保存。
$
$ # コンフリクト解消を Git に知らせるには git add
$ git add controllers/code1.php
$
$ # git status でコンフリクト解消済みである、
$ # と Git がみなしたことが確認できる。
$ # マージを完了させるためにはコミットする。
$ git status
On branch feature1-2-3
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

        modified:    controllers/code1.php
        modified:    models/code6.php

$
$ # コミットする前に、コミットされる差分を確認
$ git diff --cached --name-only
controllers/code1.php
models/code6.php
$ git diff --cached
$ # 差分表示は省略
$
$ # 2回目のマージをコミット
$ # コミットメッセージとして、自動的にテンプレート文章が設定されていた。
$ # テンプレートをそのまま利用した。
$ git commit
$
$ # マージ結果確認
$ git log --all --decorate --graph --oneline
*   7ce6253 (HEAD -> feature1-2-3) Merge remote-tracking branch 'origin/feature2' into feature1-2-3
|\
| * a2e47a0 (origin/feature2) feature2完成
| * 6386bbb (feature2) feature2途中
* | 8ed3e0a Merge remote-tracking branch 'origin/feature1' into feature1-2-3
|\ \
| |/
|/|
| * 640e7c9 (origin/feature1, feature1) feature1完成
|/
| * 3e9c40f (origin/feature3) feature3完成
|/
* clell8f (HEAD -> featrure1-2-3, origin/master, master) 最初のコミット
$
$ # 3回目のマージ。コンフリクト発生
$ git merge --no-commit origin/feature3
Auto-merging controllers/code1.php
CONFLICT (content): Merge conflict in controllers/code1.php
Automatic merge failed; fix conflicts and then commit the result.
$
$ # 作業ディレクトリ、インデックスの状態を確認
$ # UU: コンフリクトが発生しているファイル。作業ディレクトリにある。
$ # A : コンフリクトが発生していない新規追加ファイル。ステージングにある。
$ git status -sb
## feature1-2-3
UU controllers/code1.php
A  html/code7.css
$
$ # 差分を確認したが、今回も自分と相手だけでは何をマージすべきかがわからない。
$ git diff
$
$ # もう一度チェックアウトし、コンフリクトマーカーを書き直す。
$ # 自分たちの分 (ours)、相手側 (マージしようとしているブランチ) の分 (theirs)、
$ # 共通 (両方のブランチの共通の祖先) の分 (base) の3つのバージョンを表示
$ git checkout --conflict=diff3 .
$
$ # ours: origin/feature1 と origin/feature2 をマージして取り込んだ feature1-2-3
$ # base: 共通の祖先である master 
$ # theirs: これから取り込む origin/feature3
$ # エディタでコンフリクトを解消し、保存。
$
$ # コンフリクト解消を Git に知らせるには git add
$ git add controllers/code1.php
$
$ # git status でコンフリクト解消済みである、
$ # と Git がみなしたことが確認できる。
$ # マージを完了させるためにはコミットする。
$ git status
On branch feature1-2-3
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

        modified:    controllers/code1.php
        new file:    html/code7.css

$
$ # コミット
$ git commit
[feature1-2-3 4fc132d] Merge remote-tracking branch 'origin/feature3' into feature1-2-3
$
$ # マージ完了!ログを確認
$ git log --all --decorate --graph --oneline
*   4fc132d (HEAD -> feature1-2-3) Merge remote-tracking branch 'origin/feature3' into feature1-2-3
|\
| * 3e9c40f (origin/feature3) feature3完成
* |   7ce6253 (HEAD -> feature1-2-3) Merge remote-tracking branch 'origin/feature2' into feature1-2-3
|\ \
| * | a2e47a0 (origin/feature2) feature2完成
| * | 6386bbb (feature2) feature2途中
| |/
* |   8ed3e0a Merge remote-tracking branch 'origin/feature1' into feature1-2-3
|\ \
| |/
|/|
| * 640e7c9 (origin/feature1, feature1) feature1完成
|/
* clell8f (HEAD -> featrure1-2-3, origin/master, master) 最初のコミット
$

おわりに

複数のブランチ、それもリモートリポジトリの追跡ブランチ、をマージし、コンフリクトを 2 つではなく 3 つのソースと比べて解消したりと、随分と難しいことを行ってきました。

ですけれども、ひとつひとつのコマンドや実行していることの内容はほとんど今まで体験してきた Git 操作でしたの!

積み重ねですわね♪

次のページが参考になりました!ありがとう存じます♪

以上です。

コメントを残す