skip to content

How do you drive a Git interactive rebase from a script without an editor?

level: seniorimportance: nice to knowfreq 20%

answer

  1. the todo list is just a file
  2. the editor is only a command Git runs
  3. one environment variable overrides it
  4. a shell no-op accepts the plan as generated
  5. message prompts come from a different setting

basics

~10 s

Set GIT_SEQUENCE_EDITOR to a command that edits or simply accepts the todo file. GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash <base> accepts the generated plan unchanged, while a sed command can rewrite the verbs programmatically.

solid answer

~40 s

Git opens the rebase todo list with the command in `GIT_SEQUENCE_EDITOR`, falling back to the `sequence.editor` config and then your normal editor. Because it is just a command that receives the todo file path, you can point it at anything: `GIT_SEQUENCE_EDITOR=:` (the shell no-op) accepts the plan as generated, which combined with `--autosquash` gives a fully automatic fold of `fixup!` commits; `GIT_SEQUENCE_EDITOR="sed -i -e 's/^pick/reword/'"` rewrites the verbs in place. Note that the todo editor is a **separate** setting from the commit-message editor — `reword` and `squash` still open `GIT_EDITOR`/`core.editor`, so a truly unattended run usually needs `GIT_EDITOR=true` as well. This is how release tooling and scripted cleanups avoid an interactive prompt.

code

console · 2 lines
console
$ GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --autostash origin/main
Successfully rebased and updated refs/heads/feature.

go deeper

for a junior

Just recall that the todo list Git opens is an ordinary file and that an environment variable controls which command opens it.

for a middle

Explain the resolution order for the todo editor versus the message editor, and why a no-op sequence editor plus autosquash runs with no prompts.

for a senior

Show where scripted rewriting belongs — mechanical, reproducible cleanups — and how the automation handles a conflict that leaves the repo paused mid-rebase.

for a principal

Judge how much history rewriting should be automated at all, and what review step you give up when a tool composes the plan instead of a person.

## Two different editors An interactive rebase can open an editor twice for different purposes, and Git resolves them from different settings: - The **todo list** (the plan with `pick`/`squash`/… lines) is opened with `GIT_SEQUENCE_EDITOR`, or if unset the `sequence.editor` config, or if that is unset the ordinary editor. - **Commit messages** — for `reword`, for `squash`, for an amended commit at an `edit` stop — are opened with `GIT_EDITOR`, then `core.editor`, then the usual `VISUAL`/`EDITOR` fallbacks. Confusing the two is the classic mistake: setting only `GIT_SEQUENCE_EDITOR` and then being surprised that a `reword` still blocks on an editor. ## How the sequence editor is invoked Git writes the todo file and runs the configured command with the file's path appended as an argument, in a shell. Whatever the command leaves in the file is the plan Git executes. So it can be: - `:` or `true` — a no-op that changes nothing, meaning "run the plan exactly as generated". - `sed -i -e '...'` — a stream edit of the verbs or line order. - a script of your own that reads the file, computes a plan, and writes it back. Combining a no-op sequence editor with `--autosquash` is the most useful pattern in practice: autosquash generates the correct plan, the no-op accepts it, and the fold happens with no prompts at all. `--autostash` pairs well here too, since a script cannot answer a complaint about a dirty working tree. On macOS and BSD, `sed -i` requires an argument, so scripts that use it need to be written portably or use another tool. ## What it is good for - **Repo maintenance scripts** that fold marker commits or reword a batch of messages the same way. - **Reproducible cleanups** — a documented command that produces the same history from the same starting point, rather than "open the editor and drag these lines". - **Test harnesses** for Git tooling, where an interactive prompt would hang the run. ## What it is not good for Unattended rewriting removes the review step that the todo editor exists to provide. Whenever the plan depends on judgment — which fixes deserve a message, whether two commits are really independent — the human pass is the valuable part, and scripting it away just makes mistakes faster. Conflicts also stop a scripted rebase dead, so any automation must handle a non-zero exit and a repository left mid-rebase rather than assume success. ## Related settings and gotchas - `sequence.editor` is the persistent config equivalent, useful if you genuinely prefer a different tool for the plan than for prose. - The environment variable wins over the config, and both win over `core.editor`, so exporting it in one shell affects nothing permanently — which is exactly what you want for a one-off. - A sequence editor that exits non-zero makes Git treat the rebase as aborted. - Emptying the todo file still means "do nothing", so a buggy `sed` that deletes every line silently produces a no-op rather than a disaster — a small mercy worth knowing. - Because the rebase still rewrites commits, everything else about rewriting applies: new SHAs from the first rewritten commit onward, and a published branch that will have diverged. ## How to describe it in an interview The crisp version: the todo list is a file, the "editor" is just a command Git runs on that file, so anything that can edit a text file can drive an interactive rebase — including a no-op that accepts the generated plan. That framing shows you understand interactive rebase as a scripted replay rather than as a special interactive mode.

  • Why might a scripted rebase still stop and open an editor?
    Because commit messages use a different setting. `GIT_SEQUENCE_EDITOR` only covers the todo list; `reword` and `squash` open the message editor from `GIT_EDITOR` or `core.editor`. For an unattended run set `GIT_EDITOR=true` as well, or keep the plan to verbs that never prompt, such as `pick` and `fixup`.
  • What is the risk of automating the todo list away?
    You lose the review step. The editor pass is where you notice that two commits are not independent or that a fix deserves its own message. Scripting is right when the transformation is mechanical — folding `fixup!` markers, for example — and wrong when the plan needs judgment. Automation must also handle conflicts, which leave the repo mid-rebase.
  • How would you fold all fixup! commits on a branch with no prompts at all?
    Run the rebase with autosquash and a no-op sequence editor: `GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash <base>`. Autosquash writes the correct plan and the no-op accepts it. Adding `--autostash` avoids a failure on a dirty working tree, and a non-zero exit means a conflict left the rebase paused.

saying these in an interview costs you the question

  • Thinking GIT_SEQUENCE_EDITOR also supplies commit messages
  • Believing interactive rebase cannot run unattended at all
  • Assuming the sequence editor receives the todo on standard input
  • Scripting plans that actually require human judgment
  • Ignoring that a conflict leaves the repository mid-rebase

context