Git ブランチ 入門ガイド:コマンドと概念を徹底解説
はじめに:なぜGitブランチを学ぶ必要があるのか?
現代のソフトウェア開発において、バージョン管理システム(VCS)は不可欠なツールです。中でもGitは、分散型バージョン管理システムとして最も広く普及しており、個人開発から大規模なチーム開発まで、あらゆる場面で活用されています。
Gitの強力な機能の一つに「ブランチ(branch)」があります。ブランチは、開発の流れを分岐させ、複数の作業を並行して進めることを可能にする機能です。このブランチを理解し、効果的に使いこなすことは、Gitを使った開発を円滑に進める上で避けては通れません。
しかし、「ブランチとは何か?」「どうやって使うのか?」「マージとリベースはどう違うのか?」といった疑問を持ち、戸惑う方も少なくありません。本記事では、Gitのブランチ機能について、その概念から主要なコマンド、実践的な使い方、そしてよくあるトラブルシューティングまでを、約5000語の詳細なボリュームで徹底的に解説します。
この記事を読むことで、あなたは以下のことができるようになります。
- Gitにおけるブランチの仕組みを理解する。
- ブランチの作成、切り替え、削除といった基本的な操作を習得する。
- 複数のブランチの変更を統合するマージとリベースの違いを理解し、使い分けられるようになる。
- リモートリポジトリとブランチの関係を把握する。
- 一般的なブランチ運用戦略の考え方を理解する。
- ブランチ関連で発生しがちなトラブルに対処できるようになる。
Gitを使った開発の効率と安全性を飛躍的に向上させるために、ぜひ最後までお付き合いください。
第1章:Gitの基本とブランチの概念
Gitのブランチを理解するためには、まずGitの基本的な仕組みを少しだけ知っておく必要があります。
1.1 Gitの役割とバージョン管理の必要性
Gitは、プロジェクトのファイルの変更履歴を記録・管理するためのシステムです。これにより、いつ、誰が、何を、なぜ変更したのかを追跡でき、過去の状態に戻したり、異なる変更点を組み合わせたりすることが容易になります。
バージョン管理がなければ、ファイルのコピーを大量に作成したり、「ファイル名_最終版」「ファイル名_本当に最終版」といった管理不能な状況に陥ったり、複数人での共同作業が非常に困難になったりします。Gitはこれらの問題を解決し、開発プロセスを効率化し、安全性を高めます。
1.2 リポジトリとコミット
Gitでのバージョン管理は「リポジトリ(Repository)」と呼ばれる場所で行われます。リポジトリは、プロジェクトのすべてのファイルと、それらの変更履歴が保存されている場所です。ローカルマシン上のリポジトリを「ローカルリポジトリ」、GitHubやGitLabなどのサーバー上のリポジトリを「リモートリポジトリ」と呼びます。
変更履歴の最小単位は「コミット(Commit)」です。コミットは、ある時点でのプロジェクトのファイルの状態を記録したスナップショットのようなものです。各コミットには、一意の識別子(ハッシュ値)、作者、日時、コミットメッセージ(なぜその変更を行ったかの説明)、そして一つ以上の親コミットへの参照が含まれます。
最初のコミットは親を持ちませんが、それ以降のコミットは通常、一つ前のコミットを親として参照します。これにより、コミットはチェーン状につながり、プロジェクトの変更履歴が形成されます。このつながりを視覚化したものが「コミットグラフ」です。
[最初のコミット A]
↓
[コミット B]
↓
[コミット C]
コミットメッセージは、変更内容を簡潔かつ分かりやすく記述することが重要です。未来の自分やチームメンバーが履歴を見たときに、そのコミットで何が行われたのかをすぐに理解できるように心がけましょう。
1.3 ブランチとは何か? Gitにおけるブランチの仕組み
さあ、いよいよブランチの登場です。Gitにおけるブランチとは、非常にシンプルに言うと、「特定のコミットを指し示すポインタ」です。
想像してみてください。プロジェクトの変更履歴は、コミットが連なった一本の線(グラフ)のようなものです。初期状態では、この線の上を「master」や「main」といった名前のポインタが、最新のコミットを指しています。
[コミット A] --- [コミット B] --- [コミット C] <--- main (または master)
ここで新しいブランチを作成すると、それは現在のHEAD(後述)が指しているコミットを指す、新しいポインタが作られるだけです。例えば、「feature/add-login」というブランチを作成すると、それはmain
ブランチが現在指しているコミット(この例ではコミットC)を指すようになります。
[コミット A] --- [コミット B] --- [コミット C] <--- main, feature/add-login
Gitのブランチが他のVCSと比べて非常に優れている点の一つは、この「ポインタである」という仕組みです。ブランチを作成しても、実際にファイルを丸ごとコピーしたり、新しいディレクトリを作成したりするわけではありません。ただ単に、41桁のコミットハッシュが書かれた小さなファイル(.git/refs/heads
ディレクトリ以下に格納されます)が作られるだけなのです。このため、ブランチの作成や切り替えは非常に高速に行えます。
1.4 HEADとは?
GitにはHEAD
という特別なポインタがあります。HEAD
は、「現在作業しているブランチの、最新のコミット」を常に指しています。つまり、HEAD
は今、自分がリポジトリのどの時点の状態を見ているか、そして次にコミットした時にどのブランチの先端に新しいコミットが追加されるかを教えてくれます。
ブランチを切り替える(チェックアウトする)ということは、このHEAD
ポインタを、別のブランチの先端のコミットに付け替えるということです。そして、そのコミットが指す時点でのファイルの状態が、ワーキングツリー(実際にファイルがある場所)に展開されます。
例えば、feature/add-login
ブランチに切り替えると、HEAD
はfeature/add-login
ブランチを指すようになります。
[コミット A] --- [コミット B] --- [コミット C] <--- main
^
|
HEAD --- feature/add-login
この状態で新しいコミット(コミットD)を作成すると、そのコミットはHEAD
が指しているブランチ(feature/add-login
)の先端に追加され、feature/add-login
ブランチのポインタも新しいコミットを指すように移動します。main
ブランチのポインタは、まだコミットCを指したままです。
[コミット A] --- [コミット B] --- [コミット C] <--- main
^ \
| \
HEAD [コミット D] <--- feature/add-login
これが、ブランチが独立した開発ラインとなる仕組みです。それぞれのブランチは独自のコミット履歴を持つことができ、他のブランチの変更に影響を与えずに作業を進めることができます。
1.5 Master/Mainブランチ
リポジトリを新規作成した際に最初に作られるブランチは、慣習的にmaster
またはmain
という名前が付けられます。(Gitのバージョン2.28以降では、デフォルトブランチ名がmaster
からmain
に変更されることが多くなっています。)
このデフォルトブランチは、通常、プロジェクトの安定版やリリース版、あるいは主要な開発ラインを示すものとして扱われます。開発者は、通常このmaster
/main
ブランチから新しいブランチを作成し、そこで作業を行い、作業が完了・安定したら再びmaster
/main
ブランチに統合するというワークフローをとることが一般的です。
第2章:なぜブランチを使うのか? その目的とメリット
ブランチの仕組みが分かったところで、次に「なぜ私たちは積極的にブランチを使うべきなのか?」という理由を見ていきましょう。
2.1 独立した開発ラインの確保
ブランチを使う最大の目的は、他の開発者の作業や、プロジェクトの安定版から独立した作業空間を確保することです。新しい機能の開発やバグ修正を行う際に、メインブランチ(main
など)に影響を与えずに作業を進めることができます。
もしブランチを使わずに全員が同じブランチ(例えばmain
)で作業していたらどうなるでしょう? 誰かが未完成のコードをコミットしたり、テストが通らない変更をプッシュしたりすると、他の開発者の作業環境が壊れてしまう可能性があります。
ブランチを使うことで、このようなリスクを回避できます。自分のブランチでの作業は、他のブランチには影響しません。
2.2 実験や新機能開発
新しいアイデアを試したい、あるいは複雑な新機能を追加したい場合、それをいきなりメインブランチで行うのは危険です。もしその試みが失敗に終わったり、開発に時間がかかったりした場合、メインブランチが不安定になったり、他の重要な作業がブロックされたりする可能性があります。
専用のブランチを作成して作業すれば、メインブランチの状態を汚すことなく、自由に実験や開発を進められます。もしその試みが上手くいかなかったとしても、そのブランチを削除するだけで済みます。成功すれば、そのブランチの変更をメインブランチに統合すれば良いのです。
2.3 バグ修正
本番環境で発生したバグや、リリース済みのバージョンで見つかった問題など、緊急性の高い修正が必要な場合があります。このような場合も、現在開発中の最新ブランチとは別に、安定版のブランチから新しいブランチ(例:hotfix/issue-123
)を切って修正を行うのが一般的です。
これにより、進行中の開発に影響を与えずに、迅速にバグ修正版を作成し、リリースすることができます。修正が完了したら、その修正をメインの開発ブランチや、場合によっては将来のリリースブランチにもマージして、変更が取り込まれるようにします。
2.4 並行開発
ブランチは、複数人が同じプロジェクトで並行して作業する上で不可欠な機能です。各開発者は、それぞれ異なるブランチで独立した機能開発やタスクを進めることができます。
例えば、一人はログイン機能を、別の人はユーザー登録機能を、さらに別の人はデザインの改善を、それぞれ異なるブランチで同時に開発できます。作業が完了したら、それぞれのブランチの変更をメインブランチに統合していきます。これにより、開発効率が大幅に向上します。
2.5 リスクの分散
重要な変更や大規模な変更を行う際、一つのブランチで全てを行うとリスクが高まります。ブランチを細かく切って、小さなタスクごとにブランチを作成し、少しずつメインブランチに統合していくことで、問題が発生した場合の影響範囲を限定できます。
問題が発生したブランチだけを調査・修正すれば良く、他のブランチやメインブランチには影響が及びません。
2.6 コードレビューとの連携
GitHubやGitLabなどのリモートリポジトリホスティングサービスでは、「プルリクエスト(Pull Request)」や「マージリクエスト(Merge Request)」と呼ばれる機能が提供されています。これは、自分の開発ブランチの変更をメインブランチにマージしてもらうように依頼する機能です。
このプルリクエスト/マージリクエストは、ブランチをベースに行われます。開発者はFeatureブランチで作業し、完了したらそのブランチを対象にしたプルリクエストを作成します。チームメンバーはプルリクエスト上でコードの変更点をレビューし、問題がなければマージを承認します。
ブランチは、このようなコードレビュープロセスを円滑に行うための基盤となります。特定の機能や修正に関連する変更だけをまとめてレビューできるため、レビューの効率と質が向上します。
第3章:Gitブランチの主要コマンド詳解
Gitのブランチを操作するための基本的なコマンドを詳しく見ていきましょう。これらのコマンドをマスターすれば、日常的なブランチを使った開発はほぼ問題なく行えるようになります。
ここから先は、実際にGitコマンドを使いながら読み進めることをお勧めします。
3.1 ブランチの確認と作成
git branch
:ローカルブランチの一覧表示
現在のローカルリポジトリに存在するブランチの一覧を表示します。
bash
git branch
実行すると、以下のようにローカルブランチ名が一覧表示されます。
* main
feature/add-login
bugfix/issue-456
*
がついているブランチが、現在自分が作業している(HEAD
が指している)ブランチです。
git branch -a
:ローカルおよびリモートブランチの一覧表示
ローカルブランチだけでなく、リモートリポジトリ上のブランチも確認したい場合は -a
オプションを使用します。
bash
git branch -a
出力例:
* main
feature/add-login
bugfix/issue-456
remotes/origin/HEAD -> origin/main
remotes/origin/main
remotes/origin/feature/add-login
remotes/origin/
で始まるものがリモートブランチです。origin
は、通常、クローン元のリモートリポジトリに付けられるデフォルトの名前です。remotes/origin/HEAD -> origin/main
は、リモートリポジトリのデフォルトブランチがorigin/main
であることを示しています。
git branch <新しいブランチ名>
:新しいブランチの作成
現在いるブランチ(HEAD
が指すコミット)から、新しいブランチを作成します。このコマンドはブランチを作成するだけで、自動的に新しいブランチに移動するわけではありません。
bash
git branch feature/add-user-profile
上記のコマンドを実行すると、feature/add-user-profile
という名前の新しいブランチが作成され、これは現在あなたが立っているブランチの最新コミットを指すようになります。git branch
コマンドで確認してみてください。
3.2 ブランチの切り替え
ブランチを作成したら、そのブランチで作業するために、そのブランチに「切り替える」必要があります。ブランチを切り替えるには、主に二つのコマンドがあります。
git switch <ブランチ名>
:ブランチの切り替え (推奨)
Gitのバージョン2.23以降で導入された新しいコマンドで、ブランチの切り替えに特化しています。ファイル操作(チェックアウト)とブランチ切り替えの機能を分離することで、コマンドの意図を明確にしています。
bash
git switch feature/add-user-profile
このコマンドを実行すると、HEAD
がfeature/add-user-profile
ブランチを指すようになり、ワーキングツリーの内容がそのブランチの最新コミットの状態に切り替わります。
git switch -c <新しいブランチ名>
:ブランチの作成と切り替えを同時に (推奨)
新しいブランチを作成し、すぐにそのブランチに切り替えたい場合によく使われる便利なオプションです。現在いるブランチから新しいブランチを作成し、そのまま新しいブランチに移動します。
bash
git switch -c feature/refactor-code
これは以下の2つのコマンドを連続で実行するのと同じ効果があります。
bash
git branch feature/refactor-code
git switch feature/refactor-code
git checkout <ブランチ名>
:ブランチの切り替え (古いコマンド)
git checkout
コマンドは、かつてブランチの切り替えや作成にも使われていました。しかし、ファイルの復元 (git checkout <ファイル名>
) と同じコマンド名で機能が混在しているため、誤解や間違った操作を招きやすいという欠点がありました。Git 2.23以降では、ブランチ操作には git switch
、ファイルの復元には git restore
を使うことが推奨されています。
bash
git checkout feature/add-user-profile
このコマンドも git switch <ブランチ名>
と同じようにブランチを切り替えます。
git checkout -b <新しいブランチ名>
:ブランチの作成と切り替えを同時に (古いコマンド)
git switch -c
と同様に、新しいブランチを作成してすぐに切り替えるコマンドです。
bash
git checkout -b feature/implement-cache
これは以下の2つのコマンドを連続で実行するのと同じ効果があります。
bash
git branch feature/implement-cache
git checkout feature/implement-cache
互換性のために git checkout
を使うこともありますが、今からGitを学ぶのであれば git switch
を積極的に使うことをお勧めします。
注意: 未コミットの変更がある状態でブランチを切り替えようとすると、Gitはコンフリクトを避けるために切り替えを拒否する場合があります。この場合は、現在の変更をコミットするか、一時的に退避(stash)させてから切り替える必要があります(stashについては後述)。
3.3 ブランチの削除
役割を終えたブランチ(例えば、メインブランチにマージされて不要になった機能ブランチなど)は、後で混乱しないように削除することが推奨されます。
git branch -d <ブランチ名>
:ブランチの削除 (マージ済みの場合)
指定したブランチを削除します。ただし、このコマンドは、削除しようとしているブランチの変更が、他のブランチ(通常は現在いるブランチや他の重要なブランチ)に完全にマージされている場合にのみ成功します。変更がまだマージされていない場合は、データの損失を防ぐために削除を拒否します。
bash
git branch -d feature/add-user-profile
もしマージされていない変更がある場合、以下のようなエラーが表示されます。
error: The branch 'feature/add-user-profile' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature/add-user-profile'.
git branch -D <ブランチ名>
:ブランチの削除 (強制削除)
-D
オプション(大文字)を使うと、マージ済みかどうかに関わらず、強制的にブランチを削除します。まだマージされていない変更が含まれているブランチを誤って削除すると、その変更は失われてしまう可能性があるため、このオプションを使う際は十分注意が必要です。
bash
git branch -D feature/refactor-code
これは、例えば実験的なブランチでの試みが完全に失敗し、その変更が全く不要になった場合などに使用します。
注意: 現在作業しているブランチ(HEAD
が指しているブランチ)を削除することはできません。削除したい場合は、まず別のブランチに切り替える必要があります。
3.4 履歴の確認
ブランチを理解し、運用する上で、コミット履歴やブランチの状態を視覚的に把握することは非常に重要です。git log
コマンドは、そのための強力なツールです。
git log
:コミット履歴の表示
現在のブランチのコミット履歴を表示します。
bash
git log
git log --oneline
:履歴を一行でコンパクトに表示
各コミットをハッシュ値の先頭部分とコミットメッセージの先頭を一行で表示します。履歴をざっと見たい場合に便利です。
bash
git log --oneline
git log --graph
:コミットグラフをテキストで表示
ブランチの分岐や合流をテキストベースのグラフで表示します。これにより、どのコミットがどのブランチに属しているか、ブランチがどのように分岐・マージされたかを視覚的に理解しやすくなります。
bash
git log --graph
git log --all
:すべてのブランチの履歴を表示
現在いるブランチだけでなく、ローカルおよびリモートのすべてのブランチのコミット履歴を表示します。これと --graph
オプションを組み合わせると、リポジトリ全体のコミットグラフを見ることができます。
bash
git log --all --graph
git log --decorate
:ブランチ名やタグを表示
どのコミットがどのブランチやタグを指しているかを表示します。
bash
git log --decorate
git log --oneline --graph --all --decorate
:ブランチ運用で最もよく使う表示
これらのオプションを組み合わせたこのコマンドは、ブランチを使った開発において、現在のリポジトリの状態や履歴を把握するために非常によく使われます。すべてのブランチの履歴をコンパクトなグラフ形式で、ブランチ名やタグ付きで表示してくれます。
bash
git log --oneline --graph --all --decorate
このコマンドの出力を見れば、現在どのブランチが存在し、それぞれがどのコミットを指しており、ブランチがどのように分岐・合流しているのかが一目で分かります。
3.5 一時的な変更の退避 (git stash
)
ブランチを切り替えたいが、現在のブランチで作業中の変更がまだコミットできる状態ではない、という状況はよくあります。未コミットの変更がある状態でブランチを切り替えようとすると、Gitは通常これを拒否します。
このような場合、git stash
コマンドを使うと、未コミットの変更(ステージングエリアにある変更とワーキングツリーにある変更)を一時的に退避させることができます。これにより、ワーキングツリーをクリーンな状態に戻し、安心してブランチを切り替えたり、別の作業を行ったりできるようになります。
git stash save <メッセージ>
または git stash push -m <メッセージ>
:変更を退避
未コミットの変更を退避させます。メッセージを付けると、後でどのstashか分かりやすくなります。
“`bash
git stash save “work on login form”
または (新しいコマンド)
git stash push -m “work on login form”
“`
git stash list
:退避した変更の一覧表示
退避した変更の一覧を表示します。複数のstashがある場合、一覧で確認できます。
“`bash
git stash list
例:
stash@{0}: On feature/add-login: work on login form
stash@{1}: On main: WIP on main: … (stash時のブランチと最新コミットのメッセージ)
“`
git stash apply <stash@{n}>
:退避した変更を適用
退避しておいた変更を、現在のブランチに適用します。<stash@{n}>
は、git stash list
で表示される stash の識別子です(例: stash@{0}
)。識別子を省略すると、最新のstash (stash@{0}
) が適用されます。適用してもstashリストからその項目は削除されません。
“`bash
git stash apply stash@{0}
または最新のstashを適用
git stash apply
“`
git stash drop <stash@{n}>
:退避した変更を削除
指定したstashをstashリストから削除します。
bash
git stash drop stash@{0}
git stash pop
:退避した変更を適用して削除
最新のstashを現在のブランチに適用し、成功したらそのstashをリストから削除します。apply
と drop
を一度に行うイメージです。問題なく適用できた場合は pop
を使うと便利です。
bash
git stash pop
git stash
は、ブランチ間を頻繁に行き来しながら作業する場合や、急な割り込み対応が必要になった場合に非常に役立ちます。
第4章:ブランチの結合:マージとリベース
独立したブランチで作業を進めた後、その変更を他のブランチ(通常はメインブランチ)に取り込む必要があります。この「ブランチの結合」には、主に「マージ(Merge)」と「リベース(Rebase)」という二つの方法があります。どちらの方法も、最終的には一方のブランチの変更をもう一方のブランチに取り込みますが、その過程と結果としてのコミット履歴の形が大きく異なります。
4.1 マージ (git merge
)
マージは、二つのブランチの変更を統合し、その統合を記録するための新しいコミットを作成する方法です。これは、ブランチの履歴を保持し、誰がいつどのブランチを統合したかを明確に残すという特徴があります。
基本的なコマンドは以下の通りです。まず、変更を取り込みたいブランチ(例えばmain
)に移動し、そこにマージしたいブランチ(例えばfeature/add-login
)を指定してマージを実行します。
bash
git switch main # または git checkout main
git merge feature/add-login
このコマンドを実行すると、Gitはmain
ブランチとfeature/add-login
ブランチの共通の祖先コミットを探し出し、両ブランチの変更を比較して統合しようとします。
マージには主に二つのシナリオがあります。
4.1.1 Fast-forwardマージ
マージ元のブランチ(この例ではfeature/add-login
)が、マージ先のブランチ(main
)から分岐した後に、マージ先のブランチに新しいコミットが一つも追加されていない場合、Fast-forwardマージが発生します。
[A] --- [B] --- [C] <--- main
^
\
[D] --- [E] <--- feature/add-login
この状態でgit merge feature/add-login
をmain
ブランチで実行すると、main
ブランチのポインタが単にfeature/add-login
ブランチの先端(コミットE)まで「早送り(Fast-forward)」されるだけです。新しいマージコミットは作成されません。
[A] --- [B] --- [C] --- [D] --- [E] <--- main, feature/add-login
Fast-forwardマージは履歴が直線的になりシンプルですが、どのコミットがFeatureブランチで開発されたものなのかという情報が失われるという側面もあります。
4.1.2 3-wayマージ
マージ元のブランチとマージ先のブランチの両方に、共通の祖先コミットから分岐した後に新しいコミットが追加されている場合に発生します。この場合、Gitは共通の祖先(Base)、マージ元の先端(Theirs)、マージ先の先端(Yours)の三つのバージョンを比較して変更を統合します。
[A] --- [B] --- [C] <--- main
/
/
[D] --- [E] <--- feature/add-login
この状態でgit merge feature/add-login
をmain
ブランチで実行すると、GitはコミットC(共通の祖先)を基準に、main
の変更(コミットC以降)とfeature/add-login
の変更(コミットD, E)を統合し、その結果を新しいマージコミットとして記録します。このマージコミットは、マージ元のブランチの先端とマージ先のブランチの先端、二つの親を持ちます。
[A] --- [B] --- [C] --- [F] <--- main (Merge Commit F)
/ /
/ /
[D] --- [E] <--- feature/add-login
3-wayマージではマージコミットが作成されるため、どのブランチがいつ、どのブランチに統合されたかという履歴が明示的に残ります。これは、後から履歴を辿る際に非常に役立ちます。
--no-ff
オプション
Fast-forwardマージを避け、強制的に3-wayマージ(マージコミットの作成)を行いたい場合は、--no-ff
オプションを使います。
bash
git merge --no-ff feature/add-login
これにより、たとえFast-forward可能な状態であってもマージコミットが作成され、ブランチの統合というイベントが履歴に記録されます。特にFeatureブランチなど、特定の目的のために切られたブランチの履歴を明確に残したい場合に有効です。
4.1.3 マージコンフリクト
Gitが自動的に変更を統合できない場合、マージコンフリクト(Merge Conflict)が発生します。これは、同じファイルの同じ行、または非常に近い行を、二つのブランチでそれぞれ異なる方法で変更した場合などによく起こります。
コンフリクトが発生すると、Gitはマージを一時停止し、どのファイルでコンフリクトが発生したかを教えてくれます。コンフリクトが発生したファイルを開くと、Gitがコンフリクトしている箇所に以下のようなマーカーを挿入しているのが分かります。
“`diff
<<<<<<< HEAD (または現在のブランチ名)
// 現在のブランチの変更
int x = 10;
=======
// マージ元ブランチの変更
int x = 20;
feature/add-login (またはマージ元ブランチ名)
“`
<<<<<<< HEAD
から =======
の間が現在のブランチ(main
)での変更、=======
から >>>>>>> feature/add-login
の間がマージ元ブランチ(feature/add-login
)での変更です。
コンフリクトを解消するには、以下の手順を行います。
- コンフリクトが発生しているファイルをエディタで開き、Gitが挿入したマーカー (
<<<<<<<
,=======
,>>>>>>>
) を含めて、正しい状態になるように手動で編集します。どちらか一方の変更を採用する、両方の変更を組み合わせる、全く新しいコードを書く、といった方法があります。 -
編集が完了したら、コンフリクトを解消したファイルをステージングエリアに追加します。
bash
git add <コンフリクトを解消したファイル名>
3. すべてのコンフリクトが解消され、該当ファイルがステージングエリアに追加されたら、マージコミットを作成してマージプロセスを完了させます。Gitは自動的にマージコミットメッセージを生成してくれます(通常は「Merge branch ‘…’」のようなメッセージ)。必要に応じてメッセージを編集し、コミットします。bash
git commit
これでマージコンフリクトは解消され、マージが完了します。
4.1.4 マージの中止 (git merge --abort
)
マージ中にコンフリクトが発生したが、うまく解消できそうにない、あるいはマージ自体を取りやめたいと思った場合は、マージを中止することができます。
bash
git merge --abort
このコマンドを実行すると、マージを開始する前の状態にリポジトリが戻されます。
4.2 リベース (git rebase
)
リベースは、あるブランチの変更を、別のブランチの先端に「付け替える」方法です。マージのように新しいマージコミットを作成するのではなく、リベース元のブランチで行われた各コミットを、リベース先のブランチの最新コミットの上に順番に「作り直す」という操作を行います。
基本的なコマンドは以下の通りです。例えば、feature/add-login
ブランチでの変更をmain
ブランチの先端にリベースしたい場合、まずリベースしたいブランチ(feature/add-login
)に移動し、リベースのベースとしたいブランチ(main
)を指定します。
bash
git switch feature/add-login # または git checkout feature/add-login
git rebase main
このコマンドを実行すると、以下の手順が実行されます。
feature/add-login
ブランチとmain
ブランチの共通の祖先コミットを探します。feature/add-login
ブランチでの、その共通祖先以降のコミット(A’, B’)を一時的な場所に退避します。- 現在のブランチ(
feature/add-login
)を、リベース先のブランチ(main
)の先端(コミットC)に移動させます。 - 退避しておいたコミットを、
main
の新しい先端の上に順番に「適用」していきます。この際、各コミットは内容が同じでも、親コミットが変わるため、新しいハッシュ値を持つ別のコミットとして再作成されます。
“`
元の状態
[A] — [B] — [C] <— main
/
/
[D] — [E] <— feature/add-login
git rebase main 実行後
[A] — [B] — [C] <— main
/ \
/ \
[D’] — [E’] <— feature/add-login (D, Eが新しく作り直されたコミット)
“`
リベースの結果、feature/add-login
ブランチの履歴はmain
ブランチの履歴の「後」につながったようになり、全体として履歴が直線的で分かりやすくなります。
4.2.1 マージとリベースの違い
最も大きな違いは、コミット履歴の形です。
- マージ: 新しいマージコミットを作成し、ブランチが合流したイベントを履歴に残します。履歴は分岐・合流を含むツリー状になります。
- リベース: 元のコミットを再作成し、履歴を直線的に書き換えます。ブランチが分岐・合流したイベントは履歴に明示的に残りません。(Fast-forwardマージに近い結果になりますが、リベースは元のコミットが再作成される点が異なります)
4.2.2 リベースの利点
- 履歴が直線的で読みやすい: 開発の経緯を追うのが容易になります。特に小さな変更を頻繁に取り込む場合に有効です。
- マージコミットが不要: 不要なマージコミットが増えるのを避けられます。
4.2.3 リベースの欠点と注意点
- 履歴を書き換える: リベースは元のコミットを再作成するため、コミットのハッシュ値が変わります。既に他の開発者と共有している(リモートリポジトリにpush済みの)ブランチに対してリベースを行うと、他の開発者のリポジトリとの間で履歴の整合性が失われ、混乱や問題を引き起こす可能性が非常に高いです。 リベースは、まだ誰とも共有していないローカルのブランチに対してのみ行うべきです。
- コンフリクト解消の手間: マージではコンフリクトが一度にまとめて発生するのに対し、リベースではリベース対象の各コミットを適用する際に、それぞれコンフリクトが発生する可能性があります。複数のコミットでコンフリクトが発生すると、その都度解消作業が必要になり、手間がかかることがあります。
4.2.4 リベースコンフリクトとその解消
リベース中にコンフリクトが発生した場合、Gitはリベースを一時停止し、どのコミットを適用しようとして問題が起きたかを教えてくれます。解消手順はマージコンフリクトと似ています。
- コンフリクトが発生したファイルを編集し、手動で解消します。
- 解消したファイルをステージングエリアに追加します (
git add <ファイル名>
)。 -
コンフリクト解消をGitに通知し、リベース処理を再開します。
bash
git rebase --continue
コンフリクトが発生するコミットが複数ある場合、この手順を繰り返す必要があります。
リベースを中止したい場合は、以下のコマンドを使用します。
bash
git rebase --abort
これにより、リベースを開始する前の状態に戻ります。
また、コンフリクトが発生したコミットをスキップして次のコミットに進めたい場合は、以下のコマンドを使用します。ただし、これはそのコミットで行われた変更を完全に破棄することになるため、注意が必要です。
bash
git rebase --skip
4.2.5 インタラクティブ・リベース (git rebase -i
)
リベースには、-i
オプションを付けたインタラクティブ・リベースという強力な機能もあります。これは、リベースするコミットのリストを編集し、コミットの並べ替え、結合(squash)、分割、削除、メッセージの編集などを対話的に行うことができる機能です。
bash
git rebase -i <ベースとなるコミットまたはブランチ>
例えば、直近3つのコミットを対話的に編集したい場合は git rebase -i HEAD~3
とします。これにより、コミット履歴をよりクリーンで分かりやすいものに整形することが可能ですが、履歴を書き換える強力な機能であるため、特に共有リポジトリでの使用には十分な理解と注意が必要です。入門レベルではまず通常のリベースを理解するのが先決でしょう。
4.3 マージとリベース、どちらを使うべきか?
どちらの方法もブランチの変更を統合できますが、チームやプロジェクトの方針によって使い分けられます。
-
マージ:
- ブランチの実際の開発履歴(分岐・合流)をそのまま残したい場合。
- 他の開発者と共有しているブランチに、自分のローカルブランチの変更を取り込みたい場合。(例:
main
ブランチを自分のFeatureブランチに取り込む) - 比較的シンプルで安全な操作を好む場合。
-
リベース:
- 履歴を直線的に保ち、コミットグラフを綺麗にしたい場合。
- ローカルでの作業中に、最新のメインブランチの変更を自分のブランチに取り込みたい場合。(例:
feature/add-login
ブランチをmain
の最新状態に追従させるためにgit switch feature/add-login
してgit rebase main
を行う) - まだ誰とも共有していないブランチの履歴を整形したい場合。
一般的には、ローカルで作業中の自分のFeatureブランチを最新のMain/Developブランチに追従させる際にはリベースを、開発が完了しレビューも終えたFeatureブランチをMain/Developブランチに統合する際にはマージを使用するという使い分けが推奨されることが多いです。特に、共有ブランチに対するリベースは絶対に避けるべきです。
第5章:リモートリポジトリとブランチ
実際の開発では、ローカルリポジトリだけでなく、GitHubやGitLabなどのリモートリポジトリと連携して作業することがほとんどです。ブランチも、ローカルリポジトリだけでなくリモートリポジトリにも存在し、それらを連携させて使います。
5.1 ローカルブランチ vs リモートブランチ
- ローカルブランチ: あなたのマシン上のリポジトリに存在するブランチです。
git branch
で表示されるのは通常ローカルブランチです。 - リモートブランチ: リモートリポジトリ上のブランチを指します。例えば、
origin/main
はリモートリポジトリ(デフォルト名origin
)上のmain
ブランチを指します。リモートブランチは、リモートリポジトリのブランチの「追跡(トラッキング)」のために、ローカルリポジトリ内にミラーとして保持されます。git branch -r
で表示されます。
5.2 トラッキングブランチ
ローカルブランチは、リモートブランチと紐付けられることがあります。これを「トラッキングブランチ(Tracking Branch)」と呼びます。例えば、ローカルのmain
ブランチがリモートのorigin/main
ブランチをトラッキングしている場合、Gitはmain
ブランチがorigin/main
と同期しているか(進んでいるか、遅れているか、分岐しているか)を自動的に判定し、git status
などで表示してくれます。
新しいローカルブランチをリモートブランチから作成する際や、ローカルブランチをリモートにプッシュする際に、トラッキング関係を設定することが多いです。
git branch -vv
コマンドを使うと、ローカルブランチがどのリモートブランチをトラッキングしているか、そしてどれだけ同期が進んでいるかを確認できます。
“`bash
git branch -vv
例:
* main abcdef1 [origin/main] Fix issue #123
feature/x 1234567 [origin/feature/x: ahead 2] Implement feature Y
feature/y 7890abc Implement feature Z (no tracking branch)
“`
5.3 リモートリポジトリとの連携コマンド
リモートリポジトリとローカルリポジトリの間で変更をやり取りするために、以下のコマンドを使用します。
git clone <リモートリポジトリのURL>
:リポジトリを複製
リモートリポジトリをローカルに複製します。これにより、リモートリポジトリの内容がローカルにコピーされ、自動的にデフォルトブランチ(通常はmain
またはmaster
)のローカルブランチと、リモートのブランチ群への参照が設定されます。
bash
git clone https://github.com/yourname/yourrepo.git
git fetch <リモート名>
:リモートリポジトリの変更を取得
リモートリポジトリから最新の情報(コミット、ブランチなど)を取得しますが、現在のローカルブランチにそれらの変更を自動的にマージしたりリベースしたりはしません。取得した変更は、remotes/<リモート名>/<ブランチ名>
という形でローカルに保存されるため、git log --all --graph --decorate
などで確認できます。
bash
git fetch origin
git fetch
は、リモートの状況を知るためにまず実行することが多いコマンドです。
git pull <リモート名> <リモートブランチ名>
:リモートリポジトリの変更を取得して統合
git fetch
を実行した後、自動的に現在のローカルブランチに取得した変更を統合します。デフォルトの動作は git fetch
の後 git merge
を行うことですが、設定により git rebase
を行うように変更することも可能です (git pull --rebase
)。
bash
git pull origin main
現在いるローカルブランチがリモートブランチをトラッキングしている場合、引数を省略して git pull
だけでトラッキングしているリモートブランチから変更を取得・統合できます。
git pull
は git fetch
と git merge
(または git rebase
) を組み合わせたコマンドであるため、git fetch
でリモートの状況を確認してから手動でマージやリベースを行う方が、予期しない統合を防ぎやすいという考え方もあります。
git push <リモート名> <ローカルブランチ名>
:ローカルブランチの変更をリモートに送信
ローカルブランチの変更を、指定したリモートリポジトリのブランチにアップロードします。通常、自分のブランチでコミットした変更を他の開発者と共有するために使用します。
bash
git push origin feature/add-login
ローカルブランチに初めてプッシュする際、リモートに同名のブランチが存在しない場合は、新しいリモートブランチが作成されます。その際、ローカルブランチとリモートブランチの間にトラッキング関係を設定するために -u
(または --set-upstream
) オプションを付けてプッシュすることが多いです。
bash
git push -u origin feature/add-login
一度トラッキング関係を設定すれば、以降はそのブランチで作業している限り git push
と引数を省略してプッシュできるようになります。
注意: リモートブランチに対するリベースは、他の開発者の作業に悪影響を与えるため、基本的に避けるべきです。もしリベースしたブランチをリモートにプッシュする必要がある場合は、履歴が書き換わっているため通常の git push
は拒否されます。その場合は git push --force
または git push --force-with-lease
を使う必要がありますが、これは他の開発者が同じブランチで作業している場合に非常に危険です。強制プッシュは、そのブランチを完全に一人で管理している場合に限定すべき操作です。
第6章:実践的なブランチの運用戦略
Gitのブランチ機能は非常に柔軟であるため、チームやプロジェクトの規模、開発スタイルに応じて様々な運用戦略が考えられます。ここでは代表的な戦略の考え方と、一般的な開発ワークフローにおけるブランチの使い方を紹介します。
6.1 一般的な開発ワークフロー (Featureブランチ中心)
小規模なチームや単一のプロジェクトでよく採用される、シンプルで効果的なワークフローです。
- メインブランチ (
main
またはmaster
):常に安定した、リリース可能な状態を保ちます。直接このブランチで開発は行いません。 - 新しい機能開発やバグ修正: 新しいタスクに着手する際は、必ず最新のメインブランチからFeatureブランチ(機能開発)、Bugfixブランチ(バグ修正)などを切ります。ブランチ名には、その目的が分かるような名前を付けます(例:
feature/add-user-profile
,bugfix/issue-123
,refactor/auth-module
)。
bash
git switch main
git pull origin main # 最新状態にする
git switch -c feature/add-user-profile - 開発作業: 作成したブランチで自由に開発、コミットを行います。他の開発者やメインブランチに影響を与えずに作業できます。必要に応じて、作業中に何度かメインブランチの最新を取り込み、コンフリクトを早期に解決することも有効です (
git fetch origin main
してからgit rebase origin/main
など)。 - リモートへのプッシュ: 作業の区切りや、他の開発者と共有したい場合に、自分のブランチをリモートにプッシュします。
bash
git push -u origin feature/add-user-profile - コードレビュー (Pull Request / Merge Request): 開発が完了したら、自分のブランチをメインブランチにマージしてもらうためのプルリクエスト(GitHubなど)またはマージリクエスト(GitLabなど)を作成します。チームメンバーがコードをレビューし、承認を得ます。
- マージ: レビューが完了し、承認されたら、プルリクエスト/マージリクエストを通じて、Featureブランチの変更をメインブランチにマージします。この際、マージコミットを作成する (
--no-ff
) か、リベースして直線的な履歴にするか(共有済みブランチへのリベースは避けること)は、チームのルールに従います。一般的には、PR/MRによる統合ではマージコミットを残すことが多いです。 - ブランチの削除: メインブランチへのマージが完了し、不要になったFeatureブランチは削除します(ローカルおよびリモート)。
bash
git branch -d feature/add-user-profile # ローカルを削除
git push origin --delete feature/add-user-profile # リモートを削除
このワークフローはシンプルで理解しやすく、多くのプロジェクトで採用されています。
6.2 代表的なブランチ戦略 (概要)
上記以外にも、プロジェクトの規模や性質に応じて様々なブランチ戦略が存在します。ここでは代表的なものを概要だけ紹介します。
- Git-flow: Vincent Driessen氏が提唱した、比較的複雑なブランチモデルです。長期稼働する二つの主要ブランチ(
master
またはmain
、develop
)と、目的別の補助ブランチ(feature
,release
,hotfix
)を使用します。リリース管理やメンテナンスが重視されるプロジェクトに適していますが、運用ルールが多いため学習コストがかかります。 - GitHub Flow: GitHubで推奨されている、よりシンプルで軽量なワークフローです。
main
ブランチ一つを主要ブランチとし、そこからFeatureブランチを切って開発し、プルリクエストとコードレビューを経てmain
にマージする、という流れが基本です。常時デプロイ可能な状態を保つことを目指します。Webサービス開発など、継続的なデリバリーを行うプロジェクトに適しています。 - GitLab Flow: GitLabが提唱するワークフローで、GitHub Flowに環境別のブランチ(
staging
,production
など)を追加したり、Issue Trackingシステムとの連携を重視したりする点が特徴です。
どの戦略を採用するかは、チームの経験、プロジェクトの規模、リリースの頻度などを考慮して決定すべきです。重要なのは、チーム全体で合意したブランチ戦略に沿って作業し、一貫性を保つことです。
第7章:よくあるブランチ関連のトラブルシューティング
ブランチを使った開発では、いくつかの典型的な問題に遭遇することがあります。ここでは、それらの問題と対処法を解説します。
7.1 コンフリクトを解決する
マージやリベースのセクションで詳しく解説しましたが、コンフリクトはブランチを統合する際によく発生します。恐れずに、落ち着いて以下の手順で対応しましょう。
git status
で、コンフリクトが発生しているファイルを確認します。- 該当ファイルをエディタで開き、
<<<<<<<
,=======
,>>>>>>>
マーカーを手がかりに、正しい状態になるようにコードを編集します。 - 編集が終わったら、
git add <ファイル名>
でステージングエリアに追加します。 - すべてのコンフリクトファイルを追加したら、マージの場合は
git commit
、リベースの場合はgit rebase --continue
で処理を完了させます。
もし途中で分からなくなったり、元に戻したくなったりした場合は、マージなら git merge --abort
、リベースなら git rebase --abort
で開始前の状態に戻せます。
7.2 間違ったブランチにコミットしてしまった
作業するブランチを間違えて、意図しないブランチでコミットしてしまった!という経験は、Git初心者だけでなく経験者にもよくあるミスです。
対処法はいくつかあります。
Case 1: 間違ったブランチにコミットしたが、まだプッシュしていない場合
この場合が最も対処が容易です。
- 直前のコミットだけを移動したい場合:
- コミットを「取り消す」が、変更内容はワーキングツリーに残す (
git reset HEAD~1
)。 - 正しいブランチに切り替える (
git switch <正しいブランチ名>
)。 - 変更内容をコミットする (
git add .
,git commit
)。
- コミットを「取り消す」が、変更内容はワーキングツリーに残す (
- 複数のコミットをまとめて移動したい場合:
- 現在のブランチのHEADを、移動したいコミットの一つ前のコミットに戻す (
git reset <コミットハッシュ>
またはgit reset HEAD~<数>
)。この際、変更内容はワーキングツリーやステージングエリアに残す--soft
または--mixed
オプションが便利です。デフォルトは--mixed
で、変更はワーキングツリーに残ります。 - 正しいブランチに切り替える (
git switch <正しいブランチ名>
)。 - 変更内容を改めてコミットする (
git add .
,git commit
)。または、git stash
を使って変更を退避・適用しても良いでしょう。
- 現在のブランチのHEADを、移動したいコミットの一つ前のコミットに戻す (
Case 2: 間違ったブランチにコミットし、既にプッシュしてしまった場合
この場合は少し複雑になります。既に共有リポジトリの履歴を書き換えることになるため、チームメンバーに影響が出る可能性があります。
- 間違ってプッシュしたブランチの変更を「取り消す」コミットを作成する (
git revert
):元のコミットは履歴に残りますが、その変更を打ち消す新しいコミットが作成されます。これは最も安全な方法で、履歴の整合性を保てます。その後、正しいブランチで改めてコミットを作成します。 - 間違ってプッシュしたコミットを削除し、正しいブランチに移動して強制プッシュ (
git reset
,git push --force
):これは非推奨です。特に他の人が既にその間違ったブランチを pull している場合、彼らのローカルリポジトリとの間で履歴の不整合が起き、強制プッシュしないとプッシュできなくなったり、pull するとマージコンフリクトが頻繁に発生したりするなどの問題を引き起こします。行う場合は、必ずチームに周知し、他の開発者がそのブランチで作業していないことを確認した上で、細心の注意を払って行ってください。
原則として、共有済みのコミットを reset
や rebase
で削除・書き換える操作は避けるべきです。git revert
を使って変更を打ち消すのが安全な対応です。
7.3 ブランチを間違えて削除してしまった
うっかり必要なブランチを -D
オプションで削除してしまった!という場合でも、慌てる必要はありません。Gitは、削除されたブランチやコミットへの参照を、一定期間内部に保持しています。
git reflog
コマンドを使うと、HEADが過去に参照していたコミットの履歴(「Reflog」または「リファレンスログ」と呼ばれます)を確認できます。ここには、コミット、マージ、リベース、チェックアウトなど、HEADが移動したすべての操作が記録されています。
“`bash
git reflog
例:
abcdef0 HEAD@{0}: commit: Implement feature Y
1234567 HEAD@{1}: checkout: moving from main to feature/x
fedcba9 HEAD@{2}: merge origin/main: Merge remote-tracking branch ‘origin/main’
… 削除したブランチの先端コミットへの参照が見つかるはず …
“`
git reflog
の出力の中から、削除してしまったブランチが指していた最新のコミットのハッシュ値(例:abcdef0
)を見つけます。そのハッシュ値が分かれば、そのコミットを指す新しいブランチを作成することで、ブランチを復旧できます。
“`bash
git branch <復旧したいブランチ名> <コミットハッシュ>
例:
git branch deleted-feature-branch abcdef0
“`
これで、指定したコミットを先端とする新しいブランチが作成され、削除したブランチが復旧します。git log --graph
などで履歴を確認してみてください。
7.4 detached HEAD 状態とは?
通常、HEAD
はローカルブランチ(例:main
, feature/add-login
)を指しており、そのブランチが最新のコミットを指しています。この状態を「シンボリックリファレンス」または「Attached HEAD」と呼びます。この状態でコミットすると、HEAD
が指しているブランチの先端に新しいコミットが追加され、ブランチのポインタも更新されます。
しかし、ブランチ名ではなく、直接コミットのハッシュ値やタグ名を指定して git checkout
(または git switch
) すると、HEAD
は特定のコミットを直接指す状態になります。これを「Detached HEAD」状態と呼びます。
bash
git checkout abcdef0 # 特定のコミットハッシュに切り替える
“`
通常の状態 (Attached HEAD)
[A] — [B] — [C] <— main, HEAD
Detached HEAD 状態
[A] — [B] — [C] <— main
^
|
HEAD (直接コミット B を指している)
“`
Detached HEAD 状態で新しいコミットを作成すると、そのコミットはどのブランチにも属さない一時的な状態になります。
[A] --- [B] --- [C] <--- main
^ \
| \
HEAD [D] (どのブランチも指していない新しいコミット)
このまま別のブランチに切り替えると、Detached HEAD 状態で作成したコミット(D)はどのブランチからも参照されなくなるため、後でそのコミットを探し出すのが難しくなります。
Detached HEAD 状態は、過去の特定のコミットの状態を確認したり、そこから一時的に作業をしたりする場合に使いますが、通常はこの状態で本格的な開発作業を行うことはありません。
もしDetached HEAD 状態でコミットしてしまい、その変更を保存したい場合は、そのコミットがまだ git reflog
などから参照可能なうちに、そのコミットを先端とする新しいブランチを作成してください。
bash
git switch -c <新しいブランチ名> # 現在 Detached HEAD が指しているコミットから新しいブランチを作成し切り替える
あるいは、変更を git stash
で退避し、本来作業したかったブランチに切り替えてから git stash pop
で適用するという方法もあります。
まとめ:ブランチを使いこなすために
Gitのブランチは、その軽量さと柔軟性により、現代の開発ワークフローにおいて非常に強力な機能です。本記事では、ブランチの基本的な概念から、作成、切り替え、削除、そしてマージやリベースといった統合方法、さらにはリモートブランチとの連携やトラブルシューティングまで、幅広く解説しました。
ブランチを効果的に使いこなすことで、以下のメリットが得られます。
- 他の開発者の作業から独立し、安全に開発を進められる。
- 新しい機能の開発や実験を、メインの開発ラインに影響を与えずに実行できる。
- 複数のタスクを並行して進められる。
- コードレビュープロセスを円滑に進められる。
- 問題発生時の影響範囲を限定できる。
最初は多くのコマンドや概念に戸惑うかもしれませんが、実際に手を動かして練習することが最も重要です。以下の点を意識して、日々の開発でブランチを活用してみてください。
- 新しい作業は新しいブランチで: 機能開発、バグ修正、実験など、目的ごとに新しいブランチを作成する習慣をつけましょう。
- ブランチ名は分かりやすく: ブランチの目的が一目で分かるような名前を付けましょう(例:
feature/user-registration
,bugfix/crash-on-startup
,refactor/api-client
)。イシュー番号を含めるのも効果的です(例:feature/ISS-123-add-search-filter
)。 - こまめにコミット: 作業の区切りごとにこまめにコミットし、変更内容が分かりやすいコミットメッセージを付けましょう。
- こまめにプッシュ: ローカルの変更を定期的にリモートにプッシュし、バックアップと共有を行いましょう。
- メインブランチは常にクリーンに:
main
やdevelop
のような主要ブランチは、常に安定した状態を保つように運用しましょう。直接コミットするのではなく、Featureブランチなどを経由してマージするようにします。 - マージとリベースの違いを理解し、使い分ける: 特に「共有済みのブランチはリベースしない」というルールを厳守しましょう。
git log --graph --oneline --all --decorate
で履歴を確認する習慣をつける: 現在の状態やブランチの構成を把握することが、誤った操作を防ぎ、問題発生時の原因究明に役立ちます。
Gitのブランチ機能は奥深く、本記事で紹介しきれなかった詳細なオプションや高度なテクニックも存在します(例えば、git cherry-pick
を使った他のブランチからの特定のコミットの取り込み、サブモジュール、ワークツリーなど)。しかし、ここで解説した概念とコマンドを習得すれば、Gitを使った開発の基盤はしっかりと築けます。
このガイドが、あなたのGitブランチへの理解を深め、より効率的で安全な開発ライフの一助となれば幸いです。