revision.h: introduce blob/tree walking in order of the commits
authorStefan Beller <sbeller@google.com>
Thu, 16 Nov 2017 02:00:35 +0000 (18:00 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 16 Nov 2017 02:12:51 +0000 (11:12 +0900)
The functionality to list tree objects in the order they were seen
while traversing the commits will be used in one of the next commits,
where we teach `git describe` to describe not only commits, but blobs, too.

The change in list-objects.c is rather minimal as we'll be re-using
the infrastructure put in place of the revision walking machinery. For
example one could expect that add_pending_tree is not called, but rather
commit->tree is directly passed to the tree traversal function. This
however requires a lot more code than just emptying the queue containing
trees after each commit.

Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/rev-list-options.txt
list-objects.c
revision.c
revision.h
t/t6100-rev-list-in-order.sh [new file with mode: 0755]

index 13501e1..9066e0c 100644 (file)
@@ -686,6 +686,11 @@ ifdef::git-rev-list[]
        all object IDs which I need to download if I have the commit
        object _bar_ but not _foo_''.
 
+--in-commit-order::
+       Print tree and blob ids in order of the commits. The tree
+       and blob ids are printed after they are first referenced
+       by a commit.
+
 --objects-edge::
        Similar to `--objects`, but also print the IDs of excluded
        commits prefixed with a ``-'' character.  This is used by
index 7c2ce9c..4caa6fc 100644 (file)
@@ -239,6 +239,14 @@ void traverse_commit_list(struct rev_info *revs,
                if (commit->tree)
                        add_pending_tree(revs, commit->tree);
                show_commit(commit, data);
+
+               if (revs->tree_blobs_in_commit_order)
+                       /*
+                        * NEEDSWORK: Adding the tree and then flushing it here
+                        * needs a reallocation for each commit. Can we pass the
+                        * tree directory without allocation churn?
+                        */
+                       traverse_trees_and_blobs(revs, &csp, show_object, data);
        }
        traverse_trees_and_blobs(revs, &csp, show_object, data);
 
index d167223..9329d4e 100644 (file)
@@ -1845,6 +1845,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->dense = 0;
        } else if (!strcmp(arg, "--show-all")) {
                revs->show_all = 1;
+       } else if (!strcmp(arg, "--in-commit-order")) {
+               revs->tree_blobs_in_commit_order = 1;
        } else if (!strcmp(arg, "--remove-empty")) {
                revs->remove_empty_trees = 1;
        } else if (!strcmp(arg, "--merges")) {
index 5476120..86985d6 100644 (file)
@@ -121,7 +121,8 @@ struct rev_info {
                        bisect:1,
                        ancestry_path:1,
                        first_parent_only:1,
-                       line_level_traverse:1;
+                       line_level_traverse:1,
+                       tree_blobs_in_commit_order:1;
 
        /* Diff flags */
        unsigned int    diff:1,
diff --git a/t/t6100-rev-list-in-order.sh b/t/t6100-rev-list-in-order.sh
new file mode 100755 (executable)
index 0000000..b2bb0a7
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+test_description='rev-list testing in-commit-order'
+
+. ./test-lib.sh
+
+test_expect_success 'setup a commit history with trees, blobs' '
+       for x in one two three four
+       do
+               echo $x >$x &&
+               git add $x &&
+               git commit -m "add file $x" ||
+               return 1
+       done &&
+       for x in four three
+       do
+               git rm $x &&
+               git commit -m "remove $x" ||
+               return 1
+       done
+'
+
+test_expect_success 'rev-list --in-commit-order' '
+       git rev-list --in-commit-order --objects HEAD >actual.raw &&
+       cut -c 1-40 >actual <actual.raw &&
+
+       git cat-file --batch-check="%(objectname)" >expect.raw <<-\EOF &&
+               HEAD^{commit}
+               HEAD^{tree}
+               HEAD^{tree}:one
+               HEAD^{tree}:two
+               HEAD~1^{commit}
+               HEAD~1^{tree}
+               HEAD~1^{tree}:three
+               HEAD~2^{commit}
+               HEAD~2^{tree}
+               HEAD~2^{tree}:four
+               HEAD~3^{commit}
+               # HEAD~3^{tree} skipped, same as HEAD~1^{tree}
+               HEAD~4^{commit}
+               # HEAD~4^{tree} skipped, same as HEAD^{tree}
+               HEAD~5^{commit}
+               HEAD~5^{tree}
+       EOF
+       grep -v "#" >expect <expect.raw &&
+
+       test_cmp expect actual
+'
+
+test_expect_success 'rev-list lists blobs and trees after commits' '
+       git rev-list --objects HEAD >actual.raw &&
+       cut -c 1-40 >actual <actual.raw &&
+
+       git cat-file --batch-check="%(objectname)" >expect.raw <<-\EOF &&
+               HEAD^{commit}
+               HEAD~1^{commit}
+               HEAD~2^{commit}
+               HEAD~3^{commit}
+               HEAD~4^{commit}
+               HEAD~5^{commit}
+               HEAD^{tree}
+               HEAD^{tree}:one
+               HEAD^{tree}:two
+               HEAD~1^{tree}
+               HEAD~1^{tree}:three
+               HEAD~2^{tree}
+               HEAD~2^{tree}:four
+               # HEAD~3^{tree} skipped, same as HEAD~1^{tree}
+               # HEAD~4^{tree} skipped, same as HEAD^{tree}
+               HEAD~5^{tree}
+       EOF
+       grep -v "#" >expect <expect.raw &&
+
+       test_cmp expect actual
+'
+
+test_done