Skip to content

Instantly share code, notes, and snippets.

@xpl
Last active February 5, 2021 15:57
Show Gist options
  • Save xpl/33caec1254d9ef283e7b01010131c3e9 to your computer and use it in GitHub Desktop.
Save xpl/33caec1254d9ef283e7b01010131c3e9 to your computer and use it in GitHub Desktop.
Squash My Commits (In A Feature Branch)

Squash My Commits (In A Feature Branch)

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:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment