Closed14

突然Gitが死んだので緊急復旧作業に入る

ONOYAMA ShodaiONOYAMA Shodai

ターミナルのカレントブランチの表示が消えていたので、試しにgit statusしてみたら、マジかよ…

Gitの実態がオブジェクトファイルであることはなんとな~く知っていたので、この段階で「本来あるべきオブジェクトファイルが何らかの原因で無効になっている」と気づきました。

ONOYAMA ShodaiONOYAMA Shodai

とりあえず.git/objects/a7を見てみます。

オブジェクトファイルって複数あり得るんすか。とりあえずガッツリ怒られている8c5e...を削除します。
そしたら

まあオブジェクトファイル消したからそうなるよなー

ONOYAMA ShodaiONOYAMA Shodai

まてよ、bad object HEADってことは、今まで8c5e...がHEADだったってことか。
だったら、HEADを一つ前のコミットに戻せばいいのでは?
つまり、HEADが指す対象を一つ前のコミットのオブジェクトファイルにすればいいのでは??

ONOYAMA ShodaiONOYAMA Shodai

.git内を見てみると、なんかrefsとかいうそれっぽいディレクトリがあるので、それを見ていく。

めちゃめちゃheadが匂う。ということで見てみると、これブランチ名ですね。

作業していたブランチ名のrecreate-the-projectを見てみる。

32cb9bd4aeae9e3f4d0d9fb4ea1c2e390ae3701f

これ、明らかにコミットのオブジェクトファイル名ですよね。

ONOYAMA ShodaiONOYAMA Shodai

.git内のlogsディレクトリを見てみたら、

このうち、refsは多分さっきみたいな感じだと思う。HEADの方を見てみるか。

見せられないよ!

ちょっと公開するとマズい情報がたくさんあったんですが、このHEADファイルが、今までのコミットを記録してくれていました。git logみたいな感じです。
なので、このログを見る限り最新のコミットのキーを、さっきのrefs内のrecreate-the-projectに書けばいいのでは?

ONOYAMA ShodaiONOYAMA Shodai

と思ったら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を叩くとリポジトリの整合性を評価してくれる。つまり、壊れている箇所があったら教えてくれる。

ONOYAMA ShodaiONOYAMA Shodai

git cat-fileでGitのオブジェクトを調べます。-tでオブジェクトのタイプを、-pで中身を見れるらしいです。
んー、これ消していいよな?

ONOYAMA ShodaiONOYAMA Shodai

エラー吐いてたGitオブジェクトを消しました。今の所問題はないな…

ONOYAMA ShodaiONOYAMA Shodai

明らかにこのa7ebaf42fba5c1eebaca5153e597a194b0632bbdが悪さをしている。このオブジェクトをどうにかせねば。

ONOYAMA ShodaiONOYAMA Shodai

.git/refs/headsの中に何もファイルが無いの多分おかしい。branchに関するファイルがここにあるはずなのにない。

ONOYAMA ShodaiONOYAMA Shodai

git rm --cachedでindex変更すればいい説が出てきたのでやってみる。
さすがに全部壊れるのは嫌なので、バックアップを取っておく。
git rm -r --cached .で一回ファイルの追跡を消す。

git ls-files -cgit ls-files --stageも表示されなかったのでよさそう

ONOYAMA ShodaiONOYAMA Shodai

最終的に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の内部実装の知識も得られたので、僕的には満足です。

おわり!

このスクラップは2021/09/25にクローズされました