web-dev-qa-db-ja.com

マージ後、GITは「すでに最新」と表示しているのに、ブランチ間にまだ違いがあるのはなぜですか?

私はもともと 'newfeature'ブランチで作業しており、ライブブランチのバグを緊急に修正するように依頼されました。 「generalmaintenance」というブランチを作成し、ジョブを実行してから、開発とマージに切り替えました。次に、「newfeature」ブランチに戻り、以前にマージした変更をマージします。

「newfeature」に切り替えて「develop」でマージすると、3つのファイルで競合が発生しました。

私は衝突を解決するために葛藤し、最終的にAptana Studio 3(私のIDEです)の[チーム]メニューの[元に戻す]コマンドを使用することにしました。これにより、マージが行われる前の状態にロールバックされると期待していました。

とにかく、再び「開発」にマージすると、Already-up-to-date、ただし2つのブランチ間でファイルを比較する場合、それらは非常に異なり、他のブランチで追加した変更はマージされません。

どうすれば2つのブランチをマージできますか?

29
Peter Snow

マージの復帰とマージのリセット

私の推測では、あなたは実際にはareAlready-up-to-dateです。

問題は git revert がマージを取り消すのではなく、マージによってもたらされた変更を取り消すことだけです。マージコミットを作成すると、これら2つのブランチのコミット履歴が結合されます。

マージ

     develop
        |
A---B---C
 \       \
  E---F---M
          |
      newfeature

上記の場合、developnewfeatureにマージされ、Mコミットが作成されます。 git log newfeatureを実行すると、両方のブランチからのすべてのコミットが表示されますが、newfeatureブランチの観点から見ると、これらの変更はすべてMコミットによって実行されました。

元に戻す

git revertコマンドはコミットを削除せず、代わりに、コミットに含まれた変更を元に戻す新しいコミットを作成します。たとえば、この差分を含むコミットがある場合...

-This is the old sentence.
+This is ne new sentence.

次に、これを元に戻し、revertコマンドは、反対のdiffを実行したばかりの新しいコミットを作成し、単に符号を反転させます。

-This is ne new sentence.
+This is the old sentence.

これは、他の開発者がすでに持っているコミットによって引き起こされたダメージを取り消すのに本当に役立ちます。履歴を変更するのではなく、履歴を進めます。

マージを元に戻す

ただし、早送りでないマージのコンテキストでは、望ましくない影響が生じる可能性があります。

     develop
        |
A---B---C
 \       \
  E---F---M---W
              |
         newfeature

Wがリバートコミットであると仮定すると、実行中のgit log newfeatureにいまだに開発ブランチからのすべてのコミットが含まれることがわかります。その結果、developからの追加のマージは機能しません。ブランチから欠落しているものは何も表示されないためです。

元に戻す代わりに git reset を使用します

将来、そのマージが他の開発者と共有されていない場合は、git reset --hard <ref><ref>はマージのコミットハッシュ)を使用してマージを取り消すことを検討する必要があるかもしれません。上記の例では、マージコミットMを作成した後、コマンドgit reset --hard Fを実行すると次のようになります。

     develop
        |
A---B---C
 \       \
  E---F---M
      |
  newfeature

ご覧のように、一部の人々は考えがちなように、この手法はコミットを無効にしません。ブランチを選択したコミットに戻すだけです。ここで、git log newfeatureを実行した場合、コミットされるのはFE、およびAのみです。これで、マージは実際にブランチの履歴から削除されるため、後でdevelopに再度マージしようとしても問題は発生しません。

この方法には複雑さがないわけではありません。履歴を変更していることを認識してください。つまり、newfeatureマージが行われた後でMブランチがリモートブランチにプッシュされた場合、gitは単に時代遅れであると考え、git pullを実行する必要があることを伝えます。そのリモートブランチで作業している場合は、自由にforce-Push-git Push -f <remote> <branch>を使用してください。これは、リセットと同じ効果がありますが、リモートブランチ上です。

このブランチが複数の開発者によって使用されている場合、すでにブランチからプルされているはずですが、これは悪い考えです。これは、実際の履歴を変更せずに変更を元に戻すため、git revertが役立つ理由です。

履歴でリセットを使用することは、実際には、共有されていないコミットのオプションのみです。

解決策-復帰を元に戻します。

マージコミットがすでに共有されている場合は、そのマージでgit revertを使用するのがおそらく最善の方法です。ただし、前に述べたように、単純にブランチをマージして、そのブランチからのすべての変更が再び表示されることを期待することはできません。答えは、コミットを元に戻すことです。

developでマージを実行した後、newfeatureブランチでいくつかの作業を行ったとしましょう。あなたの歴史はこのようなものになるでしょう。

         develop
            |
A---B---C---D
 \       \
  E---F---M---W
              |
         newfeature

ここでdevelopnewfeatureにマージすると、Dブランチの履歴にまだ含まれていない唯一のコミットであるため、newfeatureのみが取得されます。また、W commitを元に戻す必要があります。git revert Wは、git merge developの後に続くトリックを実行する必要があります。

                 develop
                    |
A---B---C-----------D
 \       \           \
  E---F---M---W---M---G
                      |
                 newfeature

これは、元のマージコミットによって行われたすべての変更を復元します。これらは実際にCBによって行われましたが、Wで元に戻されました。次に、新しいマージコミットDを介してGを取り込みます。元に戻すことをお勧めしますbefore = developへの最近の変更をマージします。この順序で行うと、競合を引き起こす可能性が低くなると思います。

TL; DR

元に戻すと、「コミットの元に戻す」が作成されます。復帰を取り消す場合、最初に復帰したときに作成された復帰コミットに対して復帰コマンドを実行する必要があります。簡単に見つけられるはずです。gitは復帰時に自動コメントする傾向があるため、「復帰」という単語で始まります。

git revert <commit>

54
eddiemoya

ハックな解決策を見つけました。しかし、それは機能します。

eddiemoya の回答が何であれ、まったく役に立ちます。説明ありがとうございます。私も同じような状況に遭遇しました。 git diff <branch>で多くのコンテンツを見ることができましたが、git mergeはすでに最新の状態でした。

また、ログには多くの復帰があったため、正確な復帰コミットを見つけることができませんでした。 (うん悪いこと。そもそも起こってはならないこと)

解決

git checkout branchX -- .

これにより、branchXから現在のブランチへのすべての変更がステージングされます。お気に入りのgitクライアントを使用して、意図しないものをアンステージングして元に戻します。

新しいコミットを作って幸せになる:)

2
Katti