I do a huge amount of squashing, every day of the week. Ever the kind of engineer who wishes to optimize every single redundant operation, I wrote a simple script and then aliased it in my shell. When I do a commit that I know I will be squashing into the previous commit, I simply do a “git commit -m SQUASH -a” and then run “SQUASH_LAST” (my alias, which is autocompleted) to run the squash. The script verifies that the last commit message starts with “SQUASH” (for verification/sanity), executes the squash, and then prints the current commit, previous commit, and final commit revisions.
It is extremely convenient and saves a ton of time and annoyingly-repetitive steps.
The script (which I put in my home):
#!/bin/bash -e HEAD_COMMIT_MESSAGE=$(git log --format=%B -1 HEAD) # For safety. Our use-case is usually to always just squash into a commit # that's associated with an active change. We really don't want lose our head # and accidentally squash something that wasn't intended to be squashed. if [[ "${HEAD_COMMIT_MESSAGE}" != SQUASH* ]]; then echo "SQUASH: Commit to be squashed should have 'SQUASH' as its commit-message." exit 1 fi _FILEPATH=$(mktemp) git log --format=%B -1 HEAD~1 >"${_FILEPATH}" echo "Initial head: $(git rev-parse HEAD)" git reset --soft HEAD~2 >/dev/null echo "Head after reset: $(git rev-parse HEAD)" git commit -F $_FILEPATH >/dev/null rm $_FILEPATH echo "Head after commit: $(git rev-parse HEAD)" echo
The alias (for completeness):
alias SQUASH_LAST='<filepath>'
It really is about the little things.
I have also put the script into a gist.