skip to content

What does Git's rebase --autosquash option do to the todo list?

level: middleimportance: should knowfreq 42%

answer

  1. it works on the plan, not the commits
  2. special commit subjects are the trigger
  3. two prefixes: one silent, one prompts
  4. lines get moved next to their target
  5. the verbs are pre-filled for you

basics

~20 s

With --autosquash, git rebase -i scans commit subjects for the fixup! and squash! prefixes, moves each such commit directly below the commit it names, and pre-sets its todo verb to fixup or squash — so the plan arrives already arranged.

solid answer

~40 s

`git rebase -i --autosquash <base>` pre-processes the todo list. Any commit whose subject starts with `fixup! ` or `squash! ` followed by the subject (or a prefix of it) of an earlier commit in the range is **reordered** to sit immediately after its target, and its verb is set to `fixup` or `squash` rather than `pick`. You still see the todo list and can veto it; `--autosquash` only arranges it. Such commits are normally produced by `git commit --fixup=<sha>` or `--squash=<sha>`, which write the marker subject for you. Turn it on permanently with the `rebase.autoSquash` config so plain `git rebase -i` does it. The payoff is that review fixes can be committed as they arrive and folded into the right original commit later, without hand-editing the plan.

code

console · 3 lines
console
$ git commit --fixup=9f2a1c3
[feature 51ad7b2] fixup! add rate limiter
$ git rebase -i --autosquash 9f2a1c3^

go deeper

for a junior

Recall that certain commit subjects starting with fixup! or squash! let a later interactive rebase place those commits automatically instead of you dragging lines.

for a middle

Explain the matching rule — subject prefix against a commit in the range — and that the flag only rewrites the todo list, which you still review before saving.

for a senior

Describe the working habit it enables: commit review fixes immediately against their target, fold them in one rebase before the branch lands, and never let a fixup! subject reach the main branch.

for a principal

Weigh a clean, bisectable commit story against the cost and risk of routine rewriting, and decide what the team's default is — including whether cleanup happens on the branch at all.

## The problem it solves During review you get five comments on three different commits of your branch. If you fix them as five ordinary commits, you must later open the todo list, find each fix, drag its line under the right original commit and type `fixup`. That is fiddly and easy to get wrong, especially with ten commits in flight. `--autosquash` automates exactly that arrangement. ## What the marker is The mechanism is a **magic commit subject**. A commit whose subject line is `fixup! add rate limiter` or `squash! add rate limiter` declares that it belongs to the commit whose subject is `add rate limiter`. Nothing else about the commit is special — it is an ordinary commit with an ordinary diff. `git commit --fixup=<sha>` and `git commit --squash=<sha>` simply write that subject for you from the target commit's subject, which is why they are the usual way to create one. ## What autosquash does with it When `git rebase -i --autosquash <base>` builds the todo list, before showing it to you it: 1. Finds commits in the range whose subject starts with `fixup! ` or `squash! `. 2. Matches the rest of the subject against the subjects of other commits in the range (a unique prefix is enough), or against a commit id if the marker names one. 3. Moves each marker commit's line to sit **immediately after** its target's line. 4. Sets its verb to `fixup` for `fixup!` and `squash` for `squash!`. Then the editor opens as usual. This is the important nuance for interviews: `--autosquash` **does not skip the interactive step**, it only writes a better first draft. You can still reorder, change verbs, or bail out. Chained markers work — a `fixup!` of a `fixup!` resolves to the same original target. The result once you save is exactly what `fixup`/`squash` always do: the marker commits vanish as separate commits and their changes land in their targets, so the branch reads as though the fixes had been made correctly the first time. ## Configuration and related flags - `rebase.autoSquash = true` makes interactive rebases behave as if `--autosquash` were given, so plain `git rebase -i` arranges the list. `--no-autosquash` overrides it for one run. - `rebase.autoStash` / `--autostash` is a different thing that people mix up: it stashes uncommitted work before the rebase and re-applies it afterwards. Autosquash is about the todo list, autostash is about your dirty working tree. - `git commit --fixup=amend:<sha>` and `--fixup=reword:<sha>` in recent Git create markers that additionally take the new commit's message, which autosquash renders as `fixup -C` / `fixup -c` lines. ## Limits and failure modes - **The target must be in the rebase range.** If you fix up a commit older than `<base>`, autosquash cannot match it and the marker stays a plain `pick`, leaving a stray `fixup! …` commit in your history. Starting the rebase from the target's parent, or using `git rebase -i --autosquash <target>^`, avoids this. - **Duplicate or truncated subjects.** Matching is by subject text; two commits with the same subject make the target ambiguous, and a subject a marker only partially matches may resolve to the wrong one. Naming the target by sha when creating the marker is safer. - **Hand-edited marker subjects.** If someone rewords the marker so it no longer starts with `fixup! ` exactly, autosquash ignores it. - **Conflicts still happen.** Autosquash arranges the plan; the replay is a normal rebase, so folding a fix into an older commit can conflict with the intermediate commits. - **Markers must not escape the branch.** A `fixup! …` commit merged into the main branch is a review smell — the whole point is that it is folded away before the branch lands. ## The workflow in one line Commit fixes as they arrive with a marker subject, keep working, and when the branch is ready run one interactive rebase with autosquash: the plan is already correct, you glance at it, save, and the branch is clean. It is the standard answer to "how do you keep a branch reviewable without hand-crafting history at the end".

  • Does --autosquash mean you no longer see the todo editor?
    No. It only pre-arranges the list — reordering the marker commits under their targets and setting their verbs — and then opens the editor as usual so you can inspect, adjust or abort. To skip the editor as well you have to accept the todo non-interactively, for example by pointing `GIT_SEQUENCE_EDITOR` at a no-op command.
  • What happens if the commit a fixup! marker names is older than the rebase base?
    Autosquash cannot match a target outside the range, so the marker commit stays an ordinary `pick` and survives as a commit literally titled `fixup! …`. Start the rebase further back — at the target's parent — so the target is inside the range and the marker can be folded.
  • How can you make this the default for every interactive rebase?
    Set the `rebase.autoSquash` config to true, at whatever scope you want. Then plain `git rebase -i` arranges marker commits automatically, and `--no-autosquash` disables it for a single run. It is a safe default because the arranged list is still shown to you before anything is replayed.

saying these in an interview costs you the question

  • Claiming autosquash rewrites history without showing the todo list
  • Thinking it detects related commits by diff content rather than subject
  • Confusing --autosquash with --autostash
  • Assuming it works when the target commit is outside the rebase range
  • Believing it removes the need for fixup and squash verbs at all

context