tweeeetyのぶろぐ的めも

アウトプットが少なかったダメな自分をアウトプット<br>\(^o^)/

【git】git commitを取り消す

はじめに

git commitを取り消すメモ。 ほとんど手順メモ程度な感じ+他記事で使うスニペット記事。

とはいえ、数あるgit便利コマンドの中で毎回使うものではないけど
いざって時に役立つ、もしくは、困るのは取り消し系のコマンドですよね。

補足

他の取り消しもぱっと見たい自分用にまとめたので参考までに。

アジェンダ

  1. git resetでgit commitを取り消す
  2. git revertでgit commitを取り消す
  3. git commitでgit commitを取り消す
  4. それぞれやってみる

git resetgit revertgit commitのそれぞれのコマンド例と
やってみた操作ログ的なものは一緒にすると長くなりそうだったので、
やってみた系は最後にまとめました。

1. git resetでgit commitを取り消す

git resetgit commitを取り消します。
git addの取り消しにも使えるので便利ですね。

しかし使い方が若干違うのでこちらと比べて見てみるとよりわかりやすいかもしれません。 →【git】git addを取り消す

コマンド例

このログの状態のときを例とします

※ git logを確認
$ git log --oneline
49a715d commit sample2
693755b commit sample
8189e9c Initial commit

2つ前のcommitを取り消し
つまり8189e9c Initial commitだけの状態にするコマンドは
いつくかありますがこんな感じです。

※ 2つ前のcommitを取り消し
$ git reset --soft HEAD^^

※ 2つ前のcommitを取り消し
$ git reset --soft HEAD~2

※ 最初のコミットに戻す(2つぶんコミット取り消し)
$ git reset --soft 8189e9c
ポイント

HEADを使うと^^であれ~2であれ2つ前までのcommitを取り消す、という感じですが、
commitハッシュを用いると3つ前の8189e9cを使うところは気をつけたいですね。

また、ポイントはオプションの--soft--hardの違い、そしてHEADについてでしょうか。

--soft--hardの違い

違いを簡単にまとめるとこんな感じです。

  • --soft ... commitだけを取り消したい
  • --hard ... commit取り消し + ワークディレクトリの内容も書き換え
HEAD

HEADの後ろについては2つだけ覚えればたいていことたります。

  1. HEAD^ ... HEAD + ^で直前のcommitを表す
  2. HEAD~{n} ... HEAD + ~{n}で{n}こ前のcommitを表す

つまりHEAD^^ = HEAD~2ってことですね。

2. git revertでgit commitを取り消す

git revertを使うと、
指定したcommitを打ち消すようなcommitを行います。
逆向きのcommitというらいしですが、戻した履歴も残す取り消しな感じです。

追加したものは無かったことに、消したものは復活し、変更したものは変更を元にもどすそんな感じですね。

コマンド例
※ git logを確認
$ git log --oneline
693755b commit sample
8189e9c Initial commit
 
※ 1つ前のcommitハッシュを指定
※ エディタが開かれるのでとりあえずそのまま保存して終了でrevert確定
$ git revert 693755b

※ git logを確認
$ git log --oneline
567254a Revert "commit sample"
693755b commit sample
8189e9c Initial commit
ポイント

ログには戻したという履歴も残ります。

上記の例で言うと戻すのを戻すという操作を行いたい場合
567254aを指定して再度revertすることもできます。

3. git commitでgit commitを取り消す

git commitで取り消すというよりは、直前のcommitに上書きするといった感じです。

直前にcommitしたものに修正が足りなかった場合や、
余分にファイルをcommitしてしまった場合などに
それらを正しい状態に直して直前のcommitに無理やり入れる感じです。

コマンド例
※ git logを確認
$ git log --oneline
2ed0aab commit sample
8189e9c Initial commit

※ 足りなかった修正を加える
※ 余分なファイルを`git rm ファイル`で消す
※ などをここで行ったと仮定

※ --amendする
$ git commit --amend

※ 正しい状態を入れつつ、直前のcommitに取り込んで新しいcommitハッシュを振りなおす
$ git log --oneline
0c91475 commit sample
8189e9c Initial commit
ポイント
  • commitしたけど実は修正が漏れていた
  • 余分なファイルをcommitしてしまった

などはよくありがちなので、その際にresetでいったん戻してから再度全部commitしなおすとかしなくて良いので楽ですね。

4. それぞれやってみる

前提条件として、
git resetgit revertgit commitをやってみる前に
それぞれこの状態だったと仮定して進めます。

それぞれをやる前の初期状態

※ ログ確認
$ git log --oneline
8189e9c Initial commit

※ README.mdのみaddもcommitもしてある状態
$ ls -al 
drwxr-xr-x  15 hoge  hoge  510  6  7 04:25 .git
-rw-r--r--   1 hoge  hoge   18  6  6 15:08 README.md

※ ログ確認
$ git log --oneline
8189e9c Initial commit

※ 新規のファイルを追加・修正した状態
$ tree
.
├── README.md
├── img
│   └── sample.png
└── index.html

※ statusを確認
※ index.htmlとimgディレクトリはまだaddもしていない状態
$ git status
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    img/
    index.html

nothing added to commit but untracked files present (use "git add" to track)

git reset

git reset --softの確認
※ すべてadd
$ git add .

※ commit
$ git commit -m 'commit sample'

※ ログを確認
$ git log --oneline
98232e3 commit sample
8189e9c Initial commit

※ 直前のcommitを取り消し
$ git reset --soft HEAD^

※ ログとファイルの確認
※ commitログは最初のだけになる
※ ファイル類はそのまま
$ git log --oneline
8189e9c Initial commit

$ ls -l
-rw-r--r--  1 hoge  hoge   18  6  6 15:08 README.md
drwxr-xr-x  3 hoge  hoge  102  6  6 15:14 img
-rw-r--r--  1 hoge  hoge   83  6  6 15:14 index.html

※ statusを確認
※ addされる前に戻るわけではなく、addはした状態になっている
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   img/sample.png
    new file:   index.html
ポイント

この後の--hardと比べるとわかりやすいのですが
ファイルは残っていますがaddされる前に戻るわけでは無いと言った感じです。

git reset --hardの確認
※ すべてadd
$ git add .

※ commit
$ git commit -m 'commit sample'

※ ログを確認
$ git log --oneline
10e0dcd commit sample
8189e9c Initial commit

※ 直前のcommitを取り消し
$ git reset --hard HEAD^

※ ログとファイルの確認
※ commitログは最初のだけになる
※ 変更や新たに追加したファイル類も消える
$ git log --oneline
8189e9c Initial commit

$ ls -l
-rw-r--r--  1 hoge  hoge   18  6  6 15:08 README.md
ポイント

--softと比べるとわかりやすく、変更や追加したファイルも消えてしまいます。

git reset --soft コミットハッシュの確認

HEAD指定と違ってどれを取り消すか、ではなくどこまで戻るか、なので
最初に間違った指定もしてみます。

※ すべてadd
$ git add .

※ commit
$ git commit -m 'commit sample'

※ ログを確認
$ git log --oneline
b869e93 commit sample
8189e9c Initial commit

※ 直前のcommitハッシュを指定してみる
$ git reset --soft b869e93

※ ログとstatusの確認
※ 直前のcommitハッシュを指定しても何も変わっていない
$ git log --oneline
b869e93 commit sample
8189e9c Initial commit

$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
nothing to commit, working directory clean

※ 戻りたいコミットハッシュを指定してみる
$ git reset --soft 8189e9c

※ ログとファイルの確認
※ コミットハッシュ指定の場合は'どこまで'戻りたいかで指定
※ HEADと違い、'どれを'り消すかではない
$ git log --oneline
8189e9c Initial commit

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   img/sample.png
    new file:   index.html
ポイント

HEAD指定はどれを取り消すか
コミットハッシュ指定はどこまで戻るかのような感じで覚えると良さそうです。

git revert

revertのサンプルとしては直前のrevertを2回やってみます。
ログとファイルがどんな感じになるかに注目するとわかりやすいかと思います。

※ すべてadd
$ git add .

※ commit
$ git commit -m 'commit sample'

※ ログを確認
$ git log --oneline
1fe0f69 commit sample
8189e9c Initial commit

※ 直前のコミットハッシュを指定してrevert
$ git revert 1fe0f69

※ ログとファイルを確認
※ "commit sample"というコミットハッシュをrevertしたよ、と出る
※ 指定したコミットハッシュで追加したファイルや変更もなかったことになる
$ git log --oneline
ef9e453 Revert "commit sample"
1fe0f69 commit sample
8189e9c Initial commit

※ ファイルを確認
$ ls -l
-rw-r--r--  1 hoge  hoge  18  6  7 05:18 README.md

※ 再度、直前のコミットハッシュを指定してrevert
※ 直前のコミット=revertしたコミットハッシュ
$ git revert ef9e453

※ ログとファイルを確認
※ revertをrevertすると、なかったことになったファイルも戻る
$ git log --oneline
b058b30 Revert "Revert "commit sample""
ef9e453 Revert "commit sample"
1fe0f69 commit sample
8189e9c Initial commit

$ ls -l
-rw-r--r--  1 hoge  hoge   18  6  7 05:18 README.md
drwxr-xr-x  3 hoge  hoge  102  6  7 06:05 img
-rw-r--r--  1 hoge  hoge   83  6  7 06:05 index.html
ポイント

revertすると取り消すという意味合いのログも残る上に、
revert自体も戻すことができるので便利です。

git commit

index.htmlという余分なファイルをcommitしてしまったと仮定して
既に行ったcommitに対してindex.htmlを無しの状態にしてみます。

※ すべてadd
$ git add .

※ commit
$ git commit -m 'commit sample'

※ ログを確認
$ git log --oneline
e102d17 commit sample
8189e9c Initial commit

※ index.htmlを消す
$ git rm index.html

※ git commit --amendしてログを確認する
※ git commit した場合は消したというコミットログが残るが
※ --ammendの場合は新しくcommitハッシュを作り直して直前のコミットを上書きする
$ git commit --amend

$ git log --oneline
9ea5842 commit sample
8189e9c Initial commit
ポイント

あえて消したログを残したい場合は
git commit -m 'remove file'と通常通り行っても良いですね。

補足

resetに関してはこのあたりも参考に
マージ後のreset HEAD^は危険だった

まとめ

取り消し系の操作はいざそのときになると慌てて出てこなかったりするので
何回か練習して覚えたいですね。\(^o^)/