How do you drive a Git interactive rebase from a script without an editor?
answer
- the todo list is just a file
- the editor is only a command Git runs
- one environment variable overrides it
- a shell no-op accepts the plan as generated
- message prompts come from a different setting
basics
~10 sSet 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 sGit 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$ GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --autostash origin/main
Successfully rebased and updated refs/heads/feature.go deeper
Just recall that the todo list Git opens is an ordinary file and that an environment variable controls which command opens it.
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.
Show where scripted rewriting belongs — mechanical, reproducible cleanups — and how the automation handles a conflict that leaves the repo paused mid-rebase.
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