web-dev-qa-db-ja.com

git rebase interactive:コミットをまとめてスカッシュマージ

インタラクティブなリベース中に2つのマージコミットを一緒に押しつぶす簡単なソリューションが必要でした。

私のリポジトリは次のようになります:

   X --- Y --------- M1 -------- M2 (my-feature)
  /                 /           /
 /                 /           /
a --- b --- c --- d --- e --- f (stable)

つまり、最近2回マージされたmy-featureブランチがあり、その間に実際のコミットはありません。 my-featureブランチは、それ自体が公開されているブランチであるため、リベースしたくありません。最後の2つのマージコミットを1つにまとめるだけです(これらのコミットはまだ公開していません)。

   X --- Y ---- M (my-feature)
  /            /
 /            /
a --- ... -- f (stable)

私は試した:

git rebase -p -i M1^

しかし、私は得ました:

Refusing to squash a merge: M2

私が最後にしたことは:

git checkout my-feature
git reset --soft HEAD^  # remove the last commit (M2) but keep the changes in the index
git commit -m toto      # redo the commit M2, this time it is not a merge commit
git rebase -p -i M1^    # do the rebase and squash the last commit
git diff M2 HEAD        # test the commits are the same

現在、新しいマージコミットはマージコミットと見なされなくなりました(最初の親のみが保持されます)。そう:

git reset --soft HEAD^               # get ready to modify the commit
git stash                            # put away the index
git merge -s ours --no-commit stable # regenerate merge information (the second parent)
git stash apply                      # get the index back with the real merge in it
git commit -a                        # commit your merge
git diff M2 HEAD                     # test that you have the same commit again

しかし、私が多くのコミットをしている場合、これは複雑になる可能性があります。より良い解決策がありますか?ありがとう。

ミルドレッド

52
Mildred

これは古いトピックですが、同じような情報を探しているときに偶然見つけました。

Subtree octopus merge で説明されているのと同じようなトリックは、この種の問題に対する非常に優れた解決策です。

git checkout my-feature
git reset --soft Y
git rev-parse f > .git/MERGE_HEAD
git commit

これはmy-featureの先端に存在するインデックスを取得し、それを使用してYから新しいコミットを作成し、2番目の親として「f」を使用します。結果は、M1を一度も実行したことがない場合と同じですが、M2を実行することにまっすぐ進みました。

48
Matt

最後の2つのマージコミットを公開していない場合は、リセットと単純なマージを実行できます。

git reset --hard Y
git merge stable
8
bobDevil

単一のマージコミットを押しつぶそうとして、このトピックに行きました。だから私の答えは元の質問にはそれほど役に立ちません。

               X
                \   
                 \  
a --- b --- c --- M1 (subtree merge)

私が欲しかったのは、M1マージをリベースし、bの上に単一のコミットとしてすべてをスカッシュすることでした。

a --- b --- S (include the changes from c, X and M1)

私はあらゆる種類の異なる組み合わせを試しましたが、これはうまくいきました:

git checkout -b rebase b (checkout a working branch at point b)
git merge --squash M1

これは、変更をコミットできるインデックスに変更を適用しますgit commit

5

言及されているメソッドのいずれも、最近のgitバージョンでは機能しません。私の場合、次のことがうまくいきました:

git reset --soft Y
git reset --hard $(git commit-tree $(git write-tree) -p HEAD -p stable < commit_msg)

ただし、最初にcommit_msgファイルにコミットメッセージを書き込む必要があります。

0
Michael Wild