Git
章 ▾ 第2版

2.4 Gitの基本 - やり直す

やり直す

どのような段階でも、何かをやり直したいと思うことがあるでしょう。ここでは、行った変更をやり直すための基本的なツールをいくつか紹介します。これらのやり直しの一部は、元に戻せない場合があるため、注意してください。これは、Gitの中で、誤った操作をすると作業内容を失う可能性のある数少ない領域の1つです。

よくあるやり直しの1つは、コミットが早すぎたり、ファイルの追加を忘れたり、コミットメッセージを間違えたりした場合です。そのコミットをやり直したい場合は、追加を忘れた変更を行い、それをステージングして、--amendオプションを使用して再度コミットします。

$ git commit --amend

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

コミットメッセージエディターが起動しますが、以前のコミットのメッセージがすでに含まれています。メッセージはいつもどおりに編集できますが、以前のコミットを上書きします。

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

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

最終的には、単一のコミットになります。2回目のコミットは1回目のコミットの結果を置き換えます。

注意

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

コミットの修正の明らかな価値は、リポジトリの履歴を「しまった、ファイルの追加を忘れた」とか「しまった、最後のコミットのタイプミスを修正」のようなコミットメッセージで散らかすことなく、最後のコミットに小さな改善を加えることです。

注意

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

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

次の2つのセクションでは、ステージング領域と作業ディレクトリの変更を操作する方法を説明します。良い点は、これらの2つの領域の状態を判断するために使用するコマンドが、変更を元に戻す方法も教えてくれることです。たとえば、2つのファイルを変更し、それらを2つの別々の変更としてコミットしたいのに、誤って git add * と入力して両方をステージングしたとします。2つのうち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 <file>…​ を使用してアンステージすると書かれています。したがって、このアドバイスに従って 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 が何を行い、それを習得して本当に興味深いことを行う方法については、「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 -- <file> が危険なコマンドであることを理解することが重要です。そのファイルに対して行ったローカルな変更はすべて失われます。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 * と入力して両方をステージングしたとします。2つのうち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 <file>…​ を使用してアンステージすると書かれています。したがって、このアドバイスに従って 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 <file> が危険なコマンドであることを理解することが重要です。そのファイルに対して行ったローカルな変更はすべて失われます。Gitはそのファイルを最後にステージングまたはコミットされたバージョンで置き換えただけです。保存されていないローカルな変更を絶対に必要な場合にのみ、このコマンドを使用してください。

scroll-to-top