Chapter 10Lesson 04~105 minutes

Undoing Changes, Reset, Restore, Revert, Reflog, and Lost-Work Recovery: Diagnostics, Failure Modes, Security, and Performance

Diagnose recovery failures caused by wrong-layer hard reset, wrong-source restore, clone-local reflog assumptions, unsafe clean, merge-revert ambiguity, and premature garbage collection.

DiagnosticsMerge revertClean safetyGC red zone

Learning objectives

  • Apply a preserve-evidence-first recovery diagnostic sequence.
  • Replace broad destructive responses with path/layer-specific corrections.
  • Explain why reflog evidence does not automatically exist in another clone/server.
  • Diagnose merge-revert mainline requirements and fsck object-state messages.
  • Prevent cleanup and aggressive maintenance from destroying recovery options.

1. Diagnostic sequence for recovery incidents

  1. Preserve evidence: save exact OIDs, status/diff output, reflog, remote refs, and any deployment/review identifiers.
  2. Inspect status, refs, history, and config.
  3. Identify the affected layer: working tree, index, current ref/history, shared history, untracked files, or object retention.
  4. Choose the least destructive correction.
  5. Verify both content and graph, then document what moved.

2. Failure mode — using hard reset when only unstaging was needed

Symptom: a developer stages config.yml by mistake and thinks “reset it.” A hard reset would also overwrite tracked working-tree content.

git status --short
git diff --staged -- config.yml
git diff -- config.yml

If only the index is wrong, the narrow correction is:

git restore --staged -- config.yml
git status --short
git diff -- config.yml
Do not escalate from a one-path index mistake to git reset --hard. Recovery scope should match failure scope.

3. Failure mode — restoring from the wrong source revision

git restore --source=HEAD~2 -- app.conf intentionally copies that old tree's file into the working tree. It does not mean “undo two edits” or “find last good.”

git show HEAD~2:app.conf
git diff HEAD~2 -- app.conf
git status --short

If the wrong source was restored but not staged/committed, the current index may still contain the pre-restore version; inspect git show :app.conf, then restore from the index if that is the intended state.

4. Failure mode — expecting another clone's reflog to exist here

A teammate says “my branch was at commit X yesterday; check the reflog on the server.” Core Git reflogs are repository-local. Your clone's HEAD@{1} describes your ref movements, not theirs.

git reflog --all
git remote -v
git ls-remote origin
git log --all --decorate --oneline --max-count=30

Search refs/remote state and ask the teammate to inspect their own reflog. A hosting service may have separate administrative recovery capabilities, but those are platform-specific and not guaranteed by core Git.

5. Failure mode — running clean without dry-run

Untracked files are not protected by normal commit history. A forced clean can permanently remove local-only files.
git status --short
git clean -n
git clean -nd
git clean -nx

Only after confirming every candidate in a disposable lab should you demonstrate deletion with a narrow pathspec. Avoid -x unless the explicit goal is to include ignored artifacts; avoid -fdx as a routine cleanup pattern.

6. Intentionally broken example — reverting a merge without mainline

A merge commit has more than one parent. Running:

git revert <merge-commit>

typically fails with an error explaining that the commit is a merge and no -m option was given. This is valuable: Git refuses to guess which parent represents the mainline.

git show --no-patch --format='%H %P %s' <merge-commit>
git rev-list --parents -n 1 <merge-commit>

If parent 1 is the mainline you intend to preserve, the deliberate form is git revert -m 1 <merge-commit>. But understand the semantic consequence: reverting a merge declares that the tree changes introduced by that merge are unwanted; later merge behavior can therefore differ from “pretend the merge never happened.”

7. Failure mode — aggressive maintenance before recovery

If you are searching for reset-away or deleted-branch objects, do not expire reflogs or prune unreachable objects first.

Red zone: git reflog expire --expire=now --all, git prune --expire=now, and git gc --prune=now can reduce or destroy recovery options. Preserve evidence and create safety refs before maintenance.
git reflog --all
git fsck --unreachable
git fsck --no-reflogs --unreachable

The difference between the last two commands can reveal objects protected only through reflog roots.

8. Read fsck diagnostics precisely

Diagnostic Meaning
unreachable commit Object exists but no selected root reaches it
dangling commit Commit exists but is not directly used in the traversed graph
missing blob/tree/commit A referenced object is absent; this is corruption, not merely lost reachability
hash mismatch Serious object-integrity problem

A missing/corrupt object must generally come from another intact copy, backup, or archive; reflog cannot recreate bytes that no longer exist.

9. Security implications tied to recovery

  • Do not expose private repository contents by uploading a full bundle to an untrusted location merely because you are under incident pressure.
  • A recovered secret-bearing commit remains sensitive; rotate/revoke leaked credentials first.
  • Do not disable server protections or use force push merely to “make history match” during recovery.
  • Preserve forensic timestamps/OIDs before destructive repair if an incident investigation is underway.

10. Performance implications that matter during recovery

git fsck and full object traversal can be expensive in large repositories. Start with narrow evidence—known refs, reflogs, exact OIDs, git show—and escalate to broader connectivity checks when needed. Likewise, do not run aggressive GC merely because the repository feels slow while recovery is unresolved; performance optimization and evidence preservation have different priorities.

11. Symptom → evidence → narrow response

Symptom First evidence Narrow response
Wrong file staged staged/unstaged diff restore --staged path
Wrong historical file restored index + source commit content Restore from correct source/index
Branch deleted HEAD/all reflog + known OID Create recovery branch
Published bad commit remote refs + graph Revert
Untracked clutter clean -n Narrow forced clean only if every candidate is disposable
Potential lost object reflog then fsck Create safety ref before maintenance

12. Knowledge check

Question 1. Why is hard reset an incorrect response to accidental staging?

Question 2. Why can't you rely on your local reflog to recover a teammate's deleted local branch?

Question 3. Why does reverting a merge require a mainline parent?

Question 4. Why is clean -n more than a convenience?

Question 5. What is the difference between an unreachable object and a missing object?

13. Summary

The dangerous recovery shortcuts all share one mistake: changing more state than the diagnosis justifies. Preserve evidence, identify the exact layer and source, choose the smallest correction, and delay cleanup/maintenance until recovery is complete.

Next

Checkpoint the recovery decision tree across independent clones

Lesson 5 creates five separate failures—unstaged edit, staged mistake, local commit, published bad commit, deleted branch—and requires an explicit decision record for each.

Authoritative references

 git-reset
 git-restore
 git-clean
 git-revert
 git-fsck
 git-gc

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.