NITICNoobsによるGit/GitHub講座 第5回 〜競合を解決する〜

フライさん(loxygen)です。[限界開発鯖](https://approvers.dev/)でのだのだ言っています。~~フライさんにおまかせなのだ！~~
説明はあまり得意ではありません。

**※この記事は茨城高専生向けに書かれたものです。**

# お説明
前回使用したリポジトリを引っ張ってきて、そこでGit Bashを開いておいてください。
現在のコミット履歴は以下のようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/1e5bb865-e96a-284c-33e2-ff43735b1713.png)

## コンフリクト

`hello.txt`がこれまでどのように編集されてきたかを見てみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/68bfa1fb-e4f1-b472-2d4f-11d289560219.png)

`add-new-func`ブランチと`add-new-func-2`ブランチの編集場所が**まるっきりかぶっています**。
これでは**`add-new-func`ブランチと`add-new-func-2`ブランチ両方の内容を取り入れることができません**。
だからと言ってどちらかの変更を消し飛ばすのも人間性がありません。

通常Gitは`git merge 〇〇`コマンドを打てば自動でマージしてくれますが、こうなってしまうとどうすれば良いのかわかりません。するとGitは「**コンフリクト**」を宣言します。

コンフリクトになると、Gitの代わりに**開発者自らの手で変更内容をマージする**作業が必要になります。
だから開発者はコンフリクトを忌み嫌うわけですね。

## 確認作業
[前回](https://qiita.com/Flisan/items/e6398225905e0ed906dc#マージする前の確認作業)、「マージする前に確認作業をするとお作法がいいよ」という話をしました。
### どうして確認作業が必要なんですか
確認作業の説明の前に、存在意義を説明させてください。
ちょっとこの図をご覧ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/074c5226-cf5b-d26a-de16-6f8320f50ad4.png)
さっき上に出した図の簡略版です。
[前回のお練習](https://qiita.com/Flisan/items/e6398225905e0ed906dc#%E3%81%8A%E7%B7%B4%E7%BF%92)の中で`add-new-func-2`ブランチを作りましたね。
同じ要領でマージしようとしてみました。

すると、先程の理由で**コンフリクトします。**コミット履歴はこのようになります:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/7be54dc4-7812-52f1-c7d9-842f4d46fedd.png)

この後手動でマージ作業を行うわけですが、その作業を行うブランチは先程チェックアウトした**`master`ブランチ**です。
[前回**`master`ブランチは品質が保証される**ということを記述しました](https://qiita.com/Flisan/items/e6398225905e0ed906dc#品質を保証できる)が、そんな`master`ブランチで作業をするのは**極めておっかない**ことはわかりますよね。
マージ作業に失敗したら**バグがあったり、最悪の場合全く動かない状態のものが`master`ブランチにコミットされてしまいます**。ああ、怖い怖い！

### 確認作業
そこで、**`master`ブランチにチェックアウトした状態でのコンフリクトを防ぐ**ために、
**事前に`add-new-func-2`ブランチでコンフリクトを発生させる**ということを行います。
これこそが**確認作業**です。便宜上確認作業と読んでいますが、正式なお名前はたぶんないです。

こういうことです:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/a21d3a50-42ed-0dfc-bcb5-1ef4c381dc3d.png)
`master`ブランチから`add-new-func-2`に、**逆方向にマージ**してから`master`にマージしています。
こうすることで**マージ作業を`add-new-func-2`ブランチで行ってから`master`にマージ**することができます。
`master`ブランチじゃないところでマージ作業ができるので、気が楽ですし、**何より安全です**。

## 確認作業を行った上でマージしてみる

習うより慣れろ、と昔偉い人は言いました。実際にやってみましょう。

### 逆マージする

まずは`add-new-func-2`に`master`をマージするんでしたね。
マージの方法は[前回説明しました](https://qiita.com/Flisan/items/e6398225905e0ed906dc#マージする)。やってみましょう。

```bash:Bash
$ git checkout add-new-func-2
Switched to branch 'add-new-func-2'.

$ git merge master
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.
```

…ん？**`failed`ですって？**
はい。先程の理由で**コンフリクトしました**。

`git status`も見てみましょう。

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

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

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

`You have unmerged paths`…まだマージしきれてないやつがあるで！
と言われていますね。

現在、コミット履歴は以下のようになっています:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/991e7bc1-2a4e-d9ac-2a88-aaac5cc46b10.png)

## ファイルには何が起こっている?
`hello.txt`の中身を見てみましょう。
中身は`cat`コマンドで見れます。もちろん任意のテキストエディタで見ても大丈夫です。

```bash:Bash
$ cat hello.txt
```
上のコマンドを叩く、またはテキストファイルを任意のエディタで見ると以下のようになっています:

```text:hello.txt
<<<<<<< HEAD
I am the kindest person.
=======
I am the greatest people.
>>>>>>> add-new-func-2
```

世界が急に混沌に包まれてしまいました。落ち着いて読み解いて行きましょう。と言っても簡単です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/d2c6ea1b-3d5f-e5cb-a058-db6273e32d16.png)
これだけです。**現在のブランチ**(マージ先)の状態と**マージ元**の変更内容が一緒に書いてあるだけです。

## 解消する
解消方法は至って簡単で、2つのブランチの変更内容をいい感じにフュージョンしてやればOKです。[^2]
今回の場合は、**`I am the kindest human.`と`I am the greatest people.`をいい感じにフュージョン**してやればいいわけです。

`hello.txt`をご自由に変更してみてください。

<details open>
<summary>おヒント</summary>
<div>

筆者の場合は…

- `kindest`と`greatest`については、２つの特徴を両方取り入れて、`I am the kindest and greatest ***.`にしたい
- `human`と`people`という単語は不適切[^3]なので、`person`に修正したい

と考えました。

というわけで、筆者であれば以下のように修正します。

```text:hello.txt
I am the kindest and greatest person.
```
----

</div></details>

いい感じにフュージョンできたら、「`<<<<<<< HEAD`」から「`>>>>>>> add-new-func-2`」は消してください。

## コンフリクト解消

全てのコンフリクトが解消できたら(今回の場合は一箇所だけなのでこれで終わりです)、いつものようにAddしてCommitしましょう。

```bash:Bash
$ git add --all
```

`git status`も見ておきましょう。

```bash:Bash
$ git status   
On branch add-new-func-2
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
	modified:   hello.txt
```

`All conflicts fixed but you are still merging`…「コンフリクトは全部直ったけどまだマージ作業中やで！」と言われています。まだコミットしてないからですね。コミットをしましょう。

```bash:Bash
$ git commit -m "Resolved conflict between master and add-new-func-2"
[add-new-func-2 ef01234] Resolved conflict between master and add-new-func-2
```

これでコンフリクトが解消され、`add-new-func-2`上でコンフリクトの修正に成功しました。
コミット履歴はこうなっています:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/7a66b7fd-74c9-4322-b811-d40c2be5792e.png)
## masterにマージする

これで`master`ブランチとのコンフリクトが起きない状態になったので、心に余裕を持ってマージすることができます。ちゃちゃっとやってしまいましょう。

```bash:Bash
$ git checkout master
Switched to branch 'master'

Updating 38f1b56..03eafb0
Fast-forward
 hello.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
```

一応`hello.txt`の中身も見てみましょう。例のごとく`cat`コマンドを使用しますが、お好みのエディタで確認しても大丈夫です。

```bash:Bash
$ cat hello.txt
I am the kindest and greatest person.
```

先程修正した内容が正常に`master`ブランチに反映されていますね。
コミット履歴はこうなりました:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413967/b402f03c-0f31-338b-3b24-ecea10fb2853.png)

これでようやく**コンフリクトした状態からのマージに成功しました**。お疲れ様でした。

## マージ作業を取りやめたい場合
なにか事情があって途中でマージ作業をキャンセルしたくなったとします。その時は以下のコマンドを入力してください:

```bash:Bash
$ git merge --abort
```

## 「コンフリクト起こらんやろ！」って場合
例えば小さい変更だったり、他の人が全くいじらなかったところを変更したりした場合などで、コンフリクトする確率は低いと判断できる場合があります。
その場合はちょっとお行儀悪いですが、**確認作業を踏まずにmasterにマージして問題ない**でしょう。

コンフリクトしてしまった場合は、そこで直さずに`git merge --abort`を実行してから、マージする元のブランチにいって確認作業を踏むと世界が平和になります。

以下に**「コンフリクト起こらんやろ！と信じて`master`ブランチに直接マージしようとしたものの、コンフリクトしてしまい元のブランチで確認作業を行ったときの動き」**を記しておきます。
(なお、すでに`add-new-func-2`はマージしてしまったので以下のコマンドは動きません)

```bash:Bash(動きません)
$ git checkout master
Switched to branch 'master'

$ git merge add-new-func-2
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.

$ git merge --abort # 一旦マージ作業をやめる

$ git checkout add-new-func-2
Switched to branch 'add-new-func-2'

# 以下確認作業を行う
```

# おまとめ
- 別々のブランチで同じファイルの同じ場所を編集すると**コンフリクト**が起こる
- 以下の「確認作業」を踏むのが好ましい
    - 1.`master`ブランチを作業中のブランチにマージする
    - 2. コンフリクトが発生したら以下の手段を踏む:
        - 1. `>>>>>>> 〇〇`と`<<<<<<< ⬜⬜`の間をいい感じにフュージョンする
        - 2. 全部終わったら`git add --all`して`git commit`
    - 3. `master`ブランチにチェックアウトする
    - 4. マージする
- 強制ではないので、「多分コンフリクト起こらんやろ〜」と判断できる場合は飛ばしても良い

これでブランチについてはひとまず終了です。ここまで本当にお疲れ様でした！

# おリンク
**[第1回](https://qiita.com/Colk-tech/items/e75c61146cabc887ad29)** インストール編
**[第2回](https://qiita.com/Colk-tech/items/f0817df7c6fdc9a7f283)** 設定編
**[第3回](https://qiita.com/Colk-tech/items/8d4b28b9001b862eeb99)** 実際に使ってみよう-基本技能編
**[第4回](https://qiita.com/Flisan/items/e6398225905e0ed906dc)** ブランチ(平行世界)編-1
**第5回 いまここ**
**[第6回](https://qiita.com/ko_5/items/c0c45c80f12e0072e51e)** GitHub入門編
**[第7回](https://qiita.com/isso0424/items/a7a0816d9a7f0caf1de6)** fetch/pull編
**[第8回](https://qiita.com/isso0424/items/6fc09a68bf0011dfc922)** issue/Pull Request編

# 執筆者
- [いっそう](https://twitter.com/kousou4129)
- [こ](https://twitter.com/ko_CottonLove)
- [こるく](https://twitter.com/Colk_)
- [フライさん](https://twitter.com/loxygenK)

[^1]: もし叩いてしまったら、`git merge --abort`してください。マージ作業がキャンセルされます。
[^2]: 実際のプログラミングでコンフリクトに遭遇すると、フュージョンさせるのが大変だから困るんですよね…
      もちろん楽なケースもあります。場合によってはツールが自動解決してくれる場合もあります。
[^3]: 主語が`I`なので、単数であることは確実です。単数に対して`people`は使わないので不適切です。
      `human`は良いかも知れませんが…`person`のほうが自然です。不適切とまでは行きませんが、`person`のほうが適切です。