Sometimes I squash git commits. Generally I do this when I’m making a pull
request which takes some time, and it accumulates a lot of commits, many of
which were just kind of trying things out. The sum of all the commits adds up to
one valuable addition, but each one is kind of garbage. Here’s a good post from
Thoughtbot: Git Interactive Rebase, Squash, Amend and Other Ways of Rewriting
Here’s what it generally looks like when I do it:
And this works pretty well for me.
Sometimes I do a really big squash, where 35 commits become one, which brings me
to one behavioral detail of squashes that I’ve always found counter-intuitive:
squashes always go up. When you’re in that interactive list of commits, and
you’re telling each commit what to do, it’s relative to the previous
chronological commit. When you tell a commit to squash, you’re telling it to
squash itself into the previous commit. When you tell this to the 34 newest
commits, you’re making your very first commit absorb all of the changes. That’s
probably fine, but imagine if those commits took place over the course of 3
days, or 3 weeks. Each commit has a timestamp of when the work was done, and
your big, squashed commit has a timestamp of… 3 weeks ago.
That sort of feels wrong to me. When the pull request is merged, the commit will
sink down in the commit log below all the work that came before it.
Sooo sometimes I find myself taking things into my own hands to fix that. How?
Well, it’s kind of weird. Changing the last commit’s message is pretty easy:
commit --amend; changing the last commit’s author is pretty easy too:
commit --amend --author="Kimmy Schmidt <firstname.lastname@example.org>".
But changing the last commit’s timestamp is kind of tricky. As far as I know,
it’s not built in to git itself, so it takes a few commands to achieve. Here’s
what I’ve been doing:
- squash all the commits
- use my mouse to copy and paste the last commit message to the clipboard
- uncommit the last commit (
git reset HEAD~1)
- re-stage all the changes (
git add -A)
- make a fresh commit, pasting in the old commit message (and probably having to
fix some formatting issues because pasting into vim never works)
- sometimes I’ll amend the last commit’s author to give someone else credit if
they did the lion’s share of the work, because this strategy automatically
uses my git name and email even if the commit we’re trying to time shift was
created by someone else
Here’s what I do now:
Here’s a gif (ignore the part when I got stuck in a dquote confusion please):
Get it here: https://github.com/maxjacobson/dotfiles/blob/master/bin/git-fib
I learned with git-sleep that
scripts whose filename begins with
git- can be referenced without the hyphen,
making git a nicely extensible tool. I still think that’s so cool.
I’m pretty proud of this because it’s a kind of gnarly shell script and it works
a lot better than I expected.
Some things I might do:
- rename it to something that makes more sense
- put it on homebrew so it’s easier to install
- suppress more of the git output (not sure, maybe it’s nice to have it?)
EDIT 2019: At some point in the intervening few years, I noticed someone run
git commit --amend --date, and I made a note in my to do list to update this
script and this post, and today I did.