ブランチ戦略の実習
目標
リポジトリを1つ最初から作り、3つのマージ方式(no-ffマージ、早送り、チェリーピック)の結果が、履歴にどう違って残るかを目で確認し、その結果を数字で数えて、戦略の比較表を書きます。
なぜ重要なのか
ブランチ戦略の議論は、たいてい好みの争いで終わります。しかし、決定を下す本当の問いは1つです。障害が起きたとき、このリポジトリで原因のコミットをどう見つける計画か。--no-ffマージは「このまとまりがいつ統合されたか」を残し、早送りは一直線の履歴を与える代わりに統合の時点を消し、スカッシュマージは二分探索の解像度をPRのサイズに固定し、Gitから見るとそのブランチがマージされたことがない状態にします。この違いは、説明を読んでではなく、git rev-list --min-parents=2で数えてみて、はじめて身につきます。
ステップ
このイメージにはグローバルなgitの作成者情報が設定されていません。新しく作るすべてのリポジトリで、git config user.emailとgit config user.nameをローカルで設定しないと、コミットが失敗します。
/root/gitx1/repoにリポジトリを作成します。現在のブランチはmainとし、このリポジトリには、user.emailとuser.nameをローカルで設定しておく必要があります。また、README.mdを含むコミットが最低1つ必要です。feature/loginブランチを作成し、コミットを2つ積みます。コミットのタイトルは、正確にlogin: formとlogin: validationである必要があり、ブランチにlogin.txtファイルがある必要があります。login:で始まるコミットはちょうど2つである必要があります。mainに移動し、feature/loginをマージコミットが残るように(親が2つのコミット)マージします。マージ後、mainにlogin.txtがある必要があります。mainからfeature/quickブランチを作成し、quick.txtを追加するコミットを1つ作ります。タイトルは正確にquick: typoです。そして、mainに早送りだけでマージします。このコミットの親は1つである必要があり、mainのマージコミットの数は、ステップ3で作った1つのままである必要があります。mainの現在の位置に、v1.0.0という注釈付きタグを付けます。タグのメッセージは、空であってはいけません。v1.0.0の地点からrelease/1.0ブランチを作成し、hotfix.txtを追加するコミットを作ります。タイトルは正確にhotfix: null guardです。そのあと、同じ変更をmainにも反映します。条件: 2つのブランチのhotfix.txtの内容が同じであること、両方ともhotfix: null guardのコミットを持つこと、ただし2つのコミットのハッシュは互いに異なる必要があります。- ブランチを整理します。
feature/quickは削除し、feature/loginは残し、新しくfeature/wipブランチを作成して、mainにないコミットを1つ以上積んでおきます(まだマージしていない状態である必要があります)。 /root/gitx1/strategy.mdを書きます。必ず含めるもの:merge_commits=:mainのマージコミットの数branches=: このリポジトリのローカルブランチの数tags=: タグの数- Git Flow / GitHub Flow / Trunk-Basedの3つの戦略についての説明
- このリポジトリがどの戦略に近いかについての判断(「このリポジトリ」「私たち」「現在」のいずれかを意味する韓国語の表現が入っている必要があります)
参考
- 作成者情報の設定:
git config user.email "you@lab.local"とgit config user.name "Lab"を、リポジトリの中で実行します。--globalは使わないでください。 - デフォルトのブランチ名:
git init -b mainを使うか、git initのあとにgit symbolic-ref HEAD refs/heads/mainで変更します。 - 数の数え方: マージコミットは
git rev-list --min-parents=2 --count main、ブランチはgit branch --format='%(refname:short)' | grep -c .、タグはgit tag | grep -c .です。 - よくある間違い1: ステップ3で、ただの
git mergeを使ってしまうことです。分岐した履歴がないと、早送りになり、マージコミットができません。 - よくある間違い2: ステップ6で
git merge release/1.0を使ってしまうことです。マージコミットがもう1つできて、ステップ4の採点が壊れます。コミットを1つだけ持ってくるコマンドを使ってください。 - コミットのタイトルは、大文字小文字と空白まで、正確に一致する必要があります。
git log --format='%s'で確認してください。
リポジトリを作成して作成者情報を設定する
/root/gitx1/repoにリポジトリを作成します。現在のブランチはmainとし、このリポジトリには、user.emailとuser.nameをローカルで設定しておく必要があります。また、README.mdを含むコミットが最低1つ必要です。
/root/gitx1/repoでgit initを行い、デフォルトのブランチ名をmainにします。このイメージにはグローバルなgitの作成者情報がないため、user.emailとuser.nameをこのリポジトリに直接設定しないと、コミット自体が失敗します。
機能ブランチにコミットを2つ積む
feature/loginブランチを作成し、コミットを2つ積みます。コミットのタイトルは、正確にlogin: formとlogin: validationである必要があり、ブランチにlogin.txtファイルがある必要があります。login: で始まるコミットはちょうど2つである必要があります。
feature/loginブランチを作成し、login.txtを2回に分けてコミットします。コミットのタイトルは、指示された文字列と正確に同じである必要があり、login:で始まるコミットがちょうど2つである必要があります。
早送りなしでマージする
mainに移動し、feature/loginをマージコミットが残るように(親が2つのコミット)マージします。マージ後、mainにlogin.txtがある必要があります。
mainに移動してfeature/loginをマージしますが、親が2つのコミットが残るようにマージします。ただmergeすると早送りになり、統合の記録が消えます。
小さな修正は早送りで取り込む
mainからfeature/quickブランチを作成し、quick.txtを追加するコミットを1つ作ります。タイトルは正確にquick: typoです。そして、mainに早送りだけでマージします。このコミットの親は1つである必要があり、mainのマージコミットの数は、ステップ3で作った1つのままである必要があります。
feature/quickを作成してquick.txtをコミットし、mainに早送りだけでマージします。マージコミットができると、このステップは失敗します。--ff-onlyを使うと、条件に合わないときに最初から拒否してくれます。
リリースタグを付ける
mainの現在の位置に、v1.0.0という注釈付きタグを付けます。タグのメッセージは、空であってはいけません。
mainにv1.0.0タグを付けます。軽量タグは単なるポインターなので、作成者とメッセージが残りません。タグオブジェクトが作られるオプションを使ってください。
リリースブランチのホットフィックスをmainに取り込む
v1.0.0の地点からrelease/1.0ブランチを作成し、hotfix.txtを追加するコミットを作ります。タイトルは正確にhotfix: null guardです。そのあと、同じ変更をmainにも反映します。条件: 2つのブランチのhotfix.txtの内容が同じであること、両方ともhotfix: null guardのコミットを持つこと、ただし2つのコミットのハッシュは互いに異なる必要があります。
v1.0.0からrelease/1.0を作成してhotfix.txtをコミットしたあと、同じ変更をmainにも反映します。ブランチをまるごとマージせず、そのコミット1つだけを取り込んでください。
チェリーピックは、変更を再適用して新しいコミットを作ります。移動するわけではありません。ただし、このラボのように、release/1.0をmainの先頭からそのまま作った場合は、2つのコミットの親が同じです。そのため、git cherry-pick -xを使ってください。メッセージに(cherry picked from commit ...)の1行が付き、どこから来たのかが履歴に残り、その行のおかげでコミットオブジェクトも確実に区別されます。ホットフィックスを複数のブランチに反映するとき、実務で推奨される方法が、まさにこれです。
マージ済みのブランチだけを整理する
ブランチを整理します。feature/quickは削除し、feature/loginは残し、新しくfeature/wipブランチを作成して、mainにないコミットを1つ以上積んでおきます(まだマージしていない状態である必要があります)。
すでにマージが終わったブランチは削除し、まだマージされていないブランチは残します。git branch --merged mainで、安全に削除できるものを先に確認してください。-Dではなく-dを使うと、誤って未マージのブランチを削除する事故を防げます。
リポジトリの状態を数えて戦略の比較表を書く
/root/gitx1/strategy.mdを書きます。必ず含めるもの:
merge_commits=:mainのマージコミットの数branches=: このリポジトリのローカルブランチの数tags=: タグの数- Git Flow / GitHub Flow / Trunk-Basedの3つの戦略についての説明
- このリポジトリがどの戦略に近いかについての判断(「このリポジトリ」「私たち」「現在」のいずれかを意味する韓国語の表現が入っている必要があります)
/root/gitx1/strategy.mdに、merge_commits= / branches= / tags=の3行を、実際のリポジトリで数えた値で書き、3つのブランチ戦略を比較したうえで、このリポジトリがどれに近いかの判断を書きます。数字はgitコマンドで数えてください。