
Gitで物凄く重要な概念がブランチ。
ブランチですよブランチ、王様のブランチ。
僕の周りではブランチでGitに苦手意識を持っている人って結構多いです。
そこで今日はブランチを徹底的に学んで行きましょう!
ブランチとは?
ブランチってカタカナで書くとなんとなく難しそうな感じですが、並行して様々な作業と行えるという概念です。
例えば車の製造を想像して下さい。
- ボディ等の外装
- シート等の内装
- エンジン等の機関部
みたいにいくつかのパーツがまとまっていますよね?
で、これって決して1人や1つのチームで作るわけじゃないですよね。
外装製造ライン、内装製造ライン、機関部製造ラインのようにいくつかのラインに分かれて作っているはずです。
はい、もうブランチが理解できました!ようはこうやって並行して作業を進める、これがブランチです。
ブランチの考え方
Gitにおけるブランチも車の例と全く一緒です。
例えば既にHTMLとCSSからなるWebサイトを運営しているとします。
最もメインで重要なデフォルトのブランチをmasterブランチと言いますが、もし大きくデザインを変えたい時そのままmasterブランチで行いますか?
答えはNoです。
もちろん自分の中にルールがあれば良いんですが、基本的にmasterブランチ=完成版。
このルールが破綻してしまうとブランチはもちろんリポジトリの中身が破綻してしまいます。
まずはmasterブランチ=サーバー上に公開されている状態とルールを作っておきましょう(今回は例がWebページですが、ソフトウェアなら公開版)。
ブランチを切る
ではどうするかと言うと、作業用ブランチを作ります。
masterブランチから派生させて別のブランチ、例えば開発を意味するdevelopブランチを作成します。
この新しいブランチを作成する事をブランチを切ると言います。

新しい機能を追加しようかな?

じゃあブランチ切っといて!
みたいな感じで使います。
ブランチは複数作成できる
今は例としてdevelopブランチをあげましたが、ブランチは複数作成できます。
例えば
- 開発用のdevelopブランチ
- バグ修正のfixブランチ
のような感じ。
ちなみに派生したブランチから更に派生させる事も可能ですし、それぞれ独立してmasterブランチから派生させることもできます。
僕はそこまで試した事ないんですが多分上限もありません、いくつでも派生できます。
しかしきちんと派生した後のブランチを処理しないと無限に増えてしまうので、その辺は気をつけておきたいところです。
ブランチには慣れておこう
もちろん一人でGitを使っているだけならブランチなんて1~2つあれば十分、なんならよろしくないですがmasterブランチオンリーなんて人もいます。
しかしブランチの運用ルールが事前にきっちり定義されていれば、コミットログを見ればひと目でバグ修正の作業だなと言う目視もしやすくなります。
更に将来的に大きな開発に参加する時もブランチの概念に慣れておけばすんなり入れるでしょう。
今やWeb上だけで簡単に開発に参加できる時代、ブランチには絶対慣れておいた方が良いです。
マージする
では枝分かれしたブランチはどうなるでしょう?
もちろん最終的には公開しますよね、つまりmasterブランチと合流させる必要があります。
この切ったブランチを合流させる事をマージすると言います。

developブランチで開発中の新機能、全部完成したね!

masterブランチにマージして公開しよう!
マージは機能追加、バグ修正等々何回も使う事になります。
最終的にマージすると指定したブランチと合流してその内容が取り込まれます。
実践してみよう!
では実際にブランチを操作して覚えましょう!
まず前回までにやった現在の状況を整理すると、
- testディレクトリ内にindex.htmlがある
- 今まで2回コミットしていて、ファイルの中身は以下のようになっている
<p>テスト</p>
<p>test</p>
ブランチを作る
最初の作業はブランチを作成です。
Gitは一番最初にリポジトリを作った時にmasterブランチという1個のメインブランチを作成します。
つまり今居るのがmasterブランチです、念の為確認しておきましょう。
$ git branch
* master
こんな感じでmasterブランチがある事が分かりました。
それではブランチ作成をしてみましょう。
ブランチ作成は先程ブランチ一覧を出力したgit branchコマンドの後に新しいブランチ名を続けて書けば作成できます。
今回は開発という意味でdevelopというブランチを作成してみたいと思います。
$ git branch develop
では実際に作成できているか確認します。
$ git branch
develop
* master
無事developが作成されていますね!
しかし実は今作成をしただけで、まだmasterブランチの中にいます。
よく見るとmasterの先頭に*(アスタリスク)がついていますね、これは現在居るブランチを示しています。
このままファイルの更新等をしてもそれはあくまでmasterブランチ上での作業、developブランチは作っただけ状態になってしまいます。
それでは困るので、developブランチに移動しましょう!
$ git checkout develop
Switched to branch 'develop'
ブランチを移動することをチェックアウトと言います。
今回はmasterブランチからdevelopブランチにチェックアウトしました。
Switched to branchと書いてあるのでなんだか移動できてそうな雰囲気ですね・・・!
実際に確認してみましょう!
$ git branch
* develop
master
*がdevelopに移っていますね!
これで無事移動が完了しました!
ブランチ内で作業を行う
やっぱりdevelop、開発という事ですから何か新機能を追加したいところ。
そこで今回はCSSを追加したいと思います。
$ sed -i "1i <link rel="stylesheet" href="css/style.css">" index.html
これでcssというディレクトリのstyle.cssが読み込めるようになりました。
ではcssディレクトリとstyle.cssファイルを作りましょう。
$ mkdir css
$ touch css/style.css
続いてcss/style.cssファイルにCSSを挿入します、今回はpタグの色をredに変えてみます。
$ echo "p { color: red; }" >> css/style.css
試しにちゃんと挿入できているかcatコマンドで表示してみます。
$ cat index.html
<link rel=stylesheet href=css/style.css>
<p>テスト</p>
<p>test</p>
$ cat css/style.css
p { color: red; }
大丈夫ですね、ではステージしてコミットしてみましょう!
#ステージング
$ git add .
#コミット
$ git commit -m "文字色変更"
2 files changed, 2 insertions(+)
create mode 100644 css/style.css
無事コミットできました!
masterブランチを確認してみる
masterブランチの状態を見てみましょう。
ブランチを切ってdevelopブランチで作業しているので、masterブランチのindex.htmlは<link>タグが入っていないはずだしcssディレクトリも存在しないはずです。
masterブランチにチェックアウトしてみましょう。
$ git checkout master
Switched to branch 'master'
$ git branch
develop
* master
masterブランチにチェックアウト出来たので、再びcatコマンドでindex.htmlを見てからlsコマンドでcssディレクトリが存在しているか見てみます。
$ cat index.html
<p>テスト</p>
<p>test</p>
$ ls
index.html
見事にindex.htmlの<link>タグもcssディレクトリもありません!
つまりmasterブランチはdevelopブランチの影響を全く受けていないのでdevelopブランチは自由に開発ができる、という事が証明されました。
develop→masterにマージする
最後にdevelopブランチで行った作業をmasterブランチに反映させなければいけません。
マージはコマンドで指定したブランチを現在自分が居るブランチに反映させます。
という事はdevelopブランチをmasterブランチに反映させる為にはmasterブランチに居る必要があります。
先程の確認で既にmasterブランチに居るので、このままdevelopブランチを指定してみましょう!
$ git merge develop
Updating 2008c1b..cbfeffa
Fast-forward
css/style.css | 1 +
index.html | 1 +
2 files changed, 2 insertions(+)
create mode 100644 css/style.css
これでマージ完了、無事developブランチの内容がmasterブランチに反映されました!
念には念を、catコマンドとlsコマンドでちゃんと反映されているか確認してみます。
#index.htmlの中身を見る
$ cat index.html
<link rel=stylesheet href=css/style.css>
<p>テスト</p>
<p>test</p>
#今いるディレクトリの情報を見る
$ ls
css/ index.html
#cssディレクトリの情報を見る
$ ls css
style.css
#style.cssの中身を見る
$ cat css/style.css
p { color: red; }
全部ばっちり反映されていますね!
Fast-forward
さて、今回のブランチを切りマージする作業。
思い返して頂きたいんですが、作業をしたのはあくまでdevelopブランチでしたよね?
その間masterブランチには一切の変更がありません。
developブランチを作った時、実はdevelopブランチには今までのmasterブランチの履歴が全て引き継がれています。
言い換えればdevelopブランチはmasterブランチの延長線上でしかありません。
今回のようにmasterブランチに一切の変更が無く他のブランチをマージする事をfast-forward(早送り)と言います。
$ git merge develop
Updating 2008c1b..cbfeffa
Fast-forward #←ここ!
先程マージしたログを見てみるとFast-forwardと表示されています。
実際の開発現場では同時進行(並列)で様々な修正や追加が行われていて、自分がマージする時にはmasterブランチが既に他のブランチをマージしている場合が多々あり、Fast-forwardではないマージがほとんどです。
並列進行のマージ
では実際に並列進行した場合のマージがどうなるか見てみましょう。
先程の作業でまだmasterブランチに居るので、まずはdevelopブランチにチェックアウトします。
$ git checkout develop
Switched to branch 'develop'
$ git branch
* develop
master
今回は新機能としてJavaScriptを追加します。
$ mkdir js
$ touch js/new.jp
$ ls
css/ index.html js/
$ ls js
new.jp
とりあえずjsディレクトリを作りnew.jsというからファイルを作ったので、作ったという事実をコミットしておきます。
$ git add .
$ git commit -m "js/new.js作成"
[develop 992b25d] js/new.js作成
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 js/new.jp
ここからnew.jsに機能を追加・・・と思ったら実はindex.htmlにもう一文追加しなきゃいけない事が判明しました(という設定でいきます笑)。
これはバグです、のんきにJavaScriptを追加している場合じゃありません。
という事でfixというブランチを作成して、fixブランチ内でindex.htmlに追加していきます。
ですが開発途中のdevelopブランチからfixブランチを作ると、fixブランチはdevelopブランチの作業を引き継いでしまいます(空のjsディレクトリとjs/new.jsファイルがfixブランチにも取り込まれてしまう)。
そこで一度masterブランチにチェックアウトして、新しく(developブランチとは一切関係がない)fixブランチを作って行きます。
#masterブランチにチェックアウト
$ git checkout master
#fixブランチを作成
$ git branch fix
#fixブランチに移動
$ git checkout fix
Switched to branch 'fix'
#念の為ブランチ確認
$ git branch
develop
* fix
master
developブランチとは一切関係が無いfixブランチが作成できました!
念の為jsディレクトリがfixブランチに無い事を確認しておきましょう。
$ ls
css/ index.html
jsディレクトリはありませんね。
ではindex.htmlに追記して行きます!
#index.htmlの最後に追加
$ echo "<p>キャンペーン実施中!</p>" >> index.html
#index.htmlの内容確認
$ cat index.html
<link rel=stylesheet href=css/style.css>
<p>テスト</p>
<p>test</p>
<p>キャンペーン実施中!</p>
修正が完了したのでステージ、コミットをしましょう!
$ git add .
$ git commit -m "キャンペーン告知バグ修正"
[fix 519f704] キャンペーン告知バグ修正
1 file changed, 1 insertion(+)
無事コミット出来たので、このバグ修正を急いでmasterブランチに反映させます。
#masterブランチに移動
$ git checkout master
#masterブランチでfixブランチをマージ
$ git merge fix
Updating cbfeffa..d4b0543
Fast-forward
index.html | 1 +
1 file changed, 1 insertion(+)
#index.htmlの内容表示
$ cat index.html
<link rel=stylesheet href=css/style.css>
<p>テスト</p>
<p>test</p>
<p>キャンペーン実施中!</p>
これで無事fixブランチのバグ修正がmasterブランチに取り込まれました。
並列世界の誕生
ここで一度状況を整理しておきましょう。
masterブランチはindex.htmlのバグ修正を行ったfixブランチを反映させました。
一方developブランチのindex.htmlはバグ発生前の状態です。
つまり内容が異なる2つのindex.htmlがあり、おまけにdevelopブランチには開発中のjs/new.jsがあります。
Fast-forwardの時のmasterブランチはdevelopブランチから見て一切の変更がありませんでしたが、今回はdevelopブランチから見てmasterブランチは違う状況です(developブランチには無い要素が親のmasterブランチにはある)。
ではdevelopブランチでの開発が終わったと仮定して、developブランチをmasterブランチにマージしてみましょう。
#先程の作業でmasterブランチに居るのでそのままマージします。
$ git merge develop
すると先程は一気にmerge出来ましたが、今回はVim(エディタ)が立ち上がったと思います。
Fast-forwardの時は不要でしたが、Fast-forwardではないマージの時はコミットメッセージを残す必要があります。
デフォルトは「Merge branch ‘develop’」となっていると思うので
- iキーを押して入力モードにする
- Merge branch ‘develop’を消す
- 「新機能js追加」と入力
- escキーを押してコマンドモードに戻る
- :wqキーを順番に押して最後にEnterキー
これでコミットメッセージの入力が行えます。
Merge made by the 'recursive' strategy.
js/new.jp | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 js/new.jp
これが今回のマージの結果、先ほどと違ってFast-forwardの記載がありません。
今回のようにFast-forwardではないという事をそのまま、non-Fast-forwardと言います。
微妙な違いなんですが、Fast-forwardはコミットメッセージが不要に対してnon-Fast-forwardはコミットメッセージが必要になります。
マージをマスターしてGitを使いこなそう
今回はコマンドをたくさん打って大変だったと思います笑。
マージにはFast-forwardとnon-Fast-forwardの2種類がある事が分かりました。
ここで一つ疑問が浮かんで来ます。
今回はmasterブランチとdevelopブランチのindex.htmlのうち、developブランチに1行追加されただけでした。
しかし、もし同じindex.htmlにそれぞれのブランチで別々の内容が記載されていたら・・・?
次回はこの疑問を「もうコンフリクトは怖くない!Gitで起こる衝突問題を恐れず解決しよう」で解決して行きます!
コメント