人間誰しも間違えを犯す。今回は間違えて作業をしてしまった場合に1つ前の状態に戻す方法を学習していこう。
準備
まずは以下のようにデスクトップに実験用のフォルダgittutorを作成し、そのなかに
こんにちは
という1行書かれたfile1.txtを作成しコミットしよう。
$ cd ~/desktop
$ mkdir gittutor
$ cd gittutor
$ git init
$ echo "こんにちは" >> file1.txt
$ git add .
$ git commit -m"first-commit"
間違えを犯す
意図的にミスを犯そう、以下のように入力してmistakeとかかれた1行を追加する。
$ echo "mistake" >> file1.txt
git statusをしてみよう。変更されたファイルとして認識されている。

checkout ファイル名
この状態からもとの状態に戻すには。以下のコマンドで行う
$ git checkout file1.txt
これで最新のコミットからfile1.txtを持ってきて置き換えてくれる。つまりmistakeという1行がない状態になる。
statusをしてみよう。

前回のコミットとの差分がなくなったのでcleanと表示されている。
これでOKなのだが、最近はこれと同様の作業を以下のようなrestoreコマンド使っても行える。今後はこちらに置き換わっていく流れなのでどちらも使えるようにしておくとよいだろう。
$ git restore file1.txt
reset –hard
先程はコミット前の状態だったがコミットをしたあとに取り消したい場合もある、ctrl+zのごとくそのコミットがまったくない以前の状態にもどすのがreset –hardださきほどの続きから以下を入力しよう。
$ echo "mistake" >> file1.txt $ git commit -am"second commit"
-am オプションを使うとaddとcommitを一度に行える。
しかし、この変更は全く不要だったことに気づく。
ctrl+zのごとく以前の状態にもどりたい。
そういった場合は以下のコマンド打つ。
$ git reset --hard HEAD~
これでさきほどの間違えたコミットは消え去り、ファイルの内容からもmistakeという文字が消えた。つまり今回の作業をする前の状態に全てが戻ったということだ。
HEADというのは現在のブランチの最新のコミットを指すポインタで、これに~(チルダ)をつけることで一つ前のコミットを指すことができる。
その結果,一つ前のコミットの状態に作業フォルダも含めてリセットされた。
ちなみにHEAD~2と~の後ろに数字をつけることでもっと過去の状態にresetすることもできる。仮に~2とすると2つ前のコミットの状態にリセットされる。
— amend
先程はctrl+zのようになかったことにしたが、そうではなくてcommitオブジェクトを正しい内容で保存し直したい場合がある。まずは先程同じように以下を入力
$ echo "mistake" >> file1.txt $ git commit -am"second-commit"
commitしたあとに間違いに気づくことは多い。そういったときは修正したコミットを作成しamendオプションをつけるとよい。
やってみよう!
お好みのエディターで[mistake]を[さようなら]に変更して保存した後以下を入力
する。
$ git add .
$ git commit --amend
エディタが立ち上がるのでコミットメッセージを修正する。特に変更の必要がなければそのまま保存をエディタを閉じる。これで無駄なコミット残らずに修正済みの歴史だけが残る。このamendはコミットメッセージだけを書き換えたいときなどにも有効だ。
rebase -i
直前のコミットの変更はamendが楽だがrebaseを使うと後からでも歴史を変えられる、やってみよう。
まずは以下のようにわざと[おやすみなさい]を[おやすみなされ]とスペルミスをしてコミットする。
$ echo "おやすみなされ" >> file1.txt $ git commit -am"third-commit"
その後、スペルミスを修正しコミットする
$ vi file1.txt ~~~[おやすみなされ]を[おやすみなさい]に修正し保存する~~~ $ git commit -am"fix typo"

このスペルミスをした歴史をなかったことにしたい。。。
この場合はthird-commitに変更を加えることになるのでその前のcommitであるsecond-commitのところまで戻って作り変えていく必要がある。
second-commitのオブジェクトはHEADよりも2つ前にあるので
$ git rebase -i HEAD~2
エディタが立ち上がり、second-commit以降の歴史が表示されている。
この際、表示順番がgraphしたときとは逆で上に古いものがくることに注意
間違えを修正したコミットにfixup(またはf)と書き換え保存する。

タイプミスした歴史が消えてコミットログがきれいになった!

このrebase -i からのfixupは修正コミットを作成した場合に主に用いられる。
fixupを指定されたコミットはなくなり、コミットメッセージは直前のものが採用される。
fixupは複数同時行うこともできる。少し前の状態に戻りたいので以下のようにreflogを行う
$ git reflog

fix typoコミットある状態のハッシュ(ここでは4afdd16)に以下のようにreset –hardする
$ git reset --hard 4afdd16
git graphしてみよう。rebaseする前の状態に戻っている。

git diffでこのコミットが何を行ったのかを確認しよう。
$ git diff HEAD~

そうそう、「おやすみなされ」から「おやすみなさい」に変更したのであった。
ここではさらに変更を加えてみよう。エディタで開いて「おやすみなさい」を「good night」と変更しそれを以下のようにadd & commit
$ git commit -am"英語表記に変更"
git graphしてみよう。

fix typo と英語表記に変更の歴史も修正の歴史なので、third_commitにまとめてしまおう。
$ git rebase -i HEAD~3

さきほどと同じように修正の歴史である、コミットにfを付与し、保存する。
git graphしてみよう。

修正の歴史がなくなって,コミットログがきれいになっている。
fixupを使った場合、コミットメッセージは原則、結合する前のものが採用される。
では、結合はするのだが、コミットメッセージを変えたい場合はどうすればよいだろうか?
まずはreflogして過去に戻ろう。

$ git reset --hard 193cb81
git graphしよう。rebaseする前の状態に戻った

再びrebase -i する
$ git rebase -i HEAD~3
エディタが開くので今度はsquashの略であるsを入力、保存してファイルを閉じる

すると再びエディタが立ち上がる

もととなるコミットメッセージと、sをした2つのコミットメッセージが表示されている。この画面で3つ結合した後のコミットメッセージをエディタで編集し作成する。(ここではコミットメッセージをまとめ、以下のように1行だけ入力した)

ファイルを保存して閉じるとrebaseが完了する。graphしてみよう。

3つのコミットを結合し、コミットメッセージも変更することができた。
fixupもsquashもコミットをまとめるという点では同じだが、コミットメッセージの扱いが異なる。うまく使い分けてもらいたい。
rebaseの注意点
このようにrebaseを使うとコミット履歴をきれいにすることができる。
しかし、この作業は既存のコミットオブジェクトを一旦削除して、結合した新たなコミットオブジェクトを作成する作業である。リモートに上がっているコミットなどをまとめてしまうと、重大事故になりかねないので、使うタイミングには注意してもらいたい。
コメント