YouTubeで素敵な動画を見つけたので、普段やっているGitの運用フローの整理してみました。
なお、素敵な動画はこちらです。
ちなみに、動画で紹介されていた方法については下記を使っています。
- main <-- featureの場合は、mergeします
- feature <-- mainの場合は、rebaseします
これに加えて、featureブランチ内の修正もrebaseで行うことがありますが、この辺りをフローで整理してみました。
やっていること
Step1. featureブランチを作成してPushまで
まず、mainブランチからfeatureブランチを作成して、その中で作業します。
作業が終わったら、featureブランチをリモート(GitHubなど)にpushします。
これは一般的なフローと変わらないと思います。
# featureブランチ作成
$ git checkout -b featureA
# 作業を行う
$ vim somefile.txt
# 変更をステージングしてコミット
$ git add somefile.txt
$ git commit -m "feat: Add new feature"
# featureブランチをリモートにpush
$ git push origin featureA
動画ではswitchコマンドを使っていましたが、checkoutを使っています。
gitのドキュメントには試験的なコマンドって書いてありますが、どちらでもいいのかと思います。
Step2. プルリクエストの発行&レビュー
次に、pushしたブランチからプルリクエストを発行してレビューを依頼します。
ここも、一般的な方法と同じだと思います。
ただ、一度でOKになることは少なく、レビュー指摘がくるので、次のステップの内容を実施します。
Step3. レビュー指摘の修正
レビューの指摘内容をローカルのfeatureブランチ内で修正して、コミット&pushします。
再度レビューしてもらい、OKになるまでこのステップを繰り返します。
# 変更をステージングして追加コミット
$ vim somefile.txt
$ git add somefile.txt
$ git commit -m "fix: Fix review comments"
# 修正をリモートにpush
$ git push origin featureA
Step4. レビューがOKになったら(mergeはしません)
レビューがOKになったら、次はfeatureブランチをきれいにします。
mainブランチにマージするため、rebaseを使って、コミットの粒度やコミットメッセージなどをきれいにします。
# リベースを開始
$ git rebase -i HEAD~5
# インタラクティブ リベース画面が表示される
# ここで、reword, squash, editなどを実施
具体的には、以下のようなことをやっています。
-
squash/fixup: 修正コミットの統合
- レビュー指摘で修正したコミットは、最初の機能追加のコミットの考慮漏れであったりするので、これらの関係するコミットを1つにします
- レビュー指摘内容はPRに残るので、コミット履歴に残ってもあまり意味がないですからね
-
edit: コミットの分割
- XX機能の追加というコミットの中に、余分なスペースを削除した修正が入っていたりするとコミット内容と異なる修正を実施しているので、機能追加と軽微な修正という2つのコミットに分割します
- こういう不要な修正の影響でコンフリクトが発生するので適切な範囲に分割します
-
reword: コミットメッセージの修正
- Issue番号などコミットメッセージに記載しなければならない内容が不足している場合はコミットメッセージを書き換えます
- 修正量が少ないような場合は、Step3~4をまとめてやったりします
- この手順のrebaseは、動画内のrebaseとは異なっています
リベースが終わったら、変更内容をリモートにpushします。
この時、注意が必要で、リベースによりローカルとリモートでcommit hashが変わるため、force optionが必要です
# リベース後のコミットをリモートに強制push
$ git push origin featureA --force-with-lease
Step5. 最終レビュー&マージ
最終レビューでは、修正内容に加え、コミットの粒度、コミットメッセージが適切かを確認します。
問題があれば、再度4にもどってやり直しますが、問題がなければ、featureブランチからmainブランチにマージされます。
rebaseはいつするか?
動画内でも紹介されていましたが、featureブランチ作成からmainブランチへのマージまでの期間が長くなる場合、mainブランチに他のコミットが入ることがあります。
このとき、pushやPR発行前にrebaseして同期をとっています。
具体的には、Step1や3、4のタイミングで、featureブランチをrebaseしています。
ここでのrebaseはcommit履歴をmainの最新にして、その後ろにfeature向けの修正が入るようにしています。
# ローカルのmainブランチをremoteと同期
$ git checkout main
$ git pull origin main
# featureブランチをrebase
$ git checkout featureA
$ git rebase main
運用フローの考え方
mainブランチは、プルリクエスト以外で直接変更を加えることはなく、一度マージされたものも基本的には取り消しません。
もし取り消す場合は、専用のコミットを作成してPRでマージ(revert)する運用が一般的だと思います。
そのため、mainブランチを後から変更することは困難になりますが、不要なコミットなどはきれいにしたいので、マージ前のfeatureブランチで修正を実施するというフローになっています。
featureブランチは、一時的なものであり、マージ条件を満たすまではいくらでも改変(rebase)できるというルールにしているため、featureブランチのpushは、force optionが必要になり、ここは改善が必要な箇所で悩ましいところです。