hogehoge foobar Blog Style Beta

Web,Mac,Linux,JavaScript,Perl,PHP,RegExp,Git,Vim,Redmineなど技術的なことのメモや、ちょっと便利そうなものの紹介をしています。

git commitをやり直しする&取り消しする(「get commit --amend」と「git reset」)

git commitを実行あとでコミットをやり直したり、コミット自体を取り消す方法です。

直前にしたコミットをやり直す(git commit --amend)

直前にしたコミットをやり直す場合、「git commit --amend」を使用します。

例えば、直前のコミットログが以下のような状態だったとします。
実は直前のコミットに含めるべきであった「hoge.txt」が含まれていませんでした。

コミットログ(git commit --amend 実行前)
$ git log
commit cca638b48b4c8be7ad5432f7882497534b04e2b4
Author: mrgoofy <hogehoge@example.com>
Date:   Wed Sep 8 23:03:57 2010 +0900

    2nd Commit.-> New Add File : bar.txt

この直前のコミットに対して新たにファイルを追加してコミットをやり直すには、

  • いつも通り git add でファイルを追加
  • git commit --amend で直前のコミットをやり直す

という流れになります。

git add した後に git commit --amend
$ git add hoge.txt
$ git commit --amend -m "2nd Commit.-> New Add File : bar.txt & hoge.txt"
[master 325e5d3] 2nd Commit.-> New Add File : bar.txt & hoge.txt
 2 files changed, 10 insertions(+), 0 deletions(-)
 create mode 100755 bar.txt                                                                                                         
 create mode 100755 hoge.txt

git logを見てみると、コミットコメントも書き換わった形でコミットのやり直しが出来ています。
ただ、よく見ると「commit」の部分のIDが前のコミットのモノとは違うものになっています。

コミットログ(git commit --amend 実行後)
$ git log
commit 325e5d3f193d1e7ceb57d718a15c4b28360c1bf9
Author: mrgoofy <hogehoge@example.com>
Date:   Wed Sep 8 23:03:57 2010 +0900

    2nd Commit.-> New Add File : bar.txt & hoge.txt

「git commit --amend」を使用した場合、元のコミットを上書きするのではなく、元のコミットを無効にして、新たなコミットを作るという動作になります。

   ------o (325e5d3f1) -> やり直したコミット
   /      
 -----o-------o (cca638b48) -> 間違ったコミット : コミット自体は残るが無効とされる

コミット自体を取り消したい場合

コミット自体を取り消しする(なかった事にする)には、「git reset」を使います。
「git reset」には「git reset --soft」と「git reset --hard」の2種類があります。

  • 「git reset --soft」 → ワークディレクトリの内容はそのままでコミットだけを取り消す。
  • 「git reset --hard」 → コミット取り消した上でワークディレクトリの内容も書き換える。

「git reset --soft」を使用する

「git reset --soft」は、ワークディレクトリの内容はそのままでコミットだけを取り消したい場合に使用します。
例えば、以下のような2件のコミットログのあるリポジトリに対して、「git reset --soft」をしてみます。
ワークディレクトリには「bar.txt」と「foo.txt」の2ファイルが存在しています。

コミットログ(git reset --soft 実行前)
$ git log
commit abf80570906a5b8a1db8efdb0041d774f782bf8f
Author: mrgoofy <hogehoge@example.com>
Date:   Wed Sep 8 23:05:54 2010 +0900

    2nd Commit.-> New Add File : bar.txt

commit a532d5a9ce88ddeaa0d521c13b05deb89b247bc2
Author: mrgoofy <hogehoge@example.com>
Date:   Wed Sep 8 23:05:23 2010 +0900

    1st Commit.-> New Add File : foo.txt
ワークディレクトリ(git reset --soft 実行前)
$ ls -l
total 2
-rwxr-xr-x+ 1 goofy なし 16 2010-09-08 23:05 bar.txt
-rwxr-xr-x+ 1 goofy なし 15 2010-09-08 23:05 foo.txt
git reset --soft を実行

「git reset --soft HEAD^」の「HEAD^」はひとつ前のコミットの意味になるので、ここでは直前のコミットである「abf8057090 2nd Commit.…」を取り消すことになります。

$ git reset --soft HEAD^
コミットログ(git reset --soft 実行後)

コミットログから「abf805709 2nd Commit.…」が消えています。

$ git log
commit a532d5a9ce88ddeaa0d521c13b05deb89b247bc2
Author: mrgoofy <hogehoge@example.com>
Date:   Wed Sep 8 23:05:23 2010 +0900

    1st Commit.-> New Add File : foo.txt
ワークディレクトリ(git reset --soft 実行後)

「bar.txt」と「foo.txt」の2ファイルが存在したままで、「git reset --soft」実行前の状態がそのまま保持されています。

$ ls -l
total 2
-rwxr-xr-x+ 1 goofy なし 16 2010-09-08 23:05 bar.txt
-rwxr-xr-x+ 1 goofy なし 15 2010-09-08 23:05 foo.txt

「git reset --hard」を使用する

「git reset --hard」は、コミット取り消した上でワークディレクトリの内容も書き換えたい場合に使用します。
先程の「git reset --soft」で使用したディレクトリと同じ状態で試してみます。

コミットログ(git reset --hard 実行前)
$ git log
commit abf80570906a5b8a1db8efdb0041d774f782bf8f
Author: mrgoofy <hogehoge@example.com>
Date:   Wed Sep 8 23:05:54 2010 +0900

    2nd Commit.-> New Add File : bar.txt

commit a532d5a9ce88ddeaa0d521c13b05deb89b247bc2
Author: mrgoofy <hogehoge@example.com>
Date:   Wed Sep 8 23:05:23 2010 +0900

    1st Commit.-> New Add File : foo.txt
ワークディレクトリ(git reset --hard 実行前)
$ ls -l
total 2
-rwxr-xr-x+ 1 goofy なし 16 2010-09-08 23:05 bar.txt
-rwxr-xr-x+ 1 goofy なし 15 2010-09-08 23:05 foo.txt
git reset --hard を実行

先程と同じく「HEAD^」で、直前のコミットの「abf8057090 2nd Commit.…」を取り消します。

$ git reset --hard HEAD^
HEAD is now at a532d5a 1st Commit.-> New Add File : foo.txt
コミットログ(git reset --hard 実行後)

「git reset --soft」の時と同様にコミットログから「abf805709 2nd Commit.…」が消えています。

$ git log
commit a532d5a9ce88ddeaa0d521c13b05deb89b247bc2
Author: mrgoofy <hogehoge@example.com>
Date:   Wed Sep 8 23:05:23 2010 +0900

    1st Commit.-> New Add File : foo.txt
ワークディレクトリ(git reset --hard 実行後)

「bar.txt」が削除され「foo.txt」のみが存在している状態になっています。
「git reset --hard」を実行した場合、ワークディレクトリについてもコミットを取り消した状態(今回の場合「a532d5a 1st Commit.…」)に戻されます。

$ ls -l
total 1
-rwxr-xr-x+ 1 goofy なし 15 2010-09-08 23:05 foo.txt

今回参考にしたページ

Gitを使いこなすための20のコマンド - SourceForge.JP
http://sourceforge.jp/magazine/09/03/16/0831212/3

Gitの取消練習 - sinkin' in the rain
http://tsukamoto.tumblr.com/post/267736584