GitHub - ブランチとマージ
概要
GitHubにおけるブランチ (branch) は、本線となるコードベースに影響を与えることなく、新機能の開発やバグ修正を独立した環境で行うための仕組みである。
ブランチを活用することで、複数の開発者が同時に異なる作業を進めることができ、作業が完了した時点でマージ (merge) によって変更を統合する。
ブランチの基本
ブランチとは
ブランチとは、Gitリポジトリにおける複数の開発ラインのことである。
メインの開発ラインから分岐して作業することで、本線のコードに影響を与えずに変更を提案・実装できる。
- 本線への影響なし
- ブランチ上で行った変更は、マージするまで他のブランチには反映されない。
- 並行開発のサポート
- 複数の開発者がそれぞれ異なるブランチで同時に作業を進めることができる。
- 変更の隔離
- 新機能開発、バグ修正、実験的な変更を安全に独立して行うことができる。
デフォルトブランチ
デフォルトブランチは、リポジトリ作成時に自動生成されるブランチである。
git clone コマンドでリポジトリをクローンした時に、自動的にチェックアウトされる。
- GitHubの新規リポジトリでは、main がデフォルトブランチとして設定される。
- 従来は master という名前が一般的であったが、現在は main が標準となっている。
- デフォルトブランチは、プルリクエストのベースブランチとして使用されることが多い。
ブランチの命名規則
ブランチ名には、作業内容が一目でわかる記述的な名前を付けることが推奨される。
下表に、一般的に使用されるプリフィックスを示す。
| プレフィックス | 説明 | 例 |
|---|---|---|
feature/ |
新機能の追加に使用する。 | feature/user-authentication |
bugfix/ |
バグの修正に使用する。 | bugfix/login-error |
hotfix/ |
本番環境における緊急の修正に使用する。 | hotfix/security-patch |
release/ |
リリース準備作業に使用する。 | release/v2.0.0 |
プリフィックスの後には、変更内容を端的に表す名前を付ける。
例えば、increase-test-timeout のように、ハイフン区切りで記述することが一般的である。
ブランチ操作
ブランチの作成
ブランチは、Web UI または コマンドラインから作成できる。
Web UIでの作成
- リポジトリの[Code]タブを開く。
- ブランチドロップダウン (現在のブランチ名が表示されているボタン) を選択する。
- テキストボックスに新規ブランチ名を入力する。
- 表示される[Create branch]を選択する。
コマンドラインでの作成
# ブランチを作成するのみ (チェックアウトしない) git branch <ブランチ名> # ブランチを作成して同時にチェックアウトする (旧方式) git checkout -b <ブランチ名> # ブランチを作成して同時にチェックアウトする (Git 2.23 以降推奨) git switch -c <ブランチ名>
ブランチの切り替え
既存のブランチに切り替えるには、以下に示すコマンドを実行する。
# 旧方式 git checkout <ブランチ名> # 新方式 (Git 2.23 以降推奨) git switch <ブランチ名>
git switch コマンドはGit 2.23で追加されたものであり、ブランチ操作に特化したコマンドである。
ブランチの削除
マージ済みのブランチは、不要になった時点で削除することが推奨される。
Web UIでの削除
- リポジトリの[Branches]ページを開く。
- 削除したいブランチの行にあるゴミ箱アイコンを選択する。
コマンドラインでの削除
# ローカルブランチをマージ済み確認後に削除する (安全削除) git branch -d <ブランチ名> # ローカルブランチを強制削除する (未マージでも削除) git branch -D <ブランチ名> # リモートブランチを削除する git push origin --delete <ブランチ名>
-d オプションは、ブランチが現在のブランチにマージ済みである場合のみ削除できる安全なオプションである。
未マージのブランチを削除する場合は -D オプションを使用するが、変更が失われる可能性があるため注意が必要である。
ブランチの比較
2つのブランチ間の差分を確認するには、Web UI または コマンドを実行する。
Web UIでの比較
GitHubの[Compare]ページでは、2つのブランチを選択して差分を視覚的に確認できる。
- URL形式
- https://github.com/<ユーザー名>/<リポジトリ名>/compare/<ブランチ1>...<ブランチ2>
コマンドでの比較
# 2つのブランチ間のファイル差分を確認する git diff <ブランチ1>..<ブランチ2> # 2つのブランチ間のコミット差分を確認する git log <ブランチ1>..<ブランチ2>
ブランチ保護ルール
ブランチ保護の設定
ブランチ保護ルールを設定することにより、重要なブランチへの不用意な変更やプッシュを防ぐことができる。
設定手順は以下の通りである。
- リポジトリの[Settings]タブを開く。
- 左メニューの[Branches]を選択する。
- [Branch protection rules]セクションの[Add rule]を選択する。
- [Branch name pattern]に保護するブランチ名またはパターンを入力する。
- 必要な保護ルールを選択して、[Save changes]を選択する。
保護ルールの設定項目
ブランチ保護ルールで設定できる主な項目を以下に示す。
- Require a pull request before merging (PR必須)
- 直接プッシュを禁止して、必ずプルリクエストを経由してマージするよう強制する。
- Require approvals (承認レビュー必須)
- マージ前に指定した数の承認レビューが必要となる。
- Require review from Code Owners (CODEOWNERSレビュー必須)
- CODEOWNERSファイルで指定されたレビュアーの承認が必要となる。
- Require status checks to pass before merging (ステータスチェック必須)
- CI/CDのテスト等、指定したステータスチェックが全て通過している場合のみマージ可能となる。
- Require signed commits (署名付きコミット)
- GPG等で署名されたコミットのみを受け入れる。
- Require linear history (線形履歴)
- マージコミットの作成を禁止して、スカッシュまたはリベースによるマージのみを許可する。
- Include administrators (管理者含む制限)
- リポジトリの管理者にも保護ルールを適用する。
ルールセット (Rulesets)
ルールセットは、ブランチ保護ルールの後継となる新機能である。
従来のブランチ保護ルールと比較した主な違いは以下の通りである。
- 複数のブランチおよびタグに対して一括で適用できる。
- より柔軟なターゲット指定が可能であり、ブランチパターンを複数設定できる。
- ルールセットの有効/無効を切り替えられるため、一時的な変更作業がしやすい。
- ブランチとタグの両方にルールを適用できる。
- 組織レベルでルールセットを管理できる。(GitHub Enterpriseで利用可能)
マージ
GitHubでは、プルリクエストをマージする際に3種類の方法を選択できる。
マージコミット (Create a merge commit)
全てのコミット履歴を保持したまま、マージコミットを生成してベースブランチに統合する方法である。
Gitコマンドの git merge --no-ff 相当の動作となる。
- 全てのコミットがそのまま履歴に残るため、変更の経緯を詳細に追跡できる。
- マージコミットが生成されるため、ブランチの統合履歴が明確になる。
- プルリクエストに含まれる全ての作業コミットが保持される。
スカッシュマージ (Squash and merge)
プルリクエスト内の複数のコミットを1つのコミットに圧縮してからベースブランチに統合する方法である。
- プルリクエストに含まれるコミットが1つにまとめられるため、ベースブランチの履歴がすっきりする。
- プルリクエストのコミットが1件のみの場合は、そのコミットメッセージが使用される。
- プルリクエストのコミットが複数の場合は、プルリクエストのタイトルがコミットメッセージに使用される。
- マージ後に同じブランチを再利用する場合は、履歴の不整合が生じる可能性があるため注意が必要である。
リベースマージ (Rebase and merge)
プルリクエストの各コミットをベースブランチの先端に積み直す方法である。
- マージコミットが生成されないため、線形な履歴が維持される。
- 各コミットには新しいSHAが付与される。
- コンフリクトが発生している場合は、リベースマージは使用できない。
マージ方法の比較
| マージ方法 | マージコミット | コミット履歴 | 線形履歴 | 用途 |
|---|---|---|---|---|
| マージコミット | 生成される | 全て保持 | 非線形 | 詳細な変更履歴を残したい場合 |
| スカッシュマージ | 生成されない | 1つに圧縮 | 線形 | 履歴をシンプルに保ちたい場合 |
| リベースマージ | 生成されない | 全て保持 | 線形 | 線形履歴と詳細両方を維持したい場合 |
マージ方法の設定
リポジトリで使用可能なマージ方法を制限または許可するには、以下に示す手順で設定する。
- リポジトリの[Settings]タブを開く。
- 左メニューの[General]を選択する。
- [Pull Requests]セクションの[Merge button]項目で、許可するマージ方法のチェックボックスを設定する。
- Allow merge commits
- マージコミットを許可する。
- Allow squash merging
- スカッシュマージを許可する。
- Allow rebase merging
- リベースマージを許可する。
コンフリクトの解決
コンフリクトとは
コンフリクト (競合) とは、同一ファイルの同一箇所に対して、マージしようとしている2つのブランチがそれぞれ異なる変更を行っている場合に発生するものである。
コンフリクトが発生すると、Gitは自動的にマージを完了できないため、手動での解決が必要となる。
コンフリクトが発生したファイルには、以下に示すようなマーカーが挿入される。
<<<<<<< HEAD
現在のブランチの変更内容
=======
マージしようとしているブランチの変更内容
>>>>>>> branch-a
Web UIでの解決
簡単なコンフリクトは、GitHubのWeb UIで解決できる。
- プルリクエストページを開く。
- [Resolve conflicts]ボタンを押下する。
- コンフリクトが発生しているファイルが表示される。
- コンフリクトマーカー (
<<<<<<<、=======、>>>>>>>) を参考に、残すべき変更を選択して編集する。 - 全てのコンフリクトを解決した後、[Mark as resolved]を選択する。
- [Commit merge]を選択してコンフリクト解決をコミットする。
複雑なコンフリクトはWeb UIでは解決できないため、コマンドでの作業が必要となる。
コマンドでの解決
# ベースブランチの最新変更をローカルに取得する git fetch origin # ベースブランチに切り替える git switch main # ベースブランチを最新状態にする git pull origin main # 作業ブランチに切り替える git switch feature/my-feature # ベースブランチの変更を作業ブランチにマージする git merge main # コンフリクトが発生したファイルを確認する git status # コンフリクトが発生したファイルをエディタで編集して解決する # (コンフリクトマーカーを削除し、正しい内容に修正する) # 解決したファイルをステージする git add <ファイル名> # マージを完了する git commit # 解決した変更をリモートにプッシュする git push origin feature/my-feature
GitHub Flow
GitHub Flow は、GitHubが推奨する軽量でスケーラブルなブランチ戦略である。
デフォルトブランチ (main) は常にデプロイ可能な状態を維持することが原則であり、全ての新しい作業はブランチを切って行う。
ステップ1 : ブランチを作成する
作業内容を表す記述的な名前でブランチを作成する。
git switch -c feature/add-login-feature
ブランチ名は、他の開発者が作業内容を一目で把握できるような名前にする。
ステップ2 : 変更を加える
ブランチ上でファイルを編集して、コミットを積み重ねる。
# 変更したファイルをステージする git add <ファイル名> # コミットする git commit -m "<コミットメッセージ>" # リモートにプッシュする git push origin feature/add-login-feature
作業の進捗を定期的にリモートブランチにプッシュすることにより、バックアップを確保するとともに他の開発者と進捗を共有できる。
ステップ3 : プルリクエストを作成する
作業が完了したら、ベースブランチ (main) に向けてプルリクエストを作成する。
- プルリクエストのタイトルと説明に変更内容と目的を明記する。
- レビュアーを指定してコードレビューを依頼する。
- 関連するイシュー番号があれば本文に記載する。
ステップ4 : レビューコメントに対応する
レビュアーからのフィードバックをもとに修正を行い、コミットしてプッシュする。
# 修正内容をコミットする git add <ファイル名> git commit -m "<レビュー対応: コメントへの修正内容>" # リモートブランチにプッシュする git push origin feature/add-login-feature
プッシュすると、プルリクエストに自動的に新しいコミットが追加される。
ステップ5 : マージする
全てのレビューが承認され、ステータスチェックが通過したら、プルリクエストをマージする。
- チームのポリシーに従ったマージ方法 (マージコミット、スカッシュ、リベース) を選択する。
- マージ後、main ブランチは自動的に最新の変更を含む状態になる。
ステップ6 : ブランチを削除する
マージが完了したブランチは削除する。
プルリクエストページの[Delete branch]ボタンをクリックする または コマンドを実行して削除する。
# リモートブランチを削除する git push origin --delete feature/add-login-feature # ローカルブランチを削除する git branch -d feature/add-login-feature
その他の設定
ブランチの自動削除
プルリクエストのマージ後に、ヘッドブランチを自動的に削除するよう設定できる。
設定手順を以下に示す。
- リポジトリの[Settings]タブを開く。
- 左メニューの[General]を選択する。
- [Pull Requests]セクションの[Automatically delete head branches]を有効にする。
この設定を有効にすることにより、マージ済みブランチが自動的にクリーンアップされ、リポジトリの管理が容易になる。
デフォルトブランチの変更
リポジトリのデフォルトブランチは、[Settings]から変更できる。
設定手順を以下に示す。
- リポジトリの[Settings]タブを開く。
- 左メニューの[Branches]を選択する。
- [Default branch]セクションの鉛筆アイコンを選択する。
- ドロップダウンから新しいデフォルトブランチを選択する。
- [Update]を選択して変更を確定する。
デフォルトブランチを変更しても、既存のローカルリポジトリは自動的に更新されないことに注意する。
ローカルリポジトリで新しいデフォルトブランチを使用するには、以下に示すコマンドを実行する必要がある。
# リモートの変更を取得する git fetch origin # 新しいデフォルトブランチに切り替える git switch main # ローカルブランチのアップストリームを更新する git branch --set-upstream-to=origin/main main