Git入門 part3 / ブランチ
サルでもわかるGit入門の発展編に突入です!
入門編の記事は、part1とpart2があります😊
目次
1.発展編
1-1. ブランチ
ブランチとは
Git入門 part2で少しだけ登場したブランチというものを学習します。
ブランチ(branch)は英語のとおり、履歴の流れを枝のように分岐して記録していくためのものです🌲
ブランチは他のブランチの影響を受けないため、同じリポジトリ中で複数の変更を並行して進めることができます。
また、ブランチは他のブランチと合流(マージ)し、ひとつのブランチとなることもできます🤝
そのためソフトウェア開発において、各担当者が別々のブランチでそれぞれ作業を行い、最後にマージしてひとつのソフトウェアとすることが可能になります✨
リポジトリに最初のコミットを行うときはmaster
という名前のブランチが作成されます。
それ以降のコミットは、ブランチを切り替えるまでmaster
ブランチに追加されていきます。
ブランチとの運用方法
ブランチの運用方法についてはおそらくチームごとに決めるのですが、今回は統合ブランチとトピックブランチの2つを使った運用方法について学習します💡
統合ブランチは、リリース版をいつでも作成可能な状態にしておくためのブランチです。
通常、masterブランチを統合ブランチとして使用するようです😗
トピックブランチは、機能追加やバグ修正など、ある課題に関する作業を行うためのブランチです。
統合ブランチから課題に関するトピックブランチを作成し、トピックブランチでの作業が完了したら、統合ブランチに取り込むという使い方をします。
芯となる統合ブランチがあることで、情報がごちゃごちゃしなくて良いですね😊
ブランチの切り替え
作業するブランチを切り替える操作をチェックアウトと言います。
また、現在使用しているブランチの先頭のことをHEADと表します。このHEADが移動することで、作業するブランチが変更される仕組みです💡
コミットを指定するときに、この時にHEADと後述の記号を組み合わせて、あるコミットからの相対位置で指定することもできます。
記号 | 読み方 | 用途 |
---|---|---|
~ | チルダ | 何世代前の親かを指定する |
^ | キャレット | 何番目の親かを指定する |
使い方のイメージは以下のような感じです😊凡例を書き忘れてしまったのですが、葉っぱはコミットです。
変更内容をコミットしていないままチェックアウトを行うと、その変更内容はワークツリーやインデックスに残ったまま、移動先のブランチに移ります。
ただし、移動先のブランチで既にそのファイルに変更が行われている場合、チェックアウトに失敗してしまいます💦
このような場合に、一時的に変更内容を退避させてからチェックアウトする方法があります。
stashという、ファイルの変更内容を一時的に記録しておく領域を使い、ワークツリーとインデックス内にあるコミットされていない変更を、一時的に退避させることができます!
また、退避させた変更は後から取り出して、元のブランチや別のブランチに反映させることができます👏
ブランチの統合
トピックブランチでの作業が完了したら、最終的に統合ブランチに統合されます。
ブランチを統合する方法として、mergeを使う方法と、rebaseを使う方法の2種類があります。
どちらを使うかによって、統合後のブランチの履歴が大きく異なるそうなので、しっかり学習しておきます😎
方法 | 特徴 |
---|---|
merge | ・各々の変更履歴を統合する ・変更内容の履歴がそのまま残る ・履歴が複雑になる |
rebase | ・それぞれのコミットで競合を解消し、履歴を一本化する ・元のコミットの変更履歴が変わる ・履歴は単純になる |
図で表すと以下のようになります。
うーん分かりにくい…😶笑
チュートリアルに進んでみましょう!!
1-2. チュートリアル1 ブランチを使ってみよう
早速チュートリアルに沿って進めていきます🚗
前準備
まずはtutorial
ディレクトリを作って、空のリポジトリを作成します。
$ mkdir tutorial
$ cd tutorial
$ git init
次にmyfile.txt
というファイルを作成し、サルでもわかるGitコマンド
というテキストを入力してコミットします。
今回からコンソールの入力/出力の表示を変えました〜!
今までは枠で囲ってたのですが、沢山続くと見にくいのでマーカーにしました😊
ブランチを作成する
早速、branch
コマンドを使ってissue1
という名前のブランチを作成します。
$ git branch ブランチ名
また、branch
コマンドで引数を指定しない場合、ブランチ一覧を表示します。
*
が付いているのが、現在のブランチです🌲
今はmaster
ブランチにいますが、他にissue1
ブランチがあることが確認できますね✨
ブランチを切り替える
issue1
ブランチにコミットを追加していくには、checkout
コマンドを使ってissue1
ブランチをチェックアウトします😊
宿泊施設のチェックアウトとは違って指定したブランチを出るのではなく、指定したブランチに切り替えるコマンドです!
$ git checkout ブランチ名
ここではブランチ名はissue1
になります👆
ちなみに、以下のようにcheckout
コマンドに-b
オプションを付けると、ブランチの新規作成とチェックアウトを同時に行えます✨
$ git checkout -b ブランチ名
続いて、myfile.txt
の中身に2行目を追加してコミットします🙂
ブランチをマージする
先程issue1
で行った変更をmaster
ブランチに merge します。
まずはcheckout
コマンドでmaster
ブランチに移動します。
$ git checkout master
myfile.txt
の編集はissue1
ブランチ上で行ったため、master
ブランチのほうでは内容は変更されていないことが確認できます。
ブランチのmerge はmerge
コマンドで実行できます😊
$ git merge 取り込みたいブランチ名
このコマンドを実行すると、指定したブランチがHEADの指しているブランチに取り込まれます!
master
ブランチのコミットがissue1
と同じ位置(HEAD)に移動しました👌
このマージはfast-forward
(早送り)マージと呼ばれます。
遅れているmaster
ブランチのコミットをさくっとissue1
と同じコミットの位置まで持ってくることができるので、早送りと言われるんでしょうね😶
ブランチを削除する
issue1
ブランチの内容はmaster
ブランチに無事統合されたため不要になりました。
issue1
ブランチを削除します!
ブランチの削除は、branch
コマンドに-d
オプションを指定して実行します。
$ git branch -d ブランチ名
branch
コマンドでブランチの一覧を確認すると、issue1
が削除されているのがわかります🎉
並行で作業する
今度は、2つのブランチで並行で作業してみます!
まずissue2
ブランチとissue3
ブランチを作成し、issue2
ブランチをチェックアウトします。
まずはissue2
ブランチ側の作業です!
myfile.txt
にcommit
コマンドの説明を追加してコミットします。
一方、issue3
ブランチのmyfile.txt
にはpull
コマンドの説明を追加します👀
issue3
ブランチをチェックアウトし、myfile.txt
にpull
コマンドの説明を追加してコミットします。
これでissue2
とissue3
をmaster
に統合しようとすると、衝突が起きますね…!💥
マージでの衝突を解決する
いよいよ、issue2
ブランチとissue3
ブランチそれぞれでの変更をmaster
ブランチに統合します💪
まず、master
ブランチをチェックアウトして、issue2
ブランチを merge します。
ここでは何の問題も無くfast-forward
マージが行われますね🙂
続いて、issue3
ブランチをmaster
ブランチにマージします。
自動マージに失敗し、myfile.txt
には競合箇所が示されています。
前回のおさらいですが、競合箇所の読み方は以下のとおりです!
<<<<<<<
現在チェックアウトしている側の内容(ここではmasterブランチ)
=======
競合相手の内容(ここではissue3ブランチ)
>>>>>>>
これを受け、myfile.txt
を以下のように修正します✍️
サルでもわかるGitコマンド
add 変更をインデックスに登録する
commit インデックスの状態を記録する
pull リモートリポジトリの内容を取得する
修正したら、改めてコミットします。
出てくる文字が少ないですが、エラーではないので、たぶんOKだと思います!笑
今回の merge では、競合箇所を修正して、その変更を記録するマージコミットが作成されました。そこにmasterの先頭が移動していることになります🚗
このようにfast-forward
ではないマージは、non fast-forward
マージと呼ばれます😂
rebaseでマージする
先程issue3
ブランチをマージする際にissue3
ブランチを rebase したら、履歴を一本にすることができました💡
rebase のチュートリアルをやってみます🙌
まずは一旦、reset
コマンドの--hard
オプションで先程行ったマージを取り消します!
reset
コマンドはそれだけで結構書ける内容なので、ここでは解説を割愛して以下のコマンドをそのまま実行します。
$ git reset --hard HEAD~
reset
コマンドについて詳しくは以下のブログを拝見しました!わかりやすかったです😊
git reset コマンドの使い方と、主要オプションまとめ | WWWクリエイターズ
実行するとこんな感じになります。
これで現状issue2
がmaster
ブランチにマージ済みで、これからissue3
ブランチをマージするところまで戻りました!
ここでissue3
ブランチをチェックアウトし、master
ブランチに対して rebase を実行します!
やはりmyfile.txt
で競合が発生するため、mergeの時と同じmyfile.txt
を修正します。
myfile.txt
の中身は先程と全く同じなので、修正も割愛します〜👣
競合箇所を修正したら、rebase の場合にはコミットではなく、rebase
コマンドに--continue
オプションを指定して実行します。
これにより、master
ブランチはissue3
ブランチをfast-forward
マージできるようになります✨
master
ブランチをチェックアウトしてマージを実行します。
mergeと比べて履歴(経緯)は異なりますが、myfile.txt
の最終的な内容は同じです🤝
1-3. リモートリポジトリ
リモートリポジトリに対する動作として、pushやpullを学びました。
参考記事:Git入門 part1 / Gitの基本
おさらいを兼ねて、Fetchも合わせて意味を確認します!
用語 | 意味 |
---|---|
Push | ローカルリポジトリの履歴をリモートリポジトリにアップロードすること |
Pull | リモートリポジトリの履歴をローカルリポジトリにダウンロードすること 自動的にマージコミットが作成されるが、競合があれば手動で解決する 内部的に Fetch + merge をしている |
Fetch | マージせずにリモートリポジトリの履歴を取得すること 取得したコミットは名前の無いブランチとして作成される (FETCH_HEADという名前でチェックアウトできる) |
本日は以上です🙂