2020-08-16
|~5 min read
|873 words
Of late, I’ve been getting more and more interested in learning about how to write better commits. This has led me to discover not only how to write more meaningful messages, but also how to tell a story with my commit logs - both for archeological purposes, but also to tell a story. The latter is something I’m working on through intentional rebasing. It’s also this latter point that led me to discover two options of the Git’s commit
command which is the topic of today’s discussion: fixup
and squash
. Using these options may obviate the need to use an interactive rebase by declaring up front which commits should be squashed or combined.1 At a minimum, they can make a rebase simpler by putting in some work up front.
Imagine you noticed an error in your code that’s part of the feature you’re working on. All of the code is still private (i.e. it’s not been pushed up to be shared / used by others). At this point, you have a few common options to fixing it:
--fixup
or --squash
option to make the future rebase even easier.It’s the third option which is the focus of this post.
First, what do these options actually do? From the Git manual:
--fixup=<commit>
Construct a commit message for use with rebase —autosquash. The commit message will be the subject line from the specified commit with a prefix of “fixup! “. See git-rebase[1] for details.
--squash=<commit>
Construct a commit message for use with rebase —autosquash. The commit message subject line is taken from the specified commit with a prefix of “squash! “. Can be used with additional commit message options (-m/-c/-C/-F). See git-rebase[1] for details.
(As a reminder, the difference between a fixup and a squash has to do with how commit messages are handled.)
Now that we have a decent understanding of what these commands can do and why we might want to use them, let’s look at an example.
The current feature we’re implementing is related to authentication. Imagine the following commit history for a project:
git log --pretty=format:'%h | %s%d [%an]' --graph
* a384e6b | feat: reset password (HEAD -> master, origin/master, origin/HEAD) [Stephen]
* 2f76abe | feat: set password [Stephen]
* 4c0eb1b | feat: set email [Stephen]
* ...
Preparing to submit a change set for review, we notice that there are a few problems with our set password
feature. We make a few changes and are now ready to commit the updated code. In this case it’s just a fixup
, so we could do either:
$ git commit --fixup 2f76abe
# or
$ git commit --fixup :/"set password"
Now, when we print the commit history, we see a new fixup!
commit added automatically.
git log --pretty=format:'%h | %s%d [%an]' --graph
* 766d9c2 | fixup!: feat: set password (HEAD -> master, ) [Stephen]
* a384e6b | feat: reset password (origin/master, origin/HEAD) [Stephen]
* 2f76abe | feat: set password [Stephen]
* 4c0eb1b | feat: set email [Stephen]
* ...
The :/
syntax in the second option is a string search that Git interprets as “the most recent commit that contained the string foo in the first line of it’s commit message”1
This hasn’t actually achieved our goal of cleaning up the commit history (yet). So there’s one more step: rebasing.
Note that both fixup
and squash
are designed to be used with the autosquash
option of a rebase. (If this option is not included, the commits will be treated just like a normal commit during a rebase.) By using the autosquash
option with the rebase
command Git will rearrange the commits for us and preset the rebase commands for us.
For example:
git rebase --interactive 4c0eb1b --autosquash
pick 2f76abe 📝 cancelable fetch
fixup 766d9c2 fixup! 📝 cancelable fetch
pick a384e6b 📝 draft of volta
It’s easy to get comfortable with a certain way of doing things, but I find that when I ask questions about why something works one way, I invariably find a better way. That’s certainly been my experience with Git, which is a reason why I write about it so frequently. It’s an important tool for how I write software and I’d be derelict in my duties if I didn’t constantly push to find new ways to take advantage of it to be more efficient.
fixup
and squash
.Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!