Delete old git branches already merged into master

git ruby taskrabbit 
Thu Dec 20 2012 - Originally posted at tech.taskrabbit.com



It was time to clean up some old git branches at TaskRabbit today. It turned out that we had hundreds of branches that were "old", and could be removed. What do I mean by "old"? As with many things, coming up with the proper definition is 1/2 the battle. At the end of the day, "old" meant "I have been merged into master, and contain no un-merged code" (where master is your integration branch).

When phrased this way, there are some systematic and simple ways to due some git pruning. Here’s a simple rake task:

1namespace :git do 2 3 desc "delete remote branches which have already been merged into master" 4 task :clean_merged_branches do 5 local_branches = `git branch`.split("\n").map{ |line| line.gsub(" ","") } 6 raise "You need to be in master to start this game" unless local_branches.include?('* master') 7 say_and_do("git fetch --prune") #clean up your local and remove deleted branches 8 bad_branches = `git branch -r --merged`.split("\n").map{ |line| line.gsub(" ","") } 9 bad_branches.each do |bad_branch| 10 parts = bad_branch.split("/") 11 remote = parts.shift 12 if remote == "origin" 13 branch = parts.join("/") 14 next if branch =~ /^HEAD.*/ 15 next if branch == /^refs\/.*/ 16 next if branch == "master" 17 next if branch == /.*staging.*/ 18 next if branch == /.*production.*/ 19 20 say_and_do("git branch -D #{branch}") if local_branches.include?(branch) 21 say_and_do("git push origin :#{branch}") 22 else 23 puts "skipping #{bad_branch} because it doesn't have a remote of 'origin'" 24 end 25 end 26 end 27end 28 29def say_and_do(stuff, explanation=nil) 30 puts explanation if explanation 31 puts " > #{stuff}" 32 `#{stuff}` 33end

The trick here is git fetch -r -merged command which does exactly what we want: tell me about the remote branches which have all been merged into my current branch, master. We simply collect those branches, and delete them locally (if they exist) and on origin.

The logic goes like this

  1. Ensure I am in the master branch
  2. git fetch -prune (clean up my local branch list according to remote’s list)
  3. git fetch -r -merged (show me the branches which have been merged into the integration branch)
  4. loop through those branches and delete them locally and remotely

Two other points of note:

  1. It’s very likely that you will have some staging, test, and production branches which are either equivalent to or slightly behind your integration branch. You probably want to explicitly ignore those
  2. If you have more than one remote branch setup (perhaps heroku for deployment or tddium for testing), you want to be sure to ignore any branch which isn’t from "origin"
Hi, I'm Evan

I write about Technology, Software, and Startups. I use my Product Management, Software Engineering, and Leadership skills to build teams that create world-class digital products.

Get in touch