threads / discuss / 36077

RFC GSoc Idea: blame: do not overly favor earlier parents

Subject: RFC GSoc Idea: blame: do not overly favor earlier parents

## tl;dr

3 messages between Mar 6, 2014 and Mar 6, 2014.

replies: 2people: 2as markdown or json

Junio C Hamano· Mar 6, 2014, 20:02 UTC · lore

When looking at a merge, "git blame" inspects the blob object names of all parents and if one of them exactly match the merge result, pass the entire blame down to that parent. This is very much in line with the history simplification done with "git log" when traversing a history with merges.

On the other hand, when the blob object in the merge result and none of the parents match exactly, we let each parent to take as much blame as they can, starting from the earlier parent, and later parents get a chance to take blame on the "leftover bits".

Combination of the above can lead to an unexpected results.

Let's say that M is a two-parent merge, M^1 == A and M^2 == B, and that M:path == B:path != A:path (i.e. the merge result matches its second parent exactly). The entire contents of the path is blamed to the history leading to B; the history leading to A but not involved in B will not get any blame.

Now, imagine if you amend M to create N, to add a single line at the end of path. M:path != N:path but there is very small difference between the two. That means B:path != N:path but the difference between this merged result and the second parent is very small.

Because we give the chance to get blamed for the whole thing to the first parent, however, A will grab blame for all the lines that are common between A:path and B:path. For the lines that are the same between M:path and N:path, ideally, we should get identical results, but it results in a very inconsistent behaviour.

Update blame.c::pass_blame() and give an option to arrange the list of "scapegoats" in the order that are similar to the end result, in order to address this issue. That way, when blaming N:path, we will inspect B:path first and let it grab as much blame, as it would happen when we started the blame for M:path.

David Kastrup· Mar 6, 2014, 20:21 UTC · re: Junio C Hamano · lore

Re: RFC GSoc Idea: blame: do not overly favor earlier parents

Junio C Hamano <gitster@pobox.com> writes:
Show 5 quoted lines
> When looking at a merge, "git blame" inspects the blob object names
> of all parents and if one of them exactly match the merge result,
> pass the entire blame down to that parent.  This is very much in
> line with the history simplification done with "git log" when
> traversing a history with merges.
[...]
> Now, imagine if you amend M to create N, to add a single line at the
> end of path.  M:path != N:path but there is very small difference
> between the two.  That means B:path != N:path but the difference
> between this merged result and the second parent is very small.
That sounds very much like
commit d5df1593f27bfceab807242a538cb3fa01256efd
Merge: 7144168 0b4e246
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Feb 28 13:51:19 2014 -0800
    Merge branch 'bl/blame-full-history' into pu
    
    By disabling the tree-same optimization (which is consistent with
    the default behaviour of "git log"-family of commands), make "git
    blame" sometimes produce different result from the original code.
    
    Because the "git blame" output can give result for each line from
    only one lineage of the history, however, this can be only useful
    when you are lucky---unlike "--full-history" of "git log"-family,
    where we can show commits from both lineages of histories with an
    equal weight.  See $gmane/240392 for more detailed discussion.
    
    * bl/blame-full-history:
      blame: new option --prefer-first to better handle merged cherry-picks
-- 
David Kastrup
Junio C Hamano· Mar 6, 2014, 20:24 UTC · re: David Kastrup · lore

Re: RFC GSoc Idea: blame: do not overly favor earlier parents

David Kastrup <dak@gnu.org> writes:
Show 23 quoted lines
> Junio C Hamano <gitster@pobox.com> writes:
>
>> When looking at a merge, "git blame" inspects the blob object names
>> of all parents and if one of them exactly match the merge result,
>> pass the entire blame down to that parent.  This is very much in
>> line with the history simplification done with "git log" when
>> traversing a history with merges.
>
> [...]
>
>> Now, imagine if you amend M to create N, to add a single line at the
>> end of path.  M:path != N:path but there is very small difference
>> between the two.  That means B:path != N:path but the difference
>> between this merged result and the second parent is very small.
>
> That sounds very much like
>
> commit d5df1593f27bfceab807242a538cb3fa01256efd
> Merge: 7144168 0b4e246
> Author: Junio C Hamano <gitster@pobox.com>
> Date:   Fri Feb 28 13:51:19 2014 -0800
>
>     Merge branch 'bl/blame-full-history' into pu

That one was an attempt to solve the right issue in a wrong way, made things worse by breaking the consistency with the history simplification of "git log".

The "Idea" is to solve it in the way that is still consistent with the usual history simplification.

← back to recent threads