作業ツリーの変更を保存および復元するために、git stash
およびgit stash pop
を頻繁に使用します。昨日、私は自分の作業ツリーにいくつかの変更を加え、それを隠してポップしました。それから作業ツリーにさらに変更を加えました。私は昨日の隠された変更を遡って復習したいのですが、git stash pop
は関連するコミットへのすべての参照を削除するようです。
私がgit stash
を使用する場合、 .git/refs/stashには、 stashを作成するために使用されたコミットの参照が含まれることがわかります。そして .git/logs/refs/stashは stash全体を含みます。しかし、それらの参照はgit stash pop
の後に消えています。コミットがまだ私のリポジトリのどこかにあることを私は知っていますが、それが何であるかはわかりません。
昨日のstash commit参照を簡単に回復する方法はありますか?
毎日のバックアップがあり、昨日の作業ツリーに戻って変更を反映できるため、これは今日の私にとっては重要ではありません。もっと簡単な方法がなければならないので私は尋ねています!
削除した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}'
...またはWindows用のPowershellを使用する:
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}' )
...または emraginsからの回答 Powershell for Windowsを使用している場合は/を参照してください。
これは、到達可能かどうかにかかわらず、リポジトリブラウザで リポジトリ内でコミットされたすべてのコミット を表示します。
別のGUIアプリケーションよりもコンソール上のNiceグラフを好む場合は、gitk
をgit log --graph --oneline --decorate
のようなものに置き換えることができます。
Stashコミットを見つけるには、次の形式のコミットメッセージを探してください。
WIPオン 多分岐: commithashいくつかの古いコミットメッセージ
注 :git stash
を実行したときにメッセージを指定しなかった場合、コミットメッセージはこの形式( "WIP on"で始まる)にのみなります。
端末を閉じなかった場合は、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
それを枝として持つことで、自由に操作することもできます。たとえば、チェリーピックやマージなどです。
承認されたソリューションへのこの追加について言及したいだけでした。私がこの方法を最初に試したときはすぐにはわかりませんでしたが(おそらくそうなっているはずですが)、ハッシュ値から隠し場所を適用するには、単に「git stash apply」を使用します。
$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219
私がgitに慣れていなかったとき、これは私には明らかではありませんでした、そして私は "git show"、 "git apply"、 "patch"などのさまざまな組み合わせを試していました。
まだリポジトリに残っているがもうアクセスできないstashのリストを取得するには
git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP
あなたがあなたの隠し場所にタイトルを付けた場合、コマンドの最後にある-grep=WIP
の "WIP"をあなたのメッセージの一部に置き換えてください。 -grep=Tesselation
。
隠し場所のデフォルトのコミットメッセージはWIP on mybranch: [previous-commit-hash] Message of the previous commit.
の形式になっているため、コマンドは "WIP"を使用しています。
失われた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
それが返すリストはかなり大きいかもしれませんが、git fsck --unreachable | grep commit
はsha1を表示するべきです。 git show <sha1>
は、それがあなたが望むコミットであるかどうかを示します。
git cherry-pick -m 1 <sha1>
はコミットを現在のブランチにマージします。
紛失した隠し場所を再度隠したい場合は、まず紛失した隠し場所のハッシュを見つける必要があります。
Aristotle Pagaltzisがgit fsck
があなたを助けるべきであると示唆したように。
個人的にはlog-all
エイリアスを使用して、すべてのコミット(回復可能なコミット)を表示して状況を把握しています。
git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)
「WIP on」メッセージだけを探している場合は、さらに高速な検索を実行できます。
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つのパイプでこれを行うより効率的な方法がおそらくありますが、これは仕事をします。
私はAristotleのアプローチが好きでしたが、GITKを使うのは好きではありませんでした。
代わりに、ダングリングコミットを行い、コードエディタで確認するためにコードを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
それならcommit-idが見つかったらgit stash applyを実行してください{commit-id}
これがすぐに誰かに役立つことを願っています
なぜ人々はこの質問をするのですか?なぜなら彼らはまだreflogについて知らないし理解していないからです。
この質問に対する回答のほとんどは、だれも覚えていないようなオプション付きの長いコマンドを提供します。それで人々はこの質問に入って、彼らが彼らが必要と思うものは何でもコピーペーストをコピーして、そしてほとんど直後にそれを忘れます。
私はこの質問をしている人全員に、reflog(git reflog)だけをチェックするように勧めます。それ以上のことはしません。すべてのコミットの一覧が表示されたら、探しているコミットを見つけてチェリーピックするか、そこからブランチを作成する100の方法があります。その過程で、reflogとさまざまな基本的なgitコマンドの便利なオプションについて学びました。
Gitkが利用できないか、出力にXがない場合に、すべての変更を確認するもう1つの良い方法を、承認済みの解決策に追加します。
git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits
for h in `cat tmp_commits`; do git show $h | less; done
それからそれらのハッシュのすべての差分が次々に表示されます。次の差分に移動するには 'q'を押してください。
単純なコマンドウィンドウ(私の場合は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
git stash apply (your hash)
最善の解決策ではないかもしれませんが、私のために働いた
あなたはターミナルでこのコマンドを書くことによってすべての到達不可能なコミットをリストすることができます -
git fsck --unreachable
到達不能なコミットハッシュを確認します -
git show hash
あなたが隠しアイテムを見つけた場合は最後に適用されます -
git stash apply hash
アリストテレスの承認された答えは、隠れていないようなコミットを含むすべての到達可能なコミットを表示します。ノイズを除去するには:
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つの親コミットを持つコミット(stashが持つもの)を含み、そのメッセージは "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
次の手順でそれを見つけました:
削除された隠し場所ハッシュコードを識別します。
gitk --all $(git fsck --no-reflog | awk '/ dangling commit/{print $ 3}')
チェリーピック・ザ・スタッシュ:
git cherry-pick -m 1 $ stash_hash_code
使用している場合は、競合を解決します。
git mergetool
さらに、あなたがgerritを使っているのならコミットメッセージに問題があるかもしれません。次の代替案に従う前に、変更を隠してください。
私がここで探していたのは、チェックアウトしたものに関係なく、実際にスタッシュを取り戻す方法です。特に、私は何かを隠し、それから古いバージョンをチェックアウトし、そしてそれをポップしました、しかしその隠し場所はその早い時点で何もしていなかったので隠し場所は消えました。 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.
私のお気に入りはこのワンライナーです:
git log --oneline $( git fsck --no-reflogs | awk '/dangling commit/ {print $3}' )
これは基本的に this answer と同じ考え方ですが、はるかに短いです。もちろん、--graph
を追加してツリーのような表示にすることもできます。
リストにコミットが見つかったら、次を使用して適用します
git stash apply THE_COMMIT_HASH_FOUND
私にとって、--no-reflogs
を使用すると、失われたstashエントリが明らかになりましたが、--unreachable
(他の多くの回答に見られるように)は見つかりませんでした。
Windowsの場合は、git bashで実行します。
クレジット:上記のコマンドの詳細は https://Gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bf