gitでコミット済のファイルを消去後に復活させる

最近は http://bitbacket.org/ を利用してプロジェクト関連のファイルを全てレポジトリに保存しているのだが、昨日コミット&プッシュの後に誤ってファイルを別の内容で上書きしてしまった。

はいはい、こういうときには簡単に復活できるんだよね、と思いその方法を探ってみると‥。

意外と手間のかかる操作ということが判明したので、備忘録を兼ねて記録しておくことにした。情報源はこちらこちら
一度コミット&プッシュすればレポジトリにその内容は保存されているので、復活させること自体は当然出来るのだが、そのために必要な処理は大きく分けると二つある。一つはファイルを復活させることであり、そしてもう一つは、復活後に引き続き作業結果を滞り無くコミット&プッシュするための準備作業である。これを忘れると、以後、コミットは問題無いが、プッシュしても「Everything up-to-date」と表示され続けることになる。

ファイルの復活

以下の要領で、消去したファイルの最後のコミットIDを取得する。

git rev-list -n 1 HEAD -- < 消去したファイルパス>

そのIDを利用して次のコマンドを発行する。

git checkout < コミットID>^ -- < 消去したファイルパス>

以上の2階の操作を一回で済ます方法は以下の通り。

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

以上で無事復活。ただし、タイムスタンプは戻らないようだ。

その後の作業

そしてファイル復活後に忘れずに行う作業は以下の通り。

1. 最初に一時ブランチを作る。これでファイル復活時に行った、どこにも関連づいていないHEADという抽象的な名を持つコミットがこの一時ブランチに向けられる。

git branch temp
git checkout temp

上記二回の操作は以下の一度の操作に置き換え可能。

git checkout -b temp

2. 続いて本来のブランチとの比較をして問題ないことを確認する。

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

3. そして本来のブランチが一時ブランチを指すようにする。

git branch -f master temp
git checkout master

上記二回の操作は以下の一度の操作に置き換え可能。

git checkout -B master temp

4. 最後に一時ブランチを削除して、

git branch -d temp

レポジトリにプッシュする。

git push origin master