Gitで大量のコミットがあり、コミットを1つにまとめたい時どうすればいいか。🤔(rebaseやcherry-pick)

2024/02/28に公開

どんな状況

コミットを10回以上出して、rebaseしたらかなりややこしいコンフリクトが起きてしまいました。
そこでコミットをまず1つにまとめようということになりました。

方法

まずは以下のコマンドを使います。

git rebase -i HEAD~<コミット数>

⚫︎補足
<コミット数>はまとめたいコミットの数です。

エディタが開き、リベースの操作の指定

エディタが開いたら、それぞれのコミットの行に対して、picksquashfixupに変更します。これにより、選択したコミットが直前のコミットと結合されます。

説明
pick コミットをそのまま残す
squash コミットを直前のコミットと結合するが、コミットメッセージを統合する
fixup コミットを直前のコミットと結合し、そのコミットメッセージは無視されます

実行

pickをs(squash)に変更したらできます。
自分はf(fixup)を使いました。

pick コミット番号 :art: 1つにまとめたいコミット
ット数を追記)
s コミット番号 : 変更内容は直前のコミットに統合されるコミット
s コミット番号 :memo: 変更内容は直前のコミットに統合されるコミット
s コミット番号 :zap: 変更内容は直前のコミットに統合されるコミット
s コミット番号 :zap: 変更内容は直前のコミットに統合されるコミット

# Rebase 〇〇 (31 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
#         create a merge commit using the original merge commit's
#         message (or the oneline, if no original merge commit was
#         specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
#                       to this position in the new commits. The <ref> is
#                       updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
#         specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
#                       to this position in the new commits. The <ref> is
#                       updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#

cherry-pickを使う方法もある

これはあるブランチで行われた変更を別のブランチに持ってきたい時に使います。

git cherry-pick <チェリーピックしたいコミットのハッシュ値>
git cherry-pick <開始コミットのハッシュ値>^..<終了コミットのハッシュ値>

https://backlog.com/ja/git-tutorial/stepup/31/

https://qiita.com/okmtz/items/62aa5a25f75b1754a861

補足(rebaseができなった時の対処法)

以下のコマンドを実行しましたが、rebaseができませんでした。

taro% git rebase -i HEAD~14
fatal: It seems that there is already a rebase-merge directory, and
I wonder if you are in the middle of another rebase.  If that is the
case, please try
        git rebase (--continue | --abort | --skip)
If that is not the case, please
        rm -fr ".git/rebase-merge"
and run me again.  I am stopping in case you still have something

すでに別のリベース操作が進行中で、

git rebase --continue

をやってもうまくいきませんでした。その場合、一回以下のコマンドを実行して自分はこう対処しました。

git rebase --abort

その後下のコマンド実行

git rebase -i HEAD~<コミット数>

cherry-pickのトラブった事例

aというブランチでdevelopブランチにマージしました。
他にもb,c,d,,e,f,gのブランチで他の人がマージしました。
このdevelopブランチをqaブランチにaでマージした内容をcherry-pickしたいです。
その場合は、qaブランチにいる状態でaブランチをcherry-pickします。

しかしここでdevelopをcherry-pickしてしまうとどうなるでしょうか
するとb,c,d,e,f,gのブランチも全部取り込まれてカオスな状態になってしまいます

🔴注意
cherry-pickする時は、cherry-pickするブランチを気をつけましょう
git push origin mainとかも駆け出しエンジニアでやってしまう人いるような感じです。
cherry-pickを使う機会が少ないので気をつけてください。

Discussion