Skip to main content
RunBook Academy

Git, CI/CD & GitOpsFinal · Final AssessmentFinal Review

Git internals and recovery — recap

Advanced⏱ ~25 mingit

What you'll learn

  • Name the four Git object types and what each one is for
  • Trace a commit hash from working tree through tree to blob and explain why the store is tamper-evident
  • Distinguish revert from reset and pick the right one for shared versus local history
  • Recover a deleted branch, a dropped commit, or a forced-overwritten ref using the reflog
  • Plan a filter-repo history rewrite after a secret leak and the force-push protocol that must follow

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

The first part of the course established that Git is a content-addressed store; the second part established that recovery flows from the reflog and from history rewriting. This recap compresses both into the working knowledge the final assessments will test: the four object types, the shape of the commit DAG, the difference between revert and reset, and the four operations every on-call engineer must be able to execute under pressure.

The four object types and the tamper-evident store

A Git repository stores four kinds of objects, each identified by the SHA of its contents:

flowchart LR
    A["working tree file"] -->|git hash-object| B["blob"]
    B --> C["tree"]
    C --> D["commit"]
    D --> E["annotated tag"]
    D -->|points to| F["parent commit"]
    F --> D
  • Blob. The bytes of a single file. A blob has no name and no path; two files with identical contents in different directories share one blob.
  • Tree. A directory listing: a set of (mode, name, blob-or-tree-SHA) entries. Trees are how Git records paths.
  • Commit. A root tree SHA, zero or more parent commit SHAs, an author and committer, and a message. A commit is the unit of history.
  • Tag (annotated). A name, a target object SHA, a tagger, and a message. Annotated tags are first-class objects; lightweight tags are raw refs that name a commit directly without an intermediate object.

Refs, HEAD, and the reflog

Refs are the layer humans and tools actually navigate: branches, tags, and HEAD. They live under .git/refs (with packed refs in .git/packed-refs for efficiency). A branch is a movable pointer to a commit; HEAD is the pointer to the currently checked-out ref.

The reflog records every movement of HEAD and every update of branch tips. It is local to each clone, stored in .git/logs/, and retained for 90 days by default. The reflog is the safety net under every other recovery operation:

flowchart LR
    A["git reset --hard HEAD~3"] --> B["HEAD moves back 3 commits"]
    B --> C["reflog records old HEAD@{0}"]
    C --> D["git checkout HEAD@{0}"]
    D --> E["working tree restored"]
    E --> F["old commits still reachable"]
    F -->|"until 90 days elapse"| G["git gc prunes unreachable objects"]

A git reset --hard wipes the working tree, but the prior commit is still reachable from the reflog for up to 90 days. Recovery is a git checkout of the reflog entry; re-attachment is git branch rescue-branch <sha>. A git gc is what actually destroys history, and a reflog expiry is what causes a git gc to consider an entry unreachable.

Revert versus reset — the shared-history rule

The two ways to undo a change have opposite effects on shared history:

  • git revert <sha> creates a new commit that inverts the target commit’s changes. History grows; the bad SHA remains in the DAG. Safe for any branch that other people have based work on.
  • git reset --hard <sha> moves the current branch tip backwards. The intermediate commits become unreachable; they remain in the reflog briefly and are then garbage collected. Never safe on a branch that other people have based work on.

The four recovery operations

The four operations every infrastructure engineer must be able to perform under pressure:

  1. Navigate the reflog. git reflog shows the reflog; git checkout <sha-from-reflog> restores the working tree to that state; git branch rescue <sha> re-attaches a branch name to the recovered commit.
  2. Revert a shared commit. git revert <sha> produces a new commit that undoes the bad change; the history is preserved and the audit trail is intact.
  3. Reset a local branch. git reset --hard <sha> moves the branch tip back; the old commits are still in the reflog for recovery within 90 days.
  4. Rewrite history with git filter-repo. The modern replacement for git filter-branch. Used after a committed secret leak to strip the secret from every commit in the history. After rewriting, every clone must re-clone, the old refs must be deleted on the remote, and any tag pointing at the old history must be re-cut.

Production discipline

The four things the on-call engineer must be able to do without thinking:

  • Read a reflog. A reflog entry of the form <sha> HEAD@{N}: <action>: <message> is the first thing you reach for when “the branch is gone” or “the tree is empty” or “the last commit was wrong”.
  • Revert before reset on shared history. The choice is not about preference; it is about whether anyone else has a clone. If yes, revert. If no, reset is faster and the reflog still has your back.
  • --force-with-lease, never --force. A bare --force overwrites the remote unconditionally and is the proximate cause of most overwritten-deploy incidents. --force-with-lease refuses to push if the remote tip has moved since you last fetched.
  • Treat a secret leak as a forensic operation. A filter-repo rewrite without coordinating every clone, every tag, every signed commit, and every registry reference is not a fix; it is a partial fix that leaves the secret recoverable from anywhere a clone was not refreshed. Rotate the secret first, then rewrite history, then invalidate every reference that could still carry the old SHA.

Cross-course references

  • Linux for Production Sysadmins — Parts covering filesystem forensics and recovery: the same shape applies to a Git repo. The object store is recoverable until it is not; act on the assumption that unreachable objects will be reclaimed on the next gc.
  • Terraform for Production Sysadmins — State recovery has the same shape: state is recoverable until the bucket is purged, and a terraform state rm is recoverable only if you still have the old state file.

Quiz

Knowledge check · 4 questions

  1. Q1. An engineer accidentally runs `git reset --hard HEAD~3` on a feature branch three other engineers have cloned. What is the correct recovery path?

  2. Q2. A `git filter-repo` history rewrite changes the SHA of every rewritten commit, which is why every clone must re-clone and every tag must be re-signed after such a rewrite.

  3. Q3. Name the four Git object types and the command that recovers a deleted branch from the reflog.

  4. Q4. A secret AWS access key was committed to the main branch two weeks ago and has since been deployed. The security team wants the secret removed from Git history. Walk through the operations, in order, that produce a defensible result.

    An engineer notices a personal AWS access key in `infra/terraform/main.tf` on the `main` branch. The commit is two weeks old, has been merged, has been deployed via a Terraform pipeline, and is referenced by a signed tag `v3.4.0`. The key has been used from a developer laptop, not from the CI runner, and CloudTrail shows accesses from outside the corporate IP range in the last 48 hours.

Passing score: 75%. Answers are checked in this browser.