Git でドロップされたスタッシュを回復するにはどうすればよいですか?
質問
私は頻繁に使用します git stash
そして git stash pop
作業ツリーの変更を保存して復元します。昨日、隠してポップしていた作業ツリーにいくつかの変更を加え、その後、作業ツリーにさらに変更を加えました。昨日の隠し変更をもう一度見直したいのですが、 git stash pop
関連するコミットへの参照をすべて削除するようです。
使えばわかる git stash
それから .git/refs/stash には以下が含まれます スタッシュの作成に使用されるコミットの参照。そして .git/logs/refs/stash には以下が含まれます 隠し場所全体。しかし、それらの参照はその後失われています git stash pop
. 。コミットがまだリポジトリのどこかにあることはわかっていますが、それが何だったのかはわかりません。
昨日のスタッシュコミット参照を復元する簡単な方法はありますか?
私は毎日バックアップを取っており、昨日の作業ツリーに戻って変更を取得できるため、これは今日の私にとって重要ではないことに注意してください。もっと簡単な方法があるはずなので質問しました!
解決
ドロップした stash コミットのハッシュがわかったら、それを stash として適用できます。
git stash apply $stash_hash
または、次のようにして別のブランチを作成することもできます。
git branch recovered $stash_hash
その後は、通常のツールを使って何でもできるようになります。終わったら、枝を吹き飛ばすだけです。
ハッシュを見つける
ポップしたばかりでターミナルがまだ開いている場合は、 によって出力されたハッシュ値がまだ残っています git stash pop
画面上で (ありがとう、ドルダ)。
それ以外の場合は、Linux、Unix、または Windows の Git Bash を使用して見つけることができます。
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
...または Windows 用 Powershell を使用する場合:
git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}
これにより、どのブランチやタグからも参照されなくなった、コミット グラフの先端にあるすべてのコミットが表示されます。これまでに作成したすべてのスタッシュ コミットを含む、失われたすべてのコミットは、そのグラフのどこかに存在します。
必要な stash コミットを見つける最も簡単な方法は、おそらくそのリストを gitk
:
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
...または参照してください エムラギンスからの答え Windows 用 Powershell を使用している場合。
これにより、リポジトリ ブラウザが起動し、次の内容が表示されます。 リポジトリ内のすべてのコミット, 到達可能かどうかは関係ありません。
交換できます gitk
そこに次のようなものがあります git log --graph --oneline --decorate
別の GUI アプリよりもコンソール上に見栄えの良いグラフを表示したい場合。
隠しコミットを特定するには、次の形式のコミット メッセージを探します。
WIP オン どこかの枝: commithash 古いコミットメッセージ
注記:コミットメッセージは、メッセージを指定しなかった場合にのみ、この形式 (「WIP on」で始まる) になります。 git stash
.
他のヒント
ターミナルを閉じていない場合は、からの出力を見てください。 git stash pop
これで、ドロップされた隠し場所のオブジェクト ID がわかります。通常は次のようになります。
$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)
(ご了承ください git stash drop
も同じ行を生成します。)
その隠し場所を取り戻すには、実行するだけです git branch tmp 2cae03e
, 、そしてそれをブランチとして取得します。これを隠し場所に変換するには、次を実行します。
git stash apply tmp
git stash
これをブランチとして持つと、自由に操作することもできます。たとえば、それを厳選したりマージしたりすることができます。
受け入れられたソリューションへのこの追加について言及したかっただけです。初めてこの方法を試したときはすぐにはわかりませんでしたが (おそらくそうなるべきだったでしょう)、ハッシュ値から stash を適用するには、「git stash apply」を使用するだけです。
$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219
私が git を初めて使用したときは、これがよくわからず、「git show」、「git apply」、「patch」などをさまざまに組み合わせて試していました。
リポジトリ内にまだ存在するが、もうアクセスできないスタッシュのリストを取得するには、次のようにします。
git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP
スタッシュにタイトルを付けた場合は、「WIP」を置き換えてください。 -grep=WIP
コマンドの最後にメッセージの一部を追加します。例: -grep=Tesselation
.
スタッシュのデフォルトのコミットメッセージは次の形式であるため、コマンドは「WIP」を grep します。 WIP on mybranch: [previous-commit-hash] Message of the previous commit.
失われた隠しコミットを見つけるのに役立つコマンドを作成しました。
for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less
これにより、.git/objects ツリー内のすべてのオブジェクトがリストされ、コミット タイプのオブジェクトが特定され、それぞれの概要が表示されます。この時点からは、コミットを調べて適切な「作業中の WIP:6a9bb2" (「work」は私のブランチ、619bb2 は最近のコミットです)。
「git stash Pop」の代わりに「git stash apply」を使用すると、この問題は発生しないことに注意してください。また、「git stash save」を使用すると、この問題は発生しません。 メッセージ" そうすれば、コミットを見つけやすくなるかもしれません。
アップデート:ネイサンのアイデアでは、これはさらに短くなります。
for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
git fsck --unreachable | grep commit
sha1 が表示されるはずですが、返されるリストは非常に大きい可能性があります。 git show <sha1>
必要なコミットかどうかが表示されます。
git cherry-pick -m 1 <sha1>
コミットを現在のブランチにマージします。
失われたスタッシュを再スタッシュしたい場合は、まず失われたスタッシュのハッシュを見つける必要があります。
アリストテレス・パガルツィスが示唆したように、 git fsck
あなたを助けるはずです。
個人的に私は私のものを使用しています log-all
状況をよりよく把握するために、すべてのコミット (回復可能なコミット) を表示するエイリアス:
git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)
「WIP オン」メッセージのみを検索する場合は、さらに高速な検索を実行できます。
sha1 がわかったら、stash reflog を変更して古い stash を追加するだけです。
git update-ref refs/stash ed6721d
おそらくメッセージを関連付けたいと思うでしょう。 -m
git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d
そして、これをエイリアスとして使用することもできます。
restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1
gitk を使用した Windows PowerShell と同等の機能:
gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })
おそらくこれを 1 つのパイプで行うより効率的な方法がありますが、これで十分です。
私はアリストテレスのアプローチは好きでしたが、GITK を使用するのは好きではありませんでした...コマンドラインから GIT を使用することに慣れているためです。
代わりに、未解決のコミットを取得し、コード エディターでレビューできるようにコードを DIFF ファイルに出力しました。
git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff
これで、結果の diff/txt ファイル (ホーム フォルダーにある) を txt エディターにロードして、実際のコードと結果の SHA を確認できるようになります。
あとは使用するだけです
git stash apply ad38abbf76e26c803b27a6079348192d32f52219
git v2.6.4 を搭載した OSX で、誤って git stash Drop を実行してしまい、以下の手順で見つけました。
スタッシュの名前がわかっている場合は、次を使用します。
$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>
それ以外の場合は、次のように手動で結果から ID を見つけます。
$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show
次に、コミット ID を見つけたら、git stash apply {commit-id} をヒットします。
これが誰かにすぐに役立つことを願っています
なぜ人々はこの質問をするのでしょうか?なぜなら、彼らはまだreflogについて知らない、または理解していないからです。
この質問に対するほとんどの回答は、ほとんど誰も覚えていないオプションを含む長いコマンドを提供します。したがって、人々はこの質問に来て、必要だと思うものをすべてコピーペーストし、その直後に忘れてしまいます。
この質問をした人には、reflog (git reflog) を確認するだけで、それ以上はしないことをお勧めします。すべてのコミットのリストが表示されたら、探しているコミットを見つけて、それを選択したり、そこからブランチを作成したりするための 100 の方法があります。その過程で、reflog とさまざまな基本的な git コマンドの便利なオプションについて学びました。
ターミナルに次のコマンドを記述することで、到達不能なコミットをすべてリストできます。
git fsck --unreachable
到達不能なコミットハッシュを確認する -
git show hash
隠しアイテムを見つけたら最後に申請してください -
git stash apply hash
利用可能な gitk がない場合、または出力用の X がない場合に、すべての変更を実行するための別の良い方法を、受け入れられたソリューションに追加したいと思います。
git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits
for h in `cat tmp_commits`; do git show $h | less; done
次に、次々に表示されるそれらのハッシュの差分をすべて取得します。次の差分に移動するには、「q」を押します。
アリストテレスによる受け入れられた回答では、非スタッシュのようなコミットを含む、到達可能なすべてのコミットが表示されます。ノイズを除去するには:
git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
--grep="WIP on" --min-parents=3 --max-parents=3
これには、ちょうど 3 つの親コミット (スタッシュに含まれる) があり、そのメッセージに「WIP on」が含まれるコミットのみが含まれます。
スタッシュをメッセージとともに保存した場合 (例: git stash save "My newly created stash"
)、これはデフォルトの「WIP on...」メッセージをオーバーライドします。
各コミットに関する詳細情報を表示できます。コミットメッセージを表示するか、それを渡します git stash show
:
git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
--grep="WIP on" --min-parents=3 --max-parents=3 | \
xargs -n1 -I '{}' bash -c "\
git log -1 --format=medium --color=always '{}'; echo; \
git stash show --color=always '{}'; echo; echo" | \
less -R
単純なコマンド ウィンドウ (私の場合は Windows 7) で Windows 上で動作させるための答えは何も得られませんでした。 awk
, grep
そして Select-string
コマンドとして認識されませんでした。そこで、別のアプローチを試してみました。
- ファーストラン:
git fsck --unreachable | findstr "commit"
- 出力をメモ帳にコピーする
- 「到達不能なコミット」を検索して次のように置き換えます
start cmd /k git show
次のようになります:
start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4
start cmd /k git show 44078733e1b36962571019126243782421fcd8ae
start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1
start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e
- .bat ファイルとして保存して実行します
- スクリプトは多数のコマンド ウィンドウを開き、各コミットを表示します。
- 探しているものが見つかった場合は、次を実行します。
git stash apply (your hash)
最良の解決策ではないかもしれませんが、私にとってはうまくいきました
私がここに来たのは、何をチェックしたかに関係なく、実際に隠し場所を取り戻す方法です。特に、私は何かを隠してから古いバージョンをチェックアウトしてからそれをポップしましたが、その前の時点では隠しは何も操作されなかったため、隠しは消えてしまいました。ただできなかった git stash
スタックにプッシュして戻します。これは私にとってはうまくいきました:
$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^ # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.
振り返ってみると、使用すべきでした git stash apply
ない git stash pop
. 。をやっていた bisect
毎回適用したい小さなパッチがありました bisect
ステップ。今、私はこれをやっています:
$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.
次の手順で回復しました。
削除された stash ハッシュ コードを特定します。
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
隠し場所を厳選してください:
git Cherry-pick -m 1 $stash_hash_code
競合がある場合は、以下を使用して解決します。
git マージツール
さらに、gerrit を使用している場合は、コミット メッセージで問題が発生する可能性があります。次の代替手段に従う前に、変更を隠してください。
- ハード リセットを使用して以前のコミットを行ってから、この変更を再コミットします。
- 変更を隠し、リベースし、再コミットすることもできます。
GitUP アプリのスタッシュを誤って削除してしまいました。元に戻すには、Ctrl+Z を押すだけです。
たぶんそれは誰かを助けるでしょう;)