隠し場所を開けて、マージの競合がありました。重複としてリストされている質問とは異なり、私はすでにディレクトリにいくつかのコミットされていない変更を保持したいと思っていました。マージの競合を解消するだけでなく、ディレクトリをポップ前の状態に戻したいと思います。
git merge --abort
を試しましたが、gitはマージが進行中でないと主張しました。ディレクトリに元々あった変更を破壊せずにポップを中止する簡単な方法はありますか?
OK、「git stash unapply」を実行したと思います。 git apply --reverse
によってマージが行われた場合にリバースマージアクションが必要になるため、git stash apply
よりも複雑です。
逆マージでは、現在のすべての変更をインデックスにプッシュする必要があります。
git add -u
次に、merge-recursive
によって行われたgit stash apply
を反転します。
git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1
これで、スタッシュ以外の変更のみが残ります。それらはインデックスに含まれます。必要に応じて、git reset
を使用して変更のステージングを解除できます。
元のgit stash apply
が失敗したことを考えると、元に戻したいもののいくつかが完了しなかったため、逆も失敗する可能性があります。
作業コピーが(git status
を介して)再びクリーンになる方法を示す例を次に示します。
$ git status
# On branch trunk
nothing to commit (working directory clean)
$ git stash apply
Auto-merging foo.c
# On branch trunk
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: foo.c
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git add -u
$ git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1
Auto-merging foo.c
$ git status
# On branch trunk
nothing to commit (working directory clean)
私のユースケース:間違ったブランチにポップしてみて、競合が発生しました。必要なのはポップを元に戻すことですが、それをスタッシュリストに保持して、正しいブランチにポップできるようにすることです。これは私がしました:
git reset HEAD --hard
git checkout my_correct_branch
git stash pop
簡単です。
編集:ポップセクションのgit help stash
ドキュメントから:
状態を適用すると、競合が発生して失敗する可能性があります。この場合、スタッシュリストからは削除されません。手動で競合を解決し、後で手動でgit stash dropを呼び出す必要があります。
--indexオプションを使用すると、作業ツリーの変更だけでなく、インデックスの変更も復元しようとします。ただし、競合(インデックスに格納されているため、元の変更を適用できなくなる)がある場合、これは失敗する可能性があります。
すべてのリポジトリを新しいディレクトリにハードコピーしてみて(そのコピーがあるように)、次を実行します。
git stash show
そして、気になったらその出力をどこかに保存します。
その後:git stash drop
競合するスタッシュをドロップし、その後:git reset HEAD
これにより、レポジトリは以前の状態のままになります(うまくいけば、私はまだ問題を再現できませんでした)
===
私はあなたの問題を再現しようとしていますが、git stash pop
を使用したときに得られるのは次のとおりです。
error: Your local changes to the following files would be overwritten by merge:
...
Please, commit your changes or stash them before you can merge.
Aborting
きれいなディレクトリで:
git init
echo hello world > a
git add a & git commit -m "a"
echo hallo welt >> a
echo hello world > b
git add b & git commit -m "b"
echo hallo welt >> b
git stash
echo hola mundo >> a
git stash pop
Gitが変更をマージしようとしていないのがわかりますが、失敗します。私たちがあなたを助けるために従うことができる再現手順がありますか?
他に行った変更について心配する必要がなく、最後のコミットに戻りたい場合は、次のようにできます。
git reset .
git checkout .
git clean -f
OK、私はあなたが必要な場所にあなたを戻すワークフローを見つけることができたと思います(まるであなたがポップをやっていなかったかのように)。
事前にバックアップしてください!!これがあなたのために働くかどうかはわかりませんので、うまくいかない場合に備えてレポジトリ全体をコピーしてください。
1)パッチから生じるすべての変更を選択して、マージの問題を修正し、すべての競合を修正します(tortoisemergeでは、one.REMOETE(それら)として表示されます)。
git mergetool
2)これらの変更をコミットします(mergetoolコマンドで既に追加されています)。 「マージ」またはあなたが覚えている何かのコミットメッセージを与えます。
git commit -m "merge"
3)これで、パッチからの新しいコミットを使用して、最初に開始したローカルのステージングされていない変更が残ります(これは後で削除できます)。ステージングされていない変更をコミットします
git add .
git add -u .
git commit -m "local changes"
4)パッチを元に戻します。これは、次のコマンドで実行できます。
git stash show -p | git apply -R
5)これらの変更をコミットします。
git commit -a -m "reversed patch"
6)パッチ/アンパッチのコミットを取り除く
git rebase -i HEAD^^^
これから、「merge」と「reversed patch」が含まれる2行を削除します。
7)スタンジングされていない変更を元に戻し、「ローカル変更」コミットを取り消します
git reset HEAD^
簡単な例を使って説明しました。スタッシュがポップされる直前、ローカルの変更、スタッシュがまだポップできる状態に戻ります。
これをやや異なる方法で解決しました。ここで何が起こったのかです。
最初に、間違ったブランチにポップして競合が発生しました。隠し場所はそのまま残りましたが、インデックスは競合解決にあり、多くのコマンドをブロックしました。
単純なgit reset HEAD
は競合の解決を中止し、コミットされていない(および不要な)変更を残しました。
いくつかのgit co <filename>
がインデックスを初期状態に戻しました。最後に、git co <branch-name>
を使用してブランチを切り替え、新しいgit stash pop
を実行しました。これは競合なしに解決されました。
いくつかのアイデア:
git mergetool
を使用して、マージファイルを元の部分と新しい部分に分割します。願わくば、それらの1つが、非stashの変更を含むファイルです。
これらの変更のみを元に戻すには、隠し場所の差分を逆に適用します。おそらく、マージの競合があるファイルを手動で分割する必要があります(これがうまくいけば上のトリックがうまくいきます)。
私はこれらのいずれもテストしなかったので、それらが機能するかどうかはわかりません。
コミットされていない変更を加えて、「ダーティ」ディレクトリでgit stash pop
をきれいに再現できましたが、まだマージ競合を生成するポップはありませんでした。
Ifマージの競合で、適用しようとしたスタッシュが消えなかった場合、git show stash@{0}
(オプションで--ours
または--theirs
)を調べて比較することができます。 git statis
およびgit diff HEAD
。スタッシュの適用によってどの変更が行われたかを確認できるはずです。
マージの競合のためにスタッシュがポップされなかったというDavidGが正しい場合、作業ディレクトリをクリーンアップするだけで済みます。すぐにgit commit
気になります。 (完了しない場合は、後でコミットをreset
またはsquash
することができます。)その後、あなたが安全に気を配るすべてのことで、git reset
git stash pop
があなたの作業にダンプしますディレクトリ。
git reflog
を使用して、git履歴で行われたすべての変更を一覧表示します。アクションIDをコピーしてgit reset ACTION_ID
と入力します
質問のように、git stash pop
の前に段階的な変更がなかった場合、次の2つのコマンドが機能するはずです。
git diff --name-only --cached | xargs git checkout --ours HEAD
git ls-tree stash@{0}^3 --name-only | xargs rm
1つ目は、成功したかどうかにかかわらず、スタッシュからのマージを取り消します。 2番目は、stashによって導入された追跡されていないファイルを削除します。
man git stash
から:The working directory must match the index.
@DavidGが指摘するように、現在ステージ化されていない変更されたファイルが競合する場合、stash pop
は失敗します。そのため、HEAD
に戻る以外に、マージの競合を解消することを心配する必要はありません。残りの変更されたファイルはスタッシュとは無関係であり、stash pop
の前に変更されました
段階的な変更があった場合、同じコマンドに依存できるかどうかは不明であり、@ Ben Jacksonのテクニックを試してみてください。提案に感謝します。
以下は、さまざまなケースすべてのテスト設定です https://Gist.github.com/here/4f3af6dafdb4ca15e804
# Result:
# Merge succeeded in m (theirs)
# Conflict in b
# Unstaged in a
# Untracked in c and d
# Goal:
# Reverse changes to successful merge m
# Keep our version in merge conflict b
# Keep our unstaged a
# Keep our untracked d
# Delete stashed untracked c
他の人が私の答えを見つけてくれることを期待して、ここに投稿しています。隠していたブランチとは異なるブランチでスタッシュポップを実行しようとしたときに、同様の問題が発生しました。私の場合、コミットされていないファイルやインデックスにあるファイルはありませんでしたが、それでもマージ競合のケースになりました(@pidと同じケース)。他の人が以前に指摘したように、失敗したgit stashポップは実際に私の隠し場所を保持し、それからクイックgitリセットHEADプラス元のブランチに戻ってそこから隠蔽することで問題が解決しました。