Here's a script for squashing up to the first commit coming after a merge commit (with confirmation). Useful for working in a branch and then squashing temporary commits before merging into trunk.
Save the script as squash
. Upon executing, it brings your git editor (vim/nano/whatever) to confirm the prepped rebase
todo — so you would only need to simply save-and-exit (in most cases).
#!/usr/bin/env python3
# flake8: noqa
import subprocess, re, sys, os
def shell(what):
return subprocess.check_output(what, shell=True, universal_newlines=True)
def execute(bin, args, **env):
path = shell(f'which {bin}').strip()
os.execve(path, [path, *args], {**os.environ, **env})
if len(sys.argv) == 1:
first_merge_commit = shell('git log -n1 --pretty=%H --merges').strip()
ourselves = os.path.abspath(sys.argv[0])
execute('git', ['rebase', '-i', first_merge_commit], GIT_SEQUENCE_EDITOR=ourselves)
# ...and it continues here (gets called by git rebase)
else:
rebase_todo = open(sys.argv[1], 'r').read()
rebase_todo = re.sub('^pick', 'fixup', rebase_todo, flags=re.MULTILINE)
rebase_todo = re.sub('^fixup', 'pick', rebase_todo) # Leave first commit as "pick"
open(sys.argv[1], 'w').write(rebase_todo)
execute(shell('git config --global core.editor'), sys.argv[1:])