Skip to content
  • Thomas Rast's avatar
    log: use true parents for diff even when rewriting · 53d00b39
    Thomas Rast authored and Junio C Hamano's avatar Junio C Hamano committed
    
    
    When using pathspec filtering in combination with diff-based log
    output, parent simplification happens before the diff is computed.
    The diff is therefore against the *simplified* parents.
    
    This works okay, arguably by accident, in the normal case:
    simplification reduces to one parent as long as the commit is TREESAME
    to it.  So the simplified parent of any given commit must have the
    same tree contents on the filtered paths as its true (unfiltered)
    parent.
    
    However, --full-diff breaks this guarantee, and indeed gives pretty
    spectacular results when comparing the output of
    
      git log --graph --stat ...
      git log --graph --full-diff --stat ...
    
    (--graph internally kicks in parent simplification, much like
    --parents).
    
    To fix it, store a copy of the parent list before simplification (in a
    slab) whenever --full-diff is in effect.  Then use the stored parents
    instead of the simplified ones in the commit display code paths.  The
    latter do not actually check for --full-diff to avoid duplicated code;
    they just grab the original parents if save_parents() has not been
    called for this revision walk.
    
    For ordinary commits it should be obvious that this is the right thing
    to do.
    
    Merge commits are a bit subtle.  Observe that with default
    simplification, merge simplification is an all-or-nothing decision:
    either the merge is TREESAME to one parent and disappears, or it is
    different from all parents and the parent list remains intact.
    Redundant parents are not pruned, so the existing code also shows them
    as a merge.
    
    So if we do show a merge commit, the parent list just consists of the
    rewrite result on each parent.  Running, e.g., --cc on this in
    --full-diff mode is not very useful: if any commits were skipped, some
    hunks will disagree with all sides of the merge (with one side,
    because commits were skipped; with the others, because they didn't
    have those changes in the first place).  This triggers --cc showing
    these hunks spuriously.
    
    Therefore I believe that even for merge commits it is better to show
    the diffs wrt. the original parents.
    
    Reported-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
    Helped-by: default avatarJunio C Hamano <gitster@pobox.com>
    Helped-by: default avatarRamsay Jones <ramsay@ramsay1.demon.co.uk>
    Signed-off-by: default avatarThomas Rast <trast@inf.ethz.ch>
    Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
    53d00b39