ハックガールズと学ぼう!ゼロから学ぶGit講座

第6回ブランチを活用した開発

皆さん、こんにちは!

エンジニアアイドル「ハックガールズ」の堤沙也と濱ヶ崎美季です。

私たちと一緒にGitを学ぶこの連載も、いよいよ今回で最終回となりました。最終回はGitの醍醐味である複数人での共同開発時に欠かせないブランチを活用した開発について紹介します!

ブランチの意義

ブランチは、個人で開発をする時にも、複数人で共同開発する時にも活用できます。たとえば複数の機能を平行して開発したい場合。

上司:
来月頭までに機能Aと機能Bをリリースする!
あなた:
了解です。機能Aをリリースしたあとに、機能Bの開発に着手すれば良いですか?
上司:
それが、取引先の要望次第で、機能Bのリリースだけが先になるかもしれないんだ……。同時に下準備だけ進めておいてくれないか。
あなた:

すなわち、機能Aと機能Bの開発を同時に進めたいが、どちらを先にリリースするかはまだ未定。1つのリポジトリに対して開発する機能ですが、各々影響を与えあわない状況下で同時に開発を進めたい、といった要件で活躍します。

このとき、機能Aと機能Bを開発しているのが個人であっても、機能AをAさんが開発して、機能BをBさんが開発するという複数人での開発であっても、ブランチを分けて開発を進めれば良いということです。

masterブランチという現実世界に対して、別のブランチという、複数のパラレルワールドを作るイメージです。

図1 masterブランチからほかのブランチをつくる
図1 masterブランチからほかのブランチをつくる
illustration by Youko Watanabe

今回紹介する、ブランチに関するgitコマンドは下記の通りです。

  • git branch
  • git fetch
  • git rebase
  • git merge
  • git pull

1つ1つ見て行きましょう!

ブランチの作成

git branch

機能Aの開発用ブランチを作成したい場合は、下記のコマンドで作成することができます。

git branch feature/A (feature/Aブランチの作成)
git co feature/A (現在のブランチから、feature/Aブランチに移動する)

git fetch

また、git fetchで、リモートリポジトリの最新の履歴を現在の作業ディレクトリに取得することができます。

たとえば、共同開発チームのAさんがAブランチをリモートリポジトリにpushしていたとします。そのとき

git fetch origin(リモートリポジトリ)

で、Aブランチが自分の作業ディレクトリで扱えるようになります。

図2 他のブランチを自分の作業ディレクトリで扱える
図2 他のブランチを自分の作業ディレクトリで扱える
illustration by Youko Watanabe

ブランチの確認

引数なしで、

git branch

と実行すると、現在の作業ディレクトリに存在するブランチを確認することができます。デフォルトの状態ではmasterブランチというブランチのみが存在する状態になっていますが、作成したブランチが別にあれば、その一覧が表示されます。接頭にアスタリスクが付いているブランチが、現在のブランチです。

また、直前で紹介した git fetchでリモートリポジトリから取得したブランチを確認するには、

git branch -a

を実行します。このとき、⁠remote/origin/branch名」といった remoteという接頭辞付きで表示されているブランチがリモートリポジトリから取得したブランチです。

変更の取り込み

リモートリポジトリから取得したブランチの変更を自分の作業ディレクトリのブランチに取り込みたい場合、もしくは自身の作業ディレクトリ内で作業用のブランチの変更をmasterブランチなど、別のブランチに合流させたい場合など、ブランチの統合を行うには、大きく分けて2つの方法があります。

それがrebaseとmergeです。

図3 rebaseとmerge
図3 rebaseとmerge
illustration by Youko Watanabe

git rebase

今回は作業用のfeat/Aブランチをmasterブランチに統合したいとします。コマンドは、

git checkout -b feat/A (-bオプションでfeat/Aブランチを作成し、checkoutで移動)
git rebase master (現在のブランチfeat/Aにmasterをrebase)

です。

このとき、仮にfeat/Aブランチの分岐元が、masterの最新commitよりも古い場所だったとしても、feat/Aブランチの分岐元がmasterブランチの最新のコミットへ移動します。これがgit rebaseの特徴です。

git merge

rebaseと似て非なる統合コマンドがmergeです。

git checkout -b feat/A (-bオプションでfeat/Aブランチを作成し、checkoutで移動)
git merge master (現在のブランチfeat/Aにmasterをmerge)

rebaseとの違いは、仮にfeat/Aブランチの分岐元が、masterの最新commitよりも古い場所だった場合、mergeコミットと呼ばれる「ブランチを統合した記録」のcommitが新たに作成されるということです。

すなわち、⁠Merge branch ⁠feat/A'」といったメッセージがついた commitが作成されるため、feat/Aブランチという別のブランチがmasterにこのタイミングで統合されたことが明示的に記録に残ることになります。

ただし、feat/Aブランチの分岐元がmasterの最新commitだった場合は、オプションを付けない限りmergeコミットは作られません。

明示的にmergeの記録を残したい場合は、

git merge -no-ff master

とオプション付きでmergeするようにしましょう。

conflictの解消

なお、rebase, mergeともに実行すると競合状態になる場合があります。競合とは、統合元のブランチと統合先のブランチでまったく同じファイルの、まったく同じ行を更新してしまった場合などに発生するもので、conflictと呼びます。

CONFLICT (content): Merge conflict in xxxx.txt

といったメッセージが現れたら、conflictを解消する必要があります。

対象ファイルを開くと、ファイル内に

<<<<<<< HEAD
ほげほげほげ
=======
ふがふがふが
>>>>>>> feat/A

といった表記がある部分があります。

これは、

HEAD(統合先の最新状態)「ほげほげほげ」と更新されていた部分をfeat/Aでは「ふがふがふが」と更新していますが、最終的にはどちらを活かしますか?

と聞かれている状態です。ここで残したい変更以外を消してファイルを保存し直してから、

rebase時
git add xxxx.txt (競合ファイル)
git rebase --continue
merge時
git add xxxx.txt (競合ファイル)
git commit(mergeコミットの作成)

を実行すれば、conflictの解消ができます。

git pull

なお、リモートのブランチの変更を反映するのによく使われるコマンド「git pull」「git fetch+git merge」と同じ挙動をします。

git pull origin master

git fetch
git merge master

は同じものです。rebaseとmergeどちらが適切かは、プロジェクトの方針や状況によって異なるので、チームで相談して方針を決めておくと良いですね。

おすすめ記事

記事・ニュース一覧