Gitでドロップした隠し場所を回復するにはどうすればよいですか?


1738

私は頻繁に使用するgit stashgit stash pop、私の作業ツリーの変更を保存して復元します。昨日、作業ツリーにいくつかの変更があり、それを隠してポップした後、作業ツリーにさらに変更を加えました。戻って昨日の隠された変更を確認したいのgit stash popですが、関連するコミットへのすべての参照を削除しているようです。

私が使用する場合git stash.git / refs / stashには、stashの作成に使用されたコミットの参照が含まれていることを知っています。また、.git / logs / refs / stashにはstash全体が含まれています。しかし、それらの参照は後になくなりましたgit stash pop。コミットがまだ私のリポジトリのどこかにあることは知っていますが、それが何であったかはわかりません。

昨日のstashコミット参照を回復する簡単な方法はありますか?

毎日のバックアップがあり、変更を取得するために昨日の作業ツリーに戻ることができるため、これは今日私にとって重要ではないことに注意してください。もっと簡単な方法があるに違いないので、私は尋ねています!


74
将来への注意:毎回の隠し場所を失いたくない場合git stash popは、git stash apply代わりに行うことができます。適用されたスタッシュへの参照を削除しないことを除いて、同じことを行います。
ケビン

3
ここですべてを試してみましたが、すでにポップされていた隠し場所は見つかりませんでした。IntelliJのjetbrains.com/help/idea/local-history.html
ファンメンデス


私はこの問題を抱えていました。私のレポを更新するには、私が走ったgit stashgit pull -r upstreamgit push -f origingit stash pop、、ポップは、「致命的な:ログはレフリーのために/スタッシュが空である」と述べました。theseこれらの答えをたくさん試しましたが、何もうまくいきませんでした。.git / refs / stashを調べたところ、SHAがそこにありました。Windowsネットワークドライブをオフライン同期用にマークする際に問題が発生する可能性がありますか?🤷‍♂️
brianary

回答:


2786

削除したstashコミットのハッシュがわかったら、それをstashとして適用できます。

git stash apply $stash_hash

または、別のブランチを作成して、

git branch recovered $stash_hash

その後は、通常のすべてのツールを使用して、好きなことを実行できます。終わったら、枝を吹き飛ばしてください。

ハッシュを見つける

ポップしたばかりでターミナルがまだ開いている場合は、画面にハッシュ値git stash popが表示されます(Doldaに感謝)。

それ以外の場合は、これをLinux、Unix、またはGit Bash for Windowsで使用して見つけることができます。

git fsck --no-reflog | awk '/dangling commit/ {print $3}'

...またはPowershell for Windowsを使用:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

これにより、ブランチまたはタグから参照されなくなったコミットグラフのヒントにあるすべてのコミットが表示されます。これまでに作成したすべてのstashコミットを含め、失われたコミットはすべて、グラフのどこかにあります。

必要なstashコミットを見つける最も簡単な方法は、おそらくそのリストをgitk次のように渡すことです。

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

...または、Powershell for Windowsを使用している場合は、emraginsからの回答を参照してください。

これにより、リポジトリブラウザが起動し、到達可能かどうかに関係なく、リポジトリ内のすべてのコミットが表示されます

別のGUIアプリよりもコンソールのグラフgitkを使いたいgit log --graph --oneline --decorate場合などに置き換えることができます。

stashコミットを見つけるには、次の形式のコミットメッセージを探します。

somebranchの         WIP :commithashいくつかの古いコミットメッセージ

:コミット時にメッセージを入力しなかった場合、コミットメッセージはこの形式になります(「WIPオン」で始まる)git stash


49
ジェイデルは私の言葉を口から出しました。この投稿は私の仕事を救いました:)私は追加したいだけです-あなたが失ったものに取り組んだ日付を覚えておくと、あなたが探しているもののためにgitkを閲覧するのが簡単になります。
Sridhar Sarnobat

4
@Codey:PowerShellだから。MsysGitがAWKバイナリを出荷するかどうかはわかりません。グーグルは、PowerShell でそのようなコマンド%{ $_.Split(' ')[2]; }と同等の処理を行う必要があることを教えてくれますが、それをテストするためのWindowsシステムがなく、その部分に相当するものが必要です。とにかく、実行して出力を確認します。「dangling commit <commitID>」行のハッシュが必要です。{print $3}awk/dangling commit/git fsck --no-reflog
アリストテレスPagaltzis

7
隠しておくときに(つまり、を実行してgit stash save "<message>")独自のメッセージを指定しなかった場合、コミットメッセージには文字列 "WIP"のみが含まれることに言及する価値があります。
Samir Aguiar

12
ドロップがいつ発生したかがわかっている場合は、このワンライナーを使用して、時間を増やすことでダングリングコミットのリストを取得できます。git fsck --no-reflog | awk '/dangling commit/ {print $3}' | xargs -L 1 git --no-pager show -s --format="%ci %H" | sort最後のエントリは、おそらく目的のエントリですstash apply
ris8_allo_zen0

3
git stash apply {ref}落ちた隠し場所を復元しました!gitとても素晴らしいので違法です!
トムラッセル

707

ターミナルを閉じなかった場合は、出力を確認するだけ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

ブランチとして持つことで、自由に操作することもできます。たとえば、チェリーピックやマージを行います。


54
git stash apply commitidその後git stash、新しい隠し場所を取得することもできます。
Matthew Flaschen

32
gitがstashを自動マージして競合がある場合、ハッシュは表示されないことに注意してください。
James

31
@ジェームズ:繰り返しになりますが、これらの競合がの実行の結果である場合、スタッシュgit stash popも削除されないので、通常は問題ありません。
Dolda2000 2013

2
私のgit stash pop出力にSHAがありませんでした。:(
アカウント

2
@ハニー:それがポイントですgit stash pop。スタッシュを落とさずに適用したい場合は、git stash apply代わりに使用してください。さらに、いくつかのブランチに変更を適用したい場合は、代わりにコミットをチェリーピックすることもできます。
Dolda2000

271

受け入れられたソリューションへのこの追加について言及したかっただけです。この方法を最初に試したときはすぐにはわかりませんでしたが(おそらくそうだったはずです)、ハッシュ値からスタッシュを適用するには、「git stash apply」を使用するだけです。

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

私がgitを初めて使用したときは、これははっきりしていませんでした。「git show」、「git apply」、「patch」などのさまざまな組み合わせを試しました。


3
これはスタッシュを現在の作業ツリーに適用することに注意してください。ツリーがダーティである場合、最初に一時的なブランチまたはスタッシュを使用し、SHA-1からスタッシュを適用し、スタッシュを再度行ってから、最後から2番目のスタッシュ(stash @ {1}と呼ばれる)をポップすることができます。
musiKk 2014年

111

リポジトリにまだ残っているが到達できなくなったスタッシュのリストを取得するには:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

stashにタイトルを付けた場合-grep=WIPは、コマンドの最後にある「WIP」をメッセージの一部に置き換えます-grep=Tesselation

stashのデフォルトのコミットメッセージは次の形式であるため、コマンドは「WIP」をgreppingします。 WIP on mybranch: [previous-commit-hash] Message of the previous commit.


1
echo 'git fsck --unreachable | grep commit | カット-d "" -f3 | xargs git log --merges --no-walk --grep = WIP '> / usr / local / bin / git-stashlog; chmod a + rx / usr / local / bin / git-stashlog#git stashlog
Erik Martino

または、これをエイリアスとして.gitconfigに追加できます(コマンドの前にを付けます!)。
asmeurer

私のベーコンを保存しました-実際はそうではありませんが、日々の作業を再コーディングすることを保存しました-感謝-最近ドロップしただけなので、コマンドの出力から一番上のSHAを選んだだけです-そしてgit stash apply SHA ...他の回答で述べたように-多くのthx
danday74

75

失ったstashコミットを見つけるのに役立つコマンドを作成しました。

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ツリー内のすべてのオブジェクトが一覧表示され、commitタイプのオブジェクトが特定され、各オブジェクトの概要が表示されます。この時点から、適切な「WIP on work:6a9bb2」を見つけるためにコミットを調べるだけの問題でした(「work」は私のブランチ、619bb2は最近のコミットです)。

「git stash pop」の代わりに「git stash apply」を使用すれば、この問題は発生しないことに注意してください。「git stash save message」を使用すると、コミットを見つけやすくなる可能性があります。

更新:Nathanのアイデアにより、これは短くなります:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less

41

git fsck --unreachable | grep commitsha1が表示されるはずですが、返されるリストは非常に大きくなる可能性があります。git show <sha1>必要なコミットかどうかが表示されます。

git cherry-pick -m 1 <sha1> コミットを現在のブランチにマージします。


37

gitkを使用した同等のWindows PowerShell:

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

おそらくこれを1つのパイプで行うより効率的な方法がありますが、これで十分です。


1
私はあなたの答えのために非常に感謝しています
ВиталийШебаниц

32

紛失したスタッシュを再保管する場合は、紛失したスタッシュのハッシュを最初に見つける必要があります。

アリストテレス・パガルツィスが示唆したように、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

2
ただし、それ-d\\ -d\ (またはさらに明確に-d' ')する必要があります
joeytwiddle

エラー:「致命的:あいまいな引数 'ダングリング':不明なリビジョンまたはパスが作業ツリーにありません。」
ダニエルライアン

また、サブコマンドを引用符でgit update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721
囲む

18

私はアリストテレスのアプローチが好きでしたが、コマンドラインからGITを使用するのに慣れているため、GITKを使用するのは嫌いでした。

代わりに、ダングリングコミットを取り、コードエディターで確認するためにコードをDIFFファイルに出力しました。

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

これで、結果のdiff / txtファイル(ホームフォルダーにあります)をtxtエディターにロードして、実際のコードと結果のSHAを確認できます。

次に、単に使用します

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

17

ターミナルでこのコマンドを書くことで、到達できないすべてのコミットを一覧表示できます-

git fsck --unreachable

到達不能なコミットハッシュをチェック-

git show hash

あなたが隠しておいたアイテムを見つけたら、最後に適用します-

git stash apply hash

15

なぜ人々はこの質問をするのですか?彼らはreflogについてまだ知らないか理解していないからです。

この質問に対するほとんどの回答は、誰も覚えていないオプションを含む長いコマンドを提供します。したがって、人々はこの質問に入り、必要なものは何でもコピーして貼り付け、ほとんどすぐに忘れてしまいます。

私はこの質問を持つすべての人にreflog(git reflog)だけをチェックするようにアドバイスします。すべてのコミットのリストが表示されたら、探しているコミットを見つけてチェリーピックするか、そこからブランチを作成するための100の方法があります。このプロセスでは、reflogと、さまざまな基本的なgitコマンドの便利なオプションについて学習しました。


1
こんにちは、ロビー。これは、あなたが働いていて脇道になっていて、数週間前に中断したところに戻る必要がある場合に関係します。隠された作業が見つからないことを知るためにのみ、おそらく他の場所で失われています。やっていました。reflogは、それが最近の履歴である場合は優れていますが、長い時間のギャップがある場合はそうではありません。
悲劇的な事

1
ちょっと悲惨だと思いますが、これはまさにOPのユースケースでした。ここに投稿されている他のコマンドがどのように動作するかはわかりませんが、隠されたコミットへの参照がクリーンアップされると、それらのコマンドも機能しなくなると思います。
RobbyD 2017

1
うーん...上記のシナリオがこの質問に私を導いたものでした、そして私が(無意識のうちに)隠し場所を失ってからそれを回復することができるまでの1ヶ月にさえ近づかなくても、少なくとも2週間でした。
悲劇的なもの

15

OS Xでgit v2.6.4を使用している場合、誤って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

次に、commit-idを見つけたら、git stash apply {commit-id}

これが誰かを素早く助けることを願っています


12

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'を押して次の差分に移動します。


12

単純なコマンドウィンドウでWindows(私の場合はWindows 7)で動作するように答えを得ることができませんでした。awkgrepおよび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)

最善の解決策ではないかもしれませんが、私にとってはうまくいきました


Windowsでもgit bashを使用できます。git bashには、必要な(unixoid)コマンドラインツールがすべて揃っています。
エイドリアンW

10

アリストテレスが承認した回答には、非スタッシュのようなコミットを含む、到達可能なすべてのコミットが表示されます。ノイズを除去するには:

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オン」が含まれているコミットのみが含まれます。

スタッシュをメッセージ(など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

6

私のお気に入りはこのワンライナーです:

git log --oneline  $( git fsck --no-reflogs | awk '/dangling commit/ {print $3}' )

これは基本的にこの回答と同じ考えですが、はるかに短いです。もちろん、追加--graphしてツリーのような表示にすることもできます。

リストでコミットを見つけたら、

git stash apply THE_COMMIT_HASH_FOUND

私にとって、を使用--no-reflogsすると、失われたstashエントリが明らかになり--unreachableましたが、(他の多くの回答で見られるように)明らかにしませんでした。

Windowsの場合は、git bashで実行してください。

クレジット:上記のコマンドの詳細はhttps://gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bfから取得されます


5

次の手順を使用してそれを回復しました:

  1. 削除されたstashハッシュコードを特定します。

    gitk --all $(git fsck --no-reflog | awk '/ dangling commit / {print $ 3}')

  2. チェリーピックスタッシュ:

    git cherry-pick -m 1 $ stash_hash_code

  3. 次の方法で競合を解決します。

    git mergetool

さらに、gerritを使用している場合、コミットメッセージで問題が発生する可能性があります。次の選択肢に従う前に、変更を隠しておいてください。

  1. 以前のコミットにハードリセットを使用してから、この変更を再コミットします。
  2. 変更を隠して、リベースして再コミットすることもできます。

@ miva2あなたの編集により、この質問の最も正しい答えへのリンクが削除されました。コメント内のリンクバックの追加stackoverflow.com/questions/89332/...
Abhijeet

4

私が探していたのは、チェックアウトしたものに関係なく、実際に隠しておく方法です。特に、何かを隠しておいた後、古いバージョンをチェックアウトして、それをポップしましたが、その隠し場所は、それ以前の時点では何もできなかったため、隠されていました。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 applynot を使用していたはず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.

これは答えですか、それとも質問の続きですか?
Alex Brown

両方のビット。隠し場所をなくし、元に戻そうとしたため、このページを見つけました。私のユースケースは、各ステップでテストする前に変更を適用したいという二分法を行っています。私はあなたがポップ、テスト、スタッシュ、バイセクトだけではできないという難しい方法を学びましたstash apply
2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.