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 <sbel...@google.com>
---
 Documentation/rev-list-options.txt |  5 +++
 list-objects.c                     |  2 +
 revision.c                         |  2 +
 revision.h                         |  3 +-
 t/t6100-rev-list-in-order.sh       | 77 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100755 t/t6100-rev-list-in-order.sh

diff --git a/Documentation/rev-list-options.txt 
b/Documentation/rev-list-options.txt
index 13501e1556..9066e0c777 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -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
diff --git a/list-objects.c b/list-objects.c
index 7c2ce9c4bd..07a92f35fe 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -239,6 +239,8 @@ 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)
+                       traverse_trees_and_blobs(revs, &csp, show_object, data);
        }
        traverse_trees_and_blobs(revs, &csp, show_object, data);
 
diff --git a/revision.c b/revision.c
index d167223e69..9329d4ebbf 100644
--- a/revision.c
+++ b/revision.c
@@ -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")) {
diff --git a/revision.h b/revision.h
index 54761200ad..86985d68aa 100644
--- a/revision.h
+++ b/revision.h
@@ -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
index 0000000000..b2bb0a7f61
--- /dev/null
+++ b/t/t6100-rev-list-in-order.sh
@@ -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
-- 
2.15.0.128.gcadd42da22

Reply via email to