Web Marina

日々の業務や勉強などで得た知識をアウトプットしていきます。

【Git】git reset --hard HEADを取り消したい!!

f:id:song-of-life1352607:20180113002051p:plain

こんにちは、マリンです。

今日Gitでやらかしました。

表題の通りなのですが、それにプラスしてDBのロールバックとかも関わってきて、

「ギャーーーー!!!」

ってなったので残しておきます。





概要

やらかした内容が多すぎるので、時系列で箇条書きします。

  1. 新規でDBのテーブルを作成するのにrails g migration ~~で作ってしまった。

  2. テーブルを作った後しばらく作業を進めてからModelが無いことに気づく。(この間何度かcommitしてる)

  3. Modelだけ作れば良いところ、わざわざrake db:rollbackしようとした。

  4. だがロールバックする前に何を思ったかCommitをテーブル作る以前まで戻してしまった。

  5. しかもGitの取り消しをgit reset --hard HEAD@{n}でやってしまった。(ここが一番問題)

  6. ロールバックしようにも当然マイグレーションファイルまで消えてしまったのでできない。




やはり一番のやらかしポイントは、commitのやり直しで

git reset --hard HEAD@{n}

を使ってしまったことでしょう。

--hardオプションをつけると、ワーキングツリーまで変更されてします。

では、これに対する対処を次から書いていきます。


対処法

1、2、3まではおそらくModelファイルだけ作ってあげれば良かった話だと思うので省略します。

4、5、6について詳細と対処法を記載しようと思います。


そもそも何が起こったのか?

私が不用意に打ったgit reset --hard HEAD@{n}

これによって何が起こったのかを解説します。

飛ばしていただいて結構です。


$ git reset --hard HEAD^
  • git reset:これは任意のcommitを取り消すコマンドです。

  • --hard :resetコマンドのオプションです。コミットだけでなく、ワーキングツリーまで元の状態に書き換えます。

  • HEAD@{n} :HEADの位置をどこまで戻すかを指示しています。@{n}で遡ることn番目のcommitを表します。




問題は真ん中の--hardオプションです。

これによりワーキングツリーまで元の状態に戻ってしまったため、

テーブル作成のために書いたマイグレーションファイルまで消えてしまいました。

(今回はテーブル作成をする一つ前のコミットまで戻ったので・・・)

そしてこれをrake db:rollbackを実行する前にやってしまいました。

該当のマイグレーションファイルが無いのにロールバックしたってできるわけがありません。

なのでこの取り消し(git reset)を取り消して、マイグレーションファイルを復活させる!

それが今回の目標です。


ちなみに問題のオプションですが、

--softにを指定すればコミットだけをなかったことにしてくれます。

これにしていればアワアワすることもなかったでしょう・・・

他にもコミットとインデックスを取り消す--mixedもあります。

オプション無しのデフォルトもこれです。

こちらでより詳しく説明してくださっています。

[git reset (--hard/--soft)]ワーキングツリー、インデックス、HEADを使いこなす方法




コミット取り消しの取り消し

ここからが本題です。

消してしまった事実をなかったことにして、

マイグレーションファイルを復活させます。


$ git reflog
$ git reset --hard HEAD@{n}
$ git log

こちらが一連の流れです。

git reflog

まずどこまでコミットを戻すか履歴を見ます。

コマンドがgit logでない理由は、

リセットされたコミットはgit logの履歴に出てこないからです。

git reflogは消されたコミットも履歴として見ることができます。


git reset --hard HEAD@{n}

ここで取り消しを無かったことにします。

今回は--hardオプションで大丈夫です。

消えてしまったワーキングツリーのファイルを復活させたいので。

HEAD@{n}のnにはログで確認した該当コミットが現在地から何番目にあたるかの番号を入れてください。

reflogの時に番号入りで表示されるはずなのでわかりやすいと思います!


git log

最後に念のため確認をしましょう。

この場合はこちらの履歴で大丈夫です。

以上が解説になります。

なお、実例を交えたより詳しい説明をこちらでしてくださっていますので、

ぜひご覧ください。

git reset --hardした内容を取り消す (git reset --hard, reflog, HEAD@{x}, 取り消してしまったコミットを元に戻す) - いろいろ備忘録日記




まとめ

今までadd、commit、pushくらいしかやってこなかったGitです。

正直他のことはよくわからないから触りたく無かったし、

そもそも何ができるのかも曖昧でした。

しかし、今回初めて「履歴が残っている」ということの有り難みを感じました。

そしてむやみに手元まで変えてはならない!!ということも・・・

基本は--softでやるのが安全だし、一般的な様ですね。

大変勉強になりました!