Git: Gitの「reset」と「undo」操作に関する詳しい解説
「リセット」は、Git の強力な元に戻すコマンドです。リセットを使用すると、コミットを元に戻したり、ステージングされた変更を解除したり、変更内容を破棄したりすることができます。リセットの 3 つのモードを理解することは、バージョン管理において極めて重要です。
1. 基本概念の再確認
(1) What Is a Reset?
リセットとは、現在の分岐を指定された位置に移動させる操作のことです:
- ブランチポインタの移動:HEAD とブランチポインタを指定されたコミットに移動する
- 一時保存領域の更新:モードに基づいて、一時保存領域を更新するかどうかを判断する
- ワークスペースの更新:モードに基づいて、ワークスペースを更新するかどうかを決定します
- 操作の取り消し:コミット、ステージング、および変更を取り消す
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つの作業領域について理解する必要があります:
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
- HEAD:現在のブランチを指します
- ブランチポインタ:特定のコミットを指す
- リポジトリ:すべてのコミットを保存する
- ステージング領域:コミット準備が整った変更
- ワークスペース:実際に編集中のファイル
(3) 方向のリセット
前方向または後方向にリセットできます:
- Reset Backward:コミットを元に戻し、前の状態に戻す
- リセット・フォワード:次のコミットへ進む(ほとんど使用されない)
2. 3つのリセットモード
(1) ソフトリセット (--soft)
ステージング領域と作業領域を維持したまま、HEADポインタとブランチポインタのみを移動します。
▶ サンプル:ソフトリセット
# 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 ポインタとブランチポインタを移動し、ステージングエリアを更新し、作業ディレクトリを維持します。
▶ サンプル:ハイブリッドリセット
# 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 ポインタとブランチポインタを移動し、ステージング領域と作業ディレクトリを更新します。
▶ サンプル:ハードリセット
# 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つのモードの図解
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」の使用例:
- 提出した情報に誤りがあったため、再提出したいのですが
- 複数のコミットを1つにマージしたい
- 提出内容の編集
mixed の使用例:
- コミットを元に戻し、変更内容を整理し直す
- ステージング領域にあるファイルのチェックを外し、コミットしたいファイルを再度選択してください
- デフォルトモード。最も一般的に使用されるモードです。
「hard」の使用例:
- 現在の変更をすべて破棄する
- 特定の状態に戻る
- 作業スペースを整理する(使用には注意が必要です)
4. リセット手順の詳細な説明
(1) 特定のコミットにリセットする
▶ サンプル:特定のコミットにロールバックする
# 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) スタッシュを元に戻す
▶ サンプル:ステージングの解除
# 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) ワークスペースへの変更を元に戻す
▶ サンプル:ワークスペースの変更を破棄する
# 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 を使用してローカルコミットを元に戻す
# 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 を使用して、プッシュしたコミットを元に戻す
# 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) セキュリティのリセット手順
▶ サンプル:セキュリティのリセット
# 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 を使用した復旧
▶ サンプル:誤ったリセットからの復旧
# 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) ワークフローをリセットする
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
❓ よくある質問
resetはいつ使い、revertはいつ使えばよいですか?reset を使用し、プッシュ済みのコミットについては revert を使用してリバースコミットを作成します。reset は履歴を書き換え、revert は履歴を保持します。reset --hard を使用するとデータが失われることはありますか?git add の操作を元に戻すにはどうすればよいですか?git reset <file> または git restore --staged <file> を使用すると、ステージングを1つ破棄できます。git reset を使用すると、すべてのステージングを破棄できます。git reflog を使用して操作履歴を確認し、リセット前の HEAD の位置を特定してから、git reset --hard <commit> を使用してその状態を復元してください。あるいは、バックアップブランチがある場合は、そのブランチにリセットするだけで済みます。📖 まとめ
- リセットとは、分岐ポインタを指定された位置に移動させる操作のことです。
- 3つのモード:ソフト(変更内容を保持)、ミックス(ワークスペースを保持)、ハード(完全リセット)
- ソフトリセット:ステージング領域と作業ディレクトリを維持したまま、コミットを元に戻す
- 混合リセット:コミットとステージングを元に戻すが、作業ディレクトリは保持する(デフォルト)
- ハードリセット:すべての変更を完全に元に戻します(使用にはご注意ください)
- reset と revert の違い:「reset」はローカルブランチに対して使用され、「revert」はプッシュ済みのブランチに対して使用されます
📝 練習問題
-
基本演習:複数のコミットを作成し、3つのリセットモードそれぞれを使用してそれらをリセットし、ステージング領域と作業ディレクトリの変化を確認して、3つのモードの違いを理解する。
-
応用演習:誤ったコミットのシナリオをシミュレートします。誤ったコミットを作成し、
resetを使用してそれを元に戻した後、正しいバージョンをコミットして、resetの実用的な活用方法を体験してください。 -
課題:reflogの威力を体験しましょう。複数のリセット操作を実行し、reflogを使って操作履歴を確認し、リセットの失敗から復旧し、Gitのデータ保護メカニズムについて理解を深めましょう。