開発ブログ

WWWクリエイターズが送る、Git、CSS、HTML、コマンドライン、Macの便利機能など、開発に関する役立ち情報発信します。気まぐれに更新。

gitで変更を元に戻す。事例と対応コマンド一覧。

最終更新:2017-07-07 by Joe

git でがちゃがちゃ変更したけど、やっぱり元に戻したいときや、最初からやり直したいときのコマンドです。

特定のファイルを元に戻す

作業ツリーでいろいろ変更してしまったけど、特定のファイルだけ元に戻してやり直します。最後のコミットから、そのファイルへの変更はすべて無かったことにします。

このコマンドは、作業ツリーのファイルを強制的に現在のインデックスのファイル状態に戻します。

[インデックス] → [作業ツリー]  です。

ただし、もしファイルをaddしてしまっているのであれば、「インデックスのファイル状態に戻す」という動作しようなので、ので上記ではなにもおきません。

もしインデックスを含めて元に戻したいときには、ブランチ名やコミットを指定する必要があります。

最後のコミットからファイを参照して、戻すには、HEADを指定します。

すべてのファイルを元に戻すgit コマンド

応用です。すべてのファイルを元に戻します。正確には、最後のコミットに戻します。

git checkoutをより深く理解する

git checkout についてまとめておきます。checkoutを使ってコミットを「やり直す」といった用途に関しては、すこし混乱しやすい気がします。

作業ツリーの特定のファイルを、インデックスのファイル状態に合わせる

ファイルのチェックアウトです。ワークツリーのファイルは上書きされます。

作業ツリーの特定のファイルを、特定のブランチのファイル状態に合わせる

指定したブランチ上にあるファイルのチェックアウトです。特定のファイルで、ワークツリーを上書きします。ブランチの切り替えは発生しません。

ブランチを切り替える

ブランチのチェックアウトです。HEADは指定されたブランチの先頭に移動し、インデックスはそのコミット状態に更新されます。

ワークツリーの変更は可能な限り維持されますが、checkout先のファイル状態とコンフリクトする際は、怒られてcheckoutが中止されます。

実際、これが「作業するブランチをスイッチして、変更作業を開始できるようにする」という、git checkout 本来の用途でした。

一時的なチェックアウト

git checkout がもし作業ブランチを移動するコマンドなら、もしブランチ名でなくコミットを指定するとどうなるでしょうか。

試してみます。

 

実際はGit の仕様でコミットに対してgit checkout を実行すると、「detached HEAD」と呼ばれる状態になります。「detached」とは「分離された」「引き剥がされた」といったニュアンスの英語ですが、すなわち、いかなるブランチにも属さない匿名ブランチをチェックアウトした状態になり、HEADがその先頭を指すようになります。

一応、メッセージの意訳を載せておきます。

 

You are in ‘detached HEAD’ state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

現在、分離HEAD状態にいます。ファイルを閲覧したり、実験的な変更を作ってコミットしたりできます。別のブランチをチェックアウトすれば、この状態におけるすべてのコミトは他のブランチに影響を与えることなく消去する事ができます。

もし新しいブランチを作って変更を記録したければ、いつでもcheckoutコマンドに -b オプションを付けて実行することで実現できます。例えば:

git checkout -b <new-branch-name>

 

本当に全てを元に戻すgitコマンド

上記は、作業ツリーやインデックスを元の状態に戻すコマンドでした。

ここからは、より深く元に戻します。作業ツリーを含めて本当に特定のコミットに完全に戻りたいのであれば、git reset --hard <commit>が一撃で済みます。checkoutよりも、もうすこし直感的です。

checkoutはブランチを切り替える、reset はブランチを書き換えるコマンド、というのがそもそもの目的のように捉えています。

うまく変更を元に戻せたでしょうか?

参考