Git ブランチ入門:基本操作を徹底解説

Git ブランチ入門:基本操作を徹底解説

Gitを使ったバージョン管理において、「ブランチ」は最も強力かつ基本的な機能の一つです。適切にブランチを使いこなすことで、開発効率は飛躍的に向上し、チームでの共同開発もスムーズになります。しかし、Gitに慣れていない方にとって、ブランチの概念や操作は少し難しく感じられるかもしれません。

この記事では、Gitブランチの基本から応用、そしてチームでの活用方法まで、約5000語の大ボリュームで徹底的に解説します。この記事を最後まで読むことで、あなたはブランチを自信を持って使いこなし、日々の開発ワークフローを改善できるようになるでしょう。

さあ、Gitブランチの世界へ飛び込みましょう!

1. はじめに:なぜGitブランチが必要なのか?

ソフトウェア開発において、複数の機能開発やバグ修正が同時に進行することは珍しくありません。また、新しい機能を試したり、大胆な変更を加えたりする際には、「もし失敗しても、安定したバージョンにすぐ戻せるようにしたい」という要望が必ず生まれます。

このような状況で非常に役立つのが、Gitの「ブランチ」機能です。

ブランチは、プロジェクトの履歴から分岐して、独立した開発ラインを作成する機能です。例えるなら、メインの道路から脇道に逸れて作業を行い、作業が終わったら再びメインの道路に戻ってくるようなものです。

ブランチを使うことで、以下のようなメリットが得られます。

  • 並行開発の実現: 複数の開発者がそれぞれ独立した機能を同時に開発できます。
  • 安全性の確保: 実験的な変更や未完成のコードをメインの開発ライン(通常はmainmasterブランチ)から隔離して作業できます。これにより、安定版に悪影響を与えるリスクを最小限に抑えられます。
  • 機能開発や修正ごとの分離: 各機能やバグ修正ごとにブランチを作成することで、作業範囲を明確にし、管理しやすくなります。
  • 実験的な試みの容易さ: 新しいアイデアや技術を試す際に、気軽にブランチを切って作業できます。うまくいかなければそのブランチを削除するだけでよく、メインの履歴を汚しません。
  • リリース管理の柔軟性: 特定のバージョンをリリースするためのブランチを作成したり、過去のバージョンのバグを修正するためのブランチを作成したりと、リリースの管理を柔軟に行えます。

この記事では、ブランチの基本的な概念から始め、ブランチの作成、切り替え、削除といった基本操作、さらに異なるブランチ間での変更の統合(マージやリベース)、そしてチームでの共同開発に不可欠なリモートブランチとの連携まで、順を追って詳しく解説していきます。

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

2. Gitブランチとは何か:基本概念の理解

Gitにおけるブランチは、他のバージョン管理システムにおけるブランチとは少し異なる、非常に軽量で強力な仕組みです。Gitのブランチを理解するためには、まずGitがどのように履歴を記録しているかを簡単に把握しておく必要があります。

Gitは、プロジェクトの変更を「コミット」として記録します。各コミットは、その時点のプロジェクトのスナップショット(ファイルやディレクトリの状態)と、一つ以上の親コミットへのポインタを持っています。これにより、コミットは連鎖し、開発の履歴がグラフ構造として表現されます。

2.1 ブランチは「コミットへのポインタ」

Gitにおけるブランチは、実は非常にシンプルなものです。それは特定のコミットを指し示す単なるポインタ(参照)にすぎません。

Gitブランチの概念図イメージ
イメージ図:コミットC1, C2, C3が連なり、mainブランチが最新のコミットC3を指している様子。

例えば、あなたがmainという名前のブランチを持っていて、いくつかのコミットを重ねたとします。このmainブランチは、履歴上の最新のコミットを常に指しています。新しいコミットを追加すると、mainブランチというポインタは自動的にその新しいコミットを指すように移動します。

2.2 HEADとは

Gitには「HEAD」と呼ばれる特別なポインタがあります。HEADは、現在作業しているローカルブランチを指しています。つまり、あなたのファイルシステム上の作業ディレクトリ(ワーキングツリー)とステージングエリア(インデックス)は、HEADが指しているブランチの最新コミットの状態に対応しています。

HEADとブランチの概念図イメージ
イメージ図:mainブランチがコミットC3を指しており、HEADがそのmainブランチを指している様子。

あなたがブランチを切り替えるとき、実際にはHEADが指すブランチを変更しています。そして、Gitはそのブランチが指すコミットの状態に合わせて、ワーキングツリーとインデックスの内容を更新します。

2.3 なぜGitのブランチは「軽量」なのか?

他の多くのバージョン管理システムでは、ブランチを作成すると、プロジェクト全体のファイルやディレクトリが物理的に複製されることがあります。これは、ブランチ操作が時間とディスク容量を消費する原因となります。

一方、Gitのブランチは前述の通り単なるポインタです。ブランチを作成するということは、単に新しいポインタを作成し、それを現在のHEADが指すコミットと同じコミットに設定するだけです。ファイルシステムのコピーは発生しません。

新しいブランチ作成の概念図イメージ
イメージ図:mainブランチがC3を指している状態で、feature/Aブランチを作成。feature/AもC3を指すようになる様子。

この「軽量」な特性のおかげで、Gitではブランチの作成、切り替え、削除といった操作が非常に高速に行えます。これが、Gitを使った開発において、機能を開発するたびに気軽にブランチを切るというワークフローが推奨される理由の一つです。

2.4 ブランチを使うメリットの再確認

Gitブランチの基本概念を理解したところで、改めてそのメリットを確認しましょう。

  • 隔離性: 各ブランチは独立した開発ラインです。あるブランチでの変更は、他のブランチに影響を与えません(マージするまでは)。
  • 効率性: ブランチ操作が高速なので、開発者は機能ごとにブランチを切り替えて効率的に作業を進められます。
  • 柔軟性: 複数の開発者が同じリポジトリ内で、互いの作業を邪魔することなく同時に開発を進めることができます。
  • 履歴の整理: 機能開発やバグ修正ごとにブランチを分けることで、コミット履歴が論理的に整理され、後から追跡しやすくなります。

これらのメリットを最大限に活かすためにも、Gitブランチの基本操作をしっかりと身につけることが重要です。

3. ブランチの基本操作:コマンド徹底解説

Gitのブランチ操作は、いくつかのシンプルなコマンドで行えます。ここでは、よく使う基本的なブランチ関連コマンドを詳しく見ていきましょう。

Gitコマンドを実行する際は、対象のリポジトリのディレクトリで行います。

3.1 ブランチの一覧表示: git branch

現在存在するブランチを確認するには、git branchコマンドを使います。

bash
git branch

実行例:

$ git branch
develop
* main
feature/login

この出力の意味:
* develop, main, feature/login は、ローカルリポジトリに存在するブランチの名前です。
* ブランチ名の先頭に * がついているブランチ(この例ではmain)は、現在作業中のブランチ、つまりHEADが指しているブランチです。

3.1.1 リモートブランチも含めて表示: git branch -a

リモートリポジトリにあるブランチも含めて、すべてのブランチを表示したい場合は、-aオプションを使います。

bash
git branch -a

実行例:

$ git branch -a
develop
* main
feature/login
remotes/origin/HEAD -> origin/main
remotes/origin/develop
remotes/origin/main
remotes/origin/feature/signup

出力の意味:
* 最初の3行はローカルブランチです。(先ほどと同じ)
* remotes/origin/... から始まる行は、リモートリポジトリoriginにあるブランチです。これらは「リモート追跡ブランチ」と呼ばれ、リモートブランチの状態をローカルで確認するための参照です。
* remotes/origin/HEAD -> origin/main は、リモートリポジトリoriginでデフォルトのブランチ(通常はmainmaster)がどれであるかを示しています。

3.1.2 リモートブランチのみ表示: git branch -r

リモートブランチだけを表示したい場合は、-rオプションを使います。

bash
git branch -r

実行例:

$ git branch -r
origin/HEAD -> origin/main
origin/develop
origin/main
origin/feature/signup

3.2 新しいブランチの作成: git branch <branchname>

新しいブランチを作成するには、git branch <branchname>コマンドを使います。このコマンドは、現在いるブランチの最新コミットから新しいブランチを作成します。

bash
git branch feature/new-feature

実行例:

bash
$ git branch main
$ git commit -m "Initial commit"
$ git commit -m "Add some content"
$ git branch feature/new-feature # 現在(main)の最新コミットから feature/new-feature を作成
$ git branch
feature/new-feature
* main

新しいブランチ作成の概念図イメージ(操作後)
イメージ図:mainブランチがC2を指している状態でgit branch feature/new-featureを実行。feature/new-featureもC2を指すようになる様子。HEADはmainを指したまま。

重要: git branch <branchname>コマンドを実行しても、現在作業中のブランチは切り替わりません。 新しいブランチが作成されるだけです。新しいブランチに切り替えるには、後述するgit checkoutまたはgit switchコマンドが必要です。

3.2.1 特定のコミットからブランチを作成: git branch <branchname> <commit-ish>

新しいブランチを、現在のコミットではなく、履歴上の特定のコミットから作成することもできます。これは、過去の特定の時点からバグ修正ブランチを作成したい場合などに便利です。

コミットを指定するには、コミットのハッシュ値(SHA-1値の先頭数文字で十分なことが多い)、タグ名、別のブランチ名などを使用できます。これらをまとめてcommit-ishと呼びます。

“`bash

例:特定のコミットハッシュからブランチを作成

git branch bugfix/old-version a1b2c3d4

例:特定のタグからブランチを作成

git branch release/v1.0.1 v1.0

例:developブランチの最新コミットからブランチを作成(mainにいる場合)

git branch feature/from-develop develop
“`

特定のコミットからブランチ作成の概念図イメージ
イメージ図:mainがC3を指している状態で、C1からbugfix/Aブランチを作成。bugfix/AはC1を指す様子。

3.3 ブランチの切り替え: git checkout <branchname>

作業するブランチを切り替えるには、git checkout <branchname>コマンドを使います。

bash
git checkout feature/new-feature

実行例:

bash
$ git branch
feature/new-feature
* main
$ git checkout feature/new-feature
Switched to branch 'feature/new-feature' # ブランチが切り替わったことを示すメッセージ
$ git branch
* feature/new-feature
main

ブランチ切り替え(checkout)の概念図イメージ
イメージ図:HEADがmain(C2を指している)を指している状態から、git checkout feature/new-featureを実行。HEADがfeature/new-feature(これもC2を指している)を指すように移動。ワーキングツリーの内容は変わらない(同じコミットを指しているため)。

git checkoutコマンドを実行すると:
1. HEADが指定したブランチを指すように移動します。
2. ワーキングツリーとインデックスの内容が、HEADが新しく指すコミットの状態に合わせて更新されます。 これにより、ファイルの内容が切り替わったブランチの最新の状態に変わります。

注意点: ワーキングツリーやインデックスに未コミットの変更がある場合、git checkoutを実行するとこれらの変更が失われる可能性があります。Gitは通常、変更が失われるような切り替えはブロックしてくれますが、ブランチを切り替える前に、作業中の変更はコミットするか、git stashコマンドを使って一時的に退避させておくのが安全です。

3.4 ブランチの作成と切り替えを同時に行う: git checkout -b <branchname>

新しいブランチを作成し、さらにそのブランチにすぐに切り替えたいという状況はよくあります。この2つの操作を一度に行える便利なコマンドが、git checkout -b <branchname>です。

bash
git checkout -b feature/another-feature

実行例:

bash
$ git branch # 現在 main にいると仮定
* main
$ git checkout -b feature/another-feature # feature/another-feature を作成し、そこに切り替える
Switched to a new branch 'feature/another-feature'
$ git branch
* feature/another-feature
main

新しいブランチ作成と切り替え(checkout -b)の概念図イメージ
イメージ図:mainブランチがC2を指している状態で、git checkout -b feature/another-featureを実行。まずfeature/another-featureがC2を指すように作成され、次にHEADがfeature/another-featureを指すように移動。

このコマンドは、現在のHEADが指すコミットから新しいブランチを作成し、直ちにそのブランチに切り替えます。新しい機能開発やバグ修正を始める際に頻繁に使用されます。

3.4.1 特定のコミットからブランチ作成・切り替え: git checkout -b <branchname> <start-point>

git checkout -bコマンドでも、特定のコミットやブランチを指定して、そこから新しいブランチを作成し、切り替えることができます。

“`bash

例:developブランチの最新コミットからfeatureブランチを作成し、切り替える

git checkout -b feature/from-develop-and-switch develop
“`

3.5 ブランチの削除: git branch -d <branchname> / git branch -D <branchname>

不要になったブランチは削除して、ブランチリストを整理しましょう。ブランチを削除するには、git branch -d <branchname>コマンドを使います。

bash
git branch -d feature/old-feature

実行例:

bash
$ git branch # 現在 main にいると仮定
* main
feature/old-feature # 削除したいブランチ
$ git branch -d feature/old-feature
Deleted branch feature/old-feature (was a1b2c3d). # 削除成功
$ git branch
* main

3.5.1 マージ済みのブランチのみ削除 (-d)

git branch -dコマンドは、指定したブランチの変更が、現在のブランチまたは他のマージ済みのブランチに完全に含まれている(マージ済みである)場合のみ、ブランチを削除します。これは、誤って未マージの変更を含むブランチを削除してしまうのを防ぐための安全策です。

もし、削除しようとしているブランチがまだ他のブランチにマージされていない変更を含んでいる場合、git branch -dはエラーとなり、削除できません。

bash
$ git branch # feature/unmerged-work に未マージのコミットがあると仮定
* main
feature/unmerged-work
$ git branch -d feature/unmerged-work
error: The branch 'feature/unmerged-work' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature/unmerged-work'. # 未マージのため削除できない

3.5.2 強制削除 (-D)

未マージの変更が含まれているブランチでも、警告を無視して強制的に削除したい場合は、-Dオプションを使います。これは、そのブランチでの作業が不要になったり、他の場所でバックアップが取られていたりする場合などに使用します。

bash
git branch -D feature/unmerged-work

実行例:

bash
$ git branch -D feature/unmerged-work
Deleted branch feature/unmerged-work (was e4f5g6h). # 強制削除成功
$ git branch
* main

注意: -Dオプションでブランチを削除すると、そのブランチにのみ存在していたコミットは(他のブランチから到達不可能になるため)、将来的にGitのガベージコレクションによって削除される可能性があります。失いたくない変更が含まれている場合は、安易に-Dを使わないようにしましょう。

3.6 git switch コマンドについて (checkoutの代替)

Gitのバージョン2.23以降では、git checkoutコマンドの機能がgit switchgit restoreという2つの新しいコマンドに分割されました。

  • git switch: ブランチの切り替えや作成に特化
  • git restore: ワーキングツリーやインデックスの状態を復元する(ファイルの取り消しなどに特化)

git checkoutは多機能すぎて分かりにくいという声に応えて導入されました。ブランチ操作に関しては、今後はgit switchを使うことが推奨されています。

3.6.1 ブランチの切り替え: git switch <branchname>

既存のブランチに切り替えるには、git switch <branchname>を使います。これはgit checkout <branchname>と同じ機能です。

bash
git switch main

実行例:

bash
$ git branch
* feature/new-feature
main
$ git switch main
Switched to branch 'main'
$ git branch
feature/new-feature
* main

checkoutと同様に、未コミットの変更がある場合は、切り替えがブロックされることがあります。

3.6.2 新しいブランチの作成と切り替え: git switch -c <branchname>

新しいブランチを作成し、そこに切り替えるには、git switch -c <branchname>を使います。これはgit checkout -b <branchname>と同じ機能です。-c--createの略です。

bash
git switch -c feature/login

実行例:

bash
$ git branch # 現在 main にいると仮定
* main
$ git switch -c feature/login
Switched to a new branch 'feature/login'
$ git branch
* feature/login
main

特定の開始点から作成する場合は、同様にコマンドの末尾にstart-pointを指定します。

bash
git switch -c release/v1.1 develop

3.6.3 強制的に新しいブランチを作成・切り替え (-C)

もし、作成しようとしているブランチ名が既に存在する場合、git switch -cはエラーとなります。既存のブランチを上書きして新しいブランチを作成・切り替えたい場合は、-Cオプション(--force-createの略)を使います。これはgit checkout -Bに相当します。

“`bash

既にfeature/loginブランチが存在するが、現在のmainブランチの最新状態に上書きしたい場合

git switch -C feature/login main
“`

このコマンドは既存のfeature/loginブランチを削除し、改めてmainブランチの最新コミットからfeature/loginブランチを作成し直して切り替えます。既存のブランチの履歴が失われるため、注意して使用してください。

まとめ:

  • ブランチ一覧: git branch (-a, -r)
  • 新しいブランチ作成: git branch <name>
  • ブランチ切り替え: git checkout <name> または git switch <name> (推奨)
  • ブランチ作成+切り替え: git checkout -b <name> または git switch -c <name> (推奨)
  • ブランチ削除: git branch -d <name> (マージ済みのみ) / git branch -D <name> (強制)

これらの基本的なコマンドを理解し、スムーズに使えるようになることが、Gitブランチ活用の第一歩です。

4. ブランチの操作とワークフロー:より実践的な使い方

ブランチの作成と切り替えができるようになったら、次は異なるブランチ間での作業や、変更を統合する方法を学びましょう。ここがGitブランチの真髄であり、少し複雑になる部分です。

4.1 変更のコミットとブランチ

現在いるブランチで作業を行い、変更をコミットすると、そのコミットは現在のブランチの履歴にのみ追加されます。

“`bash

feature/new-feature ブランチにいると仮定

$ git branch
* feature/new-feature
main

$ echo “これは新しい機能です” > feature.txt
$ git add feature.txt
$ git commit -m “Add feature implementation” # feature/new-feature ブランチに新しいコミットが追加される
“`

コミットによるブランチポインタの移動イメージ
イメージ図:feature/new-featureブランチがC2を指している状態。git commitを実行すると、新しいコミットC3が作成され、feature/new-featureブランチというポインタがC3を指すように自動的に移動。mainブランチはC2を指したまま。

このように、各ブランチは独立した履歴を持つため、あるブランチでの作業が他のブランチに影響を与えることはありません。

4.2 異なるブランチ間での作業

複数のブランチで同時に作業を進める際に問題となるのが、未コミットの変更をどう扱うかです。前述の通り、未コミットの変更がある状態でブランチを切り替えようとすると、Gitはエラーを出すことがあります。

例えば、feature/Aブランチでファイルを変更したが、まだコミットしていない状態で、急ぎでbugfix/Bブランチに切り替えて作業したい場合などです。

4.2.1 作業中の変更を残したままブランチを切り替える: git stash

このような場合に便利なのがgit stashコマンドです。git stashは、ワーキングツリーとインデックスの現在の状態を一時的に保存し、ワーキングツリーをクリーンな状態に戻します。 これは、未コミットの変更を隠して、他のブランチに切り替えられるようにする機能です。

“`bash

feature/A ブランチで作業中、未コミットの変更がある

$ git status
On branch feature/A
Changes to be committed:
(use “git restore –staged …” to unstage)
new file: new_file.txt

Changes not staged for commit:
(use “git add …” to update what will be committed)
(use “git restore …” to discard changes in working directory)
modified: existing_file.txt

$ git stash # 現在の変更をスタッシュする
Saved working tree and index state WIP on feature/A: a1b2c3d Initial commit
$ git status # ワーキングツリーがクリーンになった
On branch feature/A
nothing to commit, working tree clean

これで安心して別のブランチに切り替えられる

$ git switch bugfix/B
Switched to branch ‘bugfix/B’
“`

git stashで保存された変更は、スタッシュリストに積まれていきます。スタッシュリストを確認するにはgit stash list、スタッシュされた変更を現在のブランチに適用するにはgit stash applyまたはgit stash popを使います。

  • git stash list: 保存されたスタッシュの一覧を表示
  • git stash apply: 最新のスタッシュを適用(スタッシュはリストに残る)
  • git stash pop: 最新のスタッシュを適用し、リストから削除

git stashはブランチを切り替える際だけでなく、ちょっとした実験や、別の作業を急に挟む必要が出た場合にも非常に便利です。

4.3 マージの基本: git merge

あるブランチで開発した機能を別のブランチ(通常はメインのブランチ)に取り込みたい場合、マージ (merge)という操作を行います。マージは、指定したブランチの履歴を現在のブランチに統合する操作です。

例えば、feature/loginブランチでログイン機能を開発し、それをmainブランチに取り込みたいとします。

“`bash

まず、統合先のブランチ(main)に切り替える

$ git switch main

次に、feature/login ブランチを現在のブランチ(main)にマージする

$ git merge feature/login
“`

マージの実行結果は、履歴の状態によって2つのパターンに分かれます。

4.3.1 Fast-forward マージ

マージ元のブランチ(feature/login)が、マージ先のブランチ(main)から分岐した後、マージ先のブランチに新しいコミットが一切追加されていない場合、Gitは「Fast-forward(早送り)」マージを行います。

Fast-forwardマージの概念図イメージ
イメージ図:mainブランチがC2を指している。feature/loginブランチがC4を指している(C3, C4はfeature/loginで追加されたコミット)。mainがC2から分岐した後、mainには新しいコミットが追加されていない。git merge feature/loginをmainブランチで実行すると、mainブランチというポインタがC4を指すように移動するだけ。新しいマージコミットは作成されない。

この場合、Gitは単にマージ先のブランチポインタを、マージ元のブランチの最新コミットまで進めるだけです。新しいマージコミットは作成されません。履歴が線形になり、シンプルになります。

実行例:

bash
$ git switch main # main に切り替える
$ git merge feature/login # feature/login をマージ
Updating a1b2c3d..e4f5g6h
Fast-forward
path/to/new/file.txt | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 path/to/new/file.txt

4.3.2 Three-way マージ (Recursive Strategy)

マージ元のブランチ(feature/login)とマージ先のブランチ(main)の両方で、分岐点(共通の祖先コミット)から新しいコミットが追加されている場合、Gitは「Three-way マージ」を行います。

Three-wayマージの概念図イメージ
イメージ図:mainブランチがC4を指している(C3, C4はmainで追加されたコミット)。feature/loginブランチがC6を指している(C5, C6はfeature/loginで追加されたコミット)。分岐点はC2。git merge feature/loginをmainブランチで実行すると、GitはC4, C6, そして共通の祖先C2を比較し、変更を統合した新しいコミットC7を作成する。mainブランチというポインタがC7を指すように移動。

この場合、Gitは以下の3つのコミットを比較して変更を統合します。
1. マージ先のブランチの最新コミット (mainの最新)
2. マージ元のブランチの最新コミット (feature/loginの最新)
3. 両方のブランチの共通の祖先コミット

Gitはこれらのコミット間の差分を分析し、可能な限り自動的に変更を統合します。そして、新しい「マージコミット」を作成します。 このマージコミットは、マージ対象となった両方のブランチの最新コミットを親として持ちます。

実行例:

bash
$ git switch main # main に切り替える
$ git merge feature/login # feature/login をマージ
Merge made by the 'recursive' strategy.
path/to/feature_file.txt | 20 ++++++++++++++++++++
path/to/main_file.txt | 15 +++++++++++++++
2 files changed, 35 insertions(+)
create mode 100644 path/to/feature_file.txt
create mode 100644 path/to/main_file.txt

4.3.3 コンフリクトの解決

Gitが自動的に変更を統合できない場合があります。これは、同じファイルの同じ部分(または非常に近い部分)が、両方のブランチで異なる方法で変更された場合に発生します。この状態を「コンフリクト (Conflict)」と呼びます。

コンフリクトが発生すると、Gitはマージを一時停止し、コンフリクトが発生したファイルを教えてくれます。

実行例(コンフリクト発生):

bash
$ git switch main
$ git merge feature/login
Auto-merging conflicted_file.txt
CONFLICT (content): Merge conflict in conflicted_file.txt
Automatic merge failed; fix conflicts and then commit the result.

Gitは、コンフリクトが発生したファイルの中に、コンフリクトマーカーという特殊な目印を追加します。

“`
<<<<<<< HEAD
これは main ブランチでの変更です。
=======
これは feature/login ブランチでの変更です。

feature/login
“`

  • <<<<<<< HEAD: 現在のブランチ(main)での変更の始まり
  • =======: 変更の区切り
  • >>>>>>> feature/login: マージ対象のブランチ(feature/login)での変更の終わり

コンフリクトを解決する手順:

  1. コンフリクトが発生したファイルを確認する: git statusコマンドで、Unmerged paths のリストを確認します。
  2. ファイルを編集してコンフリクトを解決する: コンフリクトマーカー (<<<<<<<, =======, >>>>>>>) を削除し、両方のブランチの変更を適切に統合するようにファイルを編集します。どちらか一方の変更を採用しても良いですし、両方の変更を組み合わせたり、全く新しいコードを書いたりしても構いません。
  3. 解決したファイルをステージングエリアに追加する: 編集が終わったら、git add <解決したファイル>でファイルをステージします。
  4. マージを完了させるためのコミットを行う: コンフリクトが発生したすべてのファイルをステージしたら、git commitコマンドを実行します。Gitは自動的にマージコミットのメッセージを生成してくれます(通常はそのまま使います)。

“`bash

コンフリクトが発生した conflicted_file.txt を手動で編集・解決

解決したファイルをステージング

$ git add conflicted_file.txt

git status で Unmerged paths がなくなっていることを確認

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

Changes to be committed:
(use “git restore –staged …” to unstage)
modified: conflicted_file.txt

マージを完了させるコミット

$ git commit

エディタが開き、マージコミットメッセージが表示される(デフォルトでOKなことが多い)

“`

これでマージとコンフリクトの解決が完了し、マージコミットが作成されます。

4.3.4 マージのキャンセル: git merge --abort または git reset --hard HEAD

マージ中にコンフリクトが発生したが、解決が難しい、あるいはマージ自体を取りやめたい場合は、マージ操作をキャンセルできます。

  • git merge --abort: マージ開始前の状態にワーキングツリーやインデックスを戻します。最もクリーンな方法です。
  • git reset --hard HEAD: マージ開始前のHEADの位置に戻し、ワーキングツリーとインデックスもその時点の状態に戻します。マージだけでなく、他の未コミットの変更もすべて破棄される可能性があるため注意が必要です。マージ直後(マージコミットを行う前)であれば、git reset --hard ORIG_HEADでもマージ開始前の状態に戻せます。

通常はgit merge --abortを使うのが推奨されます。

4.4 リベースの基本: git rebase

マージと同様に、あるブランチの変更を別のブランチに取り込む方法として、リベース (rebase)があります。しかし、マージとは異なり、リベースはコミット履歴の形を線形に保つことを目的としています。

例えば、feature/loginブランチで開発中に、mainブランチに新しいコミットが追加されたとします。このmainブランチの変更をfeature/loginブランチに取り込みたい場合、マージの代わりにリベースを選択できます。

マージ (git switch feature/loginしてからgit merge main) の場合、feature/loginブランチにマージコミットが作成され、履歴は分岐したままになります。

リベース (git switch feature/loginしてからgit rebase main) の場合、Gitは以下の手順を実行します。

  1. 現在のブランチ(feature/login)が分岐した時点から最新コミットまでの各コミットを一時的にどこかに保存します。
  2. 現在のブランチ(feature/loginというポインタ)を、リベース対象のブランチ(main)の最新コミットまで移動させます。
  3. 保存しておいたコミットを、新しい基点(mainの最新コミット)の上で一つずつ順番に再適用(apply)します。

リベースの概念図イメージ
イメージ図:mainブランチがC3を指している(C3はmainで追加)。feature/loginブランチがC2から分岐してC4を指している(C4はfeature/loginで追加)。git switch feature/loginしてからgit rebase mainを実行。まずfeature/loginで追加されたコミットC4が一時保存される。次にfeature/loginというポインタがmainが指すC3へ移動。最後に保存されたC4の変更内容が、C3の上に新しいコミットC4’として再適用される。結果としてfeature/loginはC4’を指し、履歴はC1 -> C2 -> C3 -> C4′ と線形になる。

実行例:

“`bash

feature/login ブランチにいると仮定

$ git switch feature/login

feature/login ブランチを main ブランチの最新状態の上にリベースする

$ git rebase main
“`

リベースが成功すると、feature/loginブランチのコミットはmainブランチの最新コミットの「上に」移動し、履歴が線形になります。元のコミット(例: C4)は新しいコミット(例: C4’)として再作成されるため、コミットのハッシュ値が変わります。

4.4.1 リベース中のコンフリクト解決

リベース中にも、コミットを再適用する際にコンフリクトが発生することがあります。リベース中のコンフリクト解決手順は、マージ中のコンフリクト解決手順と似ていますが、少し異なります。

コンフリクトが発生すると、Gitはリベースを一時停止し、コンフリクトファイルを教えてくれます。

bash
$ git rebase main
...
CONFLICT (content): Merge conflict in conflicted_file.txt
error: could not apply a1b2c3d... Add feature implementation
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted-files>", then run "git rebase --continue".

リベース中のコンフリクト解決手順:

  1. コンフリクトが発生したファイルを編集して解決する: マージの場合と同様に、コンフリクトマーカーを修正してファイルを編集します。
  2. 解決したファイルをステージングエリアに追加する: git add <解決したファイル>でファイルをステージします。
  3. リベースを続行する: コンフリクトを解決したすべてのファイルをステージしたら、git rebase --continueコマンドを実行します。Gitは次のコミットの再適用に進みます。もし、再適用したくないコミットがあれば、git rebase --skipを使います。

“`bash

コンフリクトが発生した conflicted_file.txt を手動で編集・解決

解決したファイルをステージング

$ git add conflicted_file.txt

リベースを続行

$ git rebase –continue
“`

すべてのコミットの再適用とコンフリクト解決が終わるまで、この手順を繰り返します。

4.4.2 リベースのキャンセル: git rebase --abort

リベース中に問題が発生したり、リベースを取りやめたくなったりした場合は、git rebase --abortコマンドでリベース開始前の状態に戻すことができます。

bash
$ git rebase --abort

4.4.3 マージとリベースの使い分け

マージとリベースはどちらもブランチの変更を統合する操作ですが、履歴に対する考え方が異なります。

  • マージ: ブランチが分岐した履歴をそのまま残します。マージコミットが作成され、いつどのブランチが統合されたかが履歴上で明確に分かります。共同開発で既にプッシュしたブランチ(公開ブランチ)に対して行う変更を取り込む場合に適しています。履歴が複雑になることがあります。
  • リベース: 履歴を線形に書き換えます。ブランチが分岐した事実が履歴上から消え、まるで最初から一本のラインで開発が進んだかのように見えます。ローカルでの開発中、まだ他の開発者と共有していないブランチ(非公開ブランチ)を整理する場合に適しています。履歴がシンプルで追跡しやすくなりますが、既に共有しているブランチに対してリベースを行うと、他の開発者の履歴と食い違いが発生し、問題を引き起こす可能性があります(「公開リポジトリでリベースしてはいけない」という注意点)。

一般的には、以下の使い分けが推奨されます。

  • maindevelopのような共有されている公開ブランチに、自身の開発ブランチを取り込む際はマージを使う。
  • 自身の非公開のフィーチャーブランチで作業中、maindevelopの最新の変更を取り込みたい場合はリベースを使う(ローカルでのコミット履歴を綺麗に保つため)。

Gitの運用方針やチームのルールによってどちらを選ぶかは異なりますが、それぞれの特性を理解しておくことが重要です。

5. リモートブランチとの連携:共同開発におけるブランチ

Gitは分散型バージョン管理システムであり、複数の開発者がリモートリポジトリを介して共同で開発を進めるのが一般的です。リモートリポジトリ上のブランチとローカルブランチを連携させる操作は、共同開発において非常に重要です。

5.1 リモート追跡ブランチとは

ローカルでgit branch -aを実行したときに見えたremotes/origin/...のようなブランチを「リモート追跡ブランチ」と呼びます。これらは、リモートリポジトリ上のブランチの最新の状態をローカルリポジトリ内に記録した参照です。

リモート追跡ブランチの概念図イメージ
イメージ図:リモートのoriginリポジトリにmainブランチがある。ローカルリポジトリにはmainブランチ(HEADが指している)と、リモートのorigin/mainというリモート追跡ブランチがある。origin/mainはリモートのmainの最新コミットを指している。ローカルのmainとorigin/mainが同じコミットを指している様子。

リモート追跡ブランチは、ローカルブランチとは異なり、直接チェックアウトして作業することはできません。これらはあくまで、リモートブランチの最新状態をローカルで確認するための「読み取り専用」の参照です。

5.2 リモートの情報を取得する: git fetch

リモートリポジトリから最新の情報(新しいブランチ、新しいコミットなど)をローカルリポジトリに取得するには、git fetchコマンドを使います。

bash
git fetch origin

originは通常、クローン元となったリモートリポジトリのデフォルト名です。

git fetchを実行すると:
1. リモートリポジトリに存在する新しいブランチやコミットの情報を取得します。
2. ローカルのリモート追跡ブランチ (remotes/origin/...) を更新します。

重要: git fetchはリモートの情報を取得してリモート追跡ブランチを更新するだけで、ローカルブランチやワーキングツリーには一切変更を加えません。 これにより、ローカルの作業を中断することなく、リモートの最新状態を確認できます。

実行例:

bash
$ git fetch origin
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/your/repo
* [new branch] feature/signup -> origin/feature/signup # 新しいリモートブランチが取得され、対応するリモート追跡ブランチが作成された
a1b2c3d..e4f5g6h main -> origin/main # リモートの main ブランチに新しいコミットがあり、origin/main が更新された

git branch -aを再度実行すると、新しいリモート追跡ブランチが表示されたり、既存のリモート追跡ブランチが最新のコミットを指すように更新されていることが確認できます。

5.3 リモートの変更を取り込む: git pull

リモートリポジトリの変更をローカルブランチに取り込むには、git pullコマンドを使います。git pullは、git fetchとそれに続くマージ(またはリベース)の2つの操作を組み合わせたコマンドです。

bash
git pull origin main

このコマンドは、「リモートのoriginリポジトリのmainブランチ(origin/mainリモート追跡ブランチに対応)の変更をフェッチし、現在のローカルブランチにマージ(デフォルト)する」という意味になります。

実行例:

“`bash

ローカルの main ブランチにいると仮定

$ git switch main
$ git pull origin main # リモートの origin/main をフェッチし、ローカルの main にマージ

フェッチの出力

From https://github.com/your/repo
* branch main -> FETCH_HEAD

マージの出力(Fast-forwardの場合)

Updating a1b2c3d..e4f5g6h
Fast-forward
path/to/new/file.txt | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 path/to/new/file.txt
“`

git pullのデフォルトの動作は、git fetch後にgit mergeを実行することです。しかし、--rebaseオプションを付けて実行することもできます。

bash
git pull --rebase origin main

これは、git fetch後にgit rebaseを実行します。ローカルでのコミット履歴を線形に保ちたい場合に有用ですが、公開ブランチに対してgit pull --rebaseを行うと、前述のリベースの注意点(履歴の書き換え)に該当するため、基本的には自分の開発ブランチでのみ使用するのが安全です。

どちらを使うべきか?

  • git pull (fetch + merge): リモートの履歴をローカルの履歴に統合する際に、マージコミットを作成して履歴の分岐を残したい場合。
  • git pull --rebase (fetch + rebase): リモートの履歴をローカルの履歴の基点として、ローカルのコミットをその上に再適用することで、履歴を線形に保ちたい場合(通常は非公開ブランチで)。

チームでどちらを使うか、あるいは使い分けのルールがあるかを確認しましょう。

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

ローカルブランチでの変更をリモートリポジトリに反映させるには、git pushコマンドを使います。

bash
git push origin main

このコマンドは、「ローカルのmainブランチのコミットを、リモートのoriginリポジトリのmainブランチに送信する」という意味になります。

重要: git pushは、リモートブランチがローカルブランチのコミットを含んでいない場合にのみ成功します(Fast-forwardできる場合)。もし、あなたを含む他の開発者がリモートブランチに新しいコミットをプッシュしていた場合、あなたのローカルブランチはリモートブランチよりも「遅れている」状態になります。この状態でgit pushを実行しようとすると、Gitはコンフリクトを避けるためにプッシュを拒否します。

実行例(プッシュ拒否):

bash
$ git push origin main
To https://github.com/your/repo.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'https://github.com/your/repo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

このエラーが出た場合は、hintメッセージにある通り、まずgit pull(またはgit fetchとマージ/リベース)でリモートの最新変更をローカルに取り込み、コンフリクトを解決してから再度git pushする必要があります。

5.4.1 新しいローカルブランチをリモートにプッシュ: git push -u origin <branchname>

ローカルで新しいブランチを作成し、それを初めてリモートにプッシュする場合、単にgit push origin <branchname>と実行することもできます。しかし、初回プッシュ時には通常-uまたは--set-upstreamオプションを付けてプッシュすることが推奨されます。

“`bash

ローカルで作成した feature/login ブランチを初めてリモートにプッシュ

$ git push -u origin feature/login
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for feature/login on GitHub by visiting:
remote: https://github.com/your/repo/pull/new/feature/login
remote:
To https://github.com/your/repo.git
* [new branch] feature/login -> feature/login
branch ‘feature/login’ set up to track ‘origin/feature/login’. # 追跡ブランチが設定された
“`

-uオプションを付けてプッシュすると、そのローカルブランチ(この例ではfeature/login)が、リモートの同名ブランチ(origin/feature/login)を追跡するブランチとして設定されます。

追跡ブランチが設定されると、以降はそのブランチにいるときにgit pullgit pushを実行する際に、リモート名やリモートブランチ名を省略できるようになります。

“`bash

feature/login ブランチにいるとき

$ git pull # -> git pull origin feature/login と同じ意味になる
$ git push # -> git push origin feature/login と同じ意味になる
“`

非常に便利なので、新しいブランチを初めてリモートにプッシュする際は-uオプションを付ける習慣をつけましょう。追跡ブランチの設定は、git branch --set-upstream-to=origin/<remote-branch> <local-branch>コマンドで後から設定することも可能です。

5.4.2 リモートブランチの削除をプッシュ: git push origin --delete <branchname>

ローカルでブランチを削除しても、リモートリポジトリ上のブランチはそのまま残ります。リモートブランチも削除したい場合は、git pushコマンドに--deleteオプションを付けて実行します。

“`bash

リモートの feature/old-feature ブランチを削除

$ git push origin –delete feature/old-feature
To https://github.com/your/repo.git
– [deleted] feature/old-feature
“`

このコマンドは、指定したリモートブランチを削除します。削除したブランチは基本的には復旧できないため、実行には注意が必要です。

6. よくあるブランチ戦略 (ワークフロー):チーム開発のために

ブランチの基本操作やリモート連携を理解したら、次はそれらをどのように組み合わせてチーム開発を進めるか、つまり「ブランチ戦略(ワークフロー)」について学びましょう。いくつかの代表的なブランチ戦略とその特徴を紹介します。

どの戦略を採用するかは、チームの規模、プロジェクトの種類、開発スタイルなどによって異なります。重要なのは、チーム全体で合意し、一貫したルールで運用することです。

6.1 GitHub Flow

GitHub Flowは、その名の通りGitHubでの開発と相性の良い、シンプルで人気のあるワークフローです。

  • 中心となるブランチ: main (またはmaster) ブランチのみ。このブランチは常にデプロイ可能(またはリリース可能)な安定版を保ちます。
  • 機能開発: 新しい機能やバグ修正を行う際は、必ずmainブランチから新しいフィーチャーブランチを作成します。ブランチ名は分かりやすい名前(例: feature/login, bugfix/footer-css)にします。
  • 開発: フィーチャーブランチ上で開発を進め、こまめにコミットします。必要に応じてmainブランチの最新変更をフィーチャーブランチに取り込みます(マージでもリベースでも可、チームによる)。
  • 共有とレビュー: 開発がある程度進んだら、フィーチャーブランチをリモートにプッシュし、プルリクエスト (Pull Request) を作成します(GitHubの場合)。プルリクエストは、その変更をmainに取り込んでほしいというリクエストであり、同時に他の開発者にコードレビューを依頼する場となります。
  • デプロイ: プルリクエストが承認され、自動テストなどもパスしたら、mainブランチにマージし、直ちに(あるいは自動的に)本番環境にデプロイします。 これがGitHub Flowの大きな特徴です。「デプロイはいつでもできる」という前提で、mainは常にデプロイ可能な状態であるべきとされます。
  • 完了: デプロイが完了したら、フィーチャーブランチは削除します。

GitHub Flowのメリット:
* シンプルで理解しやすい。
* デプロイサイクルが速い(継続的デリバリーと相性が良い)。
* プルリクエストを中心とした活発なコードレビュー文化を促進しやすい。

GitHub Flowのデメリット:
* リリースバージョンを明確に管理する必要があるプロジェクト(例:パッケージソフトウェア)には向かない場合がある。
* 常にデプロイ可能な状態を維持するための規律が必要。

6.2 Git Flow

Git Flowは、Vincent Driessenによって提唱された、GitHub Flowよりも規律が厳格で、リリース管理を重視したワークフローです。複数の主要ブランチとサポートブランチを使い分けます。

  • 主要ブランチ (Main Branches):

    • main (またはmaster): 常にリリース可能な本番コードを格納します。このブランチへのコミットは、タグ付けされてリリースバージョンを示します。
    • develop: 次にリリースされる予定の開発中のコードを格納します。フィーチャーブランチは通常このブランチから分岐し、このブランチにマージされます。
  • サポートブランチ (Supporting Branches):

    • feature/<feature-name>: 新しい機能を開発するためのブランチ。通常developから分岐し、開発完了後developにマージされます。
    • release/<version-name>: 次期リリース候補バージョンの準備のためのブランチ。developから分岐し、リリースに向けた最終調整(バグ修正、ドキュメント更新など)を行います。準備ができたらmaindevelopの両方にマージされ、タグ付けされます。
    • hotfix/<bugfix-name>: 本番環境で発見された緊急性の高いバグを修正するためのブランチ。mainから分岐し、修正完了後maindevelopの両方にマージされ、タグ付けされます。

Git Flowの基本的な流れ:

  1. リポジトリ作成時、maindevelopブランチを作成。
  2. 新機能開発はdevelopからfeatureブランチを作成し、そこで作業。
  3. feature開発完了後、developにマージ。
  4. 次のリリース準備段階でdevelopからreleaseブランチを作成。
  5. releaseブランチでバグ修正など最終調整。
  6. リリース準備ができたら、releasemaindevelopにマージし、mainにタグを打つ。
  7. 本番バグ修正はmainからhotfixブランチを作成。
  8. hotfix修正完了後、maindevelopにマージし、mainにタグを打つ。

Git Flowのメリット:
* リリースバージョン管理が明確で体系的。
* 安定版 (main) と開発版 (develop) が常に分離されている。
* 大規模なプロジェクトや、リリースサイクルが比較的長いプロジェクトに適している。

Git Flowのデメリット:
* ワークフローが複雑で、習得と運用にコストがかかる。
* ブランチが多くなりがちで、管理が煩雑になることがある。
* 継続的デリバリーや迅速なデプロイには不向き。

6.3 その他

他にも、GitLab Flow(GitHub FlowにCI/CDや環境別ブランチの考えを取り入れたもの)など、様々なブランチ戦略が存在します。

どの戦略を採用するにしても、重要なのはチームメンバー全員がその戦略を理解し、共通のルールに基づいてブランチ操作を行うことです。不明確なルールはコンフリクトや混乱の原因となります。

7. ブランチ活用のヒントと注意点

Gitブランチをより効果的に活用するためのヒントと、注意すべき点をまとめます。

  • ブランチ名の命名規則: チームで一貫性のあるブランチ名の命名規則を定めましょう。例えば、feature/login, bugfix/footer-css, hotfix/v1.0.1, release/v1.1, chore/update-dependenciesのように、ブランチの種類(feature, bugfix, hotfix, release, choreなど)と内容を組み合わせるのが一般的です。分かりやすい名前は、ブランチの目的をすぐに把握するのに役立ちます。
  • 小さく頻繁にコミット、ブランチを切る: 一つのブランチに大量の変更を詰め込むと、マージ時のコンフリクトが大きくなり、解決が困難になります。一つの機能やバグ修正ごとにブランチを切り、小さく意味のある単位でこまめにコミットしましょう。ブランチを短命に保つことで、コンフリクトのリスクを減らせます。
  • 不要になったブランチはこまめに削除: 開発が完了し、他のブランチにマージされたフィーチャーブランチなどは、積極的に削除しましょう。ローカルにもリモートにも不要なブランチが大量に残っていると、ブランチリストが見づらくなり、誤操作の原因にもなります。
  • コンフリクトを避けるための習慣: 定期的にメインのブランチ(maindevelop)の最新変更を自分の開発ブランチに取り込みましょう(git pullまたはgit fetch & git rebase/merge)。こまめに最新を取り込むことで、後で大きなコンフリクトに直面する可能性を減らせます。
  • 公開ブランチでのリベースは避ける: 繰り返しになりますが、maindevelopのようにチームメンバーが共同で使う公開ブランチに対して、自身のローカルブランチをリベースしてリモートに強制プッシュするような操作は、他の開発者の履歴を破壊する可能性があるため、絶対に行わないでください。
  • リモートブランチの管理: 定期的にgit fetch --prune (git fetch -p) を実行して、リモートから既に削除されたブランチに対応するローカルのリモート追跡ブランチを削除し、ローカルの状態を整理しましょう。

8. トラブルシューティング:よくある問題とその解決策

Gitブランチを扱っていると、いくつか典型的な問題に遭遇することがあります。ここでは、よくある問題とその解決策を紹介します。

8.1 ブランチ切り替え時のエラー (未コミットの変更)

bash
$ git switch main
error: Your local changes to the following files would be overwritten by checkout:
path/to/modified_file.txt
Please commit your changes or stash them before you switch branches.

原因: 現在のブランチで、コミットまたはステージされていない変更がある状態で、その変更が切り替え先のブランチに存在しない、あるいは切り替え先のブランチの状態と衝突する場合に発生します。Gitは変更が失われるのを防ぐために切り替えをブロックします。

解決策:
* 変更をコミットする: 作業中の変更をコミットして、現在のブランチの履歴に保存します。
* 変更をスタッシュする: git stashコマンドで、一時的に変更を退避させます。後で元のブランチに戻った際にgit stash popで適用できます。
* 変更を破棄する: もしその変更が不要であれば、git restore .またはgit checkout -- .(全ての未ステージ・未コミットの変更を破棄)、git clean -fdx( untracked ファイルやディレクトリも破棄)などでローカルの変更を破棄します。ただし、これは変更が完全に失われるため、慎重に行ってください。

8.2 コンフリクト解決時の失敗

マージやリベース中にコンフリクトが発生し、手動で解決したつもりが、再度git commitgit rebase --continueを実行した際にエラーになったり、意図しない結果になったりする。

原因: コンフリクトマーカー(<<<<<<<, =======, >>>>>>>)が完全に削除されていない、必要な変更が漏れている、あるいは解決したファイルをgit addし忘れている、など。

解決策:
1. git statusで状況を確認する: どのファイルがまだコンフリクト状態なのか、Unmerged paths のリストで確認します。
2. コンフリクトファイルを再度丁寧に編集する: 残っているコンフリクトマーカーがないか、必要な変更が適切に統合されているか確認します。
3. 解決したファイルを改めてgit addする: 解決したファイルは必ずステージングエリアに追加する必要があります。
4. 操作を続行する: マージ中ならgit commit、リベース中ならgit rebase --continueを実行します。

解決が困難な場合は、一旦マージ/リベースを中断する(git merge --abort / git rebase --abort)ことも検討します。

8.3 誤ったマージ/リベースの取り消し

間違ったブランチをマージ/リベースしてしまった、あるいはマージ/リベースの結果が意図と異なったため、操作を取り消したい。

原因: マージ/リベース対象のブランチを間違えた、コンフリクト解決を誤った、など。

解決策:
* マージ/リベース直後で、まだコミットしていない場合:
* マージ中の場合: git merge --abort
* リベース中の場合: git rebase --abort
* マージコミットが作成されてしまった場合:
* 直前のマージコミットを取り消す場合: git reset --hard HEAD~1。これは危険なコマンドで、ローカルのワーキングツリーの変更もすべて失われます。代わりに、マージ前のコミットのハッシュ値を調べてgit reset --hard <commit-hash>を実行するのがより安全です。
* マージを取り消すが、取り消した内容を新たなコミットとして記録する場合: git revert -m 1 HEAD。これは、マージコミットによって導入された変更を打ち消す新しいコミットを作成します。履歴は残りますが、より安全な方法です。-m 1は、親が複数あるマージコミットの場合に、どの親(ここでは現在のブランチ側)からの変更を維持して他方(マージ対象ブランチ側)の変更を打ち消すかを指定するためのオプションです。
* リベースが完了してしまった場合: リベースは履歴を書き換える操作なので、取り消しはより慎重に行う必要があります。
* git reflogコマンドで過去の操作履歴を確認し、リベース前のブランチのHEADが指していたコミットのハッシュ値を見つけます。
* git reset --hard <commit-hash>で、リベース前の状態に戻ります。ただし、これも履歴を書き換える操作であり、特に公開リポジトリにプッシュ済みのブランチに対して行ったリベースを取り消す際には、他の開発者に影響が出る可能性があります。 この場合は、履歴の書き換えを伴わない方法(例: git revertを駆使するなど)を検討する必要がありますが、複雑になるため、誤ったリベースをしないのが一番です。

履歴を書き換えるgit reset --hardは強力なコマンドですが、ローカルでの失敗を取り戻すのに役立ちます。ただし、そのブランチを既にリモートにプッシュしている場合は、他の開発者に影響が出ないか十分に考慮する必要があります。

8.4 リモートへのプッシュ失敗 (fast-forward not possible)

bash
$ git push origin main
To https://github.com/your/repo.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'https://github.com/your/repo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally.
...

原因: あなたがプッシュしようとしているリモートブランチに、まだあなたがローカルに取り込んでいない新しいコミットが追加されています。あなたのローカルブランチはリモートブランチに対して「遅れている」状態です。

解決策:
1. リモートの最新変更をローカルに取り込む: git pull origin main(または他の該当するブランチ名)を実行します。これにより、リモートの変更があなたのローカルブランチにマージ(またはリベース)されます。
2. コンフリクトを解決する: git pullによってコンフリクトが発生した場合は、それを解決し、マージ/リベースを完了させます。
3. 再度プッシュする: リモートの変更をローカルに取り込み、必要に応じてコンフリクトを解決したら、再びgit push origin mainを実行します。今度はFast-forwardが可能になっているか、マージコミットをプッシュすることになるため、通常は成功します。

このエラーは共同開発で頻繁に発生します。慌てずに、まずgit pullでリモートの変更を取り込むという手順を覚えましょう。

9. まとめ:Gitブランチマスターへの道

この記事では、Gitブランチの基本概念から、作成、切り替え、削除といった基本的な操作、さらにマージやリベースによる変更の統合、リモートブランチとの連携、そして代表的なブランチ戦略まで、幅広く解説しました。

Gitブランチは、並行開発、安全な実験、履歴の整理など、開発効率とプロジェクト管理を大きく改善するための非常に強力なツールです。その鍵は、ブランチが「コミットへの単なるポインタである」というシンプルな概念を理解し、各種コマンドがそのポインタをどのように操作しているかをイメージできるようになることです。

最初は少し難しく感じるかもしれませんが、実際に手を動かし、コマンドを繰り返し実行することで、徐々に慣れていきます。

Gitブランチを使いこなすためのステップ:

  1. 基本コマンドをマスターする: git branch, git switch (またはcheckout), git merge, git rebase, git push, git pullといったコマンドとそのオプションの意味を理解し、スムーズに使えるように練習しましょう。
  2. git statusgit logを頻繁に使う: 現在の状態(どのブランチにいるか、未コミットの変更があるかなど)を把握するためにgit statusを使い、履歴(コミットグラフ)を理解するためにgit log(特にgit log --graph --oneline --allのようなオプションを付けて)を頻繁に確認しましょう。
  3. マージとリベースの違いを理解する: どちらも変更を統合する操作ですが、履歴に対する影響が異なります。それぞれの特性と、公開/非公開ブランチでの使い分けを意識しましょう。
  4. git stashを活用する: ブランチ切り替え時の変更退避など、ちょっとした状況で非常に役立つコマンドです。
  5. チームのブランチ戦略を理解し、従う: 共同開発においては、チーム全体で合意されたブランチ運用ルールに従うことが何よりも重要です。
  6. 失敗を恐れず試す: ローカルリポジトリであれば、多くの場合git refloggit resetで過去の状態に戻ることができます(ただし注意して)。小さなプロジェクトや個人練習用のリポジトリで積極的にブランチ操作を試してみましょう。

Gitブランチをマスターすることは、より高度なGitの機能を使いこなすための基盤となります。タグ付け (git tag) による特定のコミットへの参照、履歴を修正するインタラクティブなリベース (git rebase -i)、特定のコミットの変更だけを取り込むチェリーピック (git cherry-pick) など、さらに便利な機能はたくさんありますが、それらはまずブランチの概念をしっかりと理解した上で学ぶと効率的です。

この記事が、あなたのGitブランチ理解の一助となり、より快適で効率的な開発ライフにつながることを願っています。

Happy Git-ting!

コメントする

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

上部へスクロール