Undoing Changes, Reset, Restore, Revert, Reflog, and Lost-Work Recovery: Configuration, Design Choices, and Tradeoffs
Design recovery policy around reflog retention, garbage-collection grace periods, clean safety, advice settings, revert-versus-rewrite rules, and verified bundles before invasive repository surgery.
Learning objectives
- Explain default reflog retention conceptually and why it is not a recovery guarantee.
- Understand garbage-collection/pruning implications for unreachable-object recovery.
- Keep clean.requireForce and dry-run behavior as untracked-data safety rails.
- Choose revert versus rewrite from publication/provenance policy.
- Create and verify a Git bundle before invasive history surgery while understanding what it omits.
1. Recovery policy protects the safety window before an incident happens
Git recovery depends on what evidence still exists. Reflog retention, object pruning, untracked-file cleanup, backups, and team rules can expand or shrink that window. The goal is not to disable maintenance forever; it is to prevent routine cleanup from racing ahead of incident diagnosis.
2. Reflog retention is finite and repository-local
Current Git defaults generally retain ordinary reflog entries for
about 90 days and entries unreachable from the current ref tip for
about 30 days. These are configurable through
gc.reflogExpire and
gc.reflogExpireUnreachable, including
ref-pattern-specific overrides.
git config --show-origin --get gc.reflogExpire
git config --show-origin --get gc.reflogExpireUnreachable
git reflog --date=iso -10
Unset values mean defaults apply. Do not assume your company, IDE, hosting service, or cleanup tooling kept those defaults. A reflog is not a substitute for backup because it is local, time-limited, and designed around ref movement rather than complete workstation state.
3. Garbage collection can end object-level recovery
Git maintenance repacks objects and may eventually prune unreachable
objects after grace periods. Current configuration documents a
typical gc.pruneExpire default of about two weeks for
loose unreachable objects. Exact physical retention can also involve
cruft packs and maintenance behavior.
git gc --prune=now eliminates the normal age grace
period and current documentation warns that immediate pruning
increases corruption risk when another process writes concurrently.
It also destroys the very unreachable objects you may be trying to
recover.
4. clean.requireForce is an intentional untracked-file
safety rail
Current Git defaults clean.requireForce to true, so
destructive clean normally requires explicit -f.
Dry-run -n and interactive -i do not
require force because they provide their own safety behavior.
git config --show-origin --get clean.requireForce
git clean -n
git clean -nd
git clean -nx
-x includes ignored files in the candidate set, which
can include local build caches or environment artifacts you did not
intend to delete. Treat git clean -fdx as a red-zone
operation. The course never makes it the routine way to “fix” a
dirty working tree.
5. Advice messages are operational clues, not noise to disable blindly
Git's advice.* settings control contextual hints for
ambiguous or risky situations. Teams sometimes disable advice to
make logs quieter, but training and incident-response environments
benefit from preserving useful hints.
git config --show-origin --get-regexp '^advice\.' || true
A safer automation pattern is to use machine-readable output (status --porcelain, explicit exit codes, exact OIDs) rather than disabling advice
globally because scripts accidentally parse human output.
6. Team policy: revert shared mistakes, rewrite private mistakes
| State | Preferred correction | Reason |
|---|---|---|
| Unpublished local commit | Reset/amend/rebase may be appropriate | No external OID dependency |
| Published review branch with explicit rewrite policy | Coordinate, preserve old OID, guarded update | Review anchors may change |
| Shared trunk/release history | Usually revert | Preserves provenance and descendant graph |
| Leaked secret | Rotate/revoke first, then coordinated history remediation | History rewrite cannot make exposed credential safe |
7. Create a Git bundle before invasive history surgery
A bundle can preserve refs and all objects reachable from them in a portable file. Before a high-risk repair on a repository that is still readable:
git status --short --branch
git for-each-ref --format='%(refname) %(objectname)'
git bundle create ../pre-surgery.bundle --all
git bundle verify ../pre-surgery.bundle
git bundle list-heads ../pre-surgery.bundle
A full --all bundle protects refs/commits reachable
from those refs. It does not back up uncommitted
working-tree edits, the index, repository configuration, hooks, or
every possible unreachable object. Preserve those separately when
they matter.
8. Backup choice depends on what state must survive
| Need | Approach | Limitation |
|---|---|---|
| Published refs/commit graph | Remote mirror/clone or verified bundle | Does not include dirty working tree/index |
| Current uncommitted incident evidence | Filesystem copy/export plus captured status/diffs | Must be done consistently; naive live copy of Git internals can race writes |
| Exact old commit known by OID | Create temporary safety branch/tag | Only protects what it references |
| Broad repository forensic snapshot | Quiesce writers and use organization-approved backup process | Operational process, not one universal Git command |
9. Configuration scope and precedence
git config --list --show-origin --show-scope | grep -E '(gc\.|clean\.requireForce|advice\.)'
Retention/safety behavior may be system-wide, user-global, repository-local, worktree-specific, or overridden per command/environment. Before relying on a recovery window, inspect the effective source. Avoid lowering safety globally to solve one repository's workflow annoyance.
10. Git core versus host/server retention
Your local reflog retention says nothing about a hosting provider's internal backups, deleted-branch retention, review refs, or support recovery capabilities. Likewise, server branch protection does not preserve your local unstaged edits. Treat local Git recovery and hosted disaster recovery as separate layers with separately documented retention objectives.
11. Worked policy scenario — regulated deployment repository
A team deploys from trunk, records commit OIDs in
deployment metadata, and requires an incident timeline. A sensible
policy is:
- Never reset/rebase already deployed trunk history as routine correction; use revert so old deployment OIDs remain interpretable.
- Before invasive repair, preserve current refs in a verified bundle and capture status/diff/reflog evidence.
- Do not run clean/prune/expire during an active recovery incident.
- Allow private topic rewrite, but require communication and force-with-lease if an explicitly rewritable review branch has already been published.
- Document local reflog retention separately from server backup retention.
12. Knowledge check
Question 1. Why is a 90-day reflog default not a 90-day recovery guarantee?
Question 2. Why must git clean -n precede a clean
demonstration?
Question 3. What does a full
git bundle create backup.bundle --all omit?
Question 4. Why prefer revert on deployed shared history?
Question 5. Why avoid gc --prune=now during
recovery?
13. Summary
Recovery policy is about preserving evidence long enough to make a correct decision. Reflogs and pruning have retention windows, clean has safety rails, shared history should usually be corrected additively, and verified bundles/safety refs should precede invasive repository surgery.
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.