Gitマージコミットのリベース


183

次のケースを考えてみましょう:

私はトピックブランチでいくつかの作業をしており、マスターにマージする準備ができています:

* eb3b733 3     [master] [origin/master]
| * b62cae6 2   [topic]
|/  
* 38abeae 1

マスターからマージを実行し、競合を解決すると、次のようになります。

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | eb3b733 3                     [origin/master]
|/  
* 38abeae 1

マージには少し時間がかかったので、別のフェッチを実行すると、リモートマスターブランチに新しい変更が加えられています。

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
| | * e7affba 4                   [origin/master]
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

マスターから「git rebase origin / master」を実行しようとすると、すべての競合を再度解決する必要があり、マージコミットも失われます。

* d4de423 2       [master]
* e7affba 4       [origin/master]
* eb3b733 3
| * b62cae6 2     [topic]
|/  
* 38abeae 1

マージコミットをリベースするためのクリーンな方法はありますか?そのため、以下に示すような履歴になってしまいますか?

*   51984c7 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | e7affba 4                     [origin/master]
* | eb3b733 3
|/  
* 38abeae 1

74
TL; DR:git rebase --preserve-merges origin/master
Ilia K.

6
競合を再解決する必要があることについては、git rerereを参照してください
Parker Coates

git config --global pull.rebase preserve 常にリベース中にマージコミットを維持するために
galath

4
警告:Git 2.18(2018年第2四半期、5年後)以降、git --rebase-merges最終的には古いに置き換わりgit --preserve-mergesます。Gitの「rebase --preserve-merges」が正確に何をしているのか(そしてその理由は何か)を
VonC '27

1
--preserve-merges廃止予定です。使用git rebase --rebase-merges origin/master
Arjun Sreedharan

回答:


126

ここには2つのオプションがあります。

1つは、インタラクティブなリベースを実行してマージコミットを編集し、手動でマージをやり直してリベースを続行することです。

もう1つは、マニュアルで次のように説明されている--rebase-mergesonオプションを使用するgit rebaseことです。「デフォルトでは、リベースはマージコミットをtodoリストから削除し、リベースされたコミットを単一の線形ブランチに配置します。--rebase-マージの場合、リベースは、マージコミットを再作成することにより、リベースされるコミット内の分岐構造を保持しようとします。解決されたマージの競合またはこれらのマージコミットの手動の修正は、手動で解決または再適用する必要があります。」


16
-pオプションを試してみたところ、確かにコミット履歴は希望どおりに残っていますが、origin / masterで編集されていないファイルでも、競合を解決する必要があります。最初の提案の時点で、コマンドの正確なシーケンスはどれですか?
jipumarino 2011年

2
@jipumarino:git rebase -i(マージコミットを編集するように伝えます)、マージコミットに到達したら、git reset --hard HEAD ^、gitマージ、競合の修正、git commit、git rebase --continue。この種のことで役立つはずのgit rerereを確認することもできます(ただし、私は使用したことがないので、アドバイスやヘルプは提供できません)。
siride

2
ありがとう。rerereを有効にしてrebase -pを試しましたが、正常に機能しています。
jipumarino 2011年

3
この正確な状況を説明する優れたブログ投稿は次のとおり
リベース

1
まだ最初に手動でマージを解決する必要があるため、rereは解決策ではありません。
Flimm 2014年

29

わかりました。これは古い質問であり、すでにによる回答を受け入れてい@sirideますが、私の場合は、--preserve-mergesすべての競合を2回目に解決する必要があるため、その回答では不十分でした。私のソリューションはアイデアに基づいています@Tobi Bが、正確なステップバイステップのコマンドを使用しています

したがって、質問の例に基づいて、そのような状態から始めます。

*   8101fe3 Merge branch 'topic'  [HEAD -> master]
|\  
| * b62cae6 2                     [topic]
| |
| | * f5a7ca8 5                   [origin/master]
| | * e7affba 4
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

マスターの前に2つのコミットがあるため、チェリーピックは機能しないことに注意してください。

  1. まず、必要な正しい履歴を作成しましょう。

    git checkout -b correct-history # create new branch to save master for future
    git rebase --strategy=ours --preserve-merges origin/master
    

    --preserve-mergesマージコミットを履歴に保存するために使用します。--strategy=oursマージコミットの内容が何であるかを気にしないので、すべてのマージの競合を無視するために使用します。今必要なのは素晴らしい履歴だけです。

    履歴は次のようになります(マスターは無視)。

    *   51984c7 Merge branch 'topic'  [HEAD -> correct-history]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
  2. 正しいインデックスを取得しましょう。

    git checkout master # return to our master branch
    git merge origin/master # merge origin/master on top of our master
    

    ここで追加のマージの競合が発生する可能性がありますが、これはとの間8101fe3で変更されたファイルの競合のみでありf5a7ca8、既に解決されたからの競合は含まれませんtopic

    履歴は次のようになります(修正履歴は無視されます)。

    *   94f1484 Merge branch 'origin/master'  [HEAD -> master]
    |\  
    * | f5a7ca8 5                   [origin/master]
    * | e7affba 4
    | *   8101fe3 Merge branch 'topic'
    | |\  
    | | * b62cae6 2                     [topic]
    |/ /
    * / eb3b733 3
    |/  
    * 38abeae 1
    
  3. 最後の段階は、ブランチを正しい履歴と組み合わせ、ブランチを正しいインデックスで組み合わせることです

    git reset --soft correct-history
    git commit --amend
    

    reset --softブランチ(および履歴)をcorrect-historyにリセットするために使用しますが、インデックスと作業ツリーはそのままにしておきます。次にcommit --amend、マスターからの適切なインデックスを使用して、誤ったインデックスを使用していたマージコミットを書き換えます。

    最後に、そのような状態になります(トップコミットの別のIDに注意してください)。

    *   13e6d03 Merge branch 'topic'  [HEAD -> master]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    

これは素晴らしく、多くのことを助けました!しかし、私はcommit --amendでトリックを取得しませんでした。それについてさらに情報を追加できますか?実行すると正確にはどうなりますか?コミットのSHAが変更されたことに気付きましたが、なぜですか?または、これを実行しないとどうなりますか?
ZenJ 2018

1
@ZenJ git commit --amendは、変更を最後のコミット(HEAD、この場合はマージコミット)に追加します。コミット内容が変わるため、ハッシュが更新されます。
スタレンスを乾燥させる

1
競合を修正する前に「rerere」を有効にしていない人にとって、この解決策は、競合を再度修正する必要がないため、優れています。ありがとう!
シャクルフォード、

6

私がこれを理解しようとする一日を失い、同僚の助けを借りて実際に解決策を見つけたので、私は口をそろえるべきだと思いました。

大きなコードベースがあり、同時に大幅に変更される2つのブランチに対処する必要があります。もしそうなら、メインブランチとセカンダリブランチがあります。

セカンダリブランチをメインブランチにマージしている間、メインブランチで作業が続行され、完了した時点では、互換性がないため変更をプッシュできません。

したがって、「マージ」を「リベース」する必要があります。

これが最後に行った方法です:

1)SHAを書き留めます。例:c4a924d458ea0629c0d694f1b9e9576a3ecf506b

git log -1

2)適切な履歴を作成しますが、これによりマージが壊れます。

git rebase -s ours --preserve-merges origin/master

3)SHAを書き留めます。例:29dd8101d78

git log -1

4)以前の状態にリセットします

git reset c4a924d458ea0629c0d694f1b9e9576a3ecf506b --hard

5)現在のマスターを作業ブランチにマージします

git merge origin/master
git mergetool
git commit -m"correct files

6)正しいファイルがあり、誤った履歴があるので、次のコマンドを使用して、変更に加えて正しい履歴を取得します。

git reset 29dd8101d78 --soft

7)次に-元のマージコミットの結果を修正します

git commit --amend

出来上がり!


1

最初のマージを削除したいようです。次の手順に従ってください。

git checkout master      # Let's make sure we are on master branch
git reset --hard master~ # Let's get back to master before the merge
git pull                 # or git merge remote/master
git merge topic

それはあなたが望むものをあなたに与えるでしょう。


4
rerereが有効になっていると、これはsirideによって上記のrebase -pソリューションと同じ結果を与えるようです。
jipumarino 2011年

0
  • マージコミットから
  • 簡単なはずの新しい変更をチェリーピック
  • あなたのものをコピーする
  • マージをやり直し、ローカルコピーからファイルをコピーするだけで競合を解決します;)

1
この回答は良さそうですが、ユーザーがgitを初めて使う場合に備えて、実際のgitコマンドを指定した方が便利です
Louise Davies
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.