Skip to content

Rebasing

Also see the git-rebase(1) manpage. For information on how to resolve conflicts that occur during rebases see the preceding section.

r (magit-rebase)

This transient prefix command binds the following suffix commands along with the appropriate infix arguments and displays them in a temporary buffer until a suffix is invoked.

When no rebase is in progress, then the transient features the following suffix commands.

Using one of these commands starts a rebase sequence. Git might then stop somewhere along the way, either because you told it to do so, or because applying a commit failed due to a conflict. When that happens, then the status buffer shows information about the rebase sequence which is in progress in a section similar to a log section. See Information About In-Progress Rebase.

For information about the upstream and the push-remote, see The Two Remotes.

r p (magit-rebase-onto-pushremote)

This command rebases the current branch onto its push-remote.

With a prefix argument or when the push-remote is either not configured or unusable, then let the user first configure the push-remote.

r u (magit-rebase-onto-upstream)

This command rebases the current branch onto its upstream branch.

With a prefix argument or when the upstream is either not configured or unusable, then let the user first configure the upstream.

r e (magit-rebase-branch)

This command rebases the current branch onto a branch read in the minibuffer. All commits that are reachable from head but not from the selected branch TARGET are being rebased.

r s (magit-rebase-subset)

This command starts a non-interactive rebase sequence to transfer commits from START to HEAD onto NEWBASE. START has to be selected from a list of recent commits.

This command calls git rebase --onto NEWBASE START HEAD. Because the range always ends at HEAD, you must first check out the branch or commit you want as the upper bound (a detached HEAD works too).

By default Magit uses the --autostash argument, which causes uncommitted changes to be stored in a stash before the rebase begins. These changes are restored after the rebase completes and if possible the stash is removed. If the stash does not apply cleanly, then the stash is not removed. In case something goes wrong when resolving the conflicts, this allows you to start over.

Even though one of the actions is dedicated to interactive rebases, the transient also features the infix argument --interactive. This can be used to turn one of the other, non-interactive rebase variants into an interactive rebase.

For example if you want to clean up a feature branch and at the same time rebase it onto master, then you could use r-iu. But we recommend that you instead do that in two steps. First use ri to cleanup the feature branch, and then in a second step ru to rebase it onto master. That way if things turn out to be more complicated than you thought and/or you make a mistake and have to start over, then you only have to redo half the work.

Explicitly enabling --interactive won’t have an effect on the following commands as they always use that argument anyway, even if it is not enabled in the transient.

r i (magit-rebase-interactive)

This command starts an interactive rebase sequence.

r f (magit-rebase-autosquash)

This command combines squash and fixup commits with their intended targets.

By default only commits that are not reachable from the upstream branch are potentially squashed into. If no upstream is configured or with a prefix argument, the user is prompted for the first commit to potentially squash into.

r m (magit-rebase-edit-commit)

This command starts an interactive rebase sequence that lets the user edit a single older commit.

r w (magit-rebase-reword-commit)

This command starts an interactive rebase sequence that lets the user reword a single older commit.

r k (magit-rebase-remove-commit)

This command removes a single older commit using rebase.

When a rebase is in progress, then the transient instead features the following suffix commands.

r r (magit-rebase-continue)

This command restart the current rebasing operation.

In some cases this pops up a commit message buffer for you do edit. With a prefix argument the old message is reused as-is.

r s (magit-rebase-skip)

This command skips the current commit and restarts the current rebase operation.

r e (magit-rebase-edit)

This command lets the user edit the todo list of the current rebase operation.

r a (magit-rebase-abort)

This command aborts the current rebase operation, restoring the original branch.

6.9.1 Editing Rebase Sequences

C-c C-c (with-editor-finish)

Finish the current editing session by returning with exit code 0. Git then uses the rebase instructions it finds in the file.

C-c C-k (with-editor-cancel)

Cancel the current editing session by returning with exit code 1. Git then forgoes starting the rebase sequence.

RET (git-rebase-show-commit)

Show the commit on the current line in another buffer and select that buffer.

SPC (git-rebase-show-or-scroll-up)

Show the commit on the current line in another buffer without selecting that buffer. If the revision buffer is already visible in another window of the current frame, then instead scroll that window up.

DEL (git-rebase-show-or-scroll-down)

Show the commit on the current line in another buffer without selecting that buffer. If the revision buffer is already visible in another window of the current frame, then instead scroll that window down.

p (git-rebase-backward-line)

Move to previous line.

n (forward-line)

Move to next line.

M-p (git-rebase-move-line-up)

Move the current commit (or command) up.

M-n (git-rebase-move-line-down)

Move the current commit (or command) down.

r (git-rebase-reword)

Edit message of commit on current line.

e (git-rebase-edit)

Stop at the commit on the current line.

s (git-rebase-squash)

This command folds the commit on the current line into the previous commit, giving the user a change to manually merge the two messages.

S (git-rebase-squish)

This command folds the commit on the current line into the previous commit, discarding the message of the previous commit but giving the user a change to edit the final message, based on the message of the current commit.

This action’s indicator, shown in the list of commits, is fixup -c (with a lower-case c).

f (git-rebase-fixup)

This command folds the commit on the current line into the previous commit, using only the message of the previous commit as-is and discarding the message of the current commit.

F (git-rebase-alter)

This command folds the commit on the current into the previous commit, discarding the message of the previous commit and instead using the message of the current commit as-is.

This is like git-rebase-alter, except that it uses the other message. This is also like git-rebase-squish, except that it lets the user edit the message.

This action’s indicator, shown in the list of commits, is fixup -C (with a upper-case C).

k (git-rebase-kill-line)

Comment the current action line, or if it is already commented, then uncomment it.

c (git-rebase-pick)

Use commit on current line.

x (git-rebase-exec)

Insert a shell command to be run after the proceeding commit.

If there already is such a command on the current line, then edit that instead. With a prefix argument insert a new command even when there already is one on the current line. With empty input remove the command on the current line, if any.

b (git-rebase-break)

Insert a break action before the current line, instructing Git to return control to the user.

y (git-rebase-insert)

Read an arbitrary commit and insert it below current line.

C-x u (git-rebase-undo)

Undo some previous changes. Like undo but works in read-only buffers.

User Option: git-rebase-auto-advance

Whether to move to next line after changing a line.

User Option: git-rebase-show-instructions

Whether to show usage instructions inside the rebase buffer.

User Option: git-rebase-confirm-cancel

Whether confirmation is required to cancel.

When a rebase is performed with the --rebase-merges option, the sequence will include a few other types of actions and the following commands become relevant.

l (git-rebase-label)

This commands inserts a label action or edits the one at point.

t (git-rebase-reset)

This command inserts a reset action or edits the one at point. The prompt will offer the labels that are currently present in the buffer.

MM (git-rebase-merge)

The command inserts a merge action or edits the one at point. The prompt will offer the labels that are currently present in the buffer. Specifying a message to reuse via -c or -C is not supported; an editor will always be invoked for the merge.

Mt (git-rebase-merge-toggle-editmsg)

This command toggles between the -C and -c options of the merge action at point. These options both specify a commit whose message should be reused. The lower-case variant instructs Git to invoke the editor when creating the merge, allowing the user to edit the message.

6.9.2 Information About In-Progress Rebase

While a rebase sequence is in progress, the status buffer features a section that lists the commits that have already been applied as well as the commits that still have to be applied.

The commits are split in two halves. When rebase stops at a commit, either because the user has to deal with a conflict or because s/he explicitly requested that rebase stops at that commit, then point is placed on the commit that separates the two groups, i.e., on HEAD. The commits above it have not been applied yet, while the HEAD and the commits below it have already been applied. In between these two groups of applied and yet-to-be applied commits, there sometimes is a commit which has been dropped.

Each commit is prefixed with a word and these words are additionally shown in different colors to indicate the status of the commits.

The following colors are used:

  • Commits that use the same foreground color as the default face have not been applied yet.
  • Yellow commits have some special relationship to the commit rebase stopped at. This is used for the words "join", "goal", "same" and "work" (see below).
  • Gray commits have already been applied.
  • The blue commit is the HEAD commit.
  • The green commit is the commit the rebase sequence stopped at. If this is the same commit as HEAD (e.g., because you haven’t done anything yet after rebase stopped at the commit, then this commit is shown in blue, not green). There can only be a green and a blue commit at the same time, if you create one or more new commits after rebase stops at a commit.
  • Red commits have been dropped. They are shown for reference only, e.g., to make it easier to diff.

Of course these colors are subject to the color-theme in use.

The following words are used:

  • Commits prefixed with pick, reword, edit, squash, and fixup have not been applied yet. These words have the same meaning here as they do in the buffer used to edit the rebase sequence. See Editing Rebase Sequences. When the --rebase-merges option was specified, reset, label, and merge lines may also be present.

  • Commits prefixed with done and onto have already been applied. It is possible for such a commit to be the HEAD, in which case it is blue. Otherwise it is grey.

    • The commit prefixed with onto is the commit on top of which all the other commits are being re-applied. This commit itself did not have to be re-applied, it is the commit rebase did rewind to before starting to re-apply other commits.
    • Commits prefixed with done have already been re-applied. This includes commits that have been re-applied but also new commits that you have created during the rebase.
  • All other commits, those not prefixed with any of the above words, are in some way related to the commit at which rebase stopped.

    To determine whether a commit is related to the stopped-at commit their hashes, trees and patch-ids [1] are being compared. The commit message is not used for this purpose.

    Generally speaking commits that are related to the stopped-at commit can have any of the used colors, though not all color/word combinations are possible.

    Words used for stopped-at commits are:

    • When a commit is prefixed with void, then that indicates that Magit knows for sure that all the changes in that commit have been applied using several new commits. This commit is no longer reachable from HEAD, and it also isn’t one of the commits that will be applied when resuming the session.

    • When a commit is prefixed with join, then that indicates that the rebase sequence stopped at that commit due to a conflict - you now have to join (merge) the changes with what has already been applied. In a sense this is the commit rebase stopped at, but while its effect is already in the index and in the worktree (with conflict markers), the commit itself has not actually been applied yet (it isn’t the HEAD). So it is shown in yellow, like the other commits that still have to be applied.

    • When a commit is prefixed with stop or a blue or green same, then that indicates that rebase stopped at this commit, that it is still applied or has been applied again, and that at least its patch-id is unchanged.

      • When a commit is prefixed with stop, then that indicates that rebase stopped at that commit because you requested that earlier, and its patch-id is unchanged. It might even still be the exact same commit.
      • When a commit is prefixed with a blue or green same, then that indicates that while its tree or hash changed, its patch-id did not. If it is blue, then it is the HEAD commit (as always for blue). When it is green, then it no longer is HEAD because other commit have been created since (but before continuing the rebase).
    • When a commit is prefixed with goal, a yellow same, or work, then that indicates that rebase applied that commit but that you then reset HEAD to an earlier commit (likely to split it up into multiple commits), and that there are some uncommitted changes remaining which likely (but not necessarily) originate from that commit.

      • When a commit is prefixed with goal, then that indicates that it is still possible to create a new commit with the exact same tree (the "goal") without manually editing any files, by committing the index, or by staging all changes and then committing that. This is the case when the original tree still exists in the index or worktree in untainted form.
      • When a commit is prefixed with a yellow same, then that indicates that it is no longer possible to create a commit with the exact same tree, but that it is still possible to create a commit with the same patch-id. This would be the case if you created a new commit with other changes, but the changes from the original commit still exist in the index or working tree in untainted form.
      • When a commit is prefixed with work, then that indicates that you reset HEAD to an earlier commit, and that there are some staged and/or unstaged changes (likely, but not necessarily) originating from that commit. However it is no longer possible to create a new commit with the same tree or at least the same patch-id because you have already made other changes.
    • When a commit is prefixed with poof or gone, then that indicates that rebase applied that commit but that you then reset HEAD to an earlier commit (likely to split it up into multiple commits), and that there are no uncommitted changes.

      • When a commit is prefixed with poof, then that indicates that it is no longer reachable from HEAD, but that it has been replaced with one or more commits, which together have the exact same effect.
      • When a commit is prefixed with gone, then that indicates that it is no longer reachable from HEAD and that we also cannot determine whether its changes are still in effect in one or more new commits. They might be, but if so, then there must also be other changes which makes it impossible to know for sure.

Do not worry if you do not fully understand the above. That’s okay, you will acquire a good enough understanding through practice.

For other sequence operations such as cherry-picking, a similar section is displayed, but they lack some of the features described above, due to limitations in the git commands used to implement them. Most importantly these sequences only support "picking" a commit but not other actions such as "rewording", and they do not keep track of the commits which have already been applied.


  1. The patch-id is a hash of the changes introduced by a commit. It differs from the hash of the commit itself, which is a hash of the result of applying that change (i.e., the resulting trees and blobs) as well as author and committer information, the commit message, and the hashes of the parents of the commit. The patch-id hash on the other hand is created only from the added and removed lines, even line numbers and whitespace changes are ignored when calculating this hash. The patch-ids of two commits can be used to answer the question "Do these commits make the same change?". ↩︎