チャプター ▾ 第2版

2.4 Gitの基本 - 取り消し

取り消し

どの段階においても、何らかの操作を取り消したいと考えることがあるでしょう。ここでは、行った変更を取り消すためのいくつかの基本的なツールをレビューします。これらの取り消しの中には、常に元に戻せないものもあるので注意してください。これは、Gitの数少ない領域の一つであり、間違った方法で行うと作業の一部を失う可能性があります。

一般的な取り消しの1つは、コミットを早めに行いすぎた場合や、いくつかのファイルを追加し忘れた場合、またはコミットメッセージを間違えた場合に発生します。そのコミットをやり直したい場合は、忘れていた追加の変更を行い、それらをステージングし、--amend オプションを使用して再度コミットします。

$ git commit --amend

このコマンドは、ステージングエリアをコミットに使用します。最後のコミット以降に変更を加えていない場合(たとえば、直前のコミットの直後にこのコマンドを実行した場合)、スナップショットはまったく同じになり、変更されるのはコミットメッセージだけです。

同じコミットメッセージエディタが起動しますが、すでに以前のコミットのメッセージが含まれています。メッセージは通常と同じように編集できますが、以前のコミットを上書きします。

例として、コミットした後、このコミットに追加したかったファイルの変更をステージングし忘れたことに気づいた場合、次のようにすることができます。

$ git commit -m 'Initial commit'
$ git add forgotten_file
$ git commit --amend

結果的に単一のコミットになります。2番目のコミットが最初のコミットの結果を置き換えます。

最後のコミットを修正する際、それを修正するというよりも、古いコミットを排除し、新しいコミットをその場所に入れる、新しい改善されたコミットで完全に_置き換える_ということを理解することが重要です。事実上、以前のコミットはなかったことになり、リポジトリ履歴には表示されません。

コミットを修正することの明らかな利点は、「おっと、ファイルを追加し忘れました」や「しまった、前回のコミットのタイプミスを修正」といった形式のコミットメッセージでリポジトリの履歴を散らかすことなく、最後のコミットにわずかな改善を加えることです。

まだローカルであり、どこにもプッシュされていないコミットのみを修正してください。以前にプッシュされたコミットを修正し、ブランチを強制的にプッシュすると、協力者に問題を引き起こします。これを行った場合に何が起こるか、そして受信側になった場合にどのように回復するかについては、リベースの危険性を読んでください。

ステージングされたファイルのステージング解除

次の2つのセクションでは、ステージングエリアとワーキングディレクトリの変更を操作する方法を示します。良い点は、これらの2つの領域の状態を判別するために使用するコマンドが、それらの変更を取り消す方法も思い出させてくれることです。たとえば、2つのファイルを変更し、それらを2つの別々の変更としてコミットしたいが、誤って git add * と入力して両方をステージングしてしまったとします。そのうちの1つをステージング解除するにはどうすればよいでしょうか?git status コマンドが思い出させてくれます。

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

「コミットされる変更」というテキストのすぐ下に、ステージング解除するには git reset HEAD …​ を使用すると書かれています。では、そのアドバイスに従って CONTRIBUTING.md ファイルをステージング解除してみましょう。

$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M	CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

このコマンドは少し奇妙ですが、機能します。CONTRIBUTING.md ファイルは変更されていますが、再びステージング解除されています。

git reset は危険なコマンドであることは事実です。特に --hard フラグを指定した場合がそうです。しかし、上記で説明したシナリオでは、ワーキングディレクトリ内のファイルは触れられないため、比較的安全です。

今のところ、この魔法の呼び出しで git reset コマンドについて知る必要があるのはこれだけです。reset が何をするのか、そして本当に興味深いことをするためにそれをマスターする方法については、リセットの謎を解き明かすで詳しく説明します。

変更されたファイルの変更を元に戻す

CONTRIBUTING.md ファイルへの変更を保持したくないと気づいたらどうしますか?どのように簡単に変更を元に戻すことができますか — 最後にコミットしたとき(または最初にクローンしたとき、またはワーキングディレクトリにどのように取り込んだかに関わらず)の状態に戻すにはどうすればよいでしょうか?幸いなことに、git status はそれを行う方法も教えてくれます。最後の出力例では、ステージングされていない領域は次のようになっています。

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

行った変更を破棄する方法が非常に明確に示されています。指示通りに実行しましょう。

$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

変更が元に戻されたことがわかります。

重要

git checkout -- が危険なコマンドであることを理解することが重要です。そのファイルに行ったローカルの変更はすべて消去されます — Gitはそのファイルを最後にステージングされたバージョンまたはコミットされたバージョンに置き換えるだけです。これらの保存されていないローカルの変更が絶対にいらないとわかっている場合以外は、このコマンドを使用しないでください。

そのファイルに行った変更を保持したいが、今のところ邪魔にならないようにする必要がある場合は、Gitのブランチでスタッシュとブランチについて説明します。これらは通常、より良い方法です。

Gitで_コミットされた_ものは、ほぼ常に回復できることを忘れないでください。削除されたブランチにあったコミットや、--amend コミットで上書きされたコミットでさえ回復できます(データ回復についてはデータ回復を参照してください)。しかし、コミットされなかった失われたものは、二度と見ることができない可能性が高いです。

git restore での取り消し

Git バージョン 2.23.0 では、新しいコマンド git restore が導入されました。これは、私たちが今説明した git reset の代替手段です。Git バージョン 2.23.0 以降、Git は多くの取り消し操作で git reset の代わりに git restore を使用します。

手順をさかのぼり、git reset の代わりに git restore で取り消しを行いましょう。

git restore でステージングされたファイルをステージング解除する

次の2つのセクションでは、git restore を使用してステージングエリアとワーキングディレクトリの変更を操作する方法を示します。良い点は、これらの2つの領域の状態を判断するために使用するコマンドが、それらの変更を取り消す方法も思い出させてくれることです。たとえば、2つのファイルを変更し、それらを2つの別々の変更としてコミットしたいが、誤って git add * と入力して両方をステージングしてしまったとします。そのうちの1つをステージング解除するにはどうすればよいでしょうか?git status コマンドが思い出させてくれます。

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   CONTRIBUTING.md
	renamed:    README.md -> README

「コミットされる変更」というテキストのすぐ下に、ステージング解除するには git restore --staged …​ を使用すると書かれています。では、そのアドバイスに従って CONTRIBUTING.md ファイルをステージング解除してみましょう。

$ git restore --staged CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	renamed:    README.md -> README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   CONTRIBUTING.md

CONTRIBUTING.md ファイルは変更されていますが、再びステージング解除されています。

git restore で変更されたファイルの変更を元に戻す

CONTRIBUTING.md ファイルへの変更を保持したくないと気づいたらどうしますか?どのように簡単に変更を元に戻すことができますか — 最後にコミットしたとき(または最初にクローンしたとき、またはワーキングディレクトリにどのように取り込んだかに関わらず)の状態に戻すにはどうすればよいでしょうか?幸いなことに、git status はそれを行う方法も教えてくれます。最後の出力例では、ステージングされていない領域は次のようになっています。

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   CONTRIBUTING.md

行った変更を破棄する方法が非常に明確に示されています。指示通りに実行しましょう。

$ git restore CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	renamed:    README.md -> README
重要

git restore は危険なコマンドであることを理解することが重要です。そのファイルに行ったローカルの変更はすべて消去されます — Gitはそのファイルを最後にステージングされたバージョンまたはコミットされたバージョンに置き換えるだけです。これらの保存されていないローカルの変更が絶対にいらないとわかっている場合以外は、このコマンドを使用しないでください。

scroll-to-top