Git Rebase
Rebasing consists of moving or combining a series of commits to a new base commit. Rebasing is most used in the context of a feature branching workflow. Rebasing a branch is the process of updating one branch into another by applying the sequence commits of one branch on top of the other branch's commits. This is done by executing the git rebase
command.
Rebasing is often used as an alternative to merging.
The general process of rebasing can be illustrated as follows:

Git accomplishes rebasing by creating new commits from old commits and applying them to the specified base. Even if the branch looks the same, it is composed entirely of new commits.
Usage of the Git Rebase Command
The main reason for rebasing is to maintain a linear project history. For example, consider the case where some new commits have been added to the Master branch after you started working in the Feature branch. You want to include the recent update to the Master branch in your Feature branch, but you want to reserve your Feature branch history clean, so it looks like you are working from the latest master branch.
There are two ways for integrating a Feature branch into the Master branch:
- Merging directly: This option results in a 3-way merge and a merge commit
- Rebasing and then merging: This option results in a fast-forward merge and perfectly linear history.
Rebasing is a popular way to include upstream modifications into your local repository. Pulling upstream modifications with Git merge results in an excessive merge commit every time you want to see the project's progression.
What are the Advantages of Rebasing
No Merge Commits
Merging two branches every time requires a merge commit. So if a Feature branch is continually updated with a Master branch using a merge, the results will be the creation of different merge commits that will make the History less clear. These merge commits can be avoided if rebasing is used instead of merging to update the Feature branch.
Linear and Sequential Git History
When rebasing a branch is used before a merge, all the Feature branch commits are grouped at the end of the Master branch. While the Feature branch commits are distributed in the Master branch when a rebase is not used before a merge. The reason for this is that merging arranges the commits chronologically.
Rebasing groups the Feature commits together, which makes it simple to understand and analyze the Git History.
Simpler Time Resolving Conflicts
When using the rebase, Git applies each commit one at a time to resolve conflicts progressively. However, all the conflicts must be resolved using the merge at once, making it a little more difficult to handle.
While rebasing if a conflict is encountered, Git will indicate which files are causing the conflict. After resolving the conflict, Git offers the git rebase --continue
command to resume the process of rebasing and the git rebase --abort
command to cancel the rebase and leave the branch untouched.
Well Organized and Clean Git History
Rebase also has the advantage of changing commit messages, combining commits, and reorganizing commits. Using the rebase makes the History very clean so easy to understand. Having a clean Git History helps find when a certain bug or Feature was introduced to the project.
Avoid Rebasing Public History
Never rebase commits that have already been published in a public repository. Same as resetting and amending, rebasing if used in public history will cause problems for team collaboration. The rebase would replace the old commits with new ones, and it would seem like that part of project history has vanished.
Git Rebase Standard vs. Git Rebase Interactive
There are two ways to use the git rebase
command:
- Standard Rebasing
- Interactive Rebasing
Standard Rebasing:
In standard mode git rebase
command will take the commits in the current working branch and apply them in the passed branch's HEAD.
$ git rebase <base>
Above the current branch will be rebased onto . The base () can be any commit references like a branch name, an ID, a tag, or a relative reference to HEAD.
Interactive Rebasing
The git rebase
command's interactive mode is executed with the -i
or --interactive
flag, which will start an interactive rebasing session. Rather than using a standard rebase that will move all the commits to the new base at once without changing anything, the interactive rebase allow altering individual commits in the process. This gives the possibility to clean up history by removing, combining, and changing the existing sequence of commits.
To start an interactive rebase, run the following command :
$ git rebase -i <base>
The above command will start the interactive rebasing by opening the default editor, where you can choose between commands (described below ) to be applied before the commit is rebased. These commands define how individuals commit will be moved to the new base. Once you finished selecting commands for each commit in the rebase, Git will start playing back commits implementing the rebase commands.
The rebasing edit commands look as follows:
pick 4b3251c adding more text on file1
pick c3bf48e file1 modified
# Rebase 6b5548f..c3bf48e onto 6b5548f (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
Additional interactive rebase commands
The git rebase
command has some additional command options that can be useful in more complex scenarios.
git rebase option d
means that the commit will be removed from the final combined commit block during playback.git rebase option p
means that the commit will stay at it is. The commit's message or its content will not be touched.git rebase option x
means that during the playback, executes a command-line shell script on each marked commit. Running a test series on specific commits will be a useful example.
Interactive Rebase Recap
Interactive rebasing gives complete control over what the project History will look like. This gives developers the freedom to work in the way they want on their Feature branch because they have the possibility to come back after and clean the History before merging into the main codebase.
The use of interactive rebasing keeps the project History clean and significant.
Configuration options
Some rebase properties can be set using the help of the git config command. These options change the git rebase
output look and sense.
rebase.autoSquash
: A boolean value toggling the --autosquash behaviorrebase.stat
: A boolean, the default option is False. The option switches display of visual diffstat content that indicates what changed since the last rebase.rebase.instructionFormat
: A string in git log format used for formatting interactive rebase output.rebase.missingCommitsCheck
: It can be set to different values, which change rebase behavior around missing commits.warn Warning output is printed in the interactive mode and warns about deleted commits error The rebase is stopped and deleted commit warning messages are printed ignore The default option that ignores any missing commit warnings
Advanced Rebase Application: git rebase --onto
The --onto
option of the git rebase
command allows to change the ref where a rebased branch start and finishes. The git rebase --onto
is an accurate and elastic solution. It gives the controls over what and where it is being rebased.
In the example below, we will change the branch starting from C
to F
, and we will delete the commit D
from the 'new_feature' branch. Run the following command:
Syntax :
$ git rebase --onto <newbase> <oldbase>
Example:
$ git rebase --onto F D
The output will look like this:
Before After
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \
D---E---H---I (HEAD new_feature) E'---H'---I' (HEAD new_feature)
In the output above, we can see that the commit reachable attainable from HEAD
(new_feature
), which parent commit is D
on top of the F
commit. So in another way, we have changed the parent of commit E
from D
to F
.
We will have the same output as above if we run the following command:
$ git rebase --onto F D new_feature
The situation will look different when we use the I
commit ref as a third argument. The command will be as follow:
$ git rebase --onto F D I
The output will look like this:
Before After
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ | \
D---E---H---I (HEAD new-feature) | E'---H'---I' (HEAD)
\
D---E---H---I (new-feature)
In the above output, as in the default git rebase
command, we switched HEAD
to the last argument of the git rebase --onto
command. In our situation, it is the commit I
. We noticed that the 'new_feature' branch did not change. And we have a new branch which the HEAD
points.
We will have the same output as above if we run the following command:
$ git rebase --onto F D HEAD
The Dangers of Rebasing
One of the dangers when using git rebase
is that the merge conflicts may occur more frequently during the rebase workflow. This happens especially in cases when you have a long-lived branch that has deviated from Master. When you want to rebase against the Master, the Master branch may contain many new commits that may conflict with changes from the Feature branch. The solution to this is to rebase the Feature branch frequently against Master and make more periodic commits. To navigate on the git rebase
workflows, there are two command-line arguments for that: --continue
and --abort
.
The use of git rebase
can also cause the loss of commits, especially when using the interactive mode for history rewriting. When running squash or drop during the interactive mode, it will remove commits from the branch log. Those commits can be stored using the help of git reflog command.
Git rebase is not very dangerous. The real dangerous situation came when rewriting the History in interactive rebase and force pushing to a remote branch that's shared by other developers.
Recovering from Upstream Rebase
In the situation that another developer has rebased and force pushed to the branch that you're committing to, the git pull command will overwrite any commit you have based on that previous branch. Using git reflog can get the reflog of the remote branch to find a ref before it was rebased. Then you can rebase your branch against that remote ref with the help of the --onto
option of the git rebase
command.