git rebase --autosquash: Apply fixup! Commits
git rebase --autosquash recognizes commits whose messages start with "fixup!" or "squash!" and reorders them under the commit they reference, ready to fold in.
Paired with git commit --fixup, autosquash turns history cleanup into one command. With GIT_SEQUENCE_EDITOR set to true it runs unattended, which is what makes it usable in a CI cleanup step.
What it does
When you make a commit with git commit --fixup=<sha>, its message is "fixup! <original subject>". git rebase -i --autosquash reads those markers, moves each fixup/squash commit directly after its target, and marks it for folding, so the rebase plan is correct without manual editing.
Common usage
git commit --fixup=abc1234
git commit --squash=abc1234 # also opens the editor to merge messages
# unattended (no editor) in a script
GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash abc1234~1
# make autosquash the default
git config rebase.autosquash trueOptions
| Flag / config | What it does |
|---|---|
| --autosquash | Auto-reorder fixup!/squash! commits in an interactive rebase |
| --no-autosquash | Disable even when rebase.autosquash is set |
| commit --fixup=<rev> | Create a fixup! commit targeting <rev> |
| commit --squash=<rev> | Create a squash! commit targeting <rev> |
| rebase.autosquash (config) | Enable autosquash by default for -i |
| GIT_SEQUENCE_EDITOR=true | Accept the generated plan without an editor |
In CI
autosquash only takes effect with interactive rebase (-i). To run it without a human, set GIT_SEQUENCE_EDITOR=true so the todo list is accepted as generated. As with any rebase, the result has new SHAs and needs --force-with-lease to push, which protected-branch rules may reject.
Common errors in CI
"hint: Waiting for your editor to close the file" means -i opened an editor in a non-interactive shell and hung; set GIT_SEQUENCE_EDITOR=true. fixup! commits left unsquashed in the final history mean autosquash was not enabled or the subject did not match the target commit. Conflicts still require --continue/--abort.
Using this in CI
CI checkouts are shallow and detached by default, which changes the answer this command gives you. Commands that read history, branch names, or tags need the checkout configured for it.
- uses: actions/checkout@v4
with:
fetch-depth: 0 # history, tags, and git describe all need this
- run: |
git rev-parse --is-shallow-repository # expect false
git rev-parse --abbrev-ref HEAD # prints HEAD when detached