In Git, what is ORIG_HEAD, and why can it be stale after two operations in a row?
answer
- A ref Git writes for you, not one you set
- Only drastic HEAD moves update it
- It has room for exactly one value
- The second operation costs you the first
- The journal that does keep history lives elsewhere
basics
~20 sORIG_HEAD is a single ref Git overwrites with the previous HEAD position whenever a command moves HEAD drastically — reset, merge, rebase, am. Because it holds only one value, a second such command overwrites it, so it points one step back, not to the original.
solid answer
~50 s`ORIG_HEAD` is a plain ref in the repository that Git rewrites whenever a command moves HEAD in a drastic way: `git reset`, `git merge`, `git rebase` and `git am` all record the previous tip there (and `git pull` inherits it through the merge or rebase it runs). That makes `git reset --hard ORIG_HEAD` the quick undo for a bad merge or reset, and `git diff ORIG_HEAD` a fast way to see what an operation brought in. The catch is that it stores exactly one value. Reset twice, or reset and then merge, and `ORIG_HEAD` names the position before the *second* command — the original tip is no longer there. It is also not journalled the way branches are, so the durable record is the reflog: `HEAD@{n}` still lists every position in order, and that is where you go once ORIG_HEAD has been clobbered.
code
bash · 6 linesgit pull # ORIG_HEAD = tip before the pull
git diff ORIG_HEAD # what the pull changed
git log ORIG_HEAD..HEAD # commits it brought in
git merge feature # ORIG_HEAD overwritten by the merge
git reset --hard ORIG_HEAD # undo the merge, not the pullgo deeper
Recall that ORIG_HEAD holds where HEAD was before a big operation such as a merge or reset, which makes reset --hard ORIG_HEAD a quick undo.
Name the commands that write it — reset, merge, rebase, am, and pull through the merge or rebase it runs — and explain that it stores one commit id with no history.
Show the diagnostic habit: verify ORIG_HEAD before acting on it, fall through to the reflog when a second operation has overwritten it, and create a real backup branch before risky sequences.
Own the reliability argument: a single-slot convenience ref is not a recovery strategy for a team, so scripted or automated history operations should record explicit refs rather than depend on ORIG_HEAD.
## What it is `ORIG_HEAD` is an ordinary ref stored in the repository's Git directory alongside `HEAD`, holding a single commit id. Git writes it automatically: commands that move HEAD in a drastic way record where HEAD was **before** the operation. The documented writers are `git reset`, `git merge`, `git rebase` and `git am`. `git pull` gets one for free, because it finishes with a merge or a rebase. Because it is a ref, it can be used anywhere a commit can: - `git reset --hard ORIG_HEAD` — undo a merge or a reset that went the wrong way. - `git diff ORIG_HEAD` — see everything the last operation changed in the tree. - `git log ORIG_HEAD..HEAD` — list the commits the operation brought in. ## Why it exists Before reflogs were universal, `ORIG_HEAD` was the one guaranteed handle on "where I was a moment ago". It survives because it is convenient: after `git pull` drops twenty commits on you, `git diff ORIG_HEAD` is shorter to type than working out the right `HEAD@{n}`, and after a merge you regret, `git reset --hard ORIG_HEAD` is the canonical undo. ## The staleness trap `ORIG_HEAD` is a **single slot**. Every qualifying command overwrites it, and there is no history of previous values. Suppose you run `git reset --hard HEAD~5`, realise the target was wrong, and run `git reset --hard HEAD~2` from there. After the first command `ORIG_HEAD` was the original tip; after the second it is the commit you were on *between* the two resets. `git reset --hard ORIG_HEAD` now takes you to that intermediate position, not home. The same happens with reset-then-merge, or a `git pull` immediately after a rebase. Unlike branch heads and HEAD, `ORIG_HEAD` is not journalled — the default reflog configuration covers HEAD, branch heads, remote-tracking refs and notes, not this ref. There is no `ORIG_HEAD@{1}` to fall back to. ## What to use instead once it is stale The reflog. Every movement of HEAD is appended to its journal with an action label, so `git reflog` shows the sequence — `reset: moving to HEAD~5`, `reset: moving to HEAD~2` — and `HEAD@{2}` names the position two moves ago. Resetting a branch to the right reflog entry restores it exactly. That is the reason the practised answer to "how do I undo this" is *ORIG_HEAD if I am acting immediately, reflog if I am not*. ## Practical habits 1. **Use it immediately or not at all.** If more than one HEAD-moving command has run since the mistake, go straight to `git reflog` instead of trusting the ref. 2. **Verify before acting.** `git log --oneline -1 ORIG_HEAD` costs nothing and tells you whether it points where you assume. 3. **Pin the value yourself for risky work.** Before a long rebase or a scripted sequence, `git branch backup/pre-rebase` creates a real ref that nothing else will overwrite. That is strictly better than relying on a slot every subsequent command competes for. 4. **Remember what it does not cover.** `ORIG_HEAD` names a commit, so it restores committed history only. Working-tree edits destroyed by `git reset --hard` or files deleted by `git clean` were never objects; no ref brings them back. ## The one-line summary ORIG_HEAD is a convenience ref holding the pre-operation HEAD for reset, merge, rebase and am; it is overwritten by the next such operation, and the reflog — not ORIG_HEAD — is the durable record.
- If ORIG_HEAD is already stale, how do you find the position you actually wanted?Read the reflog. `git reflog` lists every HEAD movement newest-first with an action label such as `reset: moving to HEAD~5`, so you can identify the entry from before the first mistake and reset the branch to that `HEAD@{n}`. Unlike ORIG_HEAD it keeps a full ordered history, subject to its expiry window.
- How would you protect a risky rebase or scripted history operation instead of relying on ORIG_HEAD?Create a real ref first: `git branch backup/pre-rebase` or `git tag pre-rebase`. Nothing overwrites it, it survives any number of subsequent operations, and it is visible to `git log` and `git branch`. Delete it once the result is verified. ORIG_HEAD is a convenience for immediate undo, not a checkpoint mechanism.
saying these in an interview costs you the question
- Believing ORIG_HEAD keeps a stack of previous positions
- Expecting every command, including commit, to update it
- Thinking ORIG_HEAD restores uncommitted working-tree changes
- Assuming ORIG_HEAD has its own reflog to fall back on