I have a hacky shell script that I use to clean up the history on a feature branch when I'm working with people who don't understand how rebasing works and have hundreds of messy commits and multiple merge commits, meaning it is not possible to do a single squash or fixup interactive rebase.
This script basically creates a single squashed commit out of their branch vs what they are merging to, regardless of how they got there.
- this is not interactive rebasing Squash my last X commits together using Git
- this is an automated version of Git: How to squash all commits on branch
But it's really hacky, is there an existing git command that does this? Or is there a more idiomatic way to write the script?
#!/bin/bash
set -e
if [ -n "$(git status -s)" ] ; then
echo "ERROR: uncommitted changes"
exit 1
fi
if [ -z "$1" ] ; then
echo "ERROR: you must provide a base branch"
exit 1
fi
NAME=`git rev-parse --abbrev-ref HEAD`
CUR=`git rev-parse HEAD`
TO=`git rev-parse $1`
echo "backing up your branch in bak/$CUR"
git checkout -b bak/$CUR
git checkout -b tmp/$CUR
git reset --hard $TO
git merge --squash $CUR
git commit --no-edit
git checkout $NAME
git reset --hard tmp/$CUR
git branch -D tmp/$CUR
echo "created a squash commit against $1 and rewrote your history"
git-log
all messages into a tempfile,git-checkout
their latest commit,git-reset --soft
togit merge-base HEAD <branch to merge to>
and thengit-commit
with the contents from the tempfile. Not you can merge the single commit. Of course you lose all commit history with this approach. Another one would be togit-log --no-merges
tomerge-base
andcherry-pick
each commit... but merges are lost this way, which could break things.reset-soft
-approach). Also: No hard reset, so less likely to screw up things.