Skip to content

Commit

Permalink
マージ戦略パートに別ページに持っていったrebase/squashのイメージを持ってくる
Browse files Browse the repository at this point in the history
  • Loading branch information
ma91n committed Aug 10, 2024
1 parent 0b5e871 commit c54bc7b
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 62 deletions.
94 changes: 41 additions & 53 deletions documents/forGitBranch/Gitブランチフロー規約.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ meta:

# はじめに

本ドキュメントはGitブランチ管理の標準的な運用ルールをまとめている。以下の想定で作成されているため留意いただきたい
本ドキュメントはGitブランチ管理の標準的な運用ルールをまとめている。以下の想定で作成されているため留意すること

- GitHub または GitLab の利用
- 開発プロダクトには、ライブラリ(他のアプリケーションやライブラリからimportして利用されるもの)か、アプリケーション(CLIツール、サーバアプリケーションなど)という区別があるが、アプリケーション開発を想定
- GitHub / GitLab の利用
- トランクベース開発(フィーチャーフラグ)を **採用しない**

導入に際して行う、GitやGitHub/GitLabの環境設定は、[推奨設定](recommended_settings.md)ページに記載している。
- ライブラリではなく、アプリケーション(CLIツール、サーバアプリケーションなど)開発で利用する

# ブランチ戦略の選定

Expand Down Expand Up @@ -89,58 +87,52 @@ featureブランチのマージ後、マイナーバージョン(あるいは

# マージ戦略の選定

マージ戦略とは、複数のブランチ間でコードの変更を統合する際に使用される方法やポリシーを指し、以下の事項に影響を与える。

- プロジェクトのコミット履歴の管理
- コンフリクトの解決
- 開発プロセスの円滑な進行
- 最終的なソフトウェア品質

そのため、Gitの使用を開始する前に、適切な戦略を策定することが重要である。

ブランチの管理戦略に関わらず、大半のケースにおいて、メインの開発ブランチとそこから作成される個々の機能ブランチが存在する。
マージ戦略とは、複数のブランチ間で生じた変更の取り込み方針を指す。

この章では次の2ケースについて、とりうる選択肢と推奨方法を説明する
具体的には「マージコミット」「リベース」「スカッシュマージ」を次の2ケースで選択する

1. 開発中の機能ブランチに対してメインの開発ブランチの変更をどう取り込むか
2. メインの開発ブランチに開発およびレビューが完了した機能ブランチをどう取り込むか

## 1. 機能ブランチに開発ブランチの変更を取り込む
次の事項に影響を与えるため、Gitの使用を開始する前に決めることが重要である。

複数人により同時並行的に開発が進む場合、特定の機能ブランチで開発を進めている最中に、メインの開発ブランチがアップデートされることはよく起こる。
- プロジェクトのコミット履歴の管理
- コンフリクトの解決
- 開発プロセスの円滑な進行
- 最終的なソフトウェア品質

このような状況において、開発者は自らの機能ブランチに対して、最新の開発ブランチの変更を定期的に取り込むことが望まれる。
## 1. 機能ブランチに開発ブランチの変更を取り込む

![開発ブランチと機能ブランチ](img/merge_strategy_develop_to_feature.drawio.png)

[開発ブランチの変更を機能ブランチに取り込む方法](merge_develop_to_feature.md)に記載している通り、次の2つの方法があり、2の「リベース」による方法を推奨する
機能ブランチで開発を進めている最中に、別の開発者により開発ブランチがアップデートされることはよくあることである。コンフリクトしている場合は解消が必須であるし、品質保証の観点でも最新の開発ブランチの変更を機能ブランチに取り込んだ上で、テストなどの検証作業を行う必要がある

1. マージ
2. リベース(★推奨)
[開発ブランチの変更を機能ブランチに取り込む方法](merge_develop_to_feature.md)に記載した2つの方法のうち、「リベース」による方法を推奨する。

理由は次の通り。
![リベース](img/merge_strategy_develop_to_feature_rebase.drawio.png)

- 前提として、別の開発者が行った開発ブランチの変更は、適時機能ブランチに取り込んだテスト実行や動作検証を行うべきである
- 開発ブランチの変更の取り込みをマージで行うと、そのたびにマージコミットが作成され履歴が複雑になるため、レビューアの負荷軽減を目的とする
- リベースによるコンフリクトリスクについては、開発ブランチを取り込む段階でマージ・リベース問わず解消が必要となる
理由は次の通り。

開発者は `git pull` 時の挙動をリベースにするよう設定する(`git config pull.rebase true`)。
- マージを選択すると、そのたびにマージコミットが作成され履歴が複雑になり、レビューアの負荷が高まるため
- スカッシュマージはこのケースでは選択できないため
- コンフリクトリスクは、マージ・リベース問わず発生するもので、リベースの選択による悪影響は存在しないため

マージによる変更の取り込みが既存のブランチを変更しないのに対し、リベースは全く新しい(元のコミットIDとは別のコミットIDで)コミットを作成するため、次の3点に注意すること
マージによる変更の取り込みが既存のブランチを変更しないのに対し、リベースは全く新しい(元のコミットIDとは別のコミットIDで)コミットを作成するため、次の4点に注意すること

1. 複数人に影響を及ぼすpublicなブランチでは、決してリベースを使用しないこと
1. 開発者は `git pull` 時の挙動をリベースにするよう設定する(`git config pull.rebase true`)。
2. 複数人に影響を及ぼすpublicなブランチでは、決してリベースを使用しないこと
- 永続ブランチである `develop``main` ブランチが該当する
- リベースにより新しいコミットが作成されるため、他の人が作業しているブランチと整合性が取れなくなり、大きな混乱を招く可能性がある。永続ブランチは **強制プッシュできないよう保護しておく**
2. リモートにプッシュ済のブランチでリベースを行った場合、強制プッシュ(Force Push)が必要になること
3. リモートにプッシュ済のブランチでリベースを行った場合、強制プッシュ(Force Push)が必要になること
- 開発者はプッシュ時に `--force-with-lease --force-if-includes` フラグを渡すことで、意図せずリモートブランチの変更を上書きしないようにする
- `--force-with-lease`: ローカルのリモート追跡ブランチの ref とリモートの ref を比較し、ローカルの状態が最新でない場合(要はプッシュ先のリモートブランチに変更が入ったが、ローカルで `git fetch` していない場合)は、プッシュに失敗する。逆にいうと、プッシュ前に `git fetch` を実行済みの場合は、リモートの変更を上書きする形で強制プッシュができてしまうため、これを防ぐには `--force-if-includes` フラグを併用する
- `--force-if-includes`: リモート追跡ブランチの変更がローカルに全て取り込まれていない場合は、プッシュに失敗する。これにより意図せず他の人のコミットを上書きすることを防ぎつつ、必要な変更を強制的にプッシュすることができる
3. メインの開発ブランチの変更を頻繁に取り込む場合、同じようなコンフリクトの解消を何度も求められる可能性があること
4. メインの開発ブランチの変更を頻繁に取り込む場合、同じようなコンフリクトの解消を何度も求められる可能性があること
- GitのRerereを有効化する(`git config rerere.enabled true`)ことでコンフリクトの解消を記録し、繰り返しの操作を自動化できる

::: tip

強制プッシュすることにより、レビューコメントが消えてしまわないかという懸念を聞くことがある。2024年7月に実施した下表の調査結果において強制プッシュ運用による支障は無いと言える
強制プッシュすることにより、レビューコメントが消えてしまわないかという懸念を聞くことがある。2024年7月に実施した調査では強制プッシュ運用による支障は無いという結果だった

- 「a.履歴保持」: 強制プッシュを行い、GitHub投稿したレビューコメントが履歴として何かしらのページで取得できるかどうか。GitHubではConversationタブで確認
- 「b.行単位の紐づけ(該当行の変更なし)」: レビューコメントが付けられた行とは別の変更を行い、強制プッシュしたときにレビューコメントの紐づけが残るかどうか。GitHubではFile chagedタブで確認
Expand All @@ -155,24 +147,16 @@ featureブランチのマージ後、マイナーバージョン(あるいは

## 2. 開発ブランチに機能ブランチの変更を取り込む

プルリクエストを経由して、開発が完了した機能ブランチをメインの開発ブランチに取り込むためには、GitHub(GitLab)上でプルリクエスト(マージリクエスト)を経由する運用を前提とする
プルリクエスト(以下、PR)を経由して、開発が完了した機能ブランチをメインの開発ブランチに取り込むためには、GitHub(GitLab)上でPRを経由する運用を行うこと

[開発ブランチに機能ブランチの変更を取り込む方法](merge_feature_to_develop.md)に記載している通り、次の3パターンの方法があり、3の「Squash and merge」による方法を推奨する。
[開発ブランチに機能ブランチの変更を取り込む方法](merge_feature_to_develop.md)に記載した3パターンのうち、「スカッシュマージ」による方法を推奨する。

1. Create a merge commit
2. Rebase and merge
3. Squash and merge(★推奨)
![Squash and Merge](img/merge_strategy_feature_to_develop_squash_and_merge.drawio.png)

理由は次の通り。

- メインの開発ブランチの履歴をクリーンに保てるため
- 機能ブランチのPRが単一のコミットメッセージで表現できるほどシンプルで明確な単位に保ちたいため

なお、プロテクトブランチの設定にて、メインの開発ブランチに対し「require linear history」を選択することを推奨する。
本設定を行うと、開発ブランチに対して「Create a merge commit」が選択できないよう制御することができる。

また、意図しない方法でのマージを避けるためにブランチごとにマージ戦略を設定しておき、想定外のマージ戦略が選択された時に警告色を表示するとサードパーティ製のChrome拡張も存在する。こちらは必要に応じて導入することが望ましい。
https://zenn.dev/daku10/articles/github-merge-guardian
- 開発ブランチの履歴をクリーンに保てるため
- PRをよりシンプルに保つインセンティブとしたいため(単一のコミットメッセージで表現できる程度の方がレビューコストも小さいため)

「Squash and merge」による変更の取り込みを行う場合、次の4点に注意すること。

Expand All @@ -183,11 +167,11 @@ https://zenn.dev/daku10/articles/github-merge-guardian
2. 部分的なコミットの取り消しができない
- 履歴上は1つのコミットになるので、マージ後に一部の変更だけを取り消すということができない。取り消しはPRの単位となるため、PRの単位をなるべく小さなまとまりにすることが望ましい
3. Authorが失われる
- 機能ブランチにコミットを行った人がAuthorになるのではなく、「Squash and merge」を行った人がAuthorになるため、OSS開発を行う場合など、厳密にコントリビューションを管理する必要がある場合は注意されたい。GitHubでは「Squash and merge」を行う場合、デフォルトでコミットメッセージに `co-authored-by` トレーラーが追加され、1つのコミットが複数の作成者に帰属するようにするようになっている[^1]。この記述は削除しないようにする
- 機能ブランチにコミットを行った人がAuthorになるのではなく、「Squash and merge」を行った人がAuthorになるため、OSS開発を行う場合など、厳密にコントリビューションを管理する必要がある場合は注意されたい。GitHubでは「Squash and merge」を行う場合、デフォルトでコミットメッセージに `co-authored-by` トレーラーが追加され、1つのコミットが複数の作成者に帰属するようにするようになっている[^2]。この記述は削除しないようにする
4. 機能ブランチの取り込み以外のケースでは、「Squash and merge」以外を選択すること
- 例えば、`develop` ブランチを `main` ブランチや `release`ブランチにマージする場合など、取り込み元のブランチの変更が大きい場合は、コミットメッセージを1つにまとめることによる弊害が大きいため、別のマージ戦略を検討すること

[^1]: https://docs.github.com/ja/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors
[^2]: https://docs.github.com/ja/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors

# ブランチ運用アンチパターン

Expand Down Expand Up @@ -230,7 +214,7 @@ https://zenn.dev/daku10/articles/github-merge-guardian
Gitのコミットメッセージは原則自由とする。理由は以下である。

- 通常、作業はチケット管理システムを駆動に開発するため、情報が重複する
- リリースノートの自動生成での扱いは、どちらかといえばラベルとプルリクエストのタイトルが重要
- リリースノートの自動生成での扱いは、どちらかといえばラベルとPRのタイトルが重要
- メンバーによっては粒度の小さいコミットを好む場合も多く、運用の徹底化を図る負荷が高い

チーム規模や特性によっては、Gitのコミットメッセージをルール化する方ことにより、メリットがある場合は `Conventional Commits` をベースとした以下の規約を推奨する。
Expand All @@ -251,13 +235,13 @@ Gitにはタグ機能があり、リリースポイントとしてタグを作

# ラベル規則

Issueやプルリクエストを分類することができるラベルについての利用は自由とする
IssueやPRを分類することができるラベルについての利用は自由とする

プルリクエストに適切なラベルを設定し[自動生成リリースノート - GitHub Docs](https://docs.github.com/ja/repositories/releasing-projects-on-github/automatically-generated-release-notes) に記載があるように `.github/release.yml` への設定を行うことで、リリースノートの生成をラベル単位にグルーピングできる。
PRに適切なラベルを設定し[自動生成リリースノート - GitHub Docs](https://docs.github.com/ja/repositories/releasing-projects-on-github/automatically-generated-release-notes) に記載があるように `.github/release.yml` への設定を行うことで、リリースノートの生成をラベル単位にグルーピングできる。

プルリクエストを後で探しやすくするための検索キーとしての位置づけと、リリースノート自動生成という観点でラベルを準備すること。
PRを後で探しやすくするための検索キーとしての位置づけと、リリースノート自動生成という観点でラベルを準備すること。

# 参考1:ローカルでの作業例
# ローカルでの作業例

gitコマンドでの作業例を記載する。リモートブランチへのプッシュは、`--force-with-lease --force-if-includes` オプションを付けることを必須とする。

Expand All @@ -278,6 +262,10 @@ git commit -a
git push origin HEAD --force-with-lease --force-if-includes
```

# 参考2: VS Code上でのGit操作
# VS Code上でのGit操作

[VSCode上でのGit操作](vscode_git_ope.md)で、利用頻度が高いとされるGitクライアントである、VS Code上でのGit操作を紹介する。

# 推奨設定

GitやGitHub/GitLabの環境設定は、[推奨設定](recommended_settings.md)にまとめる。
6 changes: 3 additions & 3 deletions documents/forGitBranch/merge_develop_to_feature.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ author: フューチャー株式会社

# 機能ブランチに開発ブランチの変更を取り込む方法

機能ブランチに対して開発ブランチの変更を取り込む方法は「マージ」「リベース」2つの方法が考えられる。
機能ブランチに対して開発ブランチの変更を取り込む方法は「マージ」「リベース」2つの方法が考えられる。

## マージ
## 1. マージコミット

マージとは `get fetch & git merge` コマンド( = `git pull` コマンド)を使用して、開発ブランチの変更を機能ブランチに取り込む方法を指す。
マージを行った場合は下記の通り、「マージコミット」が作成される。
Expand All @@ -28,7 +28,7 @@ $ git fetch
$ git merge develop
```

## リベース
## 2. リベース

リベースとは `get fetch & git rebase` コマンド( = `git pull --rebase` コマンド)を使用して、開発ブランチの変更を機能ブランチに取り込む方法を指す。
最新の開発ブランチの先頭から新たにコミットを作りなおす動きになるので、マージによる方法と異なり「マージコミット」は作成されない。
Expand Down
Loading

0 comments on commit c54bc7b

Please sign in to comment.