突然Gitが死んだので緊急復旧作業に入る
ターミナルのカレントブランチの表示が消えていたので、試しにgit status
してみたら、マジかよ…
Gitの実態がオブジェクトファイルであることはなんとな~く知っていたので、この段階で「本来あるべきオブジェクトファイルが何らかの原因で無効になっている」と気づきました。
とりあえず.git/objects/a7
を見てみます。
オブジェクトファイルって複数あり得るんすか。とりあえずガッツリ怒られている8c5e...
を削除します。
そしたら
まあオブジェクトファイル消したからそうなるよなー
まてよ、bad object HEAD
ってことは、今まで8c5e...
がHEADだったってことか。
だったら、HEADを一つ前のコミットに戻せばいいのでは?
つまり、HEADが指す対象を一つ前のコミットのオブジェクトファイルにすればいいのでは??
.git
内を見てみると、なんかrefs
とかいうそれっぽいディレクトリがあるので、それを見ていく。
めちゃめちゃhead
が匂う。ということで見てみると、これブランチ名ですね。
作業していたブランチ名のrecreate-the-project
を見てみる。
32cb9bd4aeae9e3f4d0d9fb4ea1c2e390ae3701f
これ、明らかにコミットのオブジェクトファイル名ですよね。
.git
内のlogs
ディレクトリを見てみたら、
このうち、refs
は多分さっきみたいな感じだと思う。HEAD
の方を見てみるか。
見せられないよ!
ちょっと公開するとマズい情報がたくさんあったんですが、このHEAD
ファイルが、今までのコミットを記録してくれていました。git log
みたいな感じです。
なので、このログを見る限り最新のコミットのキーを、さっきのrefs
内のrecreate-the-project
に書けばいいのでは?
コミットできました!俺の勝ち!
と思ったらremoteにpushできない。pushしようとするとこんなメッセージが出る。
fatal: bad tree object XXXXXXXXXX.....
error: remote unpack failed: eof before pack header was fully read
To github.com:hogehoge/piyopiyo.git
! [remote rejected] recreate-the-project -> recreate-the-project (failed)
error: failed to push some refs to 'git@github.com:hogehoge/piyopiyo.git'
git fsck
を叩くとリポジトリの整合性を評価してくれる。つまり、壊れている箇所があったら教えてくれる。
git cat-file
でGitのオブジェクトを調べます。-t
でオブジェクトのタイプを、-p
で中身を見れるらしいです。
んー、これ消していいよな?
エラー吐いてたGitオブジェクトを消しました。今の所問題はないな…
明らかにこのa7ebaf42fba5c1eebaca5153e597a194b0632bbd
が悪さをしている。このオブジェクトをどうにかせねば。
.git/refs/heads
の中に何もファイルが無いの多分おかしい。branchに関するファイルがここにあるはずなのにない。
ちょっとここを見てみるよ。
git rm --cached
でindex変更すればいい説が出てきたのでやってみる。
さすがに全部壊れるのは嫌なので、バックアップを取っておく。
git rm -r --cached .
で一回ファイルの追跡を消す。
git ls-files -c
もgit ls-files --stage
も表示されなかったのでよさそう
最終的にpushができたんでメモ。
まず、現在のディレクトリのgit追跡をすべて打ち消す。
git rm --cached .
この打消しの作業をコミットする。
git commit -m "message"
そして以下のコマンドを叩く
git write-tree
git commit-tree <hash> -m "message"
git update-ref refs/heads/<branch> <hash>
ただしこのコマンドはtreeオブジェクトを新しく置き換えるので、今までのコミットが全部消えます。実際消えました。なので、新しくgit init
するのと変わらないんじゃねえのと思うかもしれません。ただ「git本体が壊れた」なんてそうそうない現象ですし、gitの内部実装の知識も得られたので、僕的には満足です。
おわり!