Issueが割り振られてから、マージされるまでの流れをご紹介します。
プロジェクトによって細かい部分は異なるかもしれませんが、概ねは大丈夫かなと思います。
概要
- 実務におけるGitの作業フローをまとめています。
- ブランチ戦略の話ではありません。
- 主に個人のトピック(作業)ブランチに焦点をあてています。
- SourceTree等のGUIツールは使用しません。Git CLIのみです。
- リモートリポジトリをクローンして、ローカルリポジトリは作成済みの想定です。
- デフォルトブランチが main ではなく develop など別のブランチになっている方は読み替えてください。
事前準備
ローカルの main ブランチを削除
ローカルの main ブランチはまったく使用しません。削除します。
古いローカルの main ブランチから新しくブランチを作成しないための予防策です。
$ git switch -d origin/main
$ git branch -D main
ローカルの main ブランチを使用しない運用については下記の記事で詳しく書いてます。
流れ
- 新しくブランチを作成する
- 作業してコミットをする
- 作業ブランチに最新のmainブランチを取り込む
- 作業ブランチを整理する
- リモートブランチへプッシュする
- プルリクエストを作成する
- レビューを受ける
- レビュー内容を反映したコミットを作る
- 変更点の再レビューを受ける
- 再度作業ブランチを整理する
- GitHub上でマージする
- ローカルのブランチを削除する
書き出してみましたが、多いので補足していきます。
新しくブランチを作成する
ブランチを作成する前に必ず、最新のリモートリポジトリの情報を取り込んでください。
これをしないと古いコミットからブランチを切り出してしまうことがあります。
$ git fetch
派生元の origin/main
リモート追跡ブランチから新しく topic-123
ブランチを作成しています。
また、派生元のブランチを指定しない場合は現在のブランチから新しいブランチが作成されます。
$ git switch -c topic-123 origin/main
理由なくマージ済みのブランチを再利用したり、そこからブランチを生やさないでください。
最新に追いつくためのマージやコンフリクト解消するコストが発生します。
ブランチ名の命名ルールはプロジェクトのブランチ戦略によるのでプロジェクトに合わせてください。
導入しているタスク管理ツールによってはタスク番号をブランチに含めると自動で紐付くものもあるのでツールに合わせた命名ルールにすると良いです。
作業してコミットをする
作業した変更内容をコミットします。
$ git add .
$ git commit
vimエディタで開くのでコミットメッセージを入力します。
git commit の便利なオプション
補足ないと手抜き感あるのでここでgit commitの便利なオプションを紹介します。
$ git commit -m "A 機能を実装しました"
-m
オプションを付けるとvimエディタを立ち上げずに1行コミットメッセージを入力できます。
$ git commit --amend
--amend
直前のコミットを変更できます。
git add してインデックス(ステージング)上がっている変更が直前のコミットに反映されます。
また、コミットメッセージの変更もできます。
$ git commit --amend --no-edit
コミットメッセージを変更する必要ない場合は --no-edit
オプションを付けます。
作業ブランチに最新のmainブランチを取り込む
[リベース前]
E---F---G topic-123
/
A---B---C---D origin/main
[リベース後]
E'---F'---G' topic-123
/
A---B---C---D origin/main
チーム開発していくと main ブランチがどんどん更新されていき、作業ブランチが古くなってしまいます。
古くなると大量にコンフリクトが発生することもあるのでこまめに取り込みましょう。
git rebase
で最新を取り込むとコミットハッシュ値が変わります。
プルリクエストを出す前にもコンフリクトしていないか確認をするために必ず最新を取り込んでください。
コンフリクトが発生したままプルリクエストを出すとレビュワーの負担と不必要なコミュニケーションコストが増えます。
$ git stash -u
作業途中のファイルがある場合は、スタッシュして一時保存するかコミットしてください。
-u
オプションを付けると未追跡ファイル(untracked file)を含めてスタッシュしてくれます。
$ git fetch
最新のリモートブランチの情報を取得します。
$ git rebase origin/main
途中コンフリクトが発生したらエディタを開いてコンフリクトを解決してください。
$ git status
# 対象のファイルを開いてコンフリクトを解消する
$ git add .
$ git rebase --continue
途中でやり直ししたい場合は git rebase --abort
してください。
リベースする前の状態に戻ります。
$ git stash pop
スタッシュに一時保存した変更を取り出します。
git rebase
のわかりやすそうなサイトをご紹介します。
https://www.atlassian.com/ja/git/tutorials/rewriting-history/git-rebase
git rebase についてはハンズオン形式で紹介した記事です。
作業ブランチを整理する
コミットメッセージを間違えたり、同じメッセージのコミットが複数あったり、wipなど試行錯誤した作業コミットは残さないようにします。
1つのコミットは1つ1つ意味のあるまとまりにします。
Issueを細かく区切って1プルリクエスト1コミットになるのが理想です。
mainブランチのコミットが綺麗になっているとあとから保守する人が助かります。
$ git rebase -i origin/main
リモートブランチへプッシュする
$ git push -u origin HEAD
-u
オプションを付けると次回以降は git push
だけで良くなります。
push.default オプション
$ git config --global push.default current
このオプションを設定している場合は git push
だけでOKです。
$ git push
プルリクエストを作成する
GitHubを開いてプルリクエストを作成します。
レビューを受ける
先輩からの手厚いレビューを受けます
レビュー内容を反映したコミットを作る
$ git add .
$ git commit -m "レビュー内容の反映"
$ git push
レビューが通るまで繰り返します💪
変更点の再レビューを受ける
Approveされたら、作業ブランチを整理してマージ作業を行います。
再度作業ブランチを整理する
レビューが完了したら、
レビューを通すために試行錯誤したコミットを見直したり、レビュー中にmainブランチが進んでいる場合があるので最新を取り込みます。
(レビュー依頼したらrebase禁止で運用しているプロジェクトもあります。その場合はスキップしてください)
$ git rebase origin/main
$ git rebase -i origin/main
$ git push --force-with-lease --force-if-includes
-
git rebase
したのでコミットハッシュ値が変わり、強制プッシュが必要 -
git push --force-with-lease --force-if-includes
ブランチを強制プッシュします- 個人で使用している作業ブランチのみ強制プッシュ
--force
or --force-with-lease --force-if-includes
の違い
リモートリポジトリのブランチにプッシュする場合、リモートリポジトリの最終コミットとローカルリポジトリの最終コミットが親子関係になっていないとエラーとなり通常はpushできません。
--force
オプションを付けるとその制限を回避できます。
こうするとGitはリモート履歴を完全に無視して、無条件にブランチを上書きします。
しかし、他の人がそのブランチを変更していた場合はその変更が失われてしまいます。
--force-with-lease
オプションは
リモートリポジトリの特定のブランチが最後にfetch
またはpull
した時から更新されていないことを確認することで安全な強制プッシュを実現します。
もし誰かがリモートブランチへ新しいコミットをプッシュしていた場合は、プッシュが拒否されます。
--force-if-includes
オプションは
リモートリポジトリにあるコミットがローカルのプッシュしようとしているブランチの履歴に含まれている場合のみ、強制プッシュを許可します。このオプションにより直前にfetch
しているとpush
が成功してしまう問題が解消します。
https://zenn.dev/mary_pp/articles/eaac544eaf600a
# エイリアス登録
$ git config --global alias.pushf 'push --force-with-lease --force-if-includes'
# 強制プッシュ実行
$ git pushf
GitHub上でマージする
GitHub上で作業者自身(レビューイ)が Create a merge commit
を選択し Merge pull request
を押してマージします。
(レビュワーがマージするとコミット整理中にマージされてしまう場合がある)
その際にリモートブランチも削除するオプションを指定してください。
マージの種類についての補足
- Create a merge commit
- マージコミットが残ります。
- 作業ブランチのコミットはそのまま残ります。
- プルリクエスト単位でリバートしやすい。
- Squash and merge
- マージコミットが残ります。
- 作業ブランチのコミットが1つにまとめられます。
- まとめる前のコミットには戻せない。
- プルリクエスト単位でリバートしやすい。
- Rebase and merge
- マージコミットは作成されず、履歴が一本化されます。
- 作業ブランチのコミットはそのまま残ります。
- プルリクエスト単位でリバートしたい場合に困る。
コミット自体はリベースで整理されていることと、何かあったときにプルリクエスト単位でリバートしたいので、個人的には Create a merge commit
が推しです。
誤って別のマージを選択してしまうのを防止するため、使用しないマージボタンを無効化できます。
https://qiita.com/ucan-lab/items/d594404d0d2c64a85a38#settings--options--merge-button
ローカルのブランチを削除する
$ git fetch -p
-p
を付けると削除されたリモートブランチも反映されます。
$ git branch -D topic-123
ローカルのブランチを削除する。
マージ済みブランチを再度利用することはないので削除します。
古いブランチが溜まると単純に見辛かったり、git fetchが遅くなる場合があります。
また、古いブランチを残して再利用すると最新に追いつくためのマージやコンフリクト解消がコストになります。
補足: 最新の main ブランチに切り替える
$ git fetch
$ git switch -d origin/main
ローカルの main ブランチは削除しているので、 -d
のdetached HEAD状態で切り替えます。
補足: git fetch -p オプションを常に有効化する
$ git config --global fetch.prune true
この設定をしておくと以降は -p
オプションを付ける必要はありません。
$ git fetch
補足: --update-refs オプション
Git 2.38.0 以降は --update-refs
オプションを使用できます。
$ git rebase --update-refs -i origin/main
とすると標準モードで取り込み、対話モードでコミットの整理が行えます。
$ git rebase origin/main
$ git rebase -i origin/main
一つのコマンドでできるようになったのでとても便利です。
毎回オプションを指定するのは面倒なのでグローバル設定しておくと良いです。
$ git config --global rebase.updateRefs true
以降は対話モードのリベースのみで標準モードの取り込みも合わせて行ってくれます。
$ git rebase -i origin/main
使わないコマンド
使用しないコマンド: git checkout
Git 2.23.0から git checkout
は git switch
と git resotre
に機能が分割されました。
使用しないコマンド: git pull
git fetch
と git rebase
で事足りるので、git pull
は使用しません。
使用しないコマンド: git merge
git rebase
を使うか、git merge
を使うかはプロジェクトの運用ルールによると思います。
コミットログが綺麗になるので個人的には git rebase
がオススメです。
関連記事