Git Branchの基本をマスター!これだけは知っておきたい使い方


Git Branchの基本をマスター!これだけは知っておきたい使い方

はじめに:なぜバージョン管理が必要なのか、そしてGitの「ブランチ」とは?

現代のソフトウェア開発において、バージョン管理システムは必要不可欠なツールです。複数人で協力して開発を進める際も、一人でプロジェクトを進める際も、変更履歴を正確に追跡し、いつでも過去の状態に戻せることは、開発の安全性と効率性を飛躍的に向上させます。数あるバージョン管理システムの中でも、Gitは分散型の特性と高い柔軟性から、現在最も広く利用されています。

Gitの強力な機能の一つに「ブランチ(Branch)」があります。初めてGitに触れる方や、なんとなくブランチを使っているという方にとって、「ブランチ」という概念は少々掴みどころがないかもしれません。しかし、Gitを真に理解し、その恩恵を最大限に引き出すためには、ブランチの仕組みと使い方をマスターすることが不可欠です。

ブランチは、開発のメインラインから一時的に分岐させ、独立した環境で作業を進めるための機能です。これにより、例えば新しい機能を開発しながら、同時に別のチームがバグ修正を行うといった並行開発が可能になります。また、新しいアイデアや実験的な変更を、安定したメインコードラインに影響を与えることなく試すこともできます。

この記事では、Gitブランチの基本概念から、作成、切り替え、削除といった基本的な操作、さらには異なるブランチの変更を統合するマージ(Merge)とリベース(Rebase)という重要な操作、リモートリポジトリとの連携、そして実践的なワークフローやテクニックまで、Gitブランチを使う上で「これだけは知っておきたい」すべてを詳細に解説します。

Gitブランチをマスターして、よりスムーズで効率的な開発を実現しましょう。

1. Gitブランチとは?その核心概念を理解する

まずは、Gitにおける「ブランチ」が一体何を意味するのか、その基本的な概念から見ていきましょう。

1.1. ブランチは開発の「分岐点」であり「独立した作業ライン」

想像してみてください。一本の大通り(開発のメインライン)があり、そこから新しい道(ブランチ)が枝分かれしていくイメージです。それぞれの道の上では、独立して工事(開発作業)を行うことができます。ある道の工事がメインの大通りに影響を与えることはありませんし、逆に大通りの交通状況が枝分かれした道に影響を与えることもありません。

Gitにおけるブランチもこれに似ています。開発の安定した状態を示すメインのライン(慣習的にmastermainと呼ばれることが多い)からブランチを作成すると、そこから新しい開発の「分岐」が生まれます。この新しいブランチの上で行ったコミットは、そのブランチだけに記録され、他のブランチには直接的な影響を与えません。これにより、複数の開発者が同時に異なる機能開発やバグ修正を進めることができるのです。

例えば、「ユーザー登録機能」を開発するチームと、「決済機能」を開発するチームがいたとします。それぞれのチームは、mainブランチから独立したfeature/signupブランチとfeature/paymentブランチを作成し、並行して作業を進めることができます。それぞれの作業が完了したら、開発した内容をmainブランチに統合します。

1.2. なぜブランチが必要なのか?

ブランチがもたらす主なメリットは以下の通りです。

  • 並行開発: 複数の開発者が互いの作業を邪魔することなく、同時に異なる機能や修正に取り組めます。
  • 機能開発/バグ修正の隔離: 新しい機能やバグ修正のための変更を、安定したコードベースから切り離して行えます。これにより、作業途中の不安定なコードがメインラインに混入するリスクを防ぎます。
  • 実験的な変更: 大胆な変更や試したいアイデアを、メインの開発ラインに影響を与えることなく試すことができます。もしうまくいかなくても、そのブランチを削除するだけで済みます。
  • リリース管理: 特定のバージョンをリリースするためのブランチを作成し、そのブランチ上でリリースに向けた最終調整を行うといった使い方ができます。

1.3. ブランチは「軽量なポインタ」である

Gitのブランチの重要な特徴は、それが非常に「軽量」であるという点です。Subversionのような古いバージョン管理システムでは、ブランチの作成や切り替えが比較的重い操作だったため、多用には向いていませんでした。しかし、Gitではブランチは実質的に「コミットを指し示すポインタ(参照)」に過ぎません。

Gitはコミットをツリー構造で管理しています。各コミットはその親コミットへの参照を持ち、変更内容はオブジェクトとして効率的に保存されています。ブランチを作成するということは、単に特定のコミットを指す新しいポインタ(ブランチ名)を作るだけです。例えば、mainブランチがコミットAを指しているときにfeature/xブランチを作成すると、feature/xも最初はコミットAを指すようになります。

Gitブランチの構造イメージ:コミット(ノード)とブランチ(ポインタ)
(注: 実際の画像は表示されませんが、コミットをノード、ブランチ名を特定のノードを指すラベルとしてイメージしてください)

新しいコミットを行うと、現在のブランチがその新しいコミットを指すようにポインタが移動します。他のブランチのポインタはそのままなので、この操作は他のブランチには影響しません。

この軽量性のおかげで、Gitでは気軽にブランチを作成し、頻繁にブランチを切り替えることができます。これがGitのブランチ活用の柔軟性と効率性の根幹となっています。

1.4. main / master ブランチと HEAD

  • main / master: Gitリポジトリを初期化すると、通常デフォルトで作成されるブランチです(最近はmainが一般的ですが、古いリポジトリや設定によってはmasterの場合もあります)。これは多くの場合、プロジェクトの最も安定した、またはリリース可能な状態を追跡するためのメインラインとして扱われます。
  • HEAD: GitにおいてHEADは、現在作業しているブランチの最新コミットを指す特殊なポインタです。つまり、「今、あなたが立っている場所」を示しています。ほとんどの場合、HEADは特定のブランチ(例: mainfeature/signup)を指しています。コミットを作成すると、HEADが指すブランチのポインタが新しいコミットに移動します。git checkoutなどでブランチを切り替えると、HEADが指すブランチも切り替わります。

これらの基本概念を理解しておくことが、今後のブランチ操作をスムーズに行うための土台となります。

2. ブランチの作成と切り替え:開発を分岐させる

Gitブランチを使う最初のステップは、新しいブランチを作成し、そこに切り替えることです。これにより、メインの開発ラインから独立した作業環境を手に入れることができます。

2.1. ブランチを作成する: git branch <branch-name>

新しいブランチを作成するには、git branch <branch-name>コマンドを使います。このコマンドは、現在のHEADが指しているコミットに対して、新しいブランチ名のポインタを作成します。

“`bash

現在のブランチを確認

$ git branch
* main

新しいブランチ ‘feature/signup’ を作成

$ git branch feature/signup

ブランチ一覧を確認

$ git branch
feature/signup
* main
“`

git branchコマンドに引数を付けずに実行すると、ローカルにあるブランチの一覧が表示されます。現在作業しているブランチ(HEADが指しているブランチ)にはアスタリスク * が付きます。

上記の例では、feature/signupという新しいブランチが作成されました。しかし、この時点ではまだmainブランチにいるため、ここで行うコミットはmainブランチに追加されます。

2.2. ブランチを切り替える: git checkout <branch-name> または git switch <branch-name>

作成したブランチに移動し、そのブランチで作業を進めるためには、ブランチを「切り替える」必要があります。ブランチの切り替えには、歴史的にgit checkoutコマンドが使われてきました。

“`bash

‘feature/signup’ ブランチに切り替え

$ git checkout feature/signup
Switched to branch ‘feature/signup’

現在のブランチを確認

$ git branch
* feature/signup
main
“`

これで、feature/signupブランチに移動しました。以降ここで行うコミットは、feature/signupブランチの先端に追加されていきます。

git checkoutはファイルやコミットの復元など、多機能すぎるため、Gitのバージョン2.23以降ではブランチの切り替えに特化したgit switchコマンドが導入されました。どちらを使っても構いませんが、git switchの方が意図が明確になります。

“`bash

(もしmainに戻るなら)

$ git switch main
Switched to branch ‘main’

(再びfeature/signupに切り替えるなら)

$ git switch feature/signup
Switched to branch ‘feature/signup’
“`

今後は、ブランチの切り替えにはgit switchを使うのが推奨される方法です。

2.3. ブランチの作成と切り替えを同時に行う

新しいブランチを作成してすぐにそこに切り替えたい、という状況は非常によくあります。この二つの操作は、以下のコマンドで一度に行うことができます。

  • git checkout -b <new-branch-name> (checkoutを使用する場合)
  • git switch -c <new-branch-name> (switchを使用する場合)

例えば、mainブランチにいる状態で新しいfeature/paymentブランチを作成し、そこに切り替える場合は、以下のようになります。

“`bash

現在 main ブランチにいるとする

$ git branch
* main

新しいブランチ ‘feature/payment’ を作成し、すぐに切り替え

$ git checkout -b feature/payment
Switched to a new branch ‘feature/payment’

または git switch を使う場合

$ git switch -c feature/payment
Switched to a new branch ‘feature/payment’

現在のブランチを確認

$ git branch
* feature/payment
main
feature/signup # 以前作ったブランチ
“`

このコマンドは、git branch <new-branch-name>を実行した後、git switch <new-branch-name>を実行するのと同じ結果になります。開発を始める際によく使う便利なコマンドです。

2.4. ブランチごとの状態を体験する

ブランチが独立した作業ラインであることを実感するために、簡単な例を試してみましょう。

  1. mainブランチで初期ファイルを作成しコミット:
    “`bash
    # リポジトリを初期化 (初めての場合)
    $ git init
    Initialized empty Git repository in /path/to/your/repo/.git/

    ファイルを作成

    $ echo “Initial content” > file.txt

    コミット

    $ git add file.txt
    $ git commit -m “Add initial file”
    [main (root-commit) …] Add initial file
    1 file changed, 1 insertion(+)

    履歴を確認

    $ git log –oneline
    (HEAD -> main) Add initial file
    “`

  2. 新しいブランチfeature/editを作成し切り替え、ファイルを編集しコミット:
    “`bash
    # 新しいブランチを作成し切り替え
    $ git switch -c feature/edit
    Switched to a new branch ‘feature/edit’

    ファイルを編集

    $ echo “Content from feature/edit” >> file.txt

    編集内容を確認

    $ cat file.txt
    Initial content
    Content from feature/edit

    コミット

    $ git add file.txt
    $ git commit -m “Edit file in feature/edit”
    [feature/edit …] Edit file in feature/edit
    1 file changed, 1 insertion(+)

    履歴を確認

    $ git log –oneline
    (HEAD -> feature/edit) Edit file in feature/edit
    Add initial file
    “`

  3. mainブランチに戻る:
    “`bash
    $ git switch main
    Switched to branch ‘main’

    file.txt の内容を確認

    $ cat file.txt
    Initial content
    “`

ご覧の通り、mainブランチに戻るとfeature/editブランチで行った変更(ファイルの編集)が消えています。これは、mainブランチのHEAD<commit-hash-1>を指しており、そのコミット時点のファイルの状態が復元されたからです。feature/editブランチに切り替えれば、再び編集後の内容が表示されます。

これが、ブランチが独立した作業空間を提供するということです。それぞれのブランチは、特定のコミット時点のスナップショットを基にしており、その後の変更はそのブランチの履歴にのみ追加されます。

3. ブランチの削除:不要になった分岐を片付ける

開発が完了し、他のブランチ(例えばmain)にマージされたブランチは、不要になることが多いです。不要なブランチは削除することで、ブランチ一覧を整理し、混乱を防ぐことができます。

3.1. ブランチを削除する: git branch -d <branch-name>

ブランチを削除するには、git branch -d <branch-name>コマンドを使います。

“`bash

ブランチ一覧を確認

$ git branch
* main
feature/edit # 削除したいブランチ

feature/edit ブランチを削除

$ git branch -d feature/edit
Deleted branch feature/edit (was ).

ブランチ一覧を再度確認

$ git branch
* main
“`

-dオプションは「safe delete」です。これは、削除しようとしているブランチの変更内容が、他のブランチ(通常は現在のHEADがあるブランチ)にマージされている場合にのみ成功します。もし、マージされていない変更(失われる可能性のある変更)があるブランチを-dで削除しようとすると、Gitは警告を出して削除を拒否します。

“`bash

まだマージされていない新しいブランチ ‘experimental’ を作成し、何かコミットする

$ git switch -c experimental
Switched to a new branch ‘experimental’
$ echo “Experimental feature” > experimental.txt
$ git add experimental.txt
$ git commit -m “Add experimental feature”
[experimental …] Add experimental feature …

main ブランチに戻る

$ git switch main
Switched to branch ‘main’

experimental ブランチを -d で削除しようとする (マージされていないため失敗)

$ git branch -d experimental
error: The branch ‘experimental’ is not fully merged.
If you are sure you want to delete it, run ‘git branch -D experimental’.
“`

Gitは親切にも、強制削除のためのコマンドを示してくれます。

3.2. ブランチを強制削除する: git branch -D <branch-name>

マージされていない変更があるブランチでも、どうしても削除したい場合は、-Dオプション(大文字)を使います。これは「force delete」です。

“`bash

マージされていない experimental ブランチを強制削除

$ git branch -D experimental
Deleted branch experimental (was ).

ブランチ一覧を確認

$ git branch
* main
“`

-Dを使うと、そのブランチで行われた、まだ他のブランチにマージされていないコミットは失われる可能性があるため、使用には注意が必要です。本当にその変更が不要であることを確認してから使いましょう。

3.3. 削除時の注意点

  • 現在のブランチは削除できない: 作業中のブランチ(HEADが指しているブランチ)は削除できません。削除したい場合は、一度別のブランチに切り替えてから実行してください。
  • マージ済みかどうかの確認: -dオプションは、削除対象ブランチの先端コミットが、現在のブランチの履歴に含まれている(つまりマージされている)かどうかを見て削除を許可します。必ずしも、削除対象ブランチから現在のブランチへマージ操作を行ったかどうかを見ているわけではない点に注意してください。

不要なブランチはこまめに削除することで、リポジトリを常に整理された状態に保つことができます。

4. ブランチの状態確認:現在の状況を把握する

現在どのようなブランチが存在し、どのブランチで作業しているのか、ブランチ間の関係はどうなっているのかを知ることは重要です。

4.1. ローカルブランチ一覧の表示: git branch

最も基本的なコマンドは、引数なしのgit branchです。ローカルリポジトリに存在するブランチの一覧を表示し、現在チェックアウトしているブランチに*を付けます。

bash
$ git branch
feature/another-feature
feature/signup
* main

4.2. ローカルおよびリモートブランチ一覧の表示: git branch -a

リモートリポジトリと連携している場合、ローカルブランチだけでなく、リモートリポジトリ上のブランチも確認したいことがあります。-aオプションを使うと、ローカルブランチに加えて、リモート追跡ブランチ(remotes/origin/...のような形式)も表示されます。

bash
$ git branch -a
feature/another-feature
feature/signup
* main
remotes/origin/HEAD -> origin/main
remotes/origin/main
remotes/origin/develop # リモートにある他のブランチ

remotes/origin/mainのような表示は、リモートリポジトリoriginmainブランチの、ローカルリポジトリが最後に知っている状態を指します。これはgit fetchコマンドで更新されます。

4.3. コミット履歴とブランチの関係を視覚的に表示: git log --decorate --oneline --graph

ブランチがどのように分岐し、どのようにマージされたかなど、ブランチ間の関係を視覚的に把握するには、git logコマンドにいくつかのオプションを組み合わせて使うのが非常に有効です。

  • --decorate: コミットに付いている参照(HEAD、ブランチ名、タグ名)を表示します。
  • --oneline: 各コミットを一行で簡潔に表示します(コミットハッシュの先頭部分とコミットメッセージ)。
  • --graph: コミットツリーをASCIIアートのグラフで表示します。

これらのオプションを組み合わせたgit log --decorate --oneline --graphは、Gitの現在の状態を理解するための強力なツールです。

bash
$ git log --decorate --oneline --graph
* <commit-hash-C> (HEAD -> feature/new) Add feature X
| * <commit-hash-B> (main) Fix critical bug
|/
* <commit-hash-A> Initial commit

上記の例では、Initial commit (<commit-hash-A>) からmainfeature/newという二つのブランチが分岐し、それぞれで独立したコミットが行われたことが分かります。HEADfeature/newブランチの先端コミット<commit-hash-C>を指していることも確認できます。

このコマンドは非常に頻繁に使うことになるでしょう。慣れてくると、このグラフを見るだけでリポジトリの履歴やブランチ構造が瞬時に理解できるようになります。

5. マージ (Merge):ブランチの変更を統合する

ブランチ上で独立して開発を進めたら、その変更を他のブランチ、例えばメインのmainブランチに取り込みたいと考えます。この「異なるブランチで行われた変更を統合する」操作が「マージ(Merge)」です。

5.1. マージとは何か?

マージは、二つの異なるブランチのコミット履歴を一つに統合する操作です。Gitは共通の祖先コミットを探し、それぞれのブランチで行われた変更を比較して、それらを一つの新しい状態にまとめます。

マージ操作は、git merge <source-branch>という形式で実行します。これは、「現在チェックアウトしているブランチ(ターゲットブランチ)に、<source-branch>の変更を取り込む」という意味になります。

例えば、mainブランチにfeature/signupブランチの変更を取り込む場合は、まずmainブランチに移動してからマージコマンドを実行します。

“`bash

feature/signup で開発を終え、main に戻る

$ git switch main
Switched to branch ‘main’

main に feature/signup の変更をマージ

$ git merge feature/signup
“`

マージの結果として、Gitは通常二つの方法のどちらかを選択します。Fast-forwardマージとThree-wayマージです。

5.2. Fast-forward マージ

Fast-forwardマージは、マージ元となるブランチ(ここではfeature/signup)の履歴が、マージ先のブランチ(main)の履歴の先端にある場合に発生します。つまり、マージ元のブランチが、マージ先のブランチが分岐した時点以降、一切変更が加えられていない場合に起こります。

この場合、Gitは複雑な統合処理を行わず、単にマージ先のブランチのポインタを、マージ元のブランチの先端コミットまで「早送り(fast-forward)」させます。新しいマージコミットは作成されず、履歴は直線的に見えます。

シナリオ例:

  1. mainブランチからfeature/Aを作成し、feature/Aでコミット1、コミット2を行う。
  2. その間、mainブランチには一切変更が加えられなかった。
  3. mainfeature/Aをマージする。

“`bash

初期状態

$ git log –oneline –graph –decorate
* (HEAD -> main) Initial commit

feature/A を作成・切り替え、コミットする

$ git switch -c feature/A
$ echo “Change 1” > file_a.txt; git add .; git commit -m “feat: Add file_a.txt”
$ echo “Change 2” >> file_a.txt; git add .; git commit -m “feat: Update file_a.txt”

$ git log –oneline –graph –decorate
* (HEAD -> feature/A) feat: Update file_a.txt
* feat: Add file_a.txt
* (main) Initial commit

main に戻り、feature/A をマージ

$ git switch main
$ git merge feature/A
Updating ..
Fast-forward
file_a.txt | 2 ++
1 file changed, 2 insertions(+)
“`

結果の履歴:

bash
$ git log --oneline --graph --decorate
* <hash-C> (HEAD -> main, feature/A) feat: Update file_a.txt
* <hash-B> feat: Add file_a.txt
* <hash-A> Initial commit

mainブランチのポインタが<hash-C>まで移動し、履歴が一本の線になっています。feature/Aブランチも同じコミットを指していますが、不要であれば削除しても構いません。

5.3. Three-way マージ

Three-wayマージは、Fast-forwardマージができない場合、つまりマージ先のブランチ(main)も、マージ元となるブランチ(feature/signup)が分岐した後で新しいコミットを持っている場合に発生します。

この場合、Gitは以下の3つのコミットを比較して統合を行います。

  1. マージ先のブランチの先端コミット (mainの現在のコミット)
  2. マージ元のブランチの先端コミット (feature/signupの現在のコミット)
  3. 両ブランチの共通の祖先コミット (両ブランチが分岐した時点、またはそれ以前の最新の共通コミット)

Gitはこれらの3つのバージョンを比較し、変更を組み合わせた新しい「マージコミット」を作成します。このコミットは、マージ元のブランチとマージ先のブランチの両方を親として持ちます。

シナリオ例:

  1. mainブランチからfeature/Bを作成。
  2. feature/Bでコミット1、コミット2を行う。
  3. その間に、mainブランチでもコミット3を行う。
  4. mainfeature/Bをマージする。

“`bash

初期状態 (Fast-forwardの例と同じ Initial commit)

$ git log –oneline –graph –decorate
* (HEAD -> main) Initial commit

feature/B を作成・切り替え、コミットする

$ git switch -c feature/B
$ echo “Feature B part 1” > file_b.txt; git add .; git commit -m “feat: Add file_b.txt (part 1)”
$ echo “Feature B part 2” >> file_b.txt; git add .; git commit -m “feat: Add file_b.txt (part 2)”

$ git log –oneline –graph –decorate
* (HEAD -> feature/B) feat: Add file_b.txt (part 2)
* feat: Add file_b.txt (part 1)
* (main) Initial commit

main に戻り、ここで新しいコミットをする

$ git switch main
$ echo “Bug fix in main” > bugfix.txt; git add .; git commit -m “fix: Fix critical bug in main”

$ git log –oneline –graph –decorate
* (HEAD -> main) fix: Fix critical bug in main
* Initial commit

main に feature/B をマージ

$ git merge feature/B
Merge made by the ‘recursive’ strategy.
file_b.txt | 2 ++
1 file changed, 2 insertions(+)
“`

結果の履歴:

bash
$ git log --oneline --graph --decorate
* <hash-E> (HEAD -> main) Merge branch 'feature/B'
|\
| * <hash-C> (feature/B) feat: Add file_b.txt (part 2)
* | <hash-D> fix: Fix critical bug in main
|/
* <hash-A> Initial commit

新しいコミット<hash-E>が作成され、これがマージコミットです。このコミットは<hash-C><hash-D>の二つを親としています。履歴には分岐と統合(マージコミット)が記録され、これがデフォルトの挙動です。

5.4. マージ時のコンフリクト(衝突)とその解決

Gitが二つのブランチの変更を自動的に統合できない場合があります。これは、同じファイルの同じ場所や、非常に近い場所で、異なる変更が行われた場合に発生します。このような状況を「コンフリクト(衝突)」と呼びます。

コンフリクトが発生すると、Gitはマージ処理を中断し、どのファイルでコンフリクトが起きているかを教えてくれます。

シナリオ例:

  1. mainブランチからfeature/Cを作成。
  2. feature/Cshared_file.txtの1行目を「変更A」に編集しコミット。
  3. その間に、mainブランチでもshared_file.txtの1行目を「変更B」に編集しコミット。
  4. mainfeature/Cをマージする。

“`bash

初期状態: shared_file.txt に “Line 1\nLine 2” と書かれている

$ git switch main
$ cat shared_file.txt
Line 1
Line 2

feature/C を作成・切り替え、shared_file.txt を編集・コミット

$ git switch -c feature/C
$ echo “Changed line 1 in feature/C” > shared_file.txt # 1行目を上書き
$ echo “Line 2” >> shared_file.txt
$ git add .
$ git commit -m “feat: Change line 1 in shared_file.txt (feature/C)”
[feature/C …] feat: Change line 1 in shared_file.txt (feature/C) …

main に戻り、同じ shared_file.txt の同じ場所を編集・コミット

$ git switch main
$ echo “Changed line 1 in main” > shared_file.txt # 1行目を上書き
$ echo “Line 2” >> shared_file.txt
$ git add .
$ git commit -m “fix: Change line 1 in shared_file.txt (main)”
[main …] fix: Change line 1 in shared_file.txt (main) …

main に feature/C をマージ

$ git merge feature/C
Auto-merging shared_file.txt
CONFLICT (content): Merge conflict in shared_file.txt
Automatic merge failed; fix conflicts and then commit the result.
“`

Gitは自動マージに失敗し、コンフリクトが発生したことを報告しました。git statusコマンドで現在の状況を確認してみましょう。

“`bash
$ git status
On branch main
You have unmerged paths.
(fix conflicts and run “git commit”)
(use “git merge –abort” to abort the merge)

Unmerged paths:
(use “git add …” to resolve)
both modified: shared_file.txt

no changes added to commit (use “git add” and/or “git commit”?)
“`

Unmerged pathsのセクションに、コンフリクトが発生したファイル(shared_file.txt)が表示されています。この状態では、マージは完了しておらず、新しいコミットも作成されていません。

コンフリクトの解決手順:

  1. コンフリクトファイルを開く: コンフリクトが発生したファイル(例: shared_file.txt)をテキストエディタで開きます。Gitがコンフリクト箇所にマーカーを挿入しています。

    “`
    <<<<<<< HEAD
    Changed line 1 in main
    =======
    Changed line 1 in feature/C

    feature/C
    Line 2
    “`

    • <<<<<<< HEADから=======の間: 現在のブランチ(main)での変更内容。
    • =======から>>>>>>> feature/Cの間: マージ元ブランチ(feature/C)での変更内容。
    • HEADfeature/Cは、それぞれのブランチの先端を指しています。
  2. 手動で編集してコンフリクトを解消する: 開発者が手動でファイルを編集し、どちらの変更を採用するか、あるいは両方の変更をどのように組み合わせるかを決定します。コンフリクトマーカー(<<<<<<<, =======, >>>>>>>)は削除します。

    例:両方の変更を組み合わせる場合
    Changed line 1 in main AND feature/C
    Line 2

  3. 解決済みのファイルをステージングエリアに追加: 編集が完了し、コンフリクトが解消されたら、そのファイルをgit addコマンドでステージングエリアに追加します。これはGitに対し、「このファイルのコンフリクトは解決しました」と知らせる行為です。

    bash
    $ git add shared_file.txt

    git statusで確認すると、Changes to be committedのセクションにshared_file.txtが表示され、コンフリクトが解決に向かっていることが分かります。

    “`bash
    $ git status
    On branch main
    All conflicts fixed but you are still merging.
    (use “git commit” to conclude merge)

    Changes to be committed:
    modified: shared_file.txt
    “`

  4. マージコミットを作成: コンフリクトが解決されたファイルをすべてステージングしたら、git commitコマンドでマージコミットを作成してマージプロセスを完了させます。Gitは通常、マージコミットメッセージを自動生成してくれます(例: “Merge branch ‘feature/C'”)。そのまま保存するか、必要に応じてメッセージを編集してコミットします。

    bash
    $ git commit

これで、feature/Cブランチの変更がmainブランチに統合されました。コンフリクトが発生した場合でも、この手順で落ち着いて対処すれば問題ありません。

コンフリクト解消ツール:
複雑なコンフリクトや多数のファイルでコンフリクトが発生した場合、テキストエディタでの手動編集は大変です。Gitにはgit mergetoolというコマンドがあり、設定した外部マージツール(DiffMerge, Meld, KDiff3など)を起動してコンフリクトをGUIで解決することができます。

bash
$ git mergetool

5.5. Fast-forward を避けて常にマージコミットを作成する: git merge --no-ff

デフォルトでは、可能な場合はFast-forwardマージが行われます。これにより履歴は直線的になりますが、元のブランチが存在していたという情報は失われます(マージ後にブランチを削除した場合)。

プロジェクトによっては、たとえFast-forwardが可能であっても、常にマージコミットを作成して、どのブランチからどのような変更が統合されたのかを履歴に明示的に残したい場合があります。このような場合は、git mergeコマンドに--no-ffオプションを付けます。

bash
$ git merge --no-ff feature/A # Fast-forward可能な場合でもマージコミットを作成

これにより、マージ元ブランチの存在が履歴グラフに残り、後から履歴を追う際に分かりやすくなるというメリットがあります。ただし、その分コミット数が増えます。どちらの方法が良いかは、プロジェクトのポリシーやチームの好みに依存します。

6. リベース (Rebase):ブランチの基点を変更する

マージと並んで、異なるブランチの変更を統合するもう一つの重要な操作が「リベース(Rebase)」です。マージが「二つのブランチを統合し、新しいマージコミットを作成する」のに対し、リベースは「あるブランチの変更を、別のブランチの先端に『乗せ換える』」操作です。

6.1. リベースとは何か?

リベースは、現在のブランチ(フィーチャーブランチなど)の作業を、別のブランチ(ベースブランチ、例えばmain)の最新状態の上に移動させる操作です。git rebase <base-branch>という形式で実行します。

例えば、feature/signupブランチで作業している途中で、mainブランチに新しいコミットが追加されたとします。この時、feature/signupmainにリベースすると、feature/signupで作成したコミットが、mainの最新コミットの「直後」に来るように履歴が書き換えられます。

リベースのプロセス:

  1. 現在いるブランチ(例: feature/signup)が、ベースブランチ(例: main)から分岐した時点からのコミットを一時的に待避します。
  2. 現在のブランチのHEADを、ベースブランチの先端コミットまで移動させます。
  3. 待避しておいたコミットを、新しいHEAD(ベースブランチの先端)の上に一つずつ順番に再適用(apply)していきます。

この再適用の過程で、元のコミットとはハッシュ値が異なる「新しいコミット」が作成されます。つまり、リベースは履歴を書き換える操作です。

シナリオ例 (マージとの比較):

マージのThree-wayマージの例と同じ状況を考えます。
* mainにはコミットAとコミットDがある。
* feature/BはコミットAから分岐し、コミットBとコミットCがある。

マージした場合の履歴:

* <hash-E> (HEAD -> main) Merge branch 'feature/B'
|\
| * <hash-C> (feature/B) feat: Add file_b.txt (part 2)
* | <hash-D> fix: Fix critical bug in main
|/
* <hash-A> Initial commit

マージコミット<hash-E>が作成され、履歴が枝分かれしています。

リベースした場合の履歴:

feature/Bブランチにいる状態で、mainブランチに対してリベースを実行します。

“`bash

feature/B ブランチにいるとする

$ git switch feature/B

main に対してリベースを実行

$ git rebase main
“`

Gitは以下の処理を行います。

  1. feature/Bのコミット<hash-B><hash-C>を一時的に保存。
  2. feature/BのHEADをmainの先端コミット<hash-D>に移動。
  3. 保存しておいたコミット<hash-B><hash-C>を、<hash-D>の上に順番に再適用。この際、コンフリクトが発生する可能性があり、その場合は解決が必要です。

再適用されたコミットは、元の<hash-B><hash-C>とは異なる新しいハッシュ値(例えば<hash-F><hash-G>)を持ちます。

“`bash

リベース後の履歴 (feature/B にいる状態)

$ git log –oneline –graph –decorate
* (HEAD -> feature/B) feat: Add file_b.txt (part 2) # コミットCが再適用されたもの
* feat: Add file_b.txt (part 1) # コミットBが再適用されたもの
* (main) fix: Fix critical bug in main
* Initial commit
“`

これで、feature/Bブランチの履歴は、mainの最新コミットの直後に続く、直線的なものになりました。この状態になったら、mainブランチに戻り、feature/BブランチをFast-forwardマージすることができます。

“`bash

main に戻る

$ git switch main
Switched to branch ‘main’

feature/B をマージ (これは Fast-forward になる)

$ git merge feature/B
Updating ..
Fast-forward
file_b.txt | 2 ++
1 file changed, 2 insertions(+)
“`

Fast-forward マージ後の履歴:

bash
$ git log --oneline --graph --decorate
* <hash-G> (HEAD -> main, feature/B) feat: Add file_b.txt (part 2)
* <hash-F> feat: Add file_b.txt (part 1)
* <hash-D> fix: Fix critical bug in main
* <hash-A> Initial commit

最終的に、履歴は完全に直線的になり、マージコミットも存在しません。

6.2. マージ vs. リベース:使い分け

特徴 マージ (Merge) リベース (Rebase)
履歴構造 ブランチの分岐・統合を保つ(非直線的) 履歴を書き換え、直線的にする
マージコミット 通常作成される (Three-wayの場合) 作成されない (最終的にFast-forwardになるため)
操作 共通の祖先と両ブランチ先端を統合 ブランチの基点を移動し、コミットを再適用
コンフリクト マージ操作中に一度に解決 再適用するコミットごとに解決が必要
安全性 履歴を改変しないため安全 履歴を改変するため、公開されたコミットには危険
利点 元のブランチの作業履歴が明確に残る 履歴がシンプルで分かりやすくなる
欠点 履歴が複雑になりやすい 履歴が改変されるリスク、コンフリクト解決の手間

使い分けの指針:

  • 公開済みのブランチには絶対リベースしない: 既にリモートリポジトリにプッシュされ、他の開発者がそのコミットを元に作業しているブランチに対してリベースを行うと、他の開発者の履歴と食い違いが発生し、非常に大きな混乱を招きます。これはGitを使う上で最も重要なルールの1つです。
  • 個人的なローカルブランチではリベースは有用: まだ誰とも共有していない、自分専用のローカルブランチであれば、リベースを使って履歴を整理し、mainなどの共有ブランチに取り込む前に履歴を綺麗にするのは有効な手法です。
  • チームのポリシーに従う: チームによってはマージを推奨したり、リベースを推奨したり、特定の状況でのみ許可したりと、異なるポリシーがあります。チームで合意したワークフローに従うことが最も重要です。一般的には、Pull Request (または Merge Request) を出す前のフィーチャーブランチを最新のmainに対してリベースして履歴を綺麗にし、その後mainにマージ(Fast-forward または no-ff)するというパターンが多く見られます。

6.3. リベース時のコンフリクト解決

リベースの過程でコミットを再適用する際に、コンフリクトが発生することがあります。マージ時のコンフリクトと同様に、Gitはリベース処理を中断し、コンフリクトファイルを知らせてくれます。

コンフリクトの発生状況:
リベースはコミットを一つずつ再適用していくため、コンフリクトが発生した場合もコミット単位で解決を進めることになります。

bash
$ git rebase main
...
Applying: feat: Add file_b.txt (part 1)
Using index info to reconstruct a base tree...
M file_b.txt
Falling back to patching 3-way merge.
Applying: feat: Add file_b.txt (part 2)
Using index info to reconstruct a base tree...
M file_b.txt
Falling back to patching 3-way merge.
Conflict in file_b.txt
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip".
To check out the original branch and stop rebasing, run "git rebase --abort".

Gitはコンフリクトが発生したコミットのメッセージを表示し、解決方法としてgit rebase --continuegit rebase --skipgit rebase --abortのコマンドを提示してくれます。

コンフリクト解決手順:

  1. コンフリクトファイルを開き手動で解決する: マージ時と同様に、コンフリクトマーカーを確認し、ファイルを編集してコンフリクトを解消します。
  2. 解決済みのファイルをステージングエリアに追加: 編集したファイルをgit addでステージングします。
    bash
    $ git add <conflicted-file>

    この時点ではコミットはまだ行いません。リベースの途中の特殊な状態です。
  3. リベースを続ける: コンフリクトを解決し、ファイルをステージングしたら、git rebase --continueコマンドを実行してリベース処理を再開します。

    bash
    $ git rebase --continue
    Applying: feat: Add file_b.txt (part 1) # コンフリクトが解消され、このコミットの適用が完了
    Applying: feat: Add file_b.txt (part 2) # 次のコミットの適用に進む

    もし次のコミットで再びコンフリクトが発生すれば、同じ手順を繰り返します。

その他のリベース操作:

  • git rebase --skip: 現在コンフリクトしているコミットをスキップし、次のコミットの再適用に進みます。このコミットで行われた変更はリベース後の履歴には含まれなくなります。
  • git rebase --abort: リベース処理を中止し、リベース開始前の状態に戻します。リベース中に何か問題が発生した場合に安全に元に戻るためのコマンドです。

リベース時のコンフリクト解決は、マージ時のそれと手順は似ていますが、コミット単位で繰り返す可能性があるため、慣れるまでは少し戸惑うかもしれません。しかし、手順を理解すれば安全に行えます。

7. リモートブランチとの連携:共同開発の要

Gitのブランチはローカルリポジトリだけでなく、リモートリポジトリとも連携することで真価を発揮します。GitHub, GitLab, Bitbucketなどのホスティングサービスを利用して、他の開発者とコードを共有・共同開発する際には、ローカルブランチとリモートブランチ間の連携が不可欠です。

7.1. リモートリポジトリと origin

通常、Gitプロジェクトを始めるとき、またはクローンするときに、一つ以上の「リモートリポジトリ」を設定します。リモートリポジトリは、他の開発者とコードを共有するための中心となるリポジトリです。

git cloneコマンドでリポジトリを複製すると、複製元のリモートリポジトリが自動的にoriginという名前で設定されます。originは単なる慣習的な名前であり、git remote add <name> <url>で任意のリモート名を設定することも可能です。

リモートリポジトリには、ローカルリポジトリと同様にブランチが存在します。git branch -aで表示されるremotes/origin/mainなどは、originという名前のリモートリポジトリにあるmainブランチの、ローカルリポジトリが把握している最新の状態を示しています。

7.2. リモートの変更を取得する: git fetch

git fetch <remote-name>コマンドは、リモートリポジトリの最新の変更内容を取得しますが、ローカルの作業ブランチにはすぐに適用しません。取得した変更は、remotes/<remote-name>/<branch-name>のようなリモート追跡ブランチとしてローカルリポジトリに取り込まれます。

“`bash

origin リモートから最新の変更を取得

$ git fetch origin
remote: Counting objects: …, done.
remote: Total … (delta …), reused … (delta …)
From github.com/user/repo
* [new branch] feature/D -> origin/feature/D
.. main -> origin/main
“`

git fetchを実行しても、現在チェックアウトしているローカルブランチ(例: main)には何も変更がありません。しかし、git branch -aで見ると、remotes/origin/mainや新しく作成されたremotes/origin/feature/Dといったリモート追跡ブランチが更新されていることが分かります。

git fetchは、他の開発者がリモートにプッシュした変更内容をローカルで確認したいが、自分の作業を中断したくない場合に便利です。取得した変更内容(例えばorigin/main)を、ローカルのmainブランチにマージするかリベースするかは、別途判断して実行します。

7.3. リモートの変更を取得し、現在のブランチに取り込む: git pull

git pull <remote-name> <branch-name>コマンドは、git fetchを実行してリモートの変更を取得した後、自動的にローカルの現在のブランチにその変更を統合します。デフォルトではマージが行われます。

“`bash

origin リモートの main ブランチの変更を取得し、ローカルの現在のブランチにマージする

$ git pull origin main
From github.com/user/repo
* branch main -> FETCH_HEAD
Auto-merging some_file.txt
Merge made by the ‘recursive’ strategy.
some_file.txt | 2 ++
1 file changed, 2 insertions(+)
“`

git pullは、頻繁に他の開発者の変更を取り込みたい場合に手軽ですが、裏でfetchmerge(またはrebase)の二つの操作が行われていることを理解しておくことが重要です。

git pullのデフォルトの統合方法は、設定によってマージとリベースの間で切り替えられます。git config pull.rebase trueを設定すると、git pullgit fetchの後にgit rebaseを実行するようになります。チームのポリシーに合わせて設定すると良いでしょう。

7.4. ローカルの変更をリモートに送信する: git push

git push <remote-name> <branch-name>コマンドは、ローカルブランチで行ったコミットをリモートリポジトリに送信し、リモートブランチを更新します。

“`bash

ローカルの main ブランチの変更を origin リモートの main ブランチにプッシュ

$ git push origin main
Enumerating objects: …, done.
Counting objects: …, done.
Delta compression using up to … threads
Compressing objects: …, done.
Writing objects: …, done.
Total …, new …, (delta …), pack-reused 0
To github.com/user/repo.git .. main -> main
“`

git pushは、ローカルブランチの先端コミットが、リモートブランチの先端コミットよりも「進んでいる」場合に成功します。もし他の開発者が先に同じリモートブランチにプッシュしていて、リモートブランチがローカルブランチよりも進んでいる場合(リモートにまだないコミットがローカルにある)、プッシュは拒否されます。この場合は、先にgit pullでリモートの変更を取り込み、ローカルブランチを最新の状態にしてから再度プッシュする必要があります。

トラッキングブランチ:
ローカルブランチを作成する際に、リモートの特定のブランチと関連付けて「トラッキング」させることができます。git cloneで作成されるデフォルトのローカルブランチ(例: main)は、自動的にリモートの対応するブランチ(origin/main)をトラッキングします。

トラッキング関係が設定されているブランチでは、git pullgit pushコマンドの引数を省略できます。例えば、ローカルのmainorigin/mainをトラッキングしている場合、単にgit pullgit pushと実行するだけで、それぞれgit pull origin maingit push origin mainとして扱われます。

新しいローカルブランチを作成し、それをリモートにプッシュする際に、トラッキング関係を設定するには、-uオプションを付けます。

“`bash

新しいローカルブランチ ‘feature/payment’ を作成・切り替え

$ git switch -c feature/payment

リモートにプッシュし、同時にリモートの同名ブランチとトラッキング関係を設定

$ git push -u origin feature/payment
Total …, new …, (delta …), pack-reused 0
remote: Create a pull request for ‘feature/payment’ on GitHub by visiting:
remote: …
To github.com/user/repo.git
* [new branch] feature/payment -> feature/payment
Branch ‘feature/payment’ set up to track remote branch ‘feature/payment’ from ‘origin’.
“`

一度-uオプション付きでプッシュしておけば、以降はそのブランチにいる限り、単にgit pullgit pushでリモートとのやり取りができるようになります。

リモートブランチの削除:
リモートリポジトリ上のブランチを削除したい場合は、以下のコマンドを使います。

“`bash
$ git push origin –delete

例: origin リモートの feature/signup ブランチを削除

$ git push origin –delete feature/signup
To github.com/user/repo.git
– [deleted] feature/signup
``
これは、リモートリポジトリに「
`という名前のブランチを削除してください」という指示をプッシュしているイメージです。

8. よくあるブランチワークフローの紹介

Gitのブランチは非常に柔軟なため、プロジェクトやチームのニーズに合わせて様々なブランチ運用方法(ワークフロー)が考案されています。ここでは代表的なものをいくつか紹介します。

8.1. Feature Branch Workflow

機能ごとに新しいブランチを作成し、そのブランチ上で開発を進め、完成したらメインブランチ(mainmaster)にマージするというシンプルなワークフローです。ほとんどのプロジェクトで採用されている、最も一般的で理解しやすいワークフローと言えるでしょう。

  1. mainブランチから新しいフィーチャーブランチ(例: feature/user-profile)を作成する。
  2. フィーチャーブランチ上で開発、コミットを繰り返す。
  3. 開発が完了したら、Pull Request (GitHub) や Merge Request (GitLab) を作成してチームメンバーにレビューを依頼する。
  4. レビューが通ったら、フィーチャーブランチをmainブランチにマージする。マージ方法はFast-forward、Three-way、または--no-ffなどが考えられる。リベースで履歴を整理してからマージすることも多い。
  5. マージ後、不要になったフィーチャーブランチは削除する。

シンプルさと柔軟性が特徴で、小規模から中規模のプロジェクトや、継続的なデリバリーを重視するプロジェクトに適しています。

8.2. Gitflow Workflow

Vincent Driessen氏によって提案された、より構造化されたワークフローです。master(またはmain)ブランチとdevelopブランチを永続的に持ち、さらにfeaturereleasehotfixといった短期的なサポートブランチを使い分けます。

  • master: 常にリリース可能な安定版コードを保持。タグでバージョンを管理。
  • develop: 次期リリースの開発を統合するブランチ。
  • feature: developから分岐し、個別の機能開発を行うブランチ。完了したらdevelopにマージ。
  • release: developから分岐し、リリースに向けた最終調整やバグ修正を行うブランチ。リリース準備が完了したらmasterdevelopの両方にマージし、タグを付けて削除。
  • hotfix: masterから分岐し、本番環境のクリティカルなバグを緊急修正するためのブランチ。完了したらmasterdevelop(または現在のrelease)の両方にマージし、タグを付けて削除。

厳格なルールに基づくため、プロジェクトの規模が大きい場合や、複数のバージョンを並行して管理する必要がある場合に有効です。ただし、ワークフローが複雑になるため、チーム全体での理解と徹底が必要です。専用のツール(git flowコマンド)も存在します。

8.3. GitHub Flow / GitLab Flow

Feature Branch Workflowをベースによりシンプルにしたワークフローです。

  • GitHub Flow: mainブランチのみを永続的に持ち、全ての変更はフィーチャーブランチで行い、mainにマージします。mainにマージされたコードはすぐにデプロイ可能であることを前提とします。リリースブランチやHotfixブランチは明示的には持ちません。
  • GitLab Flow: GitHub Flowに、環境ごとのブランチ(production, stagingなど)や、リリースごとのブランチを追加する柔軟性を持たせたものです。

継続的なデリバリーやWebアプリケーション開発など、リリースサイクルが早いプロジェクトに適しています。

どのワークフローを採用するかは、プロジェクトの規模、チームの人数、開発プロセス、リリース頻度などを考慮して決定する必要があります。

9. 実践的なブランチ活用テクニック

ブランチの基本操作やマージ/リベースをマスターしたら、さらに開発効率を上げるための実践的なテクニックをいくつか見ていきましょう。

9.1. 未コミットの変更を一時的に退避する: git stash

作業中に、別のブランチに切り替えて緊急のバグ修正を行ったり、他の作業を一時的に確認したりしたいが、現在のブランチでの作業はまだコミットできる状態ではない、という状況があります。未コミットの変更(ステージングエリアにある変更とワーキングツリーにある変更)がある状態でブランチを切り替えようとすると、Gitはコンフリクトの可能性があるとして切り替えを拒否することがあります。

このような場合、git stashコマンドを使うと、未コミットの変更を一時的に「退避(stash)」させ、ワーキングツリーをクリーンな状態に戻すことができます。

“`bash

現在の未コミットの変更を退避

$ git stash
Saved working tree and index state WIP on feature/work:

ワーキングツリーがクリーンになったことを確認

$ git status
On branch feature/work
nothing to commit, working tree clean
“`

これで、他のブランチに安全に切り替えることができます。

一時退避した変更は、後で元のブランチ、あるいは別のブランチに戻すことができます。

“`bash

退避した変更の一覧を確認

$ git stash list
stash@{0}: WIP on feature/work:

最新の退避した変更を適用し、スタッシュリストからは削除する

$ git stash pop
On branch feature/work
Changes not staged for commit:
(use “git add …” to update what will be committed)
(use “git restore …” to discard changes in working directory)
modified:

no changes added to commit (use “git add” and/or “git commit”?)
Dropped stash@{0} ( reformas …).

スタッシュリストから削除せずに適用だけ行う場合

$ git stash apply

特定のスタッシュを適用する場合 (stash@{0} を指定)

$ git stash apply stash@{0}

特定のスタッシュをスタッシュリストから削除する場合

$ git stash drop stash@{0}

全てのスタッシュをクリアする場合

$ git stash clear
“`

git stash popは、適用後にスタッシュリストから削除してくれるため、一度きりの退避によく使われます。git stash applyはリストに残すため、同じ変更を複数のブランチに適用したい場合などに使えます。

git stashはブランチを切り替える前の一時的な退避だけでなく、複数の変更のセットを分けてコミットしたいが、まだ区切りがついていない場合などにも利用できます。

9.2. 他のブランチの特定コミットを取り込む: git cherry-pick

あるブランチ(例えばfeature/X)で行われた特定のコミットだけを、別のブランチ(例えばmain)に取り込みたい場合があります。これは、例えばfeature/Xで発見・修正したバグ修正コミットを、まだfeature/X全体の開発は終わっていないが、緊急でmainやリリースブランチに適用したい、といった状況で役立ちます。このような場合にgit cherry-pick <commit-hash>コマンドを使います。

git cherry-pick <commit-hash>コマンドは、指定したコミットで行われた変更内容を取得し、現在のブランチに新しいコミットとして適用します。元のコミットをコピーしてくるイメージです。

シナリオ例:

  1. mainブランチがある。
  2. feature/Xブランチを作成し、そこでコミットA(普通の開発)、コミットB(バグ修正)、コミットC(普通の開発続き)を行った。
  3. mainブランチにコミットBのバグ修正だけを取り込みたい。

“`bash

履歴グラフ (例)

$ git log –oneline –graph –decorate
* (HEAD -> feature/X) feat: Feature X part 2
* fix: Fix bug in feature X # これを main に取り込みたい
* feat: Feature X part 1
* (main) Latest commit in main

main ブランチに切り替える

$ git switch main
Switched to branch ‘main’

コミットB () を cherry-pick する

$ git cherry-pick
[main ] fix: Fix bug in feature X # 新しいコミットとして適用された
Date: …
1 file changed, …

cherry-pick 後の履歴グラフ (例)

$ git log –oneline –graph –decorate
* (HEAD -> main) fix: Fix bug in feature X # cherry-pick されたコミット
* Latest commit in main
| * (feature/X) feat: Feature X part 2
| * fix: Fix bug in feature X # 元のコミット
| * feat: Feature X part 1
|/

“`

cherry-pickによって、<hash-B>で行われた変更がmainブランチに<new-hash>という新しいコミットとして適用されました。

注意点:
* cherry-pickは元のコミットをコピーして新しいコミットを作成するため、コミットハッシュが変わります。
* cherry-pick の対象となるコミットが他のブランチの変更に依存している場合、コンフリクトが発生しやすいです。
* cherry-pick を多用すると履歴が複雑になる可能性があります。基本的にはマージやリベースでの統合を優先し、 cherry-pick は例外的な状況(緊急のバグ修正など)に限定するのが望ましいです。

9.3. ブランチ命名規則

チームで開発を行う場合、ブランチに分かりやすい命名規則を設けることは、ブランチの目的を明確にし、リポジトリの管理を容易にする上で非常に重要です。一般的な命名規則の例です。

  • feature/<機能名>: 新機能開発用。例: feature/user-login, feature/payment-integration
  • bugfix/<バグの内容>: バグ修正用。課題管理システムのチケット番号を含めることも多い。例: bugfix/issue-123, bugfix/crash-on-save
  • hotfix/<緊急修正の内容>: 本番環境の緊急修正用。バージョン番号を含めることも。例: hotfix/v1.0.1, hotfix/critical-security-patch
  • release/<バージョン>: リリース準備用 (Gitflowなど)。例: release/v1.2.0
  • refactor/<対象>: リファクタリング用。例: refactor/authentication-module, refactor/css-cleanup
  • chore/<内容>: 開発プロセスに関わる雑務(ドキュメント更新、ビルド設定変更など)。例: chore/update-docs, chore/add-ci-config

命名規則はチームで話し合って決め、遵守することが大切です。

10. ブランチ操作時の注意点とトラブルシューティング

ブランチ操作は開発を効率化する強力な手段ですが、いくつか注意しておきたい点があります。

  • HEADがあるブランチは削除できない: 前述の通り、現在作業中のブランチは削除できません。
  • 公開済みのコミットへのリベースは避ける: これも前述の通り、最も重要なルールの1つです。ローカル専用ブランチでのみ行いましょう。
  • コンフリクトを恐れない: コンフリクトはGitが自動で統合できなかった場所を示しているだけであり、開発者が手動で最も適切な状態に修正できる機会です。手順を理解し、落ち着いて対処すれば問題ありません。
  • git statusを頻繁に使う: Gitの現在の状態(どのブランチにいるか、未コミットの変更はあるか、コンフリクトは発生しているかなど)を把握するために、git statusコマンドを常に実行する習慣をつけましょう。
  • 定期的なコミットとプッシュ: 小まめにコミットし、可能であればリモートにプッシュしておくことで、予期せぬトラブルやローカル環境の破損から作業内容を守ることができます。
  • ブランチ名を間違えない: git mergegit rebaseの際に、マージ/リベース元となるブランチ名を間違えると、意図しない履歴の変更が発生する可能性があります。コマンド実行前には必ず対象ブランチ名を確認しましょう。
  • git reflogを活用する: もし誤ったGit操作(リベースの中断、ブランチの誤削除など)で「元に戻りたい」と思ったとき、git reflogコマンドが役立ちます。これはHEADが過去にどこを指していたかの履歴(ローカルな操作ログ)を表示します。このログから過去のコミットハッシュやブランチの状態を見つけ出し、git resetgit checkoutなどで状態を戻せる可能性があります。ただし、これは少し高度な操作なので、必要になった際に調べてみると良いでしょう。

Gitの操作に慣れないうちは、GUIツールを使うのも一つの方法です。GUIツールはブランチのグラフ表示やコンフリクト解消などを視覚的にサポートしてくれるため、Gitの仕組みの理解にも役立ちます。

11. まとめ:Gitブランチを使いこなそう!

この記事では、Gitブランチの基本中の基本から、マージ、リベースといった重要な統合操作、リモート連携、実践的なテクニック、そして注意点まで、幅広く解説しました。

改めて、Gitブランチの重要なポイントを振り返りましょう。

  • ブランチは、開発のメインラインから分岐し、独立して作業を進めるための「軽量なポインタ」です。
  • ブランチを使うことで、並行開発、機能の隔離、実験などが安全かつ効率的に行えます。
  • git branchで作成、git switch (またはgit checkout) で切り替え、git branch -d (-D) で削除します。
  • 異なるブランチの変更を統合するには、git mergeまたはgit rebaseを使います。
    • git mergeは履歴を保存する統合、git rebaseは履歴を直線化する統合です。
    • 公開済みのコミットに対してリベースは絶対に行わないという重要なルールがあります。
  • コンフリクトが発生した場合は、慌てずに手動でファイルを編集し、git addgit commit (マージの場合) またはgit rebase --continue (リベースの場合) の手順で解決します。
  • git fetchでリモートの変更を取得し、git pullで取得+統合、git pushでローカルの変更をリモートに送信します。
  • Feature Branch Workflowなどのワークフローを理解し、チームで合意したルールでブランチを運用することがスムーズな共同開発につながります。
  • git stashgit cherry-pickといったテクニックは、特定の状況で開発効率を向上させます。
  • 常にgit statusで現在の状態を確認し、定期的にコミット・プッシュを行う習慣をつけましょう。

Gitブランチをマスターすることは、単にコマンドを覚えるだけでなく、開発の変更履歴をどのように管理・共有していくかという開発プロセス全体の理解につながります。最初は少し難しく感じるかもしれませんが、実際に手を動かして様々な操作を試してみることで、徐々に慣れていくはずです。

この記事で学んだ知識を活かして、Gitブランチを自在に操り、より効率的で、より安全で、そしてより楽しい開発ライフを送りましょう!


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール