git-reset.md (8312B)
1 --- 2 title: "Git Reset & Undo" 3 description: "Undo work safely: reset soft/mixed/hard, restore, revert, reflog recovery and stash rescue." 4 category: git-workflow 5 tags: [git, undo, recovery] 6 tools: [git] 7 difficulty: intermediate 8 updated: "2026-08-09" 9 source: "vault:Git/Resetting.md" 10 --- 11 12 # Git Reset & Undo 13 14 Working-tree inspection, diffing, restoring, and amending — knowing which of Git's three zones a change lives in determines which command undoes it safely. 15 16 > **Prerequisites —** 17 > 1. Must be inside a valid Git repository (`git init` or cloned). 18 > 2. `git restore` requires **Git 2.23.0+** (2019) — use legacy equivalents on older versions. 19 > 3. For `--amend`: must be on a **local-only** branch — do not amend commits already pushed to a shared remote. 20 21 > **Working tree state — conceptual overview:** Git tracks files across three zones: 22 > 1. **Working Tree** — your local filesystem; where you edit files. 23 > 2. **Staging Area (Index)** — files queued for the next commit via `git add`. 24 > 3. **Repository** — committed history; each snapshot has a unique SHA hash. 25 > 26 > Understanding which zone a file lives in determines which command to use. 27 28 > **Output state reference —** 29 > 30 > | Status Message | Meaning | 31 > |---|---| 32 > | `Changes not staged for commit` | Modified in working tree, not yet staged | 33 > | `Changes to be committed` | Staged; ready for next commit | 34 > | `nothing to commit, working tree clean` | Working tree matches last commit exactly | 35 > | `Untracked files` | New file Git has never seen | 36 37 > **Diff output prefix reference —** 38 > 39 > | Prefix | Meaning | 40 > |---|---| 41 > | `---` | Old version of the file | 42 > | `+++` | New version of the file | 43 > | `-` | Line removed in new version | 44 > | `+` | Line added in new version | 45 > | (none) | Unchanged context line | 46 > 47 > `@@ -1 +1 @@` indicates line numbers affected in the old (`-`) and new (`+`) file. 48 49 ## Inspecting Working Tree State 50 51 ```bash 52 # Check current state of working tree and staging area 53 git status 54 ``` 55 56 > **Command breakdown — `git status`:** 57 > 1. No flags required — produces full human-readable output by default. 58 > 2. `-s` / `--short` — terse, machine-friendly output format. 59 > 3. Read-only; generates no network traffic and no Git history artefacts. 60 61 ## Diffing Working Tree vs. Last Commit 62 63 ```bash 64 # Diff all modified files against staging area / last commit 65 git diff 66 67 # Explicitly diff working tree against latest commit on current branch 68 git diff HEAD 69 70 # Diff a specific file against a specific commit hash 71 git diff 4620193 example.html 72 ``` 73 74 > **Command breakdown — `git diff`:** 75 > 1. (no args) — compares working tree against the staging area; equivalent to last commit if nothing is staged. 76 > 2. `HEAD` — explicitly targets the latest commit on the current branch. 77 > 3. `<commit> <file>` — targets a specific file at a specific commit SHA. 78 > 4. Read-only; no history artefacts created. 79 80 > **Warning — Pager mode:** If output fills the terminal, Git enters pager mode (usually `less`). Scroll with arrow keys; press `q` to exit. Pager behaviour is controlled by the `$PAGER` environment variable. 81 82 > **No output shown —** The file may already be staged; staged changes are invisible to `git diff` (no args). Use `git diff --staged` to compare staged changes against the last commit. 83 84 ## Discarding Local (Unstaged) Changes 85 86 > **Danger — Destructive operation:** `git restore` on the **working tree** permanently discards uncommitted edits. Changes are **not recoverable** unless a stash or reflog entry exists. Always run `git diff` first to review what will be lost. 87 88 ```bash 89 # Restore all files in the current directory to last committed state 90 git restore . 91 92 # Restore a single named file only 93 git restore hello.html 94 95 # Restore a subdirectory 96 git restore src/ 97 ``` 98 99 > **Command breakdown — `git restore` (working tree):** 100 > 1. `.` — restores all files in the current directory recursively. 101 > 2. `<file>` — restores a single named file only. 102 > 3. `<path/>` — restores an entire subdirectory. 103 > 4. `--worktree` — explicit flag for this mode; same as omitting it (default behaviour). 104 > 5. No network activity; modifies only local files. 105 106 ```bash 107 # Confirm clean state after restoring 108 git status 109 # Expected: nothing to commit, working tree clean 110 ``` 111 112 > **Result —** `git restore` produces no output on success. Confirm with `git status` — should show `nothing to commit, working tree clean`. 113 114 > **Common errors —** 115 > 1. `error: pathspec 'X' did not match any file(s)` → check filename spelling and current working directory. 116 > 2. Accidentally discarding intended work → always run `git diff` before `git restore`. 117 118 > **Tip — Legacy equivalent:** `git checkout -- <file>` performs the same action but is superseded. Prefer `git restore` on modern installs (Git 2.23.0+). 119 120 ## Unstaging Staged Changes 121 122 ```bash 123 # Unstage all staged files — edits are preserved in working tree 124 git restore --staged . 125 126 # Unstage a single file — edits preserved 127 git restore --staged hello.html 128 129 # Unstage AND discard working tree changes in one step (destructive) 130 git restore --staged --worktree . 131 ``` 132 133 > **Command breakdown — `git restore --staged`:** 134 > 1. `--staged` — operates on the staging area (index) rather than the working tree; non-destructive. 135 > 2. `--staged --worktree` — unstages **and** discards working tree changes in a single command; destructive. 136 > 3. After `--staged` alone: file appears under `Changes not staged for commit` — edits still present. 137 > 4. After `--staged --worktree`: `git status` shows `nothing to commit, working tree clean`. 138 139 > **Warning — Easy to confuse:** `git restore .` ≠ `git restore --staged .` — the first only affects the **working tree**; it does not unstage. After `--staged` alone, edits are **not gone** — run `git restore .` separately if you also want to discard them. 140 141 > **Tip — Legacy equivalent:** `git reset HEAD <file>` performs the same unstaging action. Available on Git versions older than 2.23.0. 142 143 ## Fixing the Last Commit — `--amend` 144 145 > **Danger — History-rewriting warning:** 146 > 1. `--amend` **replaces** the last commit — a new SHA is generated; the old one disappears locally. 147 > 2. **Do not amend commits already pushed to a shared remote** — this requires `git push --force`, which is visible to all collaborators. 148 > 3. The old commit object remains accessible via `git reflog` until garbage-collected. 149 > 4. On shared branches, prefer adding a new fix commit rather than amending. 150 151 ```bash 152 # Fix only the commit message inline 153 git commit --amend -m "Added HTML tags to hello.html" 154 155 # Add a forgotten file and update the message in one step 156 git add hello.html 157 git commit --amend -m "Added H1, HTML, and BODY tags to hello.html" 158 159 # Amend message interactively via default text editor (vim/nano) 160 git commit --amend 161 ``` 162 163 > **Command breakdown — `git commit --amend`:** 164 > 1. `--amend` — replaces the most recent commit with a new one (new SHA generated). 165 > 2. `-m "<msg>"` — sets the new commit message inline; omit to open the configured text editor. 166 > 3. Pre-stage additional files with `git add` **before** running `--amend` to include them in the amended commit. 167 > 4. Git prints the updated commit summary including the new amended SHA on success. 168 169 > **Common editor traps —** 170 > 1. **Stuck in vim** (opened by omitting `-m`) → press `Esc`, type `:wq`, press `Enter` to save and exit. 171 > 2. **Stuck in nano** → `Ctrl+O` to save → `Enter` to confirm filename → `Ctrl+X` to exit. 172 > 3. **Amended a pushed commit** → coordinate with the team before force-pushing; prefer a new fix commit on shared branches. 173 174 > **Tip — Best-practice workflow:** 175 > 1. Stage any missed files: `git add <file>` 176 > 2. Review what will change: `git diff --staged` 177 > 3. Amend with corrected message: `git commit --amend -m "<message>"` 178 > 4. Verify result: `git log --oneline -1` 179 180 ## References 181 182 - [git-status Documentation](https://git-scm.com/docs/git-status) 183 - [git-diff Documentation](https://git-scm.com/docs/git-diff) 184 - [git-restore Documentation](https://git-scm.com/docs/git-restore) 185 - [git-commit --amend Documentation](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---amend) 186 - [Atlassian — Rewriting Git History](https://www.atlassian.com/git/tutorials/rewriting-history)