一年くらい前から git を使い始め、ここ半年くらいは毎日の開発に git を使っています。昨日 git stash という機能を使っている時に失敗してしまい、何人かの方にアドバイスいただくことによって無事回復することが出来たので、感謝の印として、そして運悪く同じ問題に遭遇してしまった人たち(私もまたやるかも)へのメモとして記しておきます。





長く開発していると、結構多く候補が出てきます

いきさつ

私の作業のやりかたでは、 タスク毎にブランチを切って、タスクが終了したら master (svn の trunk のような立ち位置のブランチ) 、もしくはその時の開発の mainline (開発の中心となっているブランチ) にマージします。つまり、git 上で開発している時間の 95% くらいは、ブランチ上で過ごすことになります。多い日には一日に 4 本くらいのブランチを作成してはマージしています。master 上で開発は行わず、 master からは主に完成した機能のリリースのみを行います。

git stash という機能は、まだコミットするまでには至らない変更が手元にあるものの、別ブランチで緊急作業(例えば再リリース)が必要になったときなどに、手元の変更を一時退避しておき (git stash save) 、別の仕事が終わったときに退避した作業状態を復元できる (git stash pop) というかなり便利な機能です。

詳しくは、これらのリンクをどうぞ。



で、昨日も git stash を使いました。git stash を使うときは、たいてい急いでいるときです。昨日は master からのリリースに軽微な間違いがあり、すぐ修正しつつリリースしてからまた作業に戻ってきたいという局面でした。git stash save して手元の作業を退避してから master に戻ってリリースを行い、タスクブランチに戻ってきたときに git stash pop するつもりが (ヒストリから保管したからかもしれませんが) git stash clear してしまいました。

思わず Twitter にポストしたら、直後に @walf443 さんから救いのポストが。

git gcとかしてなければ、git fsckで頑張れば発掘できたような気もする http://twitter.com/walf443/status/1461741919



おおっと思い、git fsck stash でググってみたら、私と同じうっかりものが何人かいました。



上記リンクや man git-fsck などを見ていくつかの方法を検討しました。途中で @n_iwamatsu さん、@a_matsuda さんからもアドバイスをもらいました。ありがとうございます。

結果として、私は以下の方法で復旧を行うことが出来ました。(なお、この復旧方法は「まだ git gc していなければ」という条件つきのようです)

$ git fsck | awk ' /dangling commit/ {print $3} ' 候補の sha1 がいくつか出てくる ( 長く開発していると、結構多く候補が出てきます ) $ git show --summary 候補のsha1 一つ一つの sha1 の内容を確認 $ git cherry-pick -n -m1 見つけたsha1



git fsck で宙ぶらりんになっている変更の sha1 をリストアップし、 git show でその変更の中身を確認し、目的の sha1 を見つけたら git cherry-pick で適用する、という流れです。





