Git reset hardと他のresetコマンドの違いを徹底解説|初心者向けガイド

Git

Git reset hardと他のresetコマンドの違いを徹底解説|初心者向けガイド

Gitを使用していると、コミットを取り消したい場面に何度も遭遇します。その時に活躍するのがgit resetコマンドです。しかし、git reset --hardgit reset --softgit reset --mixedの3つのオプションが存在し、どれを使うべきか迷う初心者も多いのではないでしょうか。

この記事では、これらのコマンドの違いを詳しく解説し、正しい使い方と危険性について説明します。

1. Git resetコマンドの原因の説明

Gitの3つのエリアを理解しよう

Git resetの違いを理解するには、まずGitの3つのエリアを知る必要があります。

  • ワーキングディレクトリ(Working Directory):あなたがファイルを編集している場所
  • ステージングエリア(Staging Area/Index)git addでファイルを追加する場所
  • Gitリポジトリ(Repository)git commitで確定されたコミット履歴

この3つのエリアを図解すると以下のようになります:

ワーキングディレクトリ → ステージングエリア → Gitリポジトリ
  (編集中)        (git add)      (git commit)

git resetの3つのオプションの違い

git resetコマンドには3つの主要なオプションがあり、それぞれが異なる範囲を「リセット」します。

  • –soft:Gitリポジトリのみリセット(ステージングエリアとワーキングディレクトリは変更されない)
  • –mixed:Gitリポジトリとステージングエリアをリセット(ワーキングディレクトリは変更されない)※デフォルト
  • –hard:全てのエリアをリセット(ワーキングディレクトリも含めて完全にリセット)

では、各オプションの動作をさらに詳しく見ていきましょう。

2. 各resetオプションの解決手順

git reset –soft の場合

git reset --softを使用すると、コミット履歴は取り消されますが、変更したファイルはステージングエリアに残ります。

使用場面:コミットメッセージを修正したい時や、複数のコミットを1つにまとめたい時

手順:

  1. 現在のコミットハッシュを確認
  2. git reset --soft HEAD~1を実行
  3. ステージングエリアには変更が残る
  4. 必要に応じてコミットを作り直す

git reset –mixed の場合

git reset --mixedはGitのデフォルト動作です。コミット履歴とステージングエリアがリセットされますが、ワーキングディレクトリの変更は保持されます。

使用場面:ファイルの追加を取り消したい時、またはgit addを取り消したい時

手順:

  1. git reset HEAD~1またはgit reset --mixed HEAD~1を実行
  2. 変更したファイルはワーキングディレクトリに残る
  3. もう一度ファイルを編集してgit addし直す

git reset –hard の場合

git reset --hardは最も危険で、全てのエリアを完全にリセットします。ワーキングディレクトリの変更も失われます。

使用場面:すべての変更を完全に取り消したい時(但し、非常に慎重に使用すべき)

手順:

  1. git reset --hard HEAD~1を実行
  2. 全ての変更が失われ、1つ前のコミット状態に戻る
  3. ワーキングディレクトリも元の状態に戻される

3. コード例で理解する違い

実践的なシナリオ:複数のファイル変更を例に

以下のシナリオで各コマンドの動作を比較します。

$ git log --oneline
abc1234 (HEAD) 新機能の実装
def5678 バグ修正
ghi9012 初期コミット

現在、以下のファイルが存在するとします:

$ git status
On branch main
Changes not staged for commit:
  modified:   file1.txt
  modified:   file2.txt

Untracked files:
  new_file.txt

シナリオ1:git reset –soft HEAD~1 を使った場合

$ git reset --soft HEAD~1
$ git status
On branch main
Changes to be committed:
  modified:   file1.txt
  modified:   file2.txt

Untracked files:
  new_file.txt

結果:

  • コミット「新機能の実装」は取り消された
  • file1.txt と file2.txt の変更はステージングエリアに残る
  • コミットメッセージを変更したり、ファイルを追加・削除してから再コミットできる

シナリオ2:git reset –mixed HEAD~1(またはgit reset HEAD~1)を使った場合

$ git reset HEAD~1
$ git status
On branch main
Changes not staged for commit:
  modified:   file1.txt
  modified:   file2.txt

Untracked files:
  new_file.txt

結果:

  • コミット「新機能の実装」は取り消された
  • file1.txt と file2.txt の変更はワーキングディレクトリに残る(ステージングエリアからは削除)
  • 再度 git add を実行する必要がある

シナリオ3:git reset –hard HEAD~1 を使った場合

$ git reset --hard HEAD~1
$ git status
On branch main
nothing to commit, working tree clean

結果:

  • コミット「新機能の実装」は取り消された
  • file1.txt と file2.txt の変更は完全に削除される
  • ワーキングディレクトリは「バグ修正」のコミット時点の状態に戻る
  • 変更内容は完全に失われるため、復元は困難

より実践的なコード例

実際の開発シーンでよく遭遇する例を見てみましょう:

#!/bin/bash
# 間違ったコミットを修正する流れ

# 1. 現在のログを確認
git log --oneline -5

# 2. 最後のコミットを取り消したいが、変更は保持したい場合
git reset --mixed HEAD~1
# または単に
git reset HEAD~1

# 3. 再度確認
git status

# 4. ファイルを正しく整理して再コミット
git add file1.txt
git commit -m \"修正済み:ファイル1のみをコミット\"

# 5. ファイル2は別のブランチで処理する場合
git checkout -b feature/file2-fix
git add file2.txt
git commit -m \"別タスク:ファイル2の修正\"

4. よくある間違いと対策

間違い1:git reset –hard を気軽に使用する

問題: 多くの初心者が理解せずに git reset --hard を使用し、重要な変更を失ってしまいます。

$ git reset --hard HEAD~1
# 数日間の作業が消えた...

対策:

  • git reset --hard を使用する前に、必ず git statusgit log で確認
  • 変更がある場合は、まず git stash でセーフに保存
  • 可能な限り --soft--mixed を使用
$ # 安全な手順
$ git status  # 現在の状態を確認
$ git log --oneline -5  # コミット履歴を確認
$ git diff HEAD~1  # 違いを確認
$ git reset --mixed HEAD~1  # 最初は--mixedで試す

間違い2:リモートリポジトリへのpush後にresetする

問題: すでにpushしたコミットに対して git reset を使用すると、チームメンバーとのコンフリクトが発生します。

$ git push origin main
$ git reset --hard HEAD~1  # 危険!他のメンバーが既にpullしている可能性
$ git push -f origin main  # 強制push(チーム全体に影響)

対策:

  • すでにpushしたコミットの場合は git revert を使用
  • どうしても必要な場合は、チームメンバーに事前に通知
  • 共有ブランチでは git reset --hard は避ける
$ # より安全な方法
$ git revert HEAD~1  # 新しいコミットで取り消しを記録
$ git push origin main  # 安全にpush可能

間違い3:resetの対象コミットを誤指定する

問題: HEAD~1HEAD~2 を混同し、意図しないコミットまで取り消す。

$ git log --oneline
abc1234 (HEAD) コミット3
def5678 コミット2
ghi9012 コミット1

$ git reset --hard HEAD~2  # コミット2まで取り消される(コミット3だけではない)

対策:

  • コミットハッシュで直接指定
  • 実行前に必ず git log で確認
$ # より明確な方法
$ git reset --hard ghi9012  # コミットハッシュで直接指定
$ # または
$ git reset --hard HEAD~1  # 1つ前に戻す(明確)

間違い4:削除されたコミットの復元を諦める

問題: git reset --hard で変更が消えたと思ってあきらめるユーザー

対策: Gitには git reflog コマンドで削除されたコミットを復元できる可能性があります。

$ # 削除されたと思ったコミットを復元
$ git reflog  # すべての操作履歴を表示
abc1234 HEAD@{0}: reset: moving to HEAD~1
def5678 HEAD@{1}: commit: 間違ったコミット
ghi9012 HEAD@{2}: commit: 前のコミット

$ # 削除されたコミット(def5678)に戻す
$ git reset --hard def5678

5. まとめと推奨される使い分け

各コマンドの使い分けガイド

コマンド リセット範囲 使用場面 危険度
git reset --soft Gitリポジトリのみ コミットメッセージの修正、複数コミットをまとめる 低い
git reset --mixed Gitリポジトリ+ステージング ファイルの追加取り消し、再選別 低い
git reset --hard 全エリア 完全にリセット(ローカルのみ) 高い

実務での推奨フロー

#!/bin/bash
# 推奨されるGitワークフロー

# 1. 現在の状態を常に確認
git status
git log --oneline -10

# 2. 間違ったコミットが見つかった場合
# ステップA:変更を保持したい場合
git reset --mixed HEAD~1  # またはgit reset HEAD~1
git diff  # 変更内容を確認

# ステップB:コミットメッセージだけ修正したい場合
git reset --soft HEAD~1
git commit -m \"修正されたメッセージ\"

# ステップC:完全にやり直したい場合(ローカルのみ)
git reset --hard HEAD~1

# ステップD:既にpushした場合
git revert HEAD~1
git push origin main

# 3. 危険な操作の後は必ず確認
git log --oneline -10
git status

最後のアドバイス

Gitの reset コマンドは非常に強力ですが、同時に危険です。以下のポイントを忘れずに:

  • 常に確認:実行前に必ず現在の状態を確認する
  • ローカルのみ:pushする前に修正する
  • 段階的に:いきなり --hard は避け、--soft--mixed から試す
  • バックアップ:重要なブランチではstashで変更を保存
  • reflogを活用:誤操作時は git reflog で復元を試みる

git reset コマンドを正しく理解し、使い分けることで、Gitをより効果的に活用でき、誤操作のリスクも大幅に減らせます。

タイトルとURLをコピーしました