Re: Removing useless merge commit with "filter-branch"
Hi,
I solved my issue by using "git filter-branch --parent-filter". The idea is to visit all commits and remove all "dependent" parents. To find independent parents I used "git show-branch --independent PARENT_1..PARENT_N" command. In my case (we have a lot of short-term development branches) this converted ~80% of all merges to "empty non-merge commits" and later "git filter-branch --prune-empty" removed them. This made history of my project much more simpler and linear.
I think such functionality should be available in git and enabled when "--prune-empty" flag is used. So "--prune-empty" removes not only simple commits but also empty useless merge commits. Or maybe add a --prune-empty-merges flag?
Anyway here is the script that I use, future readers might find it useful:
$ git filter-branch -f --prune-empty --parent-filter PATH_TO/rewrite_parent.rb master $ cat 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
endputs new_parents.map{|p| '-p ' + p}.join(' ')Most likely the script can be rewritten as one-line shell script.
On Tue, Mar 13, 2012 at 3:27 PM, Anatol Pomozov <anatol.pomozov@gmail.com> wrote:
Show 68 quoted lines
> Hi
>
> On Thu, Mar 8, 2012 at 3:30 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> Anatol Pomozov <anatol.pomozov@gmail.com> writes:
>>
>>> |
>>> o - merge commit that previously merged feature X
>>> |\
>>> | \
>>> | \
>>> o | - real commit
>>> | |
>>> | /
>>> |/
>>> |
>>
>> It is unclear how many commits are drawn in the above picture and
>> what "feature X" is about in the above picture. Care to redraw the
>> commit DAG to explain what you are trying to do a bit better?
>>
>> The way I read it is that you start from a history like this (note
>> that when we draw an ascii art history we often write it sideways,
>> time flows from left to right):
>>
>> ---A-----B-----M---
>> \ /
>> C-------D
>>
>> where a side branch to implement "feature X" that has C and D forked
>> at A, and it was merged at M after somebody else committed B on the
>> mainline. When you filtered out some parts of the tree, it turns
>> out that C and D are totally unintereseting because their changes
>> touch parts outside of your interest, i.e. the history is:
>>
>> ---A-----B-----M---
>> \ /
>> o-------o
>>
>> where 'o' are now no-op.
>>
>> Is that what you are talking about?
>
> Yes, in fact --prune-empty flag removes empty commits so the history looks like
>
> -----A-------B-------M--------
> \ /
> --------------
>
>
> So M is a merge that has 2 parents A and B. I would like to remove
> this merge M and leave the history as
>
> -----A-----B-----
>
> as only these commits have changes in my library that I am trying to extract.
>
> I think some trickery with "git filter-branch --parent-filter" should help here.
>
> First one runs filter-branch with --parent-filter and removes useless
> parents from merges (in this example with will be parent A---M), this
> converts such merges to regular empty commits
>
> then run filter-branch one more time with --prune-empty - it removes
> empty commits.
>>
>> I think "log --simplify-merges A..M -- path" may already has logic
>> that deals with this, so it may help if you study what it does and
>> how it does what it does.