I’ve already blogged about a rebasing git workflow, but I wanted to be more concise (it’s still long!) and perhaps more useful.
Eventually you’ll discover the Easter egg in Git: all meaningful operations can be expressed in terms of the rebase command. Once you figure that out it all makes sense. I thought the joke would be obvious: rebase, freebase, as in what was Linus smoking? – Linus Torvalds
git config
Here’s some shortcuts I’ve added to my .gitconfig
, and I’ll use them throughout this post:
fetch upstream
Keep up to date with upstream, and backup your local copy of master (which is always just a mirror of upstream/master
from the last update). You do this to your master branch as follow:
Actually I’ve a shell alias gum
which has this wrapped in git stash and apply; that is, it stores your work (without you needing to commit), while it updates local master then puts you back on the branch you were previously working on and restores your work:
rebase your current work
Once you’ve updated master, you’ll want to rebase your current work. You going to want to commit before doing this, or if you’d prefer stash, rebase, stash apply:
committing code
Once you’ve updated master, you can start, or get back to, work:
- NEVER commit to master locally (at least try not to, see below)
Work on a new branch off of master, give it a nice descriptive name (not like feature_A
!):
Or rebase what you’ve previously been doing (to minimise pain of stepping this code again later), you should either commit what you’ve been doing first, or stash, rebase and stash apply:
You may get merge conflicts here, but you’d have got them anyway if you’d tried to merge. The more frequently you rebase the less painful this process is (as you’re only having to walk over the most recent code).
oh no, I’ve committed to master
No problem (don’t push though!), first we’ll make a “back up” of master (including your latest commits):
Finish off whatever it is you were doing, and leave the working directory clean (i.e. commit everything), and make sure it has the work you’ve just been doing. Now you can go ahead and fix up your copy of master (remembering it should just that, a copy of master).
As, your commits are safely in the new branch (seriously, double check this), so we can just back up a few commits and then update from upstream:
If you’d pushed to origin, you’re going to have to force push next time.
pushing to origin
With the rebasing model you’re going to have to force push occasionally (each time you rebase):
But, NEVER force push to upstream/master (this is a recipe for disaster), although if other people are following this model the red flag will be raised the next time they update master and fail to fast forward…
squishing commits
Git history is NOT supposed to be a meandering record of your thoughts and misadventures, it should be a block of work to implement a new feature or fix a bug. If it’s taken 20 commits to implement a feature and you’ve been going back and forth on the same lines… resolving merge conflicts is going to be hell (for you and other developers).
Squish it down to several commits (or ideally one!) using “interactive” rebase:
If you’re new to squishing I recommend taking a backup branch:
In the interactive buffer (make sure at least the first commit is left as pick) and replace pick
with s
(squish), and save. Now you have another chance to clean up the commit messages for others who might be reading them.
checking out pull request locally
With the above git config you can play around / test pull requests locally very easily. If the oull request was number 1234:
If you want to make changes to it, you can create a new branch off of it locally: