Git: Gitの「reset」と「undo」操作に関する詳しい解説

「リセット」は、Git の強力な元に戻すコマンドです。リセットを使用すると、コミットを元に戻したり、ステージングされた変更を解除したり、変更内容を破棄したりすることができます。リセットの 3 つのモードを理解することは、バージョン管理において極めて重要です。

1. 基本概念の再確認

(1) What Is a Reset?

リセットとは、現在の分岐を指定された位置に移動させる操作のことです:

100%
graph TB
    A[git reset] --> B{Pattern}
    B -->|soft| C[Move only the pointer<br/>Preserve the temporary storage area and the workspace]
    B -->|mixed| D[Move the pointer+Update the temporary storage area<br/>Save Workspace]
    B -->|hard| E[Move the pointer+Update the temporary storage area+Update Workspace]
    
    style C fill:#d4edda
    style D fill:#fff3cd
    style E fill:#f8d7da

(2) Gitの3つの領域

resetを理解するには、まずGitの3つの作業領域について理解する必要があります:

100%
graph TB
    HEAD[HEADPointer] --> Branch[Branch pointer]
    Branch --> Repo[Repository<br/>Repository]
    Repo --> Stage[Buffer<br/>Staging Area]
    Stage --> Work[Workspace<br/>Working Directory]
    
    style HEAD fill:#f8d7da
    style Repo fill:#c3e6cb
    style Stage fill:#d4edda
    style Work fill:#fff3cd

(3) 方向のリセット

前方向または後方向にリセットできます:



2. 3つのリセットモード

(1) ソフトリセット (--soft)

ステージング領域と作業領域を維持したまま、HEADポインタとブランチポインタのみを移動します。

▶ サンプル:ソフトリセット

BASH
# View Current Status
git log --oneline -3

# Output:
# d4e5f6g (HEAD -> main) feat: Add FeatureC
# h7i8j9k feat: Add FeatureB
# k9l0m1n feat: Add FeatureA

# Soft reset to the previous commit
git reset --soft HEAD~1

# View Status
git status

# Output:
# On branch main
# Changes to be committed:
#   (use "git restore --staged <file>..." to unstage)
#   new file:   feature-c.js

# View History
git log --oneline -3

# Output:
# h7i8j9k (HEAD -> main) feat: Add FeatureB
# k9l0m1n feat: Add FeatureA
# a1b2c3d Initial commit

# The commit is still in the staging area,You can resubmit it.
git commit -m "feat: Re-add FeatureC"

ソフトリセットによる影響:

(2) 混合リセット (--mixed、デフォルト)

HEAD ポインタとブランチポインタを移動し、ステージングエリアを更新し、作業ディレクトリを維持します。

▶ サンプル:ハイブリッドリセット

BASH
# View Current Status
git log --oneline -3

# Output:
# d4e5f6g (HEAD -> main) feat: Add FeatureC
# h7i8j9k feat: Add FeatureB
# k9l0m1n feat: Add FeatureA

# Mixed Reset(Default Mode)
git reset HEAD~1

# Or specify explicitly
git reset --mixed HEAD~1

# View Status
git status

# Output:
# On branch main
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#   feature-c.js

# View History
git log --oneline -3

# Output:
# h7i8j9k (HEAD -> main) feat: Add FeatureB
# k9l0m1n feat: Add FeatureA

# Edits in the workspace,Needs to be redoneadd
git add feature-c.js
git commit -m "feat: Re-add FeatureC"

ハイブリッドリセットの影響:

(3) ハードリセット (--hard)

HEAD ポインタとブランチポインタを移動し、ステージング領域と作業ディレクトリを更新します。

▶ サンプル:ハードリセット

BASH
# View Current Status
git log --oneline -3

# Output:
# d4e5f6g (HEAD -> main) feat: Add FeatureC
# h7i8j9k feat: Add FeatureB
# k9l0m1n feat: Add FeatureA

# Hard Reset
git reset --hard HEAD~1

# Output:
# HEAD is now at h7i8j9k feat: Add FeatureB

# View Status
git status

# Output:
# On branch main
# nothing to commit, working tree clean

# View History
git log --oneline -3

# Output:
# h7i8j9k (HEAD -> main) feat: Add FeatureB
# k9l0m1n feat: Add FeatureA

# ⚠️ FeaturesCThe changes have been completely lost!

ハードリセットによる影響:

⚠️ 警告:ハードリセットを行うと、保存されていない変更内容はすべて失われます。ご注意の上、ご利用ください!



3. リセットモードの比較

(1) 3つのモードの比較表

モード HEAD ステージング領域 作業ディレクトリ 目的
soft 操作 変更不可 変更不可 コミットを元に戻し、再コミット
mixed Move Update Keep Revert and Stage
ハード 移動 更新 更新 完全に元に戻す、変更を破棄

(2) 3つのモードの図解

100%
graph TB
    subgraph Before the reset
        A1[HEAD -> C3] --> B1[Buffer: C3Status]
        B1 --> C1[Workspace: C3Status]
    end
    
    subgraph softReset
        A2[HEAD -> C2] --> B2[Buffer: C3Status<br/>Retain]
        B2 --> C2[Workspace: C3Status<br/>Retain]
    end
    
    subgraph mixedReset
        A3[HEAD -> C2] --> B3[Buffer: C2Status<br/>Update]
        B3 --> C3[Workspace: C3Status<br/>Retain]
    end
    
    subgraph hardReset
        A4[HEAD -> C2] --> B4[Buffer: C2Status<br/>Update]
        B4 --> C4[Workspace: C2Status<br/>Update]
    end

(3) 適切なモードを選択する

「soft」の使用例:

mixed の使用例:

「hard」の使用例:



4. リセット手順の詳細な説明

(1) 特定のコミットにリセットする

▶ サンプル:特定のコミットにロールバックする

BASH
# Revert to a Specific CommitID
git reset a1b2c3d

# Reset to a Specific Tag
git reset v1.0.0

# Reset to Relative Position
git reset HEAD~1   # Previous Commit
git reset HEAD~3   # Previous 3 commits
git reset HEAD^    # Previous Commit(Equivalent toHEAD~1)
git reset HEAD^^   # The first two commits

# Reset to a remote branch
git reset origin/main

(2) スタッシュを元に戻す

▶ サンプル:ステージングの解除

BASH
# View the Stash
git status

# Output:
# Changes to be committed:
#   new file:   file1.js
#   new file:   file2.js

# Uncheck "Save a file to the clipboard"
git reset file1.js

# Or userestore
git restore --staged file1.js

# Discard all changes
git reset

# View Status
git status

# Output:
# Untracked files:
#   file1.js
#   file2.js

(3) ワークスペースへの変更を元に戻す

▶ サンプル:ワークスペースの変更を破棄する

BASH
# View Workspace Changes
git status

# Output:
# Changes not staged for commit:
#   modified:   README.md

# Discard Workspace Changes
git restore README.md

# Or use the old syntax
git checkout -- README.md

# Discard all workspace changes
git restore .

# Or
git checkout -- .

# ⚠️ This will permanently lose any unsaved changes.!


5. 「リセット」と「リバート」の違い

(1) リセットとリバート

機能 リセット 元に戻す
使い方 ポインタを移動する 新しいコミットを作成する
履歴 履歴を削除 履歴を保持
プッシュ済み 強制プッシュが必要 通常通りプッシュ可能
安全性 コミットが失われる可能性がある コミットが失われることはない
ユースケース プッシュされていないローカルコミット プッシュ済みのコミット

(2) reset を使用してローカルコミットを元に戻す

▶ サンプル:reset を使用してローカルコミットを元に戻す

BASH
# An incorrect commit was created locally
git commit -m "Incorrect Submission"

# Undo Commit(Keep the changes)
git reset --soft HEAD~1

# Resubmit after making corrections
git commit -m "Correct Submission"

# Regular Push Notifications
git push origin main

(3) revert を使用して、プッシュしたコミットを元に戻す

▶ サンプル:revert を使用して、プッシュしたコミットを元に戻す

BASH
# Pushed commits
git push origin main

# UsagerevertCreate a Revert Commit
git revert a1b2c3d

# Output:
# [main d4e5f6g] Revert "Incorrect Submission"
#  1 file changed, 1 deletion(-)

# Regular Push Notifications
git push origin main

# The history will retain the original submission andrevertSubmit
git log --oneline

# Output:
# d4e5f6g Revert "Incorrect Submission"
# a1b2c3d Incorrect Submission
# h7i8j9k Normal submission


6. リセットに関するベストプラクティス

(1) セキュリティのリセット手順

▶ サンプル:セキュリティのリセット

BASH
# 1. View Current Status
git status
git log --oneline -5

# 2. Confirm which commit to roll back to
git log --oneline

# 3. First, create a backup branch(Optional)
git branch backup-branch

# 4. Perform a reset
git reset --hard a1b2c3d

# 5. Verification Results
git log --oneline -5
git status

# If the reset is done incorrectly,Can be restored
git reset --hard backup-branch

(2) reflog を使用した復旧

▶ サンプル:誤ったリセットからの復旧

BASH
# Operational error:A hard reset caused the commit to be lost
git reset --hard HEAD~3

# Viewreflog
git reflog

# Output:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3
# d4e5f6g HEAD@{1}: commit: feat: Add FeatureC
# h7i8j9k HEAD@{2}: commit: feat: Add FeatureB
# k9l0m1n HEAD@{3}: commit: feat: Add FeatureA

# Restore to the state prior to the reset
git reset --hard d4e5f6g

# Verification and Recovery
git log --oneline -5

(3) ワークフローをリセットする

100%
graph TB
    A[The operation needs to be undone] --> B{Has the operation been pushed??}
    B -->|Not pushed| C[Usagereset]
    B -->|Pushed| D[Usagerevert]
    C --> E{Keep or Discard Changes??}
    E -->|Yes| F[reset --soft/--mixed]
    E -->|No| G[reset --hard]
    D --> H[Create a Revert Commit]
    
    style C fill:#d4edda
    style D fill:#fff3cd
    style G fill:#f8d7da

❓ よくある質問

Q 3つのリセットモードにはどのような違いがありますか?
A --soft はポインタのみを移動し、一時領域と作業領域は変更しません。--mixed はポインタを移動し、一時領域を更新しますが、作業領域は変更しません(デフォルト)。--hard はポインタを移動し、一時領域と作業領域の両方を更新して、指定された状態を完全に復元します。
Q resetはいつ使い、revertはいつ使えばよいですか?
A プッシュされていないローカルコミットを元に戻すには reset を使用し、プッシュ済みのコミットについては revert を使用してリバースコミットを作成します。reset は履歴を書き換え、revert は履歴を保持します。
Q reset --hard を使用するとデータが失われることはありますか?
A 保存されていない変更は失われます。ただし、reflog を使用すれば、直近のリセット操作を復元することができます。コミットがリセットされた場合でも、そのコミット ID を使って復元することは可能です。
Q git add の操作を元に戻すにはどうすればよいですか?
A git reset <file> または git restore --staged <file> を使用すると、ステージングを1つ破棄できます。git reset を使用すると、すべてのステージングを破棄できます。
Q リセット後にデータを復元するにはどうすればよいですか?
A git reflog を使用して操作履歴を確認し、リセット前の HEAD の位置を特定してから、git reset --hard <commit> を使用してその状態を復元してください。あるいは、バックアップブランチがある場合は、そのブランチにリセットするだけで済みます。

📖 まとめ


📝 練習問題

  1. 基本演習:複数のコミットを作成し、3つのリセットモードそれぞれを使用してそれらをリセットし、ステージング領域と作業ディレクトリの変化を確認して、3つのモードの違いを理解する。

  2. 応用演習:誤ったコミットのシナリオをシミュレートします。誤ったコミットを作成し、reset を使用してそれを元に戻した後、正しいバージョンをコミットして、reset の実用的な活用方法を体験してください。

  3. 課題:reflogの威力を体験しましょう。複数のリセット操作を実行し、reflogを使って操作履歴を確認し、リセットの失敗から復旧し、Gitのデータ保護メカニズムについて理解を深めましょう。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%