今回はgitのコンフリクトについて考察する。
準備
desktopにSampleSiteフォルダーを作成し、main.cssを以下のように作成する。
h1{
color:red;
}
h2{
color:blue;
}
git init
ではこのフォルダーをgit管理していこう。以下のようにgit init
$ git init
add & commit
コミットしよう。以下のようにaddとcommitを行う
$ git add .
$ git commit -m"main.css作成"
ブランチをきる
ではブランチをきって開発していこう。
sub1ブランチ
$ git checkout -b sub1
main.cssを以下のように編集
p{
color:yellow;
}
h1{
color:red;
}
h2{
color:blue;
}
commit
sub1ブランチにいることを確認し以下のコマンド。作成済みのファイルに対しては-amを使うことでaddとcommitを一度に行える。
$ git commit -am"cssにp追加"
masterに戻る
ここで一度、masterブランチに戻る
$ git checkout master
新たにブランチを切る
今度はsub2ブランチを切ってmain.cssを以下のように編集する。masterブランチからブランチを切ったので先程ほど行ったpタグ部分がないことにも注目。
$ git checkout -b sub2
h1{
color:red;
}
h2{
color:blue;
}
div{
color:brown;
}
変更をcommit
$ git commit -am"cssにdiv追加"
確認
ここまでを確認しよう。masterブランチから2つのブランチが派生している。
masterにマージ
それではmasterブランチにこの変更を取り込んでいこう。
まずはmasterに移動
$ git checkout master
sub1をマージ
$ git merge sub1
masterブランチにsub1で行った変更が無事に取り込まれた。
こういった指しているポインターを先に進めるだけのマージをfast-forwardというのであった。
コンフリクト or not?
ではここでmasterブランチにさらにsub2の変更を取り込んでみよう。
実行する前にあなたも考えてもらいたい、ここでsub2をマージしたらどうなるであろうか、先ほどみたいに無事に取り込まれるのであろうか?それともコンフリクト(衝突)が起こるのであろうか?
やってみよう
$ git merge sub2
先ほどとは違いエディターが立ち上がった。このまま保存しよう。
recursive(再帰処理)によって無事に取り込むことができた。
確認
一応main.cssを確認しておこう。
masterから派生させた2つのブランチで行った。同一ファイルへの異なった追記がrecursvie処理によって無事に取り込まれたことがわかる。なぜ衝突が起こらなかったのだろうか?先頭と最後だったからだろうか?ここでさらに実験をしてみよう。
もとに戻す
最初の状態に戻そう。まずはmasterブランチで以下のコマンド
$ git reset --hard HEAD~~
これでmasterブランチで行ったコミットを2つ前(つまり一番最初)に戻ることができる。
2つのブランチを取り込む前の状態になった。ブランチでの変更もやり直したいので、2つのブランチを削除してしまおう。-Dと大文字のDを使うことで未マージのブランチでも強制的に削除することができる。
$ git branch -D sub1 sub2
これで完全に最初の状態(h1とh2だけある状態)に戻った
再び編集
再びsub1ブランチを作成し
$ git checkout -b sub1
今度は以下のように編集する
h1{
color:blue;
}
h2{
font-size:14px;
color:red;
}
$ git commit -am"h2にfont-size追加"
masterに戻って
$ git checkout master
sub2ブランチを作る
$ git checkout -b sub2
編集内容は以下。
h1{
color:blue;
}
h2{
color:red;
font-weight:bold;
}
$ git commit -am"h2にfont-weight追加"
先ほどと同様にmasterに戻り2つのブランチをマージしてみよう。
recursiveを使い先ほどと全く同じように2つの変更が無事に取り込まれることがわかる。
recursive処理によって無事に2つの変更が取り込まれた!
gitは基本的にはうまくやってくれる
今回はh2の中での変更だが、color:redの前なのか後なのかという明確な目印があった。こういった明確な目印がある場合にはmergeはrecursiveを使うことで成功する。
ではどういったときにコンフリクトが起こる?
では実際にコンフリクトを起こそう。masterブランチを最初の状態に戻して2つのブランチを削除して、また2つの異なるブランチで以下の変更を行う。
sub1ブランチでの変更
h1{
color:blue;
}
h2{
color:red;
}
p{
color:yellow;
}
sub2ブランチ
h1{
color:blue;
}
h2{
color:red;
}
div{
color:brown;
}
同じようにmasterブランチで順番にマージをしてみよう。
sub2をマージしようとしたときに以下のメッセージが表示されるはずだ。
今まではrecursiveによってうまいことmergeしてくれていたが、今回は失敗している。
今回はどちらのブランチでも文末となる7-9行目に処理を追記してしまった。このためgitはどう判断していいのかわからなくなってしまったのだ。
コンフリクトの修正
Merge conflict in main.cssとどのファイルが原因でコンフリクトが発生したのが書かれているのでそのファイルを開く
gitが判断できなかった部分を、
<<<<HEAD
=====
>>>>>sub2
という記号で教えてくれている。
エディタで望む状態に変更してあげよう。
今回は両方採用したいので以下のように編集する。
h1{
color:blue;
}
h2{
color:red;
}
p{
color:yellow;
}
div{
color:brown;
}
編集したらファイルを保存して、addする
$ git add .
そしてcommit
$ git commit -m"コンフリクト解消"
これで無事にmergeすることができた。
マージをあきらめる
今回はとても簡単なコンフリクトなのですぐに修正できたが、ときに修正作業に絶望を感じるコンフリクトが発生する場合がある。この場合はマージ自体をあきらめる以下のコマンドを覚えておくとよいだろう。
$ git merge --abort
こうすることでマージをあきらめ、その前の状態に戻ることができる。
コンフリクトがなるべく起こらないように開発を進めることが何よりも大事だが万が一コンフリクトが発生してもパニックにならずに落ち着いて対処できるようにしていこう。
コメント