リポジトリを新規作成し、コミットしたところで.gitignore
ファイルを作り忘れていることに気づくことはないでしょうか?
このような場合、直前のコミットを取り消そうとすると次のようなエラーが表示されます。
$ git reset --soft HEAD~1
fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
このエラーは、取り消したいコミットの一つ前のコミットHEAD~1
が存在しないことが原因で起きています。
初回コミットを取り消したい場合の方法について解説します。
ここで解説する方法の中には非常に強力な操作が含まれています。使い方を誤ると復旧困難な状態に陥る可能性がありますので、十分に注意してください。
もっとも簡単な方法
もっとも簡単に初回コミットを取り消す方法は、.git
ディレクトリを削除することです。当然ながらgit init
からやり直しになりますが、初回コミット時という状況に限定するのであれば、この方法がもっとも簡単かつおすすめです。
$ rm -rf .git
初回コミットを取り消すコマンド
では、.git
ディレクトリを削除せずに初回コミットを取り消す方法はないのでしょうか?
もちろん初回コミットを取り消すコマンドはあります。次のコマンドを実行することで、初回コミットを取り消すことができます。
$ git update-ref -d HEAD
取り消し後、変更はステージングエリアに残ります。ステージングエリアにある変更をワーキングディレクトリに戻す場合は、
$ git reset
で、ステージングエリアにあるすべての変更をワーキングディレクトリに戻すか、
$ git reset node_modules
で、特定のファイルまたはディレクトリのみをワーキングディレクトリに戻してください。
git update-ref -d HEAD
とはどんなコマンドなのか?
git update-ref -d
は指定した参照(ref)を削除するコマンドです。ここではHEAD
という参照を指定していますので、HEAD参照が削除され、何もコミットしていない状態まで戻されますので、初回コミットが取り消されることになります。
git update-ref -d
はリポジトリの履歴を変更する非常に強力な操作です。使い方を誤ると復旧が困難な状態に陥る場合がありますので、十分に注意して使用してください。不安な場合は前述のもっとも簡単な方法を実施してください。
(おまけ)初回コミット以外のコミットの取り消す
おまけになりますが、git reset
コマンドを使用した初回コミット以外のコミットを取り消す方法について確認しておきます。
取り消した変更をステージングエリアに保持
次のコマンドは、直前のコミットを取り消し、そのコミットの変更をステージングエリアに残します。
$ git reset --soft HEAD~1
取り消した変更をワーキングディレクトリに保持
次のコマンドは、直前のコミットを取り消し、その変更をワーキングディレクトリに残しますが、ステージングエリアには残しません。--mixed
オプションはデフォルトなので、--mixed
は省略可能です。
$ git reset --mixed HEAD~1
変更を完全に取り消し
次のコマンドは、直前のコミットを取り消し、そのコミットの変更を完全に取り消します。
$ git reset --hard HEAD~1
(おまけ)ステージングエリアの変更を取り消す
すでに説明済みですが、ステージングエリアの変更を取り消す方法についても確認します。
ステージングエリアにあるすべてのファイルやディレクトリを戻す
ステージングエリアにあるすべてのファイルやディレクトリをワーキングディレクトリに戻す場合は、次のコマンドを実行します。
$ git reset
ステージングエリアにある特定のファイルまたはディレクトリを戻す
ステージングエリアにある特定のファイルまたはディレクトリをワーキングディレクトリに戻す場合は、次のコマンドを実行します。
$ git reset node_modules
まとめ
初回コミットを取り消す方法について解説しましたが、使用タイミングを誤ると復旧不可能な事態に陥るリスクがあので注意が必要です。
ステージングエリアに上げたあとに過不足がないことをレビューすることが大切です。ステージングエリアに上げる、ステージングエリアからワーキングディレクトリに戻すという操作は安全に実施できる操作ですし、ステージングエリアと直前のコミットとの差分は、git diff --cached
またはgit diff --staged
で比較できますので、積極的に活用してレビューを行ってください。