In Git, what happens when you run git rebase -i HEAD~3?
answer
- it is a script, not a dialog
- an editor opens with a plan
- the oldest commit sits at the top
- each line starts with a verb like pick
- verbs plus line order drive the replay
basics
~20 sGit opens an editor holding a todo list of the three commits after HEAD~3, oldest first, each on a pick line. You edit the verbs and the order, save, and Git replays the commits as scripted, creating new commit IDs.
solid answer
~40 s`git rebase -i HEAD~3` means "replay everything after `HEAD~3` onto `HEAD~3`, but let me edit the plan first". Git writes a **todo list** — one line per commit, `pick <sha> <subject>`, **oldest at the top**, the opposite of `git log` order — and opens it in your editor. You change the leading verb (`pick`, `reword`, `edit`, `squash`, `fixup`, `drop`, plus `exec` and `break` lines), reorder lines to reorder commits, or delete a line to drop that commit. On save Git checks out the base, applies each entry in order, and moves the branch to the new tip. Every replayed commit is a **new object with a new SHA**, even the untouched ones, because its parent and committer timestamp changed. The base commit itself is never touched — the range is exclusive.
code
text · 11 linespick 9f2a1c3 add parser skeleton
pick 4b7e0aa fix typo in parser
pick c11d902 add parser tests
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like squash, but discard this commit's message
# d, drop = remove commitgo deeper
Be ready to open git rebase -i HEAD~3, name the common verbs, and say that the oldest commit is at the top and the range excludes the base commit.
Explain what happens on save: detached checkout at the base, entries applied in order, brand-new commit objects with new SHAs, branch ref moved only at the end.
Show judgment about when to rewrite at all — unpublished branch work, cleanup before review — and how you recover a rebase that went wrong instead of panicking.
Frame history rewriting as a team-wide contract: which branches are rewritable, what reviewers should get, and how much cleanup is worth the risk of rewriting shared work.
## What the command actually means `git rebase -i <base>` says: take every commit reachable from `HEAD` but not from `<base>`, let me script what happens to them, then re-apply them one at a time on top of `<base>`. The `-i` (`--interactive`) part only adds the scripting step; the replay itself is ordinary rebase. The range is **exclusive** at the base end. `HEAD~3` names the commit three back from the tip, so the todo list contains the **three commits after it** — the base commit is untouched. `git rebase -i <sha>` starts just after that sha. To include the very first commit of the repository you need `git rebase -i --root`, because the root commit has no parent to use as a base. ## The todo list Git writes a plain text file (`.git/rebase-merge/git-rebase-todo`) and opens it in the editor named by `GIT_SEQUENCE_EDITOR`, then `sequence.editor`, then your normal `core.editor`. It looks like: pick 9f2a1c3 add parser skeleton pick 4b7e0aa fix typo in parser pick c11d902 add parser tests Two things surprise people. First, the order is **oldest at the top** — the file reads like a script that runs downward, not like `git log`, which shows newest first. Second, the lines are **instructions, not a report**: whatever the file says when you save is what Git does. The commonly used verbs, each with a one-letter alias: - `pick` (`p`) — apply the commit unchanged. - `reword` (`r`) — apply it, then open an editor for its message only. - `edit` (`e`) — apply it, then **stop** with the commit already made so you can amend it, add files, or split it. - `squash` (`s`) — combine into the previous line's commit and open an editor with both messages. - `fixup` (`f`) — combine into the previous line's commit and discard this one's message. - `drop` (`d`) — discard the commit. Deleting the line entirely does the same thing. - `exec` (`x`) — not a commit at all; run a shell command at this point in the replay. - `break` (`b`) — stop here with no commit to edit, so you can look around. With `--rebase-merges` the todo can also contain `label`, `reset` and `merge` lines that rebuild a branch topology, and recent Git adds `update-ref` lines that carry other branch tips along. ## What Git does when you save Git checks out the base commit in a detached HEAD state and works through the todo list top to bottom, applying each commit's *change* rather than moving the commit object. Because a commit's SHA is a hash of its content **including its parent and its committer timestamp**, every replayed commit is a brand-new object with a new SHA — even the ones you left as `pick`. Only when the whole list finishes does Git move the branch ref to the new tip. If a step conflicts, Git stops and you resolve and run `git rebase --continue` (or `--skip` / `--abort`) — the general replay-and-conflict machinery is the same for interactive and non-interactive rebase. If you realise mid-rebase that the plan itself was wrong, `git rebase --edit-todo` reopens the remaining list. ## Practical notes - Deleting **all** lines and saving aborts the rebase instead of deleting all the commits — a deliberate safety valve. Lines starting with `#` are comments. - `squash` and `fixup` combine into the line **above**, so the first line can never be one of them; Git rejects the todo if it is. - The pre-rebase commits are not destroyed the moment the rebase runs — they remain reachable through the reflog until it expires, which is what makes a bad rebase recoverable. - Because every commit is rewritten, a branch you already pushed will diverge from its remote and need a force push. Rewriting history that other people have already pulled is the well-known hazard here. - Interactive rebase is for **your own unpublished work**: cleaning up a five-commit branch into a reviewable story before you open it for review.
- Why do commits you left as plain pick still end up with new SHAs?A commit's SHA hashes its tree, message, author and committer identity and timestamps, and its parent. Replaying gives it a new parent (or at least a new committer timestamp), so the hash changes. Rebase copies changes, it never moves commit objects, which is why every commit from the first rewritten one onward is new.
- What happens if you delete every line in the todo list and save?Git treats an empty todo as a request to abort: it reports that nothing was done and leaves the branch exactly where it was. It is a deliberate escape hatch, so an empty file is never read as "drop all these commits". To actually discard commits you mark them `drop` or delete only their lines.
- How do you reorder two commits, and when does that go wrong?Swap their lines in the todo list. It works cleanly when the commits touch different code, and conflicts when the later one depends on the earlier one — Git will stop on the dependent commit with a conflict, since the hunk it expects is not there yet. Reorder only commits that are genuinely independent.
The todo list is a shooting script for your branch: Git re-films the same scenes in whatever order and with whatever edits the script says, and every take that comes out is a new reel, not the original.
saying these in an interview costs you the question
- Thinking the todo list reports what Git already did
- Assuming the top line is the newest commit
- Believing untouched pick commits keep their original SHAs
- Expecting the base commit named on the command line to be included
- Treating interactive rebase as safe on a branch others already pulled