私はもともと 'newfeature'ブランチで作業しており、ライブブランチのバグを緊急に修正するように依頼されました。 「generalmaintenance」というブランチを作成し、ジョブを実行してから、開発とマージに切り替えました。次に、「newfeature」ブランチに戻り、以前にマージした変更をマージします。
「newfeature」に切り替えて「develop」でマージすると、3つのファイルで競合が発生しました。
私は衝突を解決するために葛藤し、最終的にAptana Studio 3(私のIDEです)の[チーム]メニューの[元に戻す]コマンドを使用することにしました。これにより、マージが行われる前の状態にロールバックされると期待していました。
とにかく、再び「開発」にマージすると、Already-up-to-date
、ただし2つのブランチ間でファイルを比較する場合、それらは非常に異なり、他のブランチで追加した変更はマージされません。
どうすれば2つのブランチをマージできますか?
マージの復帰とマージのリセット
私の推測では、あなたは実際にはareAlready-up-to-date
です。
問題は git revert がマージを取り消すのではなく、マージによってもたらされた変更を取り消すことだけです。マージコミットを作成すると、これら2つのブランチのコミット履歴が結合されます。
マージ
develop
|
A---B---C
\ \
E---F---M
|
newfeature
上記の場合、develop
がnewfeature
にマージされ、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
を実行した場合、コミットされるのはF
、E
、および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
ここでdevelop
をnewfeature
にマージすると、D
ブランチの履歴にまだ含まれていない唯一のコミットであるため、newfeature
のみが取得されます。また、W
commitを元に戻す必要があります。git revert W
は、git merge develop
の後に続くトリックを実行する必要があります。
develop
|
A---B---C-----------D
\ \ \
E---F---M---W---M---G
|
newfeature
これは、元のマージコミットによって行われたすべての変更を復元します。これらは実際にC
とB
によって行われましたが、W
で元に戻されました。次に、新しいマージコミットD
を介してG
を取り込みます。元に戻すことをお勧めしますbefore = develop
への最近の変更をマージします。この順序で行うと、競合を引き起こす可能性が低くなると思います。
TL; DR
元に戻すと、「コミットの元に戻す」が作成されます。復帰を取り消す場合、最初に復帰したときに作成された復帰コミットに対して復帰コマンドを実行する必要があります。簡単に見つけられるはずです。gitは復帰時に自動コメントする傾向があるため、「復帰」という単語で始まります。
git revert <commit>
ハックな解決策を見つけました。しかし、それは機能します。
eddiemoya の回答が何であれ、まったく役に立ちます。説明ありがとうございます。私も同じような状況に遭遇しました。 git diff <branch>
で多くのコンテンツを見ることができましたが、git mergeはすでに最新の状態でした。
また、ログには多くの復帰があったため、正確な復帰コミットを見つけることができませんでした。 (うん悪いこと。そもそも起こってはならないこと)
解決
git checkout branchX -- .
これにより、branchXから現在のブランチへのすべての変更がステージングされます。お気に入りのgitクライアントを使用して、意図しないものをアンステージングして元に戻します。
新しいコミットを作って幸せになる:)