Undoing Changes, Reset, Restore, Revert, Reflog, and Lost-Work Recovery: Concepts, Architecture, and Mental Model
Build a state-based Git recovery model that separates working-tree, index, local-history, and published-history mistakes; map restore, reset, revert, reflog, reachability, and object retention to the correct layer.
Learning objectives
- Classify undo problems by working tree, index, local history, and published history.
- Map restore, soft/mixed/hard reset, and revert to the layers they change.
- Explain reflogs as local time-limited ref-movement journals rather than backups.
- Distinguish reachable, unreachable, dangling, and missing object states.
- Use read-only evidence commands before attempting any recovery mutation.
1. Recovery starts by naming the layer that is wrong
Chapters 04 and 09 established the layers that Git can change: the working tree, the index, refs such as the current branch, commit history, and remote/shared history. “Undo my mistake” is therefore incomplete. A safe recovery question is: which layer contains the mistake, which layer still contains the version I want, and has the mistaken state already been published?
If a file is wrong only in the working tree, moving a branch ref is unnecessary. If one path is staged accidentally, destroying the working tree is unnecessary. If a bad commit was already shared, rewriting the branch may be worse than the original bug. This chapter turns those distinctions into a repeatable incident-response decision process.
2. Preserve evidence before mutating anything
git rev-parse --show-toplevel
git status --short --branch
git diff
git diff --staged
git log --graph --decorate --oneline --all --max-count=20
git reflog -10
git show --stat --summary HEAD
git branch -vv
This establishes location, dirty state, staged state, graph shape, recent ref movement, current commit contents, and publication/tracking clues. Capture output or exact OIDs during a real incident before running commands that move refs or overwrite files.
3. Four different “undo” problems
| Wrong state | Desired state still lives in | Typical first tool |
|---|---|---|
| Working-tree edit | Index or chosen historical tree | git restore |
| Index/staging choice | HEAD or chosen tree |
git restore --staged |
| Unpublished local branch tip/history | Earlier commit/reflog | git reset after preflight |
| Published bad commit | Shared history must remain auditable | git revert |
The table is a starting point, not permission to run a command blindly. Always inspect path scope, target commit, and publication state.
4. Restore copies content into a selected destination layer
With no --staged,
git restore path restores the
working tree from the index by default. With
--staged, the destination is the
index and the default source is HEAD.
An explicit --source=<tree> changes the source.
git diff -- app.conf
git restore -- app.conf
git diff --staged -- app.conf
git restore --staged -- app.conf
git restore --source=HEAD~1 -- app.conf
git show HEAD~1:app.conf.
5. Reset moves HEAD and optionally synchronizes lower layers
When used with a commit target, reset moves the current branch/HEAD to that commit. The mode controls what else follows the new HEAD.
| Mode | HEAD/branch | Index | Working tree | Typical learning use |
|---|---|---|---|---|
--soft |
Moves | Unchanged | Unchanged | Uncommit locally while leaving changes staged |
--mixed (default) |
Moves | Reset to target | Unchanged | Uncommit locally and leave changes unstaged |
--hard |
Moves | Reset to target | Reset to target | Disposable recovery demonstration only; discards tracked working/index changes |
git reset --hard is destructive. It
can overwrite tracked working-tree changes and remove tracked paths
that do not exist in the target commit. This course uses it only
inside disposable repositories with preflight, saved OIDs, and
post-operation recovery verification.
6. Reset mode state map
flowchart TD T[Target commit/tree] S[--soft] M[--mixed] H[--hard] HEAD[HEAD/current branch] IDX[Index] WT[Working tree] T --> S --> HEAD T --> M --> HEAD M --> IDX T --> H --> HEAD H --> IDX H --> WT
The diagram shows destination scope. Soft moves only the ref. Mixed moves the ref and makes the index match the target, while preserving working-tree files. Hard moves all three layers to the target. It does not depict remote history; reset is fundamentally a local ref/state operation until you publish a replacement ref.
7. Revert preserves history by adding a new inverse commit
git revert BAD computes the change needed to reverse
the effect of BAD and records that reversal as a new
commit. The old bad commit remains in history. That makes revert
appropriate for many shared-history corrections: the event and its
correction are both auditable.
git show --stat BAD
git revert BAD
git log --oneline -4
Revert can conflict if later history changed the same content. It also has special semantics for merge commits because Git must know which parent represents the mainline; Lesson 4 treats that explicitly.
8. Reflog is a local journal of ref movement
A reflog records recent values of refs in one repository. Entries
such as HEAD@{1} or an exact OID can reveal where a
branch/HEAD pointed before reset, rebase, amend, checkout/switch, or
commit operations.
git reflog --date=local
git show HEAD@{1}
git branch recovered-work <verified-old-oid>
Reflogs are local. Another clone/server may have different history and different retention. Current defaults normally expire reachable reflog entries after about 90 days and entries unreachable from the current tip after about 30 days, unless configuration changes those windows.
9. Reachable, unreachable, and dangling are object-graph terms
A commit is reachable when Git can walk to it from
a root such as a branch/tag/ref. An object can become
unreachable when no ref reaches it—for example
after a reset or branch deletion. git fsck can report
unreachable or dangling objects that still physically exist.
“Dangling” is a diagnostic notion for an object present in the
database but not directly used by another object in the traversed
graph.
Existence is not permanence. Reflog expiry and garbage collection can eventually remove protection and prune old unreachable objects. Recovery should happen before maintenance, not after aggressive cleanup.
10. DevOps incident-response connection
A production rollback discussion often begins with “what changed?” Git recovery adds two further questions: “which exact OID/ref represented the known-good state?” and “should we preserve the bad event in shared history?” Additive reverts are often operationally preferable on published branches because deployment records, reviews, attestations, and incident timelines keep referring to stable commit IDs.
11. Knowledge check
Question 1. A file has an unwanted unstaged edit. Which layer is wrong?
git diff -- path; if the
index contains the desired version,
git restore -- path can copy it back.
Question 2. What does
git reset --soft HEAD~1 change?
Question 3. Why is revert usually safer than reset for a published bad commit?
Question 4. Is a reflog a distributed backup?
Question 5. Does “unreachable” mean the object has already been deleted?
12. Summary
Recovery is a state-selection problem. Restore targets path content in the working tree/index; reset moves a local ref and optionally synchronizes index/working tree; revert adds an auditable correction to history; reflog helps locate prior local ref values. The safest recovery command is the narrowest one that changes the layer actually at fault.
Authoritative references
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.