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>
This commit is contained in:
Patrick Steinhardt 2021-04-19 13:47:06 +02:00 committed by Junio C Hamano
parent 169a15ebd6
commit 9cf68b27d5
8 changed files with 104 additions and 14 deletions

View File

@ -933,6 +933,11 @@ equivalent.
--no-filter::
Turn off any previous `--filter=` argument.
--filter-provided-objects::
Filter the list of explicitly provided objects, which would otherwise
always be printed even if they did not match any of the filters. Only
useful with `--filter=`.
--filter-print-omitted::
Only useful with `--filter=`; prints a list of the objects omitted
by the filter. Object IDs are prefixed with a ``~'' character.

View File

@ -3516,7 +3516,7 @@ static int pack_options_allow_reuse(void)
static int get_object_list_from_bitmap(struct rev_info *revs)
{
if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options)))
if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options, 0)))
return -1;
if (pack_options_allow_reuse() &&

View File

@ -398,7 +398,8 @@ static inline int parse_missing_action_value(const char *value)
}
static int try_bitmap_count(struct rev_info *revs,
struct list_objects_filter_options *filter)
struct list_objects_filter_options *filter,
int filter_provided_objects)
{
uint32_t commit_count = 0,
tag_count = 0,
@ -433,7 +434,7 @@ static int try_bitmap_count(struct rev_info *revs,
*/
max_count = revs->max_count;
bitmap_git = prepare_bitmap_walk(revs, filter);
bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
if (!bitmap_git)
return -1;
@ -450,7 +451,8 @@ static int try_bitmap_count(struct rev_info *revs,
}
static int try_bitmap_traversal(struct rev_info *revs,
struct list_objects_filter_options *filter)
struct list_objects_filter_options *filter,
int filter_provided_objects)
{
struct bitmap_index *bitmap_git;
@ -461,7 +463,7 @@ static int try_bitmap_traversal(struct rev_info *revs,
if (revs->max_count >= 0)
return -1;
bitmap_git = prepare_bitmap_walk(revs, filter);
bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
if (!bitmap_git)
return -1;
@ -471,14 +473,15 @@ static int try_bitmap_traversal(struct rev_info *revs,
}
static int try_bitmap_disk_usage(struct rev_info *revs,
struct list_objects_filter_options *filter)
struct list_objects_filter_options *filter,
int filter_provided_objects)
{
struct bitmap_index *bitmap_git;
if (!show_disk_usage)
return -1;
bitmap_git = prepare_bitmap_walk(revs, filter);
bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
if (!bitmap_git)
return -1;
@ -499,6 +502,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
int bisect_show_vars = 0;
int bisect_find_all = 0;
int use_bitmap_index = 0;
int filter_provided_objects = 0;
const char *show_progress = NULL;
if (argc == 2 && !strcmp(argv[1], "-h"))
@ -599,6 +603,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
list_objects_filter_set_no_filter(&filter_options);
continue;
}
if (!strcmp(arg, "--filter-provided-objects")) {
filter_provided_objects = 1;
continue;
}
if (!strcmp(arg, "--filter-print-omitted")) {
arg_print_omitted = 1;
continue;
@ -665,11 +673,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
progress = start_delayed_progress(show_progress, 0);
if (use_bitmap_index) {
if (!try_bitmap_count(&revs, &filter_options))
if (!try_bitmap_count(&revs, &filter_options, filter_provided_objects))
return 0;
if (!try_bitmap_disk_usage(&revs, &filter_options))
if (!try_bitmap_disk_usage(&revs, &filter_options, filter_provided_objects))
return 0;
if (!try_bitmap_traversal(&revs, &filter_options))
if (!try_bitmap_traversal(&revs, &filter_options, filter_provided_objects))
return 0;
}
@ -694,6 +702,16 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
return show_bisect_vars(&info, reaches, all);
}
if (filter_provided_objects) {
struct commit_list *c;
for (i = 0; i < revs.pending.nr; i++) {
struct object_array_entry *pending = revs.pending.objects + i;
pending->item->flags |= NOT_USER_GIVEN;
}
for (c = revs.commits; c; c = c->next)
c->item->object.flags |= NOT_USER_GIVEN;
}
if (arg_print_omitted)
oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
if (arg_missing_action == MA_PRINT)

View File

@ -986,7 +986,8 @@ static int can_filter_bitmap(struct list_objects_filter_options *filter)
}
struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
struct list_objects_filter_options *filter)
struct list_objects_filter_options *filter,
int filter_provided_objects)
{
unsigned int i;
@ -1081,7 +1082,8 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
if (haves_bitmap)
bitmap_and_not(wants_bitmap, haves_bitmap);
filter_bitmap(bitmap_git, wants, wants_bitmap, filter);
filter_bitmap(bitmap_git, (filter && filter_provided_objects) ? NULL : wants,
wants_bitmap, filter);
bitmap_git->result = wants_bitmap;
bitmap_git->haves = haves_bitmap;

View File

@ -50,7 +50,8 @@ void traverse_bitmap_commit_list(struct bitmap_index *,
show_reachable_fn show_reachable);
void test_bitmap_walk(struct rev_info *revs);
struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
struct list_objects_filter_options *filter);
struct list_objects_filter_options *filter,
int filter_provided_objects);
int reuse_partial_packfile_from_bitmap(struct bitmap_index *,
struct packed_git **packfile,
uint32_t *entries,

View File

@ -223,7 +223,7 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
cp.progress = progress;
cp.count = 0;
bitmap_git = prepare_bitmap_walk(revs, NULL);
bitmap_git = prepare_bitmap_walk(revs, NULL, 0);
if (bitmap_git) {
traverse_bitmap_commit_list(bitmap_git, revs, mark_object_seen);
free_bitmap_index(bitmap_git);

View File

@ -203,6 +203,34 @@ test_expect_success 'verify object:type=tag prints tag' '
test_cmp expected actual
'
test_expect_success 'verify object:type=blob prints only blob with --filter-provided-objects' '
printf "%s blob\n" $(git -C object-type rev-parse HEAD:blob) >expected &&
git -C object-type rev-list --objects \
--filter=object:type=blob --filter-provided-objects HEAD >actual &&
test_cmp expected actual
'
test_expect_success 'verify object:type=tree prints only tree with --filter-provided-objects' '
printf "%s \n" $(git -C object-type rev-parse HEAD^{tree}) >expected &&
git -C object-type rev-list --objects \
--filter=object:type=tree HEAD --filter-provided-objects >actual &&
test_cmp expected actual
'
test_expect_success 'verify object:type=commit prints only commit with --filter-provided-objects' '
git -C object-type rev-parse HEAD >expected &&
git -C object-type rev-list --objects \
--filter=object:type=commit --filter-provided-objects HEAD >actual &&
test_cmp expected actual
'
test_expect_success 'verify object:type=tag prints only tag with --filter-provided-objects' '
printf "%s tag\n" $(git -C object-type rev-parse tag) >expected &&
git -C object-type rev-list --objects \
--filter=object:type=tag --filter-provided-objects tag >actual &&
test_cmp expected actual
'
# Test sparse:path=<path> filter.
# !!!!
# NOTE: sparse:path filter support has been dropped for security reasons,

View File

@ -98,6 +98,28 @@ test_expect_success 'object:type filter' '
test_bitmap_traversal expect actual
'
test_expect_success 'object:type filter with --filter-provided-objects' '
git rev-list --objects --filter-provided-objects --filter=object:type=tag tag >expect &&
git rev-list --use-bitmap-index \
--objects --filter-provided-objects --filter=object:type=tag tag >actual &&
test_cmp expect actual &&
git rev-list --objects --filter-provided-objects --filter=object:type=commit tag >expect &&
git rev-list --use-bitmap-index \
--objects --filter-provided-objects --filter=object:type=commit tag >actual &&
test_bitmap_traversal expect actual &&
git rev-list --objects --filter-provided-objects --filter=object:type=tree tag >expect &&
git rev-list --use-bitmap-index \
--objects --filter-provided-objects --filter=object:type=tree tag >actual &&
test_bitmap_traversal expect actual &&
git rev-list --objects --filter-provided-objects --filter=object:type=blob tag >expect &&
git rev-list --use-bitmap-index \
--objects --filter-provided-objects --filter=object:type=blob tag >actual &&
test_bitmap_traversal expect actual
'
test_expect_success 'combine filter' '
git rev-list --objects --filter=blob:limit=1000 --filter=object:type=blob tag >expect &&
git rev-list --use-bitmap-index \
@ -105,4 +127,18 @@ test_expect_success 'combine filter' '
test_bitmap_traversal expect actual
'
test_expect_success 'combine filter with --filter-provided-objects' '
git rev-list --objects --filter-provided-objects --filter=blob:limit=1000 --filter=object:type=blob tag >expect &&
git rev-list --use-bitmap-index \
--objects --filter-provided-objects --filter=blob:limit=1000 --filter=object:type=blob tag >actual &&
test_bitmap_traversal expect actual &&
git cat-file --batch-check="%(objecttype) %(objectsize)" <actual >objects &&
while read objecttype objectsize
do
test "$objecttype" = blob || return 1
test "$objectsize" -le 1000 || return 1
done <objects
'
test_done