Clean your merged branches in CPython with this git alias

If sometime in the past you have thought:

Cleaning all the branches that I used for creating Pull Request that are now merged should be easy with git branch --merged master"

and then realize in horror that we squash and merge in CPython, creating a new different commit and therefore rendering branch --merged useless… This is your lucky day!

With this arcane knowledge, you can clean up all those nasty branches that are already merged into master that you have dancing around in your local git repository. Just copy this “line” in your ~/.gitconfig file and then run $ git cleanup in your repository:

        cleanup = "!f(){ git checkout -q master && git for-each-ref refs/heads/ '--format=%(refname:short)' | while read branch; do mergeBase=$(git merge-base master $branch) && [[ $(git cherry master $(git commit-tree $(git rev-parse $branch^{tree}) -p $mergeBase -m _)) == '-'* ]] && git branch -D $branch; done ; }; f"

This command will run a bunch of git cherry against some simulated git trees to find out what branches are squashed and merged into master. To further adapt it to your needs you can change ‘master’ for whatever branch/ref you use to track the upstream master branch.


I have a different strategy. I remove my local branches as soon as I published a PR. If I have to modify a PR, I type "git checkout " and Git does its thing to recreate it. I publish new commits and remove the local branch again. Sometimes, I run “git pull origin --prune” where the ‘origin’ remote is my cpython fork.

In short, I almost never have any local branch :slight_smile: I only have one or two local branches when I’m working on them.

By the way, my script to update ~/prog/python/master, ~/prog/python/3.7, etc. directories:

set -x -e

cd ~/prog/python/master
git fetch upstream --tags --prune
git fetch origin --prune

for branch in master 3.7 3.6 2.7; do
    cd ~/prog/python/$branch
    git checkout $branch
    git merge --ff

I usually just let Magit (Emacs git porcelain) do all the work. Once my PR is merged, I delete my branch on GH, and then purge-fetch and delete through the Magit U/I.


My personal (horrible) method for this is a script in ~/bin called git-clean-branches:


set -eu

git fetch -p ${1-}

git branch -vv | grep ": gone" | awk '{print $1}' | xargs git branch -D

With ~/bin on PATH, I can just run git clean-branches [remote] to clear out anything that used to have an upstream but now doesn’t.

I think this is an example of “there should be one (thousand) obvious ways to do it” :slight_smile:

GitHub provides an API to check if the pull request has been merged There is also branch name and merge state available through PR API.

http | jq -C "{branch: .head.ref, merged: .merged}"
  "branch": "bpo35877",
  "merged": true
http | jq -C "{branch: .head.ref, merged: .merged}"
  "branch": "bpo35838",
  "merged": false

I’m also using ~/bin for years. FYI ~/.local/bin is becoming a standard. Slowly, Linux distributions are including it in the default PATH with the expected priority! It solves for example the problem of installing a Python program in your home directory and that program has the priority over the program installed in the system (ex: /usr/bin). A concrete example is to upgrade pip itself in your home directory, without affecting (“breaking”) the system.

… In Fedora, we have many bug reports of people messing their system by trying to upgrade things using “sudo pip install (…)”. For example, we modified pip to no longer modify /usr/lib but only /usr/local/lib. So dnf installs .py files in /usr/lib, whereas pip installs/upgrades in /usr/local/lib.

One of the cool properties of the git alias™ is that you do not need to maintain any extra workflow like remembering to delete upstream branches or never work on local branches. I personally I sometimes forgot to click the “delete branch” once my PR is merged.

So I’ve avoided opening this thread just because it contains the word “insane” in title … :worried:

Sorry, I apologize :frowning:

I just wanted to joke about the fact that is probably over-complicated for what achieves.

I will change the title to remove those references :slight_smile: