【Git】 ブランチの役割と作り方~マージまで
ブランチを用いることでそれぞれの作業を分離し、チームでの開発を大幅にスムーズにすることができます。
また、単に各人向けのブランチを作るだけでなく、環境ごと (本番、HotFix、ステージングなど) に分ける使い方もあります。
目次
ブランチとは
ブランチはその名の通り枝です。
Aの機能、Bの修正、Cの機能、というのを普通に共同編集してしまうと、別の機能が中途半端なせいで動作確認ができない、変なバグがでてうまくテストできない、編集場所がかぶってうまく編集できないなど、様々な問題が発生します。
ブランチを分けることで、それぞれの環境で別々のソースコードになるため、互いの作業がぶつかり合うことが大幅に減少します。

また、ブランチで行った変更をまとめて別のブランチに適用できます。これをマージ(merge)と言います。

これにより、メインブランチに中途半端な状態を入れずに済むため、常に問題なく動くブランチというものを作ることができます。
ブランチの作成
ブランチはbranch
コマンドで作成できます。
git branch <ブランチ名>
例えば、test1ブランチを作成したい場合は、git branch test1
とします。
ブランチは、今いるブランチから派生します。例えば、masterブランチにいる状態なら、新しく作成したブランチはmasterブランチ (派生元ブランチ) と同じ状態から始まります。
作業中のブランチを変更
開発したいブランチを変更するには、checkout
します。
git checkout <ブランチ名>
test1ブランチに変更したい場合は、git checkout test1
となります。
ちなみに、コミットしていない変更がある場合、ブランチの変更ができない場合があります。
> git checkout test2 error: Your local changes to the following files would be overwritten by checkout: hoge.txt Please commit your changes or stash them before you switch branches. Aborting
この場合、コミットするか、スタッシュに入れるか、変更をキャンセルする(git checkout .
)かなどして、変更が無い状態にする必要があります。
追跡対象にしていないファイルの変更は影響しません。
ブランチ一覧を表示
git branch
します。
$ git branch master * test1 test2
ブランチ作成時の注意点
ブランチを作る際は、注意すべき点があります。
- 必ずブランチを作る前に今いるブランチが正しいかチェックする
- 追跡対象外のファイルを除き、全ての変更をコミットしておく
特に1個目は重要です。途中まで作業したけど派生元のブランチが間違っていました、となると頑張ってコミットの内容を移動する必要があり、かなり面倒です。気をつけましょう。
マージ
ブランチをマージすることで、2つのブランチに加えられた変更を1つにまとめることができます。
マージには方向があり、例えばtest1
ブランチからmain
ブランチにマージした場合、test1
ブランチには何も起こらず、一般的に不要なブランチになります。マージされたmain
ブランチは、test1
ブランチに加えた変更が丸々反映されます。
試す
早速マージを試してみましょう。まずはmasterブランチに適当にコミットしておきます。
ファイル作成をterminal上で行っていますが、環境によってはUTF-16LE
等になり、バイナリファイル扱いされたりするので、普通にIDE上で作成したほうが良いです。
バイナリファイルになると、部分的な変更をうまく検出できず、ファイル全体で変わったか変わってないかの判定しかできなくなります。
# 適当にファイル作成 echo "# README" > readme.md git add . git commit -m "initial commit"
したら、ブランチを作成して切り替え、ファイルを更新してコミットします。
# ブランチ作成+切り替え git branch test1 git checkout test1 # 適当にreadme.mdファイルを変更 echo "hogehoge" >> readme.md # 適当にファイルを追加 echo "fuga" > fuga.txt # コミット git add . git commit -m "update test files"
これでtest1ブランチにコミットできました。次はこのブランチをmaster
ブランチにマージしてみましょう。
マージは、マージされる側にブランチに移動し、git merge <マージしたいブランチ>
とします。
# checkoutすると、masterブランチの状態に戻る git checkout master # test1ブランチの変更を適用 git merge test1
完了です! test1ブランチに行った変更が、全てmasterブランチに反映されているはずです。
どんな挙動をしているのか
マージする際は、test1ブランチで上書きしたのではなく、test1ブランチに加えられた変更をmasterブランチにも行った、というものです。

つまり、「readme.mdの2行目にhogehoge
を追加した」、「fuga.txtを追加した」というものをmasterブランチに行ったということです。
コンフリクト
コンフリクトは、つまり競合したということです。
例えば、
- test1ブランチでreadme.mdの2行目に”hogehoge”を追加した
- test2ブランチでreadme.mdの2行目に”fugafuga”を追加した
という作業をしたとします。この時、test1ブランチをmasterにマージ後、test2ブランチをmasterにマージしようとすると、同じ2行目に変更を加えているため、どちらを反映したらよいかをコンピュータでは判別できなくなります。これをコンフリクトといいます。
そもそもコンフリクトを起こさないように作業することが大事ですが、被るときは被るのでどうしたらよいか見ていきましょう。
まずは上の例の通りの作業をしてみます。
git init # ファイルを作成してコミット echo "# README" > readme.md git add . git commit -m "initial commit" # test1ブランチで作業する git branch test1 git checkout test1 # readme.mdの2行目に追加 echo "hogehoge" >> readme.md # 反映 git commit -a -m "update readme.md" # masterに戻って、test2ブランチを作成して作業 git checkout master git branch test2 git checkout test2 # readme.mdの2行目に追加 echo "fugafuga" >> readme.md # 反映 git commit -a -m "update readme.md"
これで、masterから派生したtest1ブランチとtest2ブランチに、同じ場所に異なる変更を加えました。
まずはtest1をmasterにマージします。
git checkout master # test1ブランチを現在のブランチにmerge git merge test1
次に、test2ブランチをmasterにマージしてみます。
$ git merge test2 Auto-merging readme.md CONFLICT (content): Merge conflict in readme.md Automatic merge failed; fix conflicts and then commit the result.
エラーのようなものが出ました。CONFLICT
という文字が見えます。
それと同時に、conflictを起こしたreadme.md
のファイルの中身が、この様になっていると思います。
# README <<<<<<< HEAD hogehoge ======= fugafuga >>>>>>> test2
これは、現在のブランチの最新の内容(HEAD)はhogehoge
で、mergeしたいtest2ブランチの内容はfugafuga
で、どっちを適用したらよいか判別できない、という状態です。
この場合は、人がどちらをどう適用するか判別する必要があります。正しい状態になるように編集するということです。多くの場合は、どちらか片方を全部適用、または両方を全部適用だと思います。
VSCodeの場合は次のような表示になり、手でコピペしたり以外にもボタンで作業を選択できます。

どのように適用するかを選んだら、add
してコミットしてコンフリクトの解消完了です。
$ git add <ファイル> $ git commit -m "コメント"
git merge --abort
でマージをキャンセルできます。
コンフリクトが起きる条件
コンフリクトは、作業場所が重複した場合に発生します。ファイルが重複ではありません。
例えば、
- test1ブランチで、readme.mdの10行目に5行追加した
- test2ブランチで、readme.meの5~20行目を削除した
これは改修場所が被っているのでコンフリクトします。しかし、
- test1ブランチで、readme.mdの10行目に5行追加した
- test2ブランチで、readme.meの30~40行目を削除した
この場合、ファイルは同じですが改修場所は被っていないため、コンフリクトしません。
リモートリポジトリと連携
アップロード (push)
ブランチをリモートリポジトリに上げるには、普通にpush
するだけです。
git push -u origin HEAD # または git push -u origin <ブランチ名>
-u
は、今のブランチに対する上流ブランチを設定するものです。上流ブランチは、要はリモートリポジトリのブランチです。
-u
をするとローカルブランチとリモートのブランチが紐づき、次回からはgit push
だけでpushできるようになります。
これは、各ブランチの最初のpushだけで十分です。
ブランチの内容を更新 (pull)
リモートリポジトリにあるブランチを手元に持ってきて作業したい場合、pull
のみでokです。
git pull
ブランチを取得
リモートにはあってローカルには無いブランチで、リモートからブランチを取得するにはfetch
します。
# ブランチ取得 git fetch origin <ブランチ名> # 切り替え git checkout <ブランチ名>
まとめ
ブランチを活用することで、各作業を分離することができます。ブランチを作る際は、今いるブランチに注意を払って作成するべきです。
マージする際にもしコンフリクトが発生した場合、手動で解決する必要があるため、できるだけコンフリクトを起こさないように作業を分担しましょう。
