Git branch を 1 revision 1 issue に直す方法
Git branch を 1 revision 1 issue に直すべき理由
- Pull request での可読性を確保するため
- Git branch の差分の量が多すぎる場合、
差分を複数の pull request に分割して作成しやすくするため
Git の用語の復習
| 用語 | 説明 |
|---|---|
| Revision |
git commit によって作成される特定の変更履歴を指します |
| SHA1 checksum | Git が各 revision に対して生成する 40 文字のハッシュ値です これにより、特定の revision を一意に識別できます |
この手順内の用語
| 用語 | 説明 |
|---|---|
| 開発用 Git branch | 開発中の機能や修正を行うための Git branch 手戻りの履歴があったり、複数の issue が混在していることがある状態です この状態から 1つの issue につき 1つの revision になるように整理していきます |
手順
- 開発用 Git branch のバックアップ
- 開発用 Git branch を origin/main まで reset
- 整理作業
- 整理が終わったら開発用 Git branch のバックアップを削除
1. 開発用 Git branch のバックアップ
まず、開発用 Git branch をバックアップしておくため、名前を変えて push しておきます:
git branch <開発用 Git branch 名>-backup
git push origin <開発用 Git branch 名>-backup
2. 開発用 Git branch を origin/main まで reset
git switch <開発用 Git branch 名>
git reset --hard origin/main
3. 整理作業
開発用 Git branch と開発用 Git branch のバックアップの差分がなくなるまで
1 revision 1 issue になるように次の作業を繰り返します:
- 開発用 Git branch から revision を持ってくる
- 複数の revision を 1 つの revision にまとめる
- Revision の変更内容を足したり引いたりする
上記のそれぞれの作業手順は後述
差分がなくなっているかどうかを確認する方法
Git Graph の場合とコマンドラインの場合それぞれの方法を説明します
Git Graph の場合
開発用 Git branch をクリックした後に開発用 Git branch のバックアップを:
- Mac の場合: Command + クリック
- Windows の場合: Ctrl + クリック
コマンドラインの場合
git diff <開発用 Git branch 名>-backup --exit-code
echo $?
もし、差分がなければ 0 が表示されます
差分があれば 1 が表示されます
開発用 Git branch から revision を持ってくる
Git コマンドの cherry-pick を使います
まず、開発用 Git branch から持ってきたい revision の SHA1 checksum を確認します:
git log <開発用 Git branch 名>
持ってきたい revision の SHA1 checksum を確認したら、次のように cherry-pick します:
git cherry-pick <対象 revision の SHA1 checksum 1> <対象 revision の SHA1 checksum 2> ...
一度に範囲内の複数の revision を持ってくる場合は、次のようにします:
git cherry-pick <対象 revision の SHA1 checksum 1>^..<対象 revision の SHA1 checksum 2>
複数の revision を 1 つの revision にまとめる
複数の revision を 1 つの revision にまとめるには、
まとめる revision 全てが現在の Git branch にある必要があります
まとめたい revision が複数の Git branch に分かれている場合は、
まず上記の「開発用 Git branch から revision を持ってくる」の方法で、
それらの revision を整理用 Git branch に持ってきます
その後、1 つの revision にまとめる操作を行います
この時点の revision でブランチかタグを作成して
この時点の状態をバックアップしておくことをお奨めします
- この後のまとめる操作の中で、まとめなかった revision は削除されるため
- 操作を誤ると復旧が困難なため
ブランチの場合は次のようにします:
git branch backup
まず、まとめたい一連の revision の内、最初の revision の SHA1 checksum を確認します
VS Code 拡張機能 Git Graph などの GUI ツールの使用をお奨めします
コマンドラインだと次のようなコマンドが確認しやすそうです:
git log --oneline --graph --decorate --all
最初の revision の SHA1 checksum が確認できたら、
rebase --interactive で
最初の revision の SHA1 checksum の直前の revision を ^ を使って指定します:
git rebase -i <最初の revision の SHA1 checksum>^
すると、エディタが開きます:
pick <最初の revision の SHA1 checksum> <最初の revision のメッセージ>
pick <2 番目の revision の SHA1 checksum> <2 番目の revision のメッセージ>
pick <3 番目の revision の SHA1 checksum> <3 番目の revision のメッセージ>
pick <4 番目の revision の SHA1 checksum> <4 番目の revision のメッセージ>
# Rebase <最初の revision の SHA1 checksum> onto <最初の revision の SHA1 checksum>^ (4 commands)
# Commands:
# p, pick <revision> = use commit
# r, reword <revision> = use commit, but edit the commit message
# e, edit <revision> = use commit, but stop for amending
# s, squash <revision> = use commit, but meld into previous commit
# f, fixup <revision> = like "squash", but discard this commit
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <revision> = remove commit
ここで、最初の revision 以外の行でまとめたい revision の先頭の pick を
f または fixup に変更します
また、まとめたくない revision は先頭の pick を d または drop に変更します
例えば、2 番目と 4 番目の revision をまとめたい場合は次のようにします:
pick <最初の revision の SHA1 checksum> <最初の revision のメッセージ>
- pick <2 番目の revision の SHA1 checksum> <2 番目の revision のメッセージ>
+ f <2 番目の revision の SHA1 checksum> <2 番目の revision のメッセージ>
- pick <3 番目の revision の SHA1 checksum> <3 番目の revision のメッセージ>
+ d <3 番目の revision の SHA1 checksum> <3 番目の revision のメッセージ>
- pick <4 番目の revision の SHA1 checksum> <4 番目の revision のメッセージ>
+ f <4 番目の revision の SHA1 checksum> <4 番目の revision のメッセージ>
# Rebase <最初の revision の SHA1 checksum> onto <最初の revision の SHA1 checksum>^ (4 commands)
# Commands:
# p, pick <revision> = use commit
# r, reword <revision> = use commit, but edit the commit message
# e, edit <revision> = use commit, but stop for amending
# s, squash <revision> = use commit, but meld into previous commit
# f, fixup <revision> = like "squash", but discard this commit
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <revision> = remove commit
その後、エディタを保存して閉じると、エディタで指定した通りに revision がまとめられます
Revision の変更内容を足したり引いたりする
まず、上記「開発用 Git branch から revision を持ってくる」の方法で、
変更内容を足したり引いたりしたい revision を持ってきます
その後、足したり引いたりしたい変更内容をプロジェクトに加えてステージングし、
commit --amend --no-edit で、持ってきた revision の内容を修正します
git add .
git commit --amend --no-edit
4. 整理が終わったら開発用 Git branch のバックアップを削除
整理が終わり、
前述の「差分がなくなっているかどうかを確認する方法」で
差分がなくなっていることを確認できたら、
開発用 Git branch のバックアップを削除します:
git branch -D <開発用 Git branch 名>-backup
git push origin --delete <開発用 Git branch 名>-backup
Discussion
PRの可読性を上げたいなら cherry-pick しないほうがいいのでは?
最後に squash マージすればいいし、そのマージコミットに issue の内容いれておけばいい気がする。。。
反応ありがとうございます
まず、記事の内容が不完全だったので修正しました
開発用 Git branch を整理して、元の Git branch を削除するようにしました
cherry-pick するのは、元の Git branch を削除する前提だったためでした
その上で、
この記事では
Git branch の差分の量が多すぎる場合を想定する状況の 1 つに置いていますPR の可読性は変更の量が多いと下がると考えています
最近は AI で大量の更新が行えるようになりましたが、それらを単純に squash でまとめてしまうと
Git の graph は視認性が上がるかもしれませんが、
個別の revision の可読性は下がると考えています
具体的な例では、
バグ修正を目的とした 1 つの revision にリファクタリングが混ざっているなどの場合は
可読性が下がると考えています
そのため、この記事では 1 revision 1 issue にまとめ直し、
必要があれば複数の pull request に分割できるようにする方法を解説しました