Prune empty merge commits from history in Git repository
I have cleaned up our Git repository quite a bit, we need to remove big parts from the history. I do this using:
git filter-branch --prune-empty --tree-filter 'rm -rf some_stuff'
The --prune-empty
flag will remove commits that are left empty after the process, except commits with multiple parents (merge commits). Even if the branch being merged in contains absolutely nothing, and the merge adds nothing to the tree.
How do I also prune these empty merge commits from the history?
This is superior to the rebase solution because it preserves committer info, committer dates, and non-empty merges of the original history.
git filter-branch --prune-empty --parent-filter \
'sed "s/-p //g" | xargs -r git show-branch --independent | sed "s/\</-p /g"'
This is inspired by the same thread on the kernel mailing list than Lucas' solution. However it does not require Ruby and is a one-liner. It does require GNU versions of xargs
and sed
though.
I needed to do this after running filter-branch
on a copy of ssokolow/profile to separate out ssokolow/lap.
This did a decent job as an automatic "collapse away anything left vestigial by --prune-empty
" command:
git rebase --root HEAD
(I needed the --root
so it would replace the now-empty initial commit with the oldest one that still had content.)
This looks like it worked for me: http://git.661346.n2.nabble.com/Removing-useless-merge-commit-with-quot-filter-branch-quot-td7356544.html
git filter-branch -f --prune-empty --parent-filter FULL_PATH_TO/rewrite_parent.rb master
rewrite_parent.rb
:
#!/usr/bin/ruby
old_parents = gets.chomp.gsub('-p ', ' ')
if old_parents.empty? then
new_parents = []
else
new_parents = `git show-branch --independent #{old_parents}`.split
end
puts new_parents.map{|p| '-p ' + p}.join(' ')