Git での変更の取り消し: Reset、Restore、Revert の解説

git restore、reset、revert を理解して、ファイルのステージ解除、ローカル編集の破棄、コミットの取り消し、共有履歴の書き換え回避を実現しましょう。

Git での変更の取り消し: Reset、Restore、Revert の解説

Git での変更の取り消しは、作業ツリー、ステージングエリア、コミット履歴のどのレイヤーを変更しているかを把握していれば安全です。一般的なコマンドは git restoregit resetgit revert で、それぞれ異なる問題を解決します。

大原則はシンプルです。ファイルには restore、ローカル履歴の変更には reset、他の人がすでに持っている可能性のあるコミットの取り消しには revert を使います。

基本概念の理解

以下の領域を正しく把握しましょう。

  • 作業ツリー: 編集するファイル。
  • ステージングエリア(インデックスとも呼ばれる): 次のコミットに選択された変更。
  • コミット履歴: すでに記録されたコミット。
  • HEAD: ブランチが現在指しているコミット。

何かを取り消す前に git status を実行しましょう。変更がステージングされていないか、ステージングされているか、すでにコミットされているかを教えてくれます。

git restore: 作業ディレクトリとステージングエリアの変更を破棄する

git restore は、ブランチ履歴を移動せずに作業ツリーやステージングエリアのファイルを変更したいときに使います。

ファイルのステージ解除

誤ってファイルをステージングした場合は、--staged でステージングを解除します。

git restore --staged <file>

すべてのステージングを解除するには:

git restore --staged .

ファイルの編集内容は作業ツリーに残ります。次のコミットから削除されるだけです。

作業ディレクトリの変更を破棄する

1つのファイルのステージングされていない編集を破棄するには:

git restore <file>

これにより、作業ツリーのコピーがインデックスと一致します。ファイルがステージングされていない場合、通常は HEAD に戻ります。ローカルの編集を破棄するため、最初に git diff を確認しましょう。

ファイルのステージングされた変更とステージングされていない変更の両方を破棄し、HEAD から復元するには:

git restore --source=HEAD --staged --worktree <file>

特定のコミットからファイルを復元する

古いコミットから1つのファイルを復元することもできます。

git restore --source=<commit> -- path/to/file

これにより、作業ツリーのファイルが変更されます。古いバージョンを今後使用したい場合は、コミットしてください。

git reset: 履歴の書き換え

git reset は、現在のブランチポインタを移動したいときに使います。モードによって、ステージングエリアや作業ツリーも変更できます。

モードの理解 (--soft--mixed--hard)

3つの一般的なモードは次のとおりです。

git reset --soft HEAD^

HEAD を1つ前のコミットに移動し、取り消したコミットの変更をステージングしたままにします。

git reset --mixed HEAD^

HEAD を1つ前のコミットに移動し、取り消したコミットの変更をステージングされていない状態に保ちます。--mixed がデフォルトなので、git reset HEAD^ も同じ動作です。

git reset --hard HEAD^

HEAD を1つ前のコミットに移動し、対応する変更をステージングエリアと作業ツリーから破棄します。これは破壊的です。軽率に実行しないでください。

便利なリセットパターン:

git reset --soft HEAD^      # 最後のローカルコミットをやり直し、変更をステージングしたままにする
git reset HEAD^             # 最後のローカルコミットを取り消し、変更をステージングされていない状態にする
git reset                   # すべてのステージングされた変更をステージング解除する
git reset --hard origin/main # ローカルの変更を破棄し、origin/main に合わせる

古いコミットのリセット

ブランチを2つ前のコミットに戻し、変更を作業ツリーに保持するには:

git reset --mixed HEAD~2

ローカルコミット、またはチームが書き換えに同意したコミットのみをリセットしてください。コミットがすでに共有ブランチにある場合は、git revert を優先しましょう。

git revert: 変更を取り消す新しいコミットを作成する

git revert は、以前のコミットの逆を適用する新しいコミットを作成します。元のコミットを削除したり移動したりしないため、共有ブランチでも安全です。

1つのコミットを元に戻す:

git revert <commit-hash>

範囲を元に戻す:

git revert HEAD~3..HEAD

競合が発生した場合は、解決し、ファイルをステージングして続行します:

git add <fixed-files>
git revert --continue

マージコミットを元に戻すには、Git がどの親をメインラインとして扱うべきかを知る必要があるため、特別な注意が必要です:

git revert -m 1 <merge-commit>

これは、マージが何を導入したかを理解している場合にのみ実行してください。プロダクションブランチでは、マージの元に戻す前にレビューを依頼しましょう。

適切なコマンドの選択

以下のクイックガイドを使用してください:

  • ファイルのステージング解除: git restore --staged <file>
  • ファイルのステージングされていない編集を破棄: git restore <file>
  • 最後のローカルコミットを取り消し、変更をステージングしたままにする: git reset --soft HEAD^
  • 最後のローカルコミットを取り消し、変更をステージングされていない状態にする: git reset HEAD^
  • ローカルの変更とコミットを破壊的に破棄: git reset --hard <commit>
  • プッシュされたコミットを安全に取り消す: git revert <commit-hash>

実践的なポイント

何かを取り消す前に、git status を実行し、何を変更しているかを判断しましょう。ファイルレベルのクリーンアップには restore、ローカルのプッシュされていないコミットには reset、共有履歴には revert を使用します。--hard を含むコマンドの場合は、一時停止して最初に git diff を確認しましょう。