CI/CD入門
このぺーじでは、katacodaと呼ばれる「ブラウザから無料で勉強用のインスタンスを起動できるWebサービス」を利用してCI/CDを実践します
内容は上記リンクに沿うので、不明点があればそちらへどうぞ
Gitのバージョン管理について - Scenario5 - Fixing Merge Conflicts
ここでは、CI/CDとして欠かせないGitによるバージョン管理について学習します
このシナリオで学習することをさっと確認する場合は概要を確認
理解に間違い等がございましたら、ぜひご指摘ください
概要
- branchの分岐 × 分岐元と分岐先の同じファイル、同じ行に対して異なる変更 -> conflict発生
-
git checkout --ours/theirs <file>
で分岐先、分岐元どちらを優先するか決定。その後優先した変更をcommitし劣後の変更を加える - branch統合の方法は
git merge
とgit rebase
があるが、前者を用いた方がいい。詳しくはこちらもしくはこちら
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からできなくなった※1
$ 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
※1
<<<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という外部ツールもある
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
と見慣れない記載がされている
これはこちらに記載されている通り、コンフリクトの発生を知らせてくれる
また、どのようなコンフリクトが発生しているかも大まかに教えてくれる
注意
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からできなくなった※1
$ 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
$ 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 merge
とgit rebase
の復習
- 共通点:最新のbranchの状態は同じ(HEADの位置は異なる可能性あり)
- 差異:
- merge:コミットの履歴を出来事の通り記録
- rebase:コミットの流れを見やすく記録
- 使い分け
基本的には、git merge
一択
master branchの変更が活発でgit熟練者が複数人で使う場合はgit rebase
masterに統合->git merge
、master以外に統合->git rebase