originがhttps://github.com/[username]/[reponame]というgithub上で管理しているリモートリポジトリだとする。
ここで誰かが間違えて、必要な変更を失ってしまうようなgit push -f origin masterをやってしまった場合の話。
force-pushed branch master of [username]/[reponame] from 1e6753 to 8cec0c
8cec0cではなく1e6753の状態に戻したいが、1e6753は誰のローカルにも存在しなく、github上でもタグや名前が付けられてないのでfetchしてくることが出来ないとする。
https://github.com/[username]/[reponame]/commit/1e6753
にアクセスすれば、1e6753がどんなコミットであったか分かる。
ここでは、1e6753が255番目のMerge Pull Requestだと分かったとする。
直接、masterにpushするというような運用をしていななければ、たいてい最新のmasterは何らかのMerge Pull Request後であると思う。
$ git ls-remote origin
でremote originにある全てのreferenceがわかり、Github上にはref/pull/番号/mergeとref/pull/番号/headが全てのpull requestに対してあるというのがわかる。
これらは全てローカルにfetchしてくることが出来るので、あとは
$ git fetch origin refs/pull/255/merge
From github.com:[username]/[reponame]
* branch refs/pull/255/merge -> FETCH_HEAD
$ git checkout FEACH_HEAD
$ git checkout -b old_master
$ git log (確認)
$ git push -f origin old_master:master
とやれば1e6753と同じ内容にmasterが戻る。
実例で説明できない分ちょっとわかりにくくなってしまったが、これは実際に起った問題で、意外とWeb上に情報がない問題だったりする。実際にこうやることで直せたので誰かの役に立つことを期待。push -fはたまに必要だったりするけど怖い・・・。