rev-list: allow filtering of provided items

When providing an object filter, it is currently impossible to also filter provided items. E.g. when executing `git rev-list HEAD` , the commit this reference points to will be treated as user-provided and is thus excluded from the filtering mechanism. This makes it harder than necessary to properly use the new `--filter=object:type` filter given that even if the user wants to only see blobs, he'll still see commits of provided references. Improve this by introducing a new `--filter-provided-objects` option to the git-rev-parse(1) command. If given, then all user-provided references will be subject to filtering. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Apr 19, 2021 at 13:47 UTC 9cf68b27d50c29a0370bd61581d350b0b0a18e85
8 files changed +104 -14
Documentation/rev-list-options.txt
+5
@@ -933,6 +933,11 @@ equivalent.
933 --no-filter::
934 Turn off any previous `--filter=` argument.
935
936 +--filter-provided-objects::
937 + Filter the list of explicitly provided objects, which would otherwise
938 + always be printed even if they did not match any of the filters. Only
939 + useful with `--filter=`.
940 +
941 --filter-print-omitted::
942 Only useful with `--filter=`; prints a list of the objects omitted
943 by the filter. Object IDs are prefixed with a ``~'' character.
builtin/pack-objects.c
+1 -1
@@ -3516,7 +3516,7 @@ static int pack_options_allow_reuse(void)
3516
3517 static int get_object_list_from_bitmap(struct rev_info *revs)
3518 {
3519 - if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options)))
3519 + if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options, 0)))
3520 return -1;
3521
3522 if (pack_options_allow_reuse() &&
builtin/rev-list.c
+27 -9
@@ -398,7 +398,8 @@ static inline int parse_missing_action_value(const char *value)
398 }
399
400 static int try_bitmap_count(struct rev_info *revs,
401 - struct list_objects_filter_options *filter)
401 + struct list_objects_filter_options *filter,
402 + int filter_provided_objects)
403 {
404 uint32_t commit_count = 0,
405 tag_count = 0,
@@ -433,7 +434,7 @@ static int try_bitmap_count(struct rev_info *revs,
434 */
435 max_count = revs->max_count;
436
436 - bitmap_git = prepare_bitmap_walk(revs, filter);
437 + bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
438 if (!bitmap_git)
439 return -1;
440
@@ -450,7 +451,8 @@ static int try_bitmap_count(struct rev_info *revs,
451 }
452
453 static int try_bitmap_traversal(struct rev_info *revs,
453 - struct list_objects_filter_options *filter)
454 + struct list_objects_filter_options *filter,
455 + int filter_provided_objects)
456 {
457 struct bitmap_index *bitmap_git;
458
@@ -461,7 +463,7 @@ static int try_bitmap_traversal(struct rev_info *revs,
463 if (revs->max_count >= 0)
464 return -1;
465
464 - bitmap_git = prepare_bitmap_walk(revs, filter);
466 + bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
467 if (!bitmap_git)
468 return -1;
469
@@ -471,14 +473,15 @@ static int try_bitmap_traversal(struct rev_info *revs,
473 }
474
475 static int try_bitmap_disk_usage(struct rev_info *revs,
474 - struct list_objects_filter_options *filter)
476 + struct list_objects_filter_options *filter,
477 + int filter_provided_objects)
478 {
479 struct bitmap_index *bitmap_git;
480
481 if (!show_disk_usage)
482 return -1;
483
481 - bitmap_git = prepare_bitmap_walk(revs, filter);
484 + bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
485 if (!bitmap_git)
486 return -1;
487
@@ -499,6 +502,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
502 int bisect_show_vars = 0;
503 int bisect_find_all = 0;
504 int use_bitmap_index = 0;
505 + int filter_provided_objects = 0;
506 const char *show_progress = NULL;
507
508 if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -599,6 +603,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
603 list_objects_filter_set_no_filter(&filter_options);
604 continue;
605 }
606 + if (!strcmp(arg, "--filter-provided-objects")) {
607 + filter_provided_objects = 1;
608 + continue;
609 + }
610 if (!strcmp(arg, "--filter-print-omitted")) {
611 arg_print_omitted = 1;
612 continue;
@@ -665,11 +673,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
673 progress = start_delayed_progress(show_progress, 0);
674
675 if (use_bitmap_index) {
668 - if (!try_bitmap_count(&revs, &filter_options))
676 + if (!try_bitmap_count(&revs, &filter_options, filter_provided_objects))
677 return 0;
670 - if (!try_bitmap_disk_usage(&revs, &filter_options))
678 + if (!try_bitmap_disk_usage(&revs, &filter_options, filter_provided_objects))
679 return 0;
672 - if (!try_bitmap_traversal(&revs, &filter_options))
680 + if (!try_bitmap_traversal(&revs, &filter_options, filter_provided_objects))
681 return 0;
682 }
683
@@ -694,6 +702,16 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
702 return show_bisect_vars(&info, reaches, all);
703 }
704
705 + if (filter_provided_objects) {
706 + struct commit_list *c;
707 + for (i = 0; i < revs.pending.nr; i++) {
708 + struct object_array_entry *pending = revs.pending.objects + i;
709 + pending->item->flags |= NOT_USER_GIVEN;
710 + }
711 + for (c = revs.commits; c; c = c->next)
712 + c->item->object.flags |= NOT_USER_GIVEN;
713 + }
714 +
715 if (arg_print_omitted)
716 oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
717 if (arg_missing_action == MA_PRINT)
pack-bitmap.c
+4 -2
@@ -986,7 +986,8 @@ static int can_filter_bitmap(struct list_objects_filter_options *filter)
986 }
987
988 struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
989 - struct list_objects_filter_options *filter)
989 + struct list_objects_filter_options *filter,
990 + int filter_provided_objects)
991 {
992 unsigned int i;
993
@@ -1081,7 +1082,8 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
1082 if (haves_bitmap)
1083 bitmap_and_not(wants_bitmap, haves_bitmap);
1084
1084 - filter_bitmap(bitmap_git, wants, wants_bitmap, filter);
1085 + filter_bitmap(bitmap_git, (filter && filter_provided_objects) ? NULL : wants,
1086 + wants_bitmap, filter);
1087
1088 bitmap_git->result = wants_bitmap;
1089 bitmap_git->haves = haves_bitmap;
pack-bitmap.h
+2 -1
@@ -50,7 +50,8 @@ void traverse_bitmap_commit_list(struct bitmap_index *,
50 show_reachable_fn show_reachable);
51 void test_bitmap_walk(struct rev_info *revs);
52 struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
53 - struct list_objects_filter_options *filter);
53 + struct list_objects_filter_options *filter,
54 + int filter_provided_objects);
55 int reuse_partial_packfile_from_bitmap(struct bitmap_index *,
56 struct packed_git **packfile,
57 uint32_t *entries,
reachable.c
+1 -1
@@ -223,7 +223,7 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
223 cp.progress = progress;
224 cp.count = 0;
225
226 - bitmap_git = prepare_bitmap_walk(revs, NULL);
226 + bitmap_git = prepare_bitmap_walk(revs, NULL, 0);
227 if (bitmap_git) {
228 traverse_bitmap_commit_list(bitmap_git, revs, mark_object_seen);
229 free_bitmap_index(bitmap_git);
t/t6112-rev-list-filters-objects.sh
+28
@@ -203,6 +203,34 @@ test_expect_success 'verify object:type=tag prints tag' '
203 test_cmp expected actual
204 '
205
206 +test_expect_success 'verify object:type=blob prints only blob with --filter-provided-objects' '
207 + printf "%s blob\n" $(git -C object-type rev-parse HEAD:blob) >expected &&
208 + git -C object-type rev-list --objects \
209 + --filter=object:type=blob --filter-provided-objects HEAD >actual &&
210 + test_cmp expected actual
211 +'
212 +
213 +test_expect_success 'verify object:type=tree prints only tree with --filter-provided-objects' '
214 + printf "%s \n" $(git -C object-type rev-parse HEAD^{tree}) >expected &&
215 + git -C object-type rev-list --objects \
216 + --filter=object:type=tree HEAD --filter-provided-objects >actual &&
217 + test_cmp expected actual
218 +'
219 +
220 +test_expect_success 'verify object:type=commit prints only commit with --filter-provided-objects' '
221 + git -C object-type rev-parse HEAD >expected &&
222 + git -C object-type rev-list --objects \
223 + --filter=object:type=commit --filter-provided-objects HEAD >actual &&
224 + test_cmp expected actual
225 +'
226 +
227 +test_expect_success 'verify object:type=tag prints only tag with --filter-provided-objects' '
228 + printf "%s tag\n" $(git -C object-type rev-parse tag) >expected &&
229 + git -C object-type rev-list --objects \
230 + --filter=object:type=tag --filter-provided-objects tag >actual &&
231 + test_cmp expected actual
232 +'
233 +
234 # Test sparse:path=<path> filter.
235 # !!!!
236 # NOTE: sparse:path filter support has been dropped for security reasons,
t/t6113-rev-list-bitmap-filters.sh
+36
@@ -98,6 +98,28 @@ test_expect_success 'object:type filter' '
98 test_bitmap_traversal expect actual
99 '
100
101 +test_expect_success 'object:type filter with --filter-provided-objects' '
102 + git rev-list --objects --filter-provided-objects --filter=object:type=tag tag >expect &&
103 + git rev-list --use-bitmap-index \
104 + --objects --filter-provided-objects --filter=object:type=tag tag >actual &&
105 + test_cmp expect actual &&
106 +
107 + git rev-list --objects --filter-provided-objects --filter=object:type=commit tag >expect &&
108 + git rev-list --use-bitmap-index \
109 + --objects --filter-provided-objects --filter=object:type=commit tag >actual &&
110 + test_bitmap_traversal expect actual &&
111 +
112 + git rev-list --objects --filter-provided-objects --filter=object:type=tree tag >expect &&
113 + git rev-list --use-bitmap-index \
114 + --objects --filter-provided-objects --filter=object:type=tree tag >actual &&
115 + test_bitmap_traversal expect actual &&
116 +
117 + git rev-list --objects --filter-provided-objects --filter=object:type=blob tag >expect &&
118 + git rev-list --use-bitmap-index \
119 + --objects --filter-provided-objects --filter=object:type=blob tag >actual &&
120 + test_bitmap_traversal expect actual
121 +'
122 +
123 test_expect_success 'combine filter' '
124 git rev-list --objects --filter=blob:limit=1000 --filter=object:type=blob tag >expect &&
125 git rev-list --use-bitmap-index \
@@ -105,4 +127,18 @@ test_expect_success 'combine filter' '
127 test_bitmap_traversal expect actual
128 '
129
130 +test_expect_success 'combine filter with --filter-provided-objects' '
131 + git rev-list --objects --filter-provided-objects --filter=blob:limit=1000 --filter=object:type=blob tag >expect &&
132 + git rev-list --use-bitmap-index \
133 + --objects --filter-provided-objects --filter=blob:limit=1000 --filter=object:type=blob tag >actual &&
134 + test_bitmap_traversal expect actual &&
135 +
136 + git cat-file --batch-check="%(objecttype) %(objectsize)" <actual >objects &&
137 + while read objecttype objectsize
138 + do
139 + test "$objecttype" = blob || return 1
140 + test "$objectsize" -le 1000 || return 1
141 + done <objects
142 +'
143 +
144 test_done