CI/CDをkatacodaで体験（初心者向け） - Part5(Fixing Merge Conflicts)

# CI/CD入門
このぺーじでは、[katacoda](https://www.katacoda.com/)と呼ばれる「ブラウザから無料で勉強用のインスタンスを起動できるWebサービス」を利用してCI/CDを実践します
内容は上記リンクに沿うので、不明点があればそちらへどうぞ

## Gitのバージョン管理について - Scenario5 - Fixing Merge Conflicts
ここでは、CI/CDとして欠かせないGitによるバージョン管理について学習します
このシナリオで学習することをさっと確認する場合は**概要**を確認
**理解に間違い等がございましたら、ぜひご指摘ください**

### <font color="Red">概要</font>
>- branchの分岐 × 分岐元と分岐先の同じファイル、同じ行に対して異なる変更 -> conflict発生
- ```git checkout --ours/theirs <file>```で分岐先、分岐元どちらを優先するか決定。その後優先した変更をcommitし劣後の変更を加える
- branch統合の方法は```git merge```と```git rebase```があるが、前者を用いた方がいい。詳しくは[こちら](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%99%E3%83%BC%E3%82%B9#rrbdiag_g)もしくは[こちら](https://www.atlassian.com/ja/git/tutorials/merging-vs-rebasing)



### Step 1 - Git Merge
step1では、リモートレジストリ上にあるファイルを数人で編集する際に発生する"conflict"というエラーの対処法について学習する
ローカルレジストリの状況は下記の通り

```
$ ls -a
.  ..  .git  staging.txt
$ cat .git/config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        url = /s/remote-project/1
        fetch = +refs/heads/*:refs/remotes/origin/*
```

リモートレジストリ"origin"が登録されており、同様に別の作業者もこのリモートレジストリを登録している
ローカルレジストリ上のmaster branchとremotes/origin/master branch（リモートレジストリからダウンロードした内容が保存されるbranch）の```staging.txt```が一致していないため、conflictが発生

```
$ cat staging.txt   //master branch
Fixing Error, Let's Hope No-One Else Does
$ git branch
* ESC[32mmasterESC[m
$ git branch -a
* ESC[32mmasterESC[m
  ESC[31mremotes/origin/masterESC[m
$ git checkout remotes/origin/master
Note: checking out 'remotes/origin/master'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at 4b304c4 Fix for Bug #1234
$ git branch
* ESC[32m(HEAD detached at origin/master)ESC[m
  masterESC[m
$ cat staging.txt   //remotes/origin/master branch
Fixing Previous Error
$ git checkout master
Previous HEAD position was 4b304c4 Fix for Bug #1234
Switched to branch 'master'
$ git branch -a
* ESC[32mmasterESC[m
  ESC[31mremotes/origin/masterESC[m
$ git merge remotes/origin/master
fatal: refusing to merge unrelated histories   //関連性のないヒストリを持つbranch同士のマージはGit2.9からできなくなった※１
$ git merge --allow-unrelated-histories origin/master   //上記エラーの対応
Auto-merging staging.txt
CONFLICT (add/add): Merge conflict in staging.txt
Automatic merge failed; fix conflicts and then commit the result.
$ cat staging.txt
<<<<<<< HEAD
Fixing Error, Let's Hope No-One Else Does
=======
Fixing Previous Error
>>>>>>> origin/master
```

[※１](https://qiita.com/takanatsu/items/fc89de9bd11148da1438)
```<<<HEADから====の部分と====から>>>>origin/master```で競合発生

### Step 2 - Viewing Conflict
マージ対象の```staging.txt```の差分を確認する際の一例として```git diff （branch_a）（branch_b）```を用いる

```
$ git diff master remotes/origin/master staging.txt
ESC[1mdiff --git a/staging.txt b/staging.txtESC[m
ESC[1mindex 02a3604..9139e85 100644ESC[m
ESC[1m--- a/staging.txtESC[m
ESC[1m+++ b/staging.txtESC[m
ESC[36m@@ -1 +1 @@ESC[m
ESC[31m-Fixing Error, Let's Hope No-One Else DoesESC[m
ESC[32m+ESC[mESC[32mFixing Previous ErrorESC[m
```

異なるファイルの差分を取る際は、```git diff br1:foo/bar.txt br2:hoge/fuga.txt```のように記述する

視覚的にコンフリクトを解消する方法として[kdiff3](http://kdiff3.sourceforge.net/)という外部ツールもある

### Step 3 - Resolving Conflict
コンフリクトが発生した場合の基本的対策は下記のいずれかです。
> - **自分**の変更結果を優先しコミット。その後、**相手**（コンフリクト先）の変更を組み込む
- **相手**の変更結果を優先しコミット。その後、**自分**（コンフリクト先）の変更を組み込む

自分もしくは相手を優先する際の方法は```git checkout <option> <file/directry>```のオプションに```--ours```もしくは```theirs```を与える

```
$ git checkout --theirs staging.txt   //レポジトリ先の変更を優先
$ git status
On branch master
Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both added:      staging.txt

$ cat staging.txt
Fixing Previous Error
$ git add staging.txt
$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

        modified:   staging.txt

$ git commit -m 'checkout --theirs'
[master 46801f2] checkout --theirs
$ git log --oneline
ESC[33m46801f2ESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[1;32mmasterESC[mESC[33m)ESC[m checkout --th
ESC[33m3e7785fESC[m Fixing Error
ESC[33mc2080aeESC[mESC[33m (ESC[mESC[1;31morigin/masterESC[mESC[33m)ESC[m Fix for Bug #1234
ESC[33mae9e69bESC[m First Commit
$ cat staging.txt
Fixing Previous Error
```

最初の```git status```で```both add: staging.txt```と見慣れない記載がされている
これは[こちら](https://qiita.com/hkengo/items/f47b9f50ac2dca407d12)に記載されている通り、コンフリクトの発生を知らせてくれる
また、どのようなコンフリクトが発生しているかも大まかに教えてくれる

>**注意**
katacodaでは、step1で```$ git merge --allow-unrelated-histories remotes/origin/master```を実行するよう要求されない
この操作を実行せずにstep3を実行しても```--ours/--theirs```オプションが反映されず```git status```の結果が変わらない
これは、katacodaの環境では自分のbranchとremoteのbranchが関連性を持っていないため、```git merge remotes/origin/master```では、コンフリクトの発生を認知できず、その後の```--ours/--theirs```オプションが意味をなしていないためと思われる
おそらく、最初にこの演習を作成した時点では、2つのbranchの関連性があったにも関わらず途中で関連性がないbranchを別に用意したのだろう
（ちゃんと演習内容も修正してほしい、、、、初心者殺しやん、こんなの涙）

```
$ git merge remotes/origin/master
fatal: refusing to merge unrelated histories   //関連性のないヒストリを持つbranch同士のマージはGit2.9からできなくなった※１
$ git merge --allow-unrelated-histories origin/master   //上記エラーの対応
Auto-merging staging.txt
CONFLICT (add/add): Merge conflict in staging.txt
Automatic merge failed; fix conflicts and then commit the result.
```

### Step 4 - Non-Fast Forward
step4では、以下の図のような場面を考える
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758476/4ddc620a-90d3-b0bc-2f78-cfdcd550976f.png)


```
$ ls -a
.  ..  .git  new-file-5a.txt  new-file-5.txt  new-file.txt  staging.txt
$ git log --oneline
ESC[33mc993ea3ESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[1;32mmasterESC[mESC[33m)ESC[m Fix for Bu
ESC[33m1f30797ESC[m Merge remote-tracking branch 'origin/master'
ESC[33m7b6b4d3ESC[m Fixing Error
ESC[33m499f006ESC[mESC[33m (ESC[mESC[1;31morigin/masterESC[mESC[33m)ESC[m Fix for Bug #1234
ESC[33mf9fb9b3ESC[m First Commit
$ git pull --no-edit origin master
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (4/4), done.
From /s/remote-project/1
 * branch            master     -> FETCH_HEAD
   499f006..b35bfb6  master     -> origin/master
Merge made by the 'recursive' strategy.
 new-file-6.txt  | 1 +
 new-file-6a.txt | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 new-file-6.txt
 create mode 100644 new-file-6a.txt
$ git log --all --decorate --oneline
ESC[33m3833389ESC[mESC[33m (ESC[mESC[1;36mHEAD -> ESC[mESC[1;32mmasterESC[mESC[33m)ESC[m Merge bran
ESC[33mb35bfb6ESC[mESC[33m (ESC[mESC[1;31morigin/masterESC[mESC[33m)ESC[m Fix for Bug #58a
ESC[33mc993ea3ESC[m Fix for Bug #55
ESC[33m1b74e50ESC[m Fix for Bug #58
ESC[33m1f30797ESC[m Merge remote-tracking branch 'origin/master'
ESC[33m7b6b4d3ESC[m Fixing Error
ESC[33m499f006ESC[m Fix for Bug #1234
ESC[33mf9fb9b3ESC[m First Commit
$ ls -a
.   .git             new-file-5.txt   new-file-6.txt  staging.txt
..  new-file-5a.txt  new-file-6a.txt  new-file.txt
```

開発者が自分の変更を容易に確認できる方法としてstep5で紹介する

### Step 5 - Git Rebase
```git rebase```を用いると以下の図のようなログを生成
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758476/63cf7342-2d74-eaff-351b-2136013defb8.png)

>**```git merge```と```git rebase```の復習**

>- 共通点：最新のbranchの状態は同じ（HEADの位置は異なる可能性あり）
- 差異：
    - merge：コミットの履歴を出来事の通り記録
    - rebase：コミットの流れを見やすく記録

>- 使い分け
基本的には、```git merge```一択
master branchの変更が活発でgit熟練者が複数人で使う場合は```git rebase```
**masterに統合->```git merge```**、**master以外に統合->```git rebase```**


詳しく知りたい方は[こちら](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%99%E3%83%BC%E3%82%B9#rrbdiag_g)もしくは[こちら](https://www.atlassian.com/ja/git/tutorials/merging-vs-rebasing)