Rebasing means to move or combine a series of commits to a new base commit. In other words, it changes the basis of the current branch from one commit to another making it look like the branch has been created from another commit. This is done by executing the git rebase command. Take into account that even if the branch looks the same, it is built up of wholly new commits.
Usage of the git rebase command
Firstly, we need this command for maintaining a linear project history. For example, the master branch progresses after you start to work on a feature branch. You need the recent updates of the master branch in your feature branch, but the history of the master branch must maintain clean. We need a clear history while executing Git operations to explore the introduction of a regression. Find more information about the usage of git rebase below:
The inadmissibility of rebasing public history¶
Never rebase commits after publishing them in public history. As in the case of amending and resetting, it will cause problems for team collaboration. If you do it, the old commit will be replaced by a new one and it will appear as part of your project has disappeared.
The difference between Git rebase standard and Git rebase interactive.¶
There are two modes of git rebase command: standard and interactive. In standard mode git rebase will automatically apply the commits in the current working branch to the passed branch’s head. The current branch will be rebased onto <base> . This can be different kinds of commit references, as a tag, an ID, a branch name and so on.
git rebase <base>
In interactive mode git rebase is executed with the -i flag, which stands for “interactive”. The advantage of rebasing in interactive mode is changing the individual commits in the process, without having to move all the commits to the new base. Due to this mode, you can clean the history by removing and changing the existing sequence of commits.
Running the following command will open an editor:
git rebase --interactive <base>
In this editor enter the commands given below for each commit that must be rebased. Git will start to playback commits and apply the rebase commands, after determining the commands for each commit.
pick 11a1456 some old commit pick a23db19 Adds new feature
Additional rebase commits¶
The git rebase has some command options such as:
- git rebase -- d. Using this option will discard the commit from the final combined commit block during playback.
- git rebase -- p, which doesn’t edit the message or the content of the commit remaining an individual commit in the branch history.
- git rebase -- x, which allows to run a command line shell script on each marked commit during playback.
One of the interactive rebasing advantages is that it allows developers not to worry about the messiness of the project history, as they can later go back and clean it up. So, many developers use this tool to make the feature branch history cleaner before merging it into the master branch. Cleaning up a branch means removing meaningless or dead and gone commits. As a result, developers have a well-planned history and can easily understand what commits have been done.
There exist some rebase options that are set with the help of the git config commit. These options give another look and sense to the git rebase.
- rebase.stat: by default a false boolean, which toggles display of visual diffstat content showing changes since the last debase.
- rebase.autoSquash: A boolean value toggling the --autosquash behavior.
- rebase.missingCommitsCheck: It can be set to multiple values changing the rebase behavior around missing commits.
warn Warning output is printed in interactive mode and warns about removed commits. error The rebase is stopped and removed commit warning messages are printed. ignore The default option, which ignores any missing commit warnings.
- rebase.instructionFormat: A string in git log format used for formatting interactive rebase display.
Advanced rebase application¶
The git rebase can be passed to the --onto command line argument, in which case the command expands to the following:
git rebase --onto <newbase> <oldbase>
The --onto command provides advanced rebase application as it allows passing specific refs as the rebase tips.
Let’s see its behavior on an example:
o---o---o---o---o master \ o---o---o---o---o featureX \ o---o---o featureY
Although featureY is based on featureX, it is independent from any changes in featureX and could be branched off master.
git rebase --onto master featureX featureY
FeatureX is the <oldbase>. master is the <newbase> and featureY is reference for what <newbase> HEAD will point to. Here is the output:
o---o---o featureY / o---o---o---o---o master \ o---o---o---o---o featureX
The dangers of rebasing
The first danger of using the git rebase command is that it can cause more merge conflicts during a rebasing process, especially in cases when you have a durable branch strayed from master. Sooner or later you may decide to rebase against the master, which may contain some new commits which the changes of your branch may conflict with. The solution to the situation described above is rebasing the branch against the master more often and make more periodic commits. In order to advance or reset the rebase while copying with conflicts, you can use the --continue and --abort arguments with the git rebase. Another more serious alarm is that some commits may be lost from interactive history rewriting. Running rebase in interactive mode with some subcommands like squash or drop remove commits from the immediate log of the branch.It may seem as though the commits are removed permanently. The solution is the git reflog by the help of which these commits can be restored and you can undo the entire rebase.
Recovering from upstream rebase
In case another user has rebased and force pushed to the branch that you’re committing to, a git pull will then overwrites any commit you have based off that previous branch with the force pushed tip.Git rebase allows you to get the reflog of the remote branch. There you can find a ref before it was rebased. Then you can rebase your branch against that remote ref with the--onto option.