Code

Making pathspec limited log play nicer with --first-parent
authorJunio C Hamano <gitster@pobox.com>
Thu, 19 Jan 2012 19:58:45 +0000 (11:58 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 20 Jan 2012 00:18:27 +0000 (16:18 -0800)
In a topic branch workflow, you often want to find the latest commit that
merged a side branch that touched a particular area of the system, so that
a new topic branch to work on that area can be forked from that commit.
For example, I wanted to find an appropriate fork-point to queue Luke's
changes related to git-p4 in contrib/fast-import/.

"git log --first-parent" traverses the first-parent chain, and "-m --stat"
shows the list of paths touched by commits including merge commits.  We
could ask the question this way:

    # What is the latest commit that touched that path?
    $ git log --first-parent --oneline -m --stat master |
      sed -e '/^ contrib\/fast-import\/git-p4 /q' | tail

The above finds that 8cbfc11 (Merge branch 'pw/p4-view-updates',
2012-01-06) was such a commit.

But a more natural way to spell this question is this:

    $ git log --first-parent --oneline -m --stat -1 master -- \
      contrib/fast-import/git-p4

Unfortunately, this does not work. It finds ecb7cf9 (git-p4: rewrite view
handling, 2012-01-02). This commit is a part of the merged topic branch
and is _not_ on the first-parent path from the 'master':

    $ git show-branch 8cbfc11 ecb7cf9
    ! [8cbfc11] Merge branch 'pw/p4-view-updates'
     ! [ecb7cf9] git-p4: rewrite view handling
    --
    -  [8cbfc11] Merge branch 'pw/p4-view-updates'
    +  [8cbfc11^2] git-p4: view spec documentation
    ++ [ecb7cf9] git-p4: rewrite view handling

The problem is caused by the merge simplification logic when it inspects
the merge commit 8cbfc11. In this case, the history leading to the tip of
'master' did not touch git-p4 since 'pw/p4-view-updates' topic forked, and
the result of the merge is simply a copy from the tip of the topic branch
in the view limited by the given pathspec.  The merge simplification logic
discards the history on the mainline side of the merge, and pretends as if
the sole parent of the merge is its second parent, i.e. the tip of the
topic. While this simplification is correct in the general case, it is at
least surprising if not outright wrong when the user explicitly asked to
show the first-parent history.

Here is an attempt to fix this issue, by not allowing us to compare the
merge result with anything but the first parent when --first-parent is in
effect, to avoid the history traversal veering off to the side branch.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
revision.c
t/t6012-rev-list-simplify.sh

index c46cfaa3e4d2f06fd67ccd71c7ba47891796fd60..f03b7031e5217ffae37f102a0d4c1efe3f93d85d 100644 (file)
@@ -368,7 +368,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
 static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 {
        struct commit_list **pp, *parent;
-       int tree_changed = 0, tree_same = 0;
+       int tree_changed = 0, tree_same = 0, nth_parent = 0;
 
        /*
         * If we don't do pruning, everything is interesting
@@ -396,6 +396,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
        while ((parent = *pp) != NULL) {
                struct commit *p = parent->item;
 
+               /*
+                * Do not compare with later parents when we care only about
+                * the first parent chain, in order to avoid derailing the
+                * traversal to follow a side branch that brought everything
+                * in the path we are limited to by the pathspec.
+                */
+               if (revs->first_parent_only && nth_parent++)
+                       break;
                if (parse_commit(p) < 0)
                        die("cannot simplify commit %s (because of %s)",
                            sha1_to_hex(commit->object.sha1),
index af34a1e81711ca183680c9882353bd786b55e79f..839ad97b791c6aa757d0b82eea7fc16369ad4586 100755 (executable)
@@ -86,5 +86,6 @@ check_result 'I H E C B A' --full-history --date-order -- file
 check_result 'I E C B A' --simplify-merges -- file
 check_result 'I B A' -- file
 check_result 'I B A' --topo-order -- file
+check_result 'H' --first-parent -- another-file
 
 test_done