or “How I Learned to Stop Worrying and Love git rebase -i”.
I’ve been working with git in a more professional setting lately. We maintain our new cosmological code, Nyx, in git now and I can’t be as lazy as I have been with other git repos. We maintain 2 bare repos and about a dozen developers pull from us, so I like to be careful about what I push off.
Problem is, I don’t normally work that way. I like to code things quickly and try them, keeping track of changes as I go. Think “cowboy” development with very frequent commits. So, I could end up with a very messy commit history. Luckily, git rebase comes to the rescue.
So at the end of a bout of local coding, the commit history looks something like this.
… many commits down to …
For many reasons, I cannot rebase commits already pushed to a remote, so I need to update the remote tracking branch at this point. A simple git fetch origin master does the job. Now I can rebase off this commit and rewrite my messy history.
I find the tip of origin/master, copy the sha, and run git rebase -i [origin sha]. I think there is simpler way to do this, like git rebase -i origin/master, but I haven’t tried it. I like to be sure I’m rebasing off the right commit for now.
Now, my editor opens up and shows a list of the commits since then. For each commit, I have several choices. Here’s what git displays during a rebase:
# Rebase 3272740..9ef6432 onto 3272740
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
And here’s a snapshot of what I ended up with this time.
So I will squash 5 commits, reword 3 of the commit messages, and leave everything else as is.
After saving and closing the editor, git opens each commit I want to reword or squash while rebasing. I make the changes I want, and git finishes with “Successfully rebased and updated refs/heads/master”.
Now my commits show up as a single line of development off of the latest commit on origin/master.
Let’s just hope the non-sequential commit datetimes don’t confuse anyone.
Don’t forget to git push origin master after all that.