Over the last year we’ve introduced interactive rebase support in SourceTree on both Mac and Windows to help developers rewrite their commit history easier than ever. Often we’ve found this feature to be regarded as both mysterious and dangerous by many DVCS users, so we thought we’d help you learn what this feature does, how it can be a great asset in your workflow, and how to use it safely.
What is “rebasing interactively?”
In short, rebasing is a way of changing your commit history. You’ll often hear terms such as “replaying your commits” and “rewriting your commit history,” which can come across as confusing if you’re new to Git concepts. Why do we call it rebasing, though? Imagine your commit history looks like this:
If I were to rebase from commit a4d3a then what I’m really saying is “base all future commits on this one,” hence the term rebase. Now, imagine each commit is like a frame on a reel of film. When we say “rewind your commits” it literally means, like a reel of film, to rewind to a specific frame in time. So the term replay means just what you think, to go through each “frame” on that reel starting from the point you rewound your commits to.
Now you’ve learned about rewinding and rebasing! So how does interactive rebasing fit into this? Well, Git allows you to personally get involved in the process of replaying your commits to give you more control in changing your repository’s history. Git has a special file called git-rebase-todo which is simply a text file containing a list of the commits you’re about to get involved in. By editing this text file you can control what happens when you replay your commits.
Great, now you know all that we do! Now come work for us.
Seriously though, this is the secret of the black box. Of course Git does other magical wonders in making sure all of this goes smoothly.
So how does SourceTree fit into this? SourceTree is the middleman between you and Git, making it really easy to change your commit history through a simple user interface. You can drag and drop commits to reorder them or squash them, you can delete commits, reword the commit messages, edit them, or just leave them be.
There’s two ways to rebase interactively: The first is to right-click (or context-click) on a commit and hit Rebase children of <sha> interactively… and the second is to hit the Repository menu and go to Interactive rebase.
Let’s dive into what’s available to you.
If you’re like me, you panic commit. What’s panic committing? It’s where you write an awesome line of code and fear that the sun will throw out a huge mass of electrically charged particles causing widespread power shortage resulting in the loss of your work. So you commit things like NSLog(“test”).
Squashing allows you to quite literally “squash” commits together, resulting in more well-thought-out, meaningful commits – so instead of having 10 tiny yet related commits, you’d instead have one larger one.
To use the squashing feature in SourceTree, just drag and drop rows on top of one another. Or, you can use the squash with previous option by right-clicking or using the button at the bottom of the dialog.
Some commits just aren’t quite right. You have included too much or too little, perhaps. To counter this you, can quite literally edit a particular commit. To use this feature just check the amend commit checkbox on that particular commit. When rebasing continues, it will drop back out to SourceTree allowing you to do whatever the heck you want before continuing on.
If you’re like me, you write in a manner that’s equivocal of the elusiveness of your average Vulpes vulpes. By that I mean that I make no sense at all.
To help repair the sorry state of your commit messages, you can simply double-click on the message column in the interactive rebase screen, allowing you to change your commit message, saving your colleagues from having to translate whatever the heck it was you were saying in your commit.
Like any good programmer some of my commits have been known to be laughable. Fortunately, I can hide them away never to see the light of day again by using interactive rebase and deleting that sucker. You’re welcome.
Once upon a time many moons ago, I got into trouble because the commit history of a repository clearly showed I was working on feature Y before feature X contrary to the project plan. If only I could reorder my commits back then. Just drag and drop those commits around and save getting yourself fired.
There are lots of unusual cases that can lead to commits being lost. Sometimes deleting a commit isn’t the dangerous part but instead it could be when subsequent replays lead to Git not knowing which changeset to choose. In this scenario Git will ask you to choose mine or theirs. It’s important to understand that in this case, mine will be changes from the prior commit affecting that file, and theirs will be changes from the commit after the commit you deleted. If you choose mine then you can lose subsequent changes.
This is a confusing case that can happen quite easily, and dealing with merge conflicts can already be difficult, let alone dealing with merge conflicts that can lead to a loss of an entire commit which you think you’ve included during the rebase process. The good news is that even if you do make a mistake, as long as you don’t push those changes, you can still reset your repository into a state that won’t affect other developers.
Rebasing upstream commits
One word of caution we always see necessary to mention in practice: Never rebase commits that have already been pushed. This can lead to dangerous and confusing situations. If you have done so then SourceTree will actually tell you that you’ve got changes to pull after you’ve finished the rebase which can be even more confusing if you know you’ve pulled all changes already. As mentioned previously, even at this point you can reset your commits and ensure you don’t push the changes leading to all other developers to end up in a confusing state.
You can see that interactive rebase can be hugely useful, especially if you tend to push your changes at the end of the day. Up until the point of pushing you can do whatever you want with your unpushed commits if you’re iterating quickly on some feature or fix.
Other help & resources:
- git-scm rebase docs: http://git-scm.com/docs/git-rebase