Git
git rebase

git rebase command: --continue, --abort, cancel, --interactive, squash

The topic of this article is the git rebase command. The git rebase command, along with the git merge command, is the primary way to merge two or more branches. Let's cover the basics of using it, and some commonly used options.

1. Getting git rebase right

As I mentioned in the previous git merge post, merging two or more branches using the git rebase command gives you a straight commit history. A diagram of how rebase works is shown below.

How git rebase works

For example, let's say you want to do a rebase from the feature-a branch to the main branch. Git will merge all commits from the feature-a branch that branch from the common ancestor of the two branches into the last commit on the main branch. At the same time, it deletes any commits on the old feature-a branch that were two branches.

The result is a new feature-a branch, starting at the last branch on the main branch. This changes the commit history to create a single history instead of two.

The command we use to do this is Unlike the git merge command, we go to the source branch and run the command against the target branch.

In the example above it would look like this

$ git switch feature-a
$ git rebase main

Here's what it looks like

git rebase actual execution result

The rebase merged the develop and main branches, which have a common ancestor, commit 6519. As a result, a new develop branch was created, branching from main, and the old develop branch disappeared.

If a conflict occurs during the rebase process, the following message is displayed

$ git rebase main

Result:

Auto-merging 1.md
CONFLICT (content): Merge conflict in 1.md
error: could not apply 7fc042b... 1.md edited in develop
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm ", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 7fc042b... 1.md edited in develop

If you want to finish the rebase here, resolve the conflicts and stage the files with the git add command. Then use the options to continue the rebase process.

The options to continue the rebase process are

$ git rebase --continue

If you want to view the conflicts and revert the rebase, type the following command to revert to the state before the rebase.

$ git rebase --abort

We'll look at each of these options in more detail in later sections.

2. Abort a rebase with --abort when a conflict occurs

When Git is in the middle of a rebase, it will pause if it sees a conflict. It will then give us the option to either resolve the conflict and continue the rebase, or abort. At this point, if we want to abort, we have the --abort option.

If you use this option, the task tree will revert to the state it was in before the rebase was run. This can be useful if you encounter conflicts or problems that make it unreasonable to continue with the rebase.

This command is used as follows

$ git rebase --abort

Let's look at the actual execution results to see in which situations it can be used.

git rebase --abort execution result

Looking at the log message, we can see that the 1.md file has been modified by two branches. In this situation, the rebase command was executed and a conflict was detected, causing the rebase to pause for a while. When we aborted the rebase with the --abort option, it returned to the status quo.

3. Completing the rebase with the --continue option when a conflict occurs

Next, we'll see how to use the --continue option to resolve a conflict and complete the rebase process. The process of resolving conflicts is the same as the git merge process. You will need to open the conflicting files in an editor and make your selections. See the git merge post for more information.

Once you've fixed the files, stage them using the git add command. Then, instead of making a new commit like a merge, we continue this rebase process using the rebase command option.

Use it like this

$ git rebase --continue

Let's see the results of running it on a real crash case.

git rebase --continue execution result

Looking at the log message, we see that the 1.md file has been modified by both branches. When we run rebase, the conflict is confirmed and Git pauses the rebase process.

I cleaned up the conflicting lines with the editor, staged them, and used the --continue option. As a result, we can see that the rebase completed successfully.

4. Undoing a rebase with git reset

If you want to undo a rebase that has already been done, you need to use the git reflog and git reset commands.

As we saw in the git commit post, normal commits can also be undone or deleted using the commit ID output by the git log command. However, if you have run a git rebase, you have already made changes to an existing commit, so you cannot revert to the information in the current commit history.

The git reflog command shows a log of what you did to all values stored as ref, including branches, tags, etc. You can think of it as a more detailed git log for debugging. Thanks to this, you can go back to a previous commit, even if you have run a git rebase command.

Here is the part of the log output by the git reflog command related to the rebase we ran in Section 3.

$ git reflog

Result:

69fd9e0 (HEAD -> develop) HEAD@{0}: rebase (finish): returning to refs/heads/develop
69fd9e0 (HEAD -> develop) HEAD@{1}: rebase (continue): 1.md edited in develop
5e110f7 (main) HEAD@{2}: rebase (start): checkout main
7fc042b HEAD@{3}: rebase (abort): returning to refs/heads/develop

From the logs, we can see that the start of the rebase we just ran was at HEAD@{2}, and that we need to go back to HEAD@{3} to go back before that.

Now that you know where to go back, run the git reset command. Use the --mixed option to keep the disappearing changes in the working tree, or the --hard option to go back with everything erased.

Here is the result of using the --mixed option

Result of reverting git rebase with git reset --mixed command

You can also see that the changes from the deleted commits remain in the working tree after rebasing.

5. Modify the commit history at will with the --interactive option (feat. squash)

The --interactive or -i option to the git rebase command is an option to run an interactive rebase session. In this session we can modify commits in the current branch, squash them, reorder them, etc.

As a result, we change the commit history of the current branch. It's important to note that unlike the git rebase command we saw earlier, we are only manipulating the commits of one branch.

Now let's see the results in action.

To run a session, you'll need to enter the last commit ID of the commit you want to manipulate, like this

$ git rebase -i [commit-hash]

The current commit history looks like this

Current commit history

Here, the above command will open a window like the one below.

Example of an interactive rebase session

Here, all comments starting with # are instructions. The top uncommented part is the list of commits that are the subject of this rebase session, sorted by age.

pick 7fc042b 1.md edited in develop
pick 6d80db8 1.md edited in develop 2

In our example it's this part. You can replace the pick part with any other command, save it, and do whatever you want with it.

5.1. Key commands and how to use them

  • pick: Keep the current state
  • reword: Change only the commit message
  • edit: Change details like author, date, etc.
  • squash:Create a new commit message, merging it with the previous commit
  • fixup: Use the last commit message while merging with the previous commit
  • drop: Drop a commit

For example, to change the message of the 7fd0 commit and merge the 6d80 commit with the previous commit, make the following changes, save, and close the editor.

reword 7fc042b 1.md edited in develop
fixup 6d80db8 1.md edited in develop 2

When you perform an action that requires new information, such as reword, edit, or squash, Git will open as many new editors as necessary to ask for the necessary information.

Running reword with git rebase -i

The screen above shows the editor window prompting for a new commit message, following the reword command. The comment below shows that we are currently working on reword (Last command done), and that we will next run the fixup operation (Next command to do).

git interactive session result

If you look at the results, you can see that the commands we wrote above have completed the task of modifying the commit message and merging the previous commit.

As we have seen in the previous command git commit --amend, even for simple message modifications, Git uses the method of creating a new commit and replacing it. Therefore, you should use all commands in rebase carefully when collaborating.

6. Closing thoughts

The git rebase command has the ability to change the history of commits, one of Git's unwritten rules. As powerful as this command is, it's also powerful enough to cause unexpected chaos in a collaborative process.

For this reason, git rebase should always be used publicly, in accordance with your team's conventions.

copyright for git rebase

© 2023 All rights reserved.