git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 5/5] list-objects-filter: implement filter tree:none

From
Matthew DeVore <matvore@google.com>
Date
Aug 10, 2018, 23:06 UTC
Message-ID
<0af4ef64aa52d76a597b4e97c0626c70fb2a883b.1533941986.git.matvore@google.com>
In-Reply-To
<cover.1533941986.git.matvore@google.com>

Teach list-objects the "tree:none" filter which allows for filtering out all tree and blob objects (unless other objects are explicitly specified by the user). The purpose of this patch is to allow smaller partial clones.

The name of this filter - tree:none - does not explicitly specify that it also filters out all blobs, but this should not cause much confusion because blobs are not at all useful without the trees that refer to them.

I also consider only:commits as a name, but this is inaccurate because it suggests that annotated tags are omitted, but actually they are included.

Signed-off-by: Matthew DeVore <matvore@google.com>
---
 Documentation/rev-list-options.txt     |  2 ++
 list-objects-filter-options.c          |  4 +++
 list-objects-filter-options.h          |  1 +
 list-objects-filter.c                  | 49 +++++++++++++++++++-------
 t/t5317-pack-objects-filter-objects.sh | 27 ++++++++++++++
 t/t5616-partial-clone.sh               | 27 ++++++++++++++
 t/t6112-rev-list-filters-objects.sh    | 13 +++++++
 7 files changed, 110 insertions(+), 13 deletions(-)
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 7b273635d..68b4b9552 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -743,6 +743,8 @@ specification contained in <path>.
 	A debug option to help with future "partial clone" development.
 	This option specifies how missing objects are handled.
 +
+The form '--filter=tree:none' omits all blobs and trees.
++
 The form '--missing=error' requests that rev-list stop with an error if
 a missing object is encountered.  This is the default action.
 +
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index c0e2bd6a0..523cb00a0 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -50,6 +50,10 @@ static int gently_parse_list_objects_filter(
 			return 0;
 		}
 
+	} else if (!strcmp(arg, "tree:none")) {
+		filter_options->choice = LOFC_TREE_NONE;
+		return 0;
+
 	} else if (skip_prefix(arg, "sparse:oid=", &v0)) {
 		struct object_context oc;
 		struct object_id sparse_oid;
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 0000a61f8..af64e5c66 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -10,6 +10,7 @@ enum list_objects_filter_choice {
 	LOFC_DISABLED = 0,
 	LOFC_BLOB_NONE,
 	LOFC_BLOB_LIMIT,
+	LOFC_TREE_NONE,
 	LOFC_SPARSE_OID,
 	LOFC_SPARSE_PATH,
 	LOFC__COUNT /* must be last */
diff --git a/list-objects-filter.c b/list-objects-filter.c
index a0ba78b20..22c894093 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -26,38 +26,45 @@
 #define FILTER_SHOWN_BUT_REVISIT (1<<21)
 
 /*
- * A filter for list-objects to omit ALL blobs from the traversal.
- * And to OPTIONALLY collect a list of the omitted OIDs.
+ * A filter for list-objects to omit ALL blobs from the traversal, and possibly
+ * trees as well.
+ * Can OPTIONALLY collect a list of the omitted OIDs.
  */
-struct filter_blobs_none_data {
+struct filter_none_of_type_data {
+	/* blobs are always omitted */
+	unsigned omit_trees : 1;
 	struct oidset *omits;
 };
 
-static enum list_objects_filter_result filter_blobs_none(
+static enum list_objects_filter_result filter_none_of_type(
 	enum list_objects_filter_situation filter_situation,
 	struct object *obj,
 	const char *pathname,
 	const char *filename,
 	void *filter_data_)
 {
-	struct filter_blobs_none_data *filter_data = filter_data_;
+	struct filter_none_of_type_data *filter_data = filter_data_;
 
 	switch (filter_situation) {
 	default:
 		die("unknown filter_situation");
 		return LOFR_ZERO;
 
-	case LOFS_BEGIN_TREE:
-		assert(obj->type == OBJ_TREE);
-		/* always include all tree objects */
-		return LOFR_MARK_SEEN | LOFR_DO_SHOW;
-
 	case LOFS_END_TREE:
 		assert(obj->type == OBJ_TREE);
 		return LOFR_ZERO;
 
+	case LOFS_BEGIN_TREE:
+		assert(obj->type == OBJ_TREE);
+		if (!filter_data->omit_trees)
+			return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
+		/*
+		 * Fallthrough to insert into omitted list for trees as well as
+		 * blobs.
+		 */
+		/* fallthrough */
 	case LOFS_BLOB:
-		assert(obj->type == OBJ_BLOB);
 		assert((obj->flags & SEEN) == 0);
 
 		if (filter_data->omits)
@@ -72,10 +79,25 @@ static void *filter_blobs_none__init(
 	filter_object_fn *filter_fn,
 	filter_free_fn *filter_free_fn)
 {
-	struct filter_blobs_none_data *d = xcalloc(1, sizeof(*d));
+	struct filter_none_of_type_data *d = xcalloc(1, sizeof(*d));
+	d->omits = omitted;
+
+	*filter_fn = filter_none_of_type;
+	*filter_free_fn = free;
+	return d;
+}
+
+static void* filter_tree_none__init(
+	struct oidset *omitted,
+	struct list_objects_filter_options *filter_options,
+	filter_object_fn *filter_fn,
+	filter_free_fn *filter_free_fn)
+{
+	struct filter_none_of_type_data *d = xcalloc(1, sizeof(*d));
+	d->omit_trees = 1;
 	d->omits = omitted;
 
-	*filter_fn = filter_blobs_none;
+	*filter_fn = filter_none_of_type;
 	*filter_free_fn = free;
 	return d;
 }
@@ -374,6 +396,7 @@ static filter_init_fn s_filters[] = {
 	NULL,
 	filter_blobs_none__init,
 	filter_blobs_limit__init,
+	filter_tree_none__init,
 	filter_sparse_oid__init,
 	filter_sparse_path__init,
 };
diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh
index 5e35f33bf..28a8c916a 100755
--- a/t/t5317-pack-objects-filter-objects.sh
+++ b/t/t5317-pack-objects-filter-objects.sh
@@ -72,6 +72,33 @@ test_expect_success 'get an error for missing tree object' '
 	grep -q "bad tree object" bad_tree
 '
 
+test_expect_success 'setup for tests of tree:none' '
+	mkdir r1/subtree &&
+	echo "This is a file in a subtree" > r1/subtree/file &&
+	git -C r1 add subtree/file &&
+	git -C r1 commit -m subtree
+'
+
+test_expect_success 'verify tree:none packfile has no blobs or trees' '
+	git -C r1 pack-objects --rev --stdout --filter=tree:none >commitsonly.pack <<-EOF &&
+	HEAD
+	EOF
+	git -C r1 index-pack ../commitsonly.pack &&
+	git -C r1 verify-pack -v ../commitsonly.pack >objs &&
+	! grep -E "tree|blob" objs
+'
+
+test_expect_success 'grab tree directly when using tree:none' '
+	# We should get the tree specified directly but not its blobs or subtrees.
+	git -C r1 pack-objects --rev --stdout --filter=tree:none >commitsonly.pack <<-EOF &&
+	HEAD:
+	EOF
+	git -C r1 index-pack ../commitsonly.pack &&
+	git -C r1 verify-pack -v ../commitsonly.pack >objs &&
+	grep -E "tree|blob" objs >trees_and_blobs &&
+	test_line_count = 1 trees_and_blobs
+'
+
 # Test blob:limit=<n>[kmg] filter.
 # We boundary test around the size parameter.  The filter is strictly less than
 # the value, so size 500 and 1000 should have the same results, but 1001 should
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index bbbe7537d..4fc068716 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -170,6 +170,33 @@ test_expect_success 'partial clone fetches blobs pointed to by refs even if norm
 	git -C dst fsck
 '
 
+test_expect_success 'can use tree:none to filter partial clone' '
+	rm -rf dst &&
+	git clone --no-checkout --filter=tree:none "file://$(pwd)/srv.bare" dst &&
+	git -C dst rev-list master --missing=allow-any --objects >fetched_objects &&
+	cat fetched_objects \
+		| awk -f print_1.awk \
+		| xargs -n1 git -C dst cat-file -t >fetched_types &&
+	sort fetched_types -u >unique_types.observed &&
+	echo commit > unique_types.expected &&
+	test_cmp unique_types.observed unique_types.expected
+'
+
+test_expect_success 'show missing tree objects with --missing=print' '
+	git -C dst rev-list master --missing=print --quiet --objects >missing_objs &&
+	sed "s/?//" missing_objs \
+		| xargs -n1 git -C srv.bare cat-file -t \
+		>missing_types &&
+	sort -u missing_types >missing_types.uniq &&
+	echo tree >expected &&
+	test_cmp missing_types.uniq expected
+'
+
+test_expect_success 'do not complain when a missing tree cannot be parsed' '
+	git -C dst rev-list master --missing=print --quiet --objects 2>rev_list_err >&2 &&
+	! grep -q "Could not read " rev_list_err
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
diff --git a/t/t6112-rev-list-filters-objects.sh b/t/t6112-rev-list-filters-objects.sh
index 0a37dd5f9..ecdf6b4c3 100755
--- a/t/t6112-rev-list-filters-objects.sh
+++ b/t/t6112-rev-list-filters-objects.sh
@@ -196,6 +196,19 @@ test_expect_success 'verify sparse:oid=oid-ish omits top-level files' '
 	test_cmp observed expected
 '
 
+# Test tree:none filter.
+
+test_expect_success 'verify tree:none includes trees in "filtered" output' '
+	git -C r3 rev-list HEAD --quiet --objects --filter-print-omitted --filter=tree:none \
+		| awk -f print_1.awk \
+		| sed s/~// \
+		| xargs -n1 git -C r3 cat-file -t \
+		| sort -u >filtered_types &&
+	printf "blob\ntree\n" > expected &&
+	test_cmp filtered_types expected
+'
+
+
 # Delete some loose objects and use rev-list, but WITHOUT any filtering.
 # This models previously omitted objects that we did not receive.
 
-- 
2.18.0.597.ga71716f1ad-goog
Previous: Matthew DeVoreNext: Jeff Hostetler
Message 19 of 151 in “filter: support for excluding all trees and blobs”
  1. 0/5 filter: support for excluding all trees and blobsMatthew DeVore, Aug 9, 2018
  2. 1/5 revision: invert meaning of the USER_GIVEN flagMatthew DeVore, Aug 9, 2018
  3. Jonathan TanAug 10, 2018
  4. 2/5 list-objects-filter: implement filter only:commitsMatthew DeVore, Aug 9, 2018
  5. Jonathan TanAug 10, 2018
  6. 3/5 list-objects: store common func args in structMatthew DeVore, Aug 9, 2018
  7. 4/5 list-objects: refactor to process_tree_contentsMatthew DeVore, Aug 9, 2018
  8. 5/5 rev-list: handle missing tree objects properlyMatthew DeVore, Aug 9, 2018
  9. Jonathan TanAug 10, 2018
  10. Jonathan TanAug 10, 2018
  11. 0/5 filter: support for excluding all trees and blobsMatthew DeVore, Aug 10, 2018
  12. 1/5 list-objects: store common func args in structMatthew DeVore, Aug 10, 2018
  13. 2/5 list-objects: refactor to process_tree_contentsMatthew DeVore, Aug 10, 2018
  14. 3/5 rev-list: handle missing tree objects properlyMatthew DeVore, Aug 10, 2018
  15. Jonathan TanAug 13, 2018
  16. Matthew DeVoreAug 14, 2018
  17. Jonathan TanAug 14, 2018
  18. 4/5 revision: mark non-user-given objects insteadMatthew DeVore, Aug 10, 2018
  19. 5/5 list-objects-filter: implement filter tree:noneMatthew DeVore, Aug 10, 2018
  20. Jeff HostetlerAug 13, 2018
  21. Matthew DeVoreAug 14, 2018
  22. Jonathan TanAug 13, 2018
  23. Matthew DeVoreAug 14, 2018
  24. 0/5 filter: support for excluding all trees and blobsMatthew DeVore, Aug 13, 2018
  25. 1/5 list-objects: store common func args in structMatthew DeVore, Aug 13, 2018
  26. 2/5 list-objects: refactor to process_tree_contentsMatthew DeVore, Aug 13, 2018
  27. 3/5 rev-list: handle missing tree objects properlyMatthew DeVore, Aug 13, 2018
  28. 4/5 revision: mark non-user-given objects insteadMatthew DeVore, Aug 13, 2018
  29. 5/5 list-objects-filter: implement filter tree:0Matthew DeVore, Aug 13, 2018
  30. Jeff HostetlerAug 14, 2018
  31. Matthew DeVoreAug 14, 2018
  32. Matthew DeVoreOct 3, 2018
  33. 0/6 filter: support for excluding all trees and blobsMatthew DeVore, Aug 14, 2018
  34. 1/6 list-objects: store common func args in structMatthew DeVore, Aug 14, 2018
  35. 2/6 list-objects: refactor to process_tree_contentsMatthew DeVore, Aug 14, 2018
  36. 4/6 rev-list: handle missing tree objects properlyMatthew DeVore, Aug 14, 2018
  37. Jonathan TanAug 14, 2018
  38. Matthew DeVoreAug 14, 2018
  39. Jonathan TanAug 14, 2018
  40. Jonathan TanAug 14, 2018
  41. 3/6 list-objects: always parse trees gentlyMatthew DeVore, Aug 14, 2018
  42. 5/6 revision: mark non-user-given objects insteadMatthew DeVore, Aug 14, 2018
  43. 6/6 list-objects-filter: implement filter tree:0Matthew DeVore, Aug 14, 2018
  44. Jonathan TanAug 14, 2018
  45. Matthew DeVoreAug 14, 2018
  46. Jonathan TanAug 14, 2018
  47. Junio C HamanoAug 14, 2018
  48. Matthew DeVoreAug 14, 2018
  49. Junio C HamanoAug 15, 2018
  50. Matthew DeVoreAug 15, 2018
  51. Jeff KingAug 14, 2018
  52. Matthew DeVoreAug 14, 2018
  53. Jeff KingAug 15, 2018
  54. Junio C HamanoAug 15, 2018
  55. Matthew DeVoreAug 15, 2018
  56. 0/6 filter: support for excluding all trees and blobsMatthew DeVore, Aug 15, 2018
  57. 1/6 list-objects: store common func args in structMatthew DeVore, Aug 15, 2018
  58. 2/6 list-objects: refactor to process_tree_contentsMatthew DeVore, Aug 15, 2018
  59. 3/6 list-objects: always parse trees gentlyMatthew DeVore, Aug 15, 2018
  60. 4/6 rev-list: handle missing tree objects properlyMatthew DeVore, Aug 15, 2018
  61. 5/6 revision: mark non-user-given objects insteadMatthew DeVore, Aug 15, 2018
  62. 6/6 list-objects-filter: implement filter tree:0Matthew DeVore, Aug 15, 2018
  63. 0/6 filter: support for excluding all trees and blobsMatthew DeVore, Aug 15, 2018
  64. 1/6 list-objects: store common func args in structMatthew DeVore, Aug 15, 2018
  65. 3/6 list-objects: always parse trees gentlyMatthew DeVore, Aug 15, 2018
  66. 2/6 list-objects: refactor to process_tree_contentsMatthew DeVore, Aug 15, 2018
  67. 4/6 rev-list: handle missing tree objects properlyMatthew DeVore, Aug 15, 2018
  68. 5/6 revision: mark non-user-given objects insteadMatthew DeVore, Aug 15, 2018
  69. 6/6 list-objects-filter: implement filter tree:0Matthew DeVore, Aug 15, 2018
  70. Stefan BellerAug 17, 2018
  71. Matthew DeVoreAug 17, 2018
  72. Stefan BellerAug 17, 2018
  73. Matthew DeVoreAug 20, 2018
  74. Stefan BellerAug 21, 2018
  75. Junio C HamanoAug 21, 2018
  76. Stefan BellerAug 22, 2018
  77. Duy NguyenAug 18, 2018
  78. Matthew DeVoreAug 20, 2018
  79. Stefan BellerAug 20, 2018
  80. Matthew DeVoreAug 20, 2018
  81. Stefan BellerAug 21, 2018
  82. Duy NguyenAug 21, 2018
  83. 0/7 filter: support for excluding all trees and blobsMatthew DeVore, Sep 4, 2018
  84. 1/7 list-objects: store common func args in structMatthew DeVore, Sep 4, 2018
  85. 2/7 list-objects: refactor to process_tree_contentsMatthew DeVore, Sep 4, 2018
  86. 3/7 list-objects: always parse trees gentlyMatthew DeVore, Sep 4, 2018
  87. 4/7 rev-list: handle missing tree objects properlyMatthew DeVore, Sep 4, 2018
  88. 5/7 revision: mark non-user-given objects insteadMatthew DeVore, Sep 4, 2018
  89. Junio C HamanoSep 4, 2018
  90. Matthew DeVoreSep 5, 2018
  91. 7/7 list-objects-filter: implement filter tree:0Matthew DeVore, Sep 4, 2018
  92. Junio C HamanoSep 4, 2018
  93. Matthew DeVoreSep 6, 2018
  94. 6/7 list-objects-filter: use BUG rather than dieMatthew DeVore, Sep 4, 2018
  95. Junio C HamanoSep 4, 2018
  96. Stefan BellerSep 4, 2018
  97. 0/7 filter: support for excluding all trees and blobsMatthew DeVore, Sep 14, 2018
  98. 1/7 list-objects: store common func args in structMatthew DeVore, Sep 14, 2018
  99. 2/7 list-objects: refactor to process_tree_contentsMatthew DeVore, Sep 14, 2018
  100. 3/7 list-objects: always parse trees gentlyMatthew DeVore, Sep 14, 2018
  101. 4/7 rev-list: handle missing tree objects properlyMatthew DeVore, Sep 14, 2018
  102. 5/7 revision: mark non-user-given objects insteadMatthew DeVore, Sep 14, 2018
  103. Junio C HamanoSep 14, 2018
  104. Matthew DeVoreSep 14, 2018
  105. 6/7 list-objects-filter: use BUG rather than dieMatthew DeVore, Sep 14, 2018
  106. 7/7 list-objects-filter: implement filter tree:0Matthew DeVore, Sep 14, 2018
  107. Junio C HamanoSep 14, 2018
  108. Junio C HamanoSep 14, 2018
  109. Matthew DeVoreSep 15, 2018
  110. 0/8 filter: support for excluding all trees and blobsMatthew DeVore, Sep 21, 2018
  111. 1/8 list-objects: store common func args in structMatthew DeVore, Sep 21, 2018
  112. 2/8 list-objects: refactor to process_tree_contentsMatthew DeVore, Sep 21, 2018
  113. 3/8 list-objects: always parse trees gentlyMatthew DeVore, Sep 21, 2018
  114. 4/8 rev-list: handle missing tree objects properlyMatthew DeVore, Sep 21, 2018
  115. 5/8 revision: mark non-user-given objects insteadMatthew DeVore, Sep 21, 2018
  116. 6/8 list-objects-filter: use BUG rather than dieMatthew DeVore, Sep 21, 2018
  117. 7/8 list-objects-filter-options: do not over-strbuf_initMatthew DeVore, Sep 21, 2018
  118. 8/8 list-objects-filter: implement filter tree:0Matthew DeVore, Sep 21, 2018
  119. 0/8 filter: support for excluding all trees and blobsMatthew DeVore, Oct 3, 2018
  120. 1/8 list-objects: store common func args in structMatthew DeVore, Oct 3, 2018
  121. 2/8 list-objects: refactor to process_tree_contentsMatthew DeVore, Oct 3, 2018
  122. 3/8 list-objects: always parse trees gentlyMatthew DeVore, Oct 3, 2018
  123. 4/8 rev-list: handle missing tree objects properlyMatthew DeVore, Oct 3, 2018
  124. 5/8 revision: mark non-user-given objects insteadMatthew DeVore, Oct 3, 2018
  125. 6/8 list-objects-filter: use BUG rather than dieMatthew DeVore, Oct 3, 2018
  126. 7/8 list-objects-filter-options: do not over-strbuf_initMatthew DeVore, Oct 3, 2018
  127. 8/8 list-objects-filter: implement filter tree:0Matthew DeVore, Oct 3, 2018
  128. Matthew DeVoreOct 3, 2018
  129. 0/8 filter: support for excluding all trees and blobsMatthew DeVore, Oct 5, 2018
  130. 1/8 list-objects: store common func args in structMatthew DeVore, Oct 5, 2018
  131. 2/8 list-objects: refactor to process_tree_contentsMatthew DeVore, Oct 5, 2018
  132. 3/8 list-objects: always parse trees gentlyMatthew DeVore, Oct 5, 2018
  133. 4/8 rev-list: handle missing tree objects properlyMatthew DeVore, Oct 5, 2018
  134. 5/8 revision: mark non-user-given objects insteadMatthew DeVore, Oct 5, 2018
  135. 6/8 list-objects-filter: use BUG rather than dieMatthew DeVore, Oct 5, 2018
  136. 7/8 list-objects-filter-options: do not over-strbuf_initMatthew DeVore, Oct 5, 2018
  137. 8/8 list-objects-filter: implement filter tree:0Matthew DeVore, Oct 5, 2018
  138. Junio C HamanoOct 7, 2018
  139. Matthew DeVoreOct 8, 2018
  140. 0/8 filter: support for excluding all trees and blobsMatthew DeVore, Oct 12, 2018
  141. 1/8 list-objects: store common func args in structMatthew DeVore, Oct 12, 2018
  142. 2/8 list-objects: refactor to process_tree_contentsMatthew DeVore, Oct 12, 2018
  143. 3/8 list-objects: always parse trees gentlyMatthew DeVore, Oct 12, 2018
  144. 4/8 rev-list: handle missing tree objects properlyMatthew DeVore, Oct 12, 2018
  145. 5/8 revision: mark non-user-given objects insteadMatthew DeVore, Oct 12, 2018
  146. 6/8 list-objects-filter: use BUG rather than dieMatthew DeVore, Oct 12, 2018
  147. 7/8 list-objects-filter-options: do not over-strbuf_initMatthew DeVore, Oct 12, 2018
  148. 8/8 list-objects-filter: implement filter tree:0Matthew DeVore, Oct 12, 2018
  149. Junio C HamanoOct 15, 2018
  150. Junio C HamanoOct 15, 2018
  151. Matthew DeVoreOct 16, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.