When to Rebase
I've come to appreciate that scary git command -
git rebase. I've found two incredible uses for it:
- Updating feature branches with progress made on master.
- Avoids those nasty merge commits.
- Cleaning up feature branches before merging with master
- There's no need to keep 'fix typo' commits in our git history.
Updating feature branches
Say you've branched from master to work on a new topic. Since you've started making your edits,
your team members have pushed a commit or two to master. A
git log will demonstrate the scenario:
* a1caf92 (master) Some updates your team members have made. | * c4b61f8 (HEAD, feature-branch) Started working on a feature. |/ | * 7884fb6 Common ancestor commit.
If you want to pull in the changes made on master, while in the feature-branch branch:
$ git rebase master
I like to think of this rebase as peeling off your changes from the history, moving up the master branch, and then laying your changes back down on top of master.
By updating your feature branch with the progress made on master, you can avoid merge commits that clutter the git history and contribute (most often) meaningless commit messages.
After the rebase, your git tree will show the feature branch on top of
master, which means the common ancestor commit
is the latest update on master.
git log will give the following graph:
* c4b61f8 (HEAD, feature-branch) Started working on a feature. * a1caf92 (master) Some updates your team members have made. * 7884fb6 Common ancestor commit.
Since the changes you're pulling in from master are all wrapped up into one commit, you could have just as easily used
git cherry-pick to merge the changes
from that commit into your feature branch.
Cleaning up feature branches
Quite often, my feature branches consist of several commits. They don't have to be pretty. I commit as often as possible, and try to leave a note about what a change does as often as I make a significant change, or have encountered a state I might want to return to in the future.
Imagine the following tree:
* f3e1236 (HEAD, feature-branch) Remove unused files from repo * 8be8878 Cleanup CSS * 0a16b8c Complete testing for feature-branch * b42147c Add syntax theming and type size changes * 08e20d1 Add some more code related to feature * 9715882 Start working on feature. * 8ec539e (master) added indenting with vim post
feature-branch is complete and ready for merge into master, but it's littered with some rather embarassing commits.
Knowing that I cleaned up css or removed left over files in a repo inspires a curiosity to view the project just one
But as savvy git users, we know better. We can remove the commits related to cleaning up, and the end result will be a git history that looks like we just code perfectly without any mistakes along the way.
Given the previous git tree, we can clean up the feature branch into only 1 commit. While in the
feature-branch branch, run:
$ git rebase -i master
This will open up a Vim window unless you've configured another editor:
pick f3e1236 Remove unused files from repo squash 8be8878 Cleanup CSS squash 0a16b8c Complete testing for feature-branch squash b42147c Add syntax theming and type size changes squash 08e20d1 Add some more code related to feature squash 9715882 Start working on feature. squash 8ec539e added indenting with vim post
Change every 'pick' to 'squash' for each commit that you want to squash into the previous one.
When prompted to add a commit message for this new super clean and short rebased branch, be sure to write something meaningful. Something like "Implement Feature One" will suffice.
git log now will show our clean and readable history:
* f3e1236 (HEAD, feature-branch) Implement Feature One * 8ec539e (master) added indenting with vim post
feature-branch into master will update master without leaving a merge commit.
* f3e1236 (HEAD, master, feature-branch) Implement Feature One * 8ec539e added indenting with vim post
Be sure not to push any branches that you plan on rebasing in the future. Rewriting the history will surely raise complications for anyone else who might be working with the history you've pushed. If you want to push them so you can access the changes from a machine while out of the office, be sure to communicate that those branches are unstable and should not be used for new branches.
A note about merge conflicts while in a rebase
It can be totally scary. When manipulating the history, it feels like you could easily mess up your entire project. Fortunately, git helps us out during a merge conflict.
If you encounter a merge conflict, git will prompt you to:
- Fix the changes
git addthe files to which you made changes
git rebase --continue
That's it! If for some reason you've got merge conflicts out the wozz, you can always abort the rebase entirely with
git rebase --abort.