Rebasing in Git - A Basic Guide
Some of the more basic commands I use when rebasing in Git
Rabasing in Git allows you to make changes to commits, this may be by merging several commits into one another or renaming commits. There is another Git command called merge
which also allows you to merge commits but it will show up in your commit log which can get pretty messy. Rebasing allows you to have a straight, clean commit history.
There are GUIs which allow you to use the rebase command but I prefer to use my command line for rebasing. I have also symlinked my text editor so when I am writing commit messages or rebasing VScode will open for me instead of the default Vim.
Rebasing with the main branch
So you’ve forked off the main project to work on a new feature and you know that your colleagues have been working on other new features which have been merged into the main branch, it’s good practice to keep your work up to date frequently so you aren’t working with old code. It also helps to avoid nightmares when you eventually go to put your code up for review. I always find it a nightmare when I have merge conflicts on GitHub after thinking my code is nearly good to go! This is where rebasing come into play. Rebasing can get pretty complex but this can be partially negated by doing frequent rebases of the main branch.
The most simple rebasing
Say you have a branch client-feature
that you have been working on and the main branch has been updated, just type git rebase main
(replace main
with whatever branch you are working off i.e. development
). If you’re lucky you’ll get output that you’re up to date. If you have already pushed code up to, say, GitHub from the branch you will need to force your branch up when pushing as there will be changes between your branch on GitHub and your local branch, you can do this by running git push origin client-feature --force-with-lease
.
More complex rebasing
Let’s say you were working on a feature and had to take a few days off as you were unwell, when you come back to work it’s very likely that your feature branch is quite behind the main branch if there are other developers on your team. When you run git rebase main
this time it won’t go quite so smoothly. When rebasing Git runs through each one of your commits and compares the code contained within with what is on the branch that your rebasing with. Git will do it’s best to sort out this code but at times there will be merge conflicts that you will have to go and manually check and change.
When a merge conflict arises Vim or your symlinked text editor will open and show you the changes side by side. You then pick what you need to keep. A little tip to make sure you don’t miss any conflicts is to search the code base at this point for <<<
, I do this as this isn’t something that is generally contained within my code and I don’t inadvertently commit a merge conflict. When you have rectified the merge conflict add the changes (git add .
) and then type git rebase --continue
. This will cause Git to advance to the next commit where you may have more merge conflicts, continue to fix the conflicts, adding and continuing until Git has gone through all the commits.
Interactive rebasing
Say I have a branch on my Git called add-advertisers
, this new feature is about adding advertisers to my site. First off I’ve made my advertisers model so I might write in my commit message “Creates advertisers model”, midway through working on my advertisers controller I get pulled into a meeting and I don’t want anything to happen to my work so I quickly commit my work with the message “WIP advertisers controller”, then finish that work with another commit “Finishes advertisers controller” later and finally “Adds advertiser views”.
Eventually my commit history for this branch will look something like this:
Creates advertisers model
WIP advertisers controller
Finishes advertisers controller
Adds advertiser views
The middle two commits here refer to the same piece of work so we want to merge those together and come up with a better name than either WIP advertisers controller
or Finishes advertisers controller
. So this is where interactive rebasing comes into play. We will type git rebase main --interactive
or git rebase main --i
. main
is the name of our principle branch, if you are working off a different branch i.e. development
you will want to replace main
with the name of your branch. This will open up my text editor with the options available for rebasing. (The below image has all the options you can use with interactive rebasing.)
So we want to combine WIP advertisers controller
and Finishes advertisers controller
together and rename them. So we will use fixup
to do this, if you want to retain the commit message within the combined commit use squash
instead. So we change pick
to fixup
or f
beside our Finishes advertisers controller
commit which will merge these commits together.
Now we have combined our commits you will note that the commit SHAs have changed for the bottom two commits which is good to be aware of. Now we want to reword
the commit which is just renaming it to something which will read better in our commit history.
So now our commits have been combined we want to rename or reword
the commit. If we run git rebase main -i
again we can change pick
to reword
. You don’t edit the commit message in this screen though, wait for your text editor or Vim to reopen after you save and close the file, then edit the commit message there.
Now if we run git log
we can see that our commits are as we’d expect them to be:
As this article is named this is a basic guide to rebasing and it can get very complex. My main advice would be to be deliberate about your commit messages and content and to keep up to date with the main branch of your project. This can be a difficult thing to do if you are working on a large team with numerous developers working within the same files.