Skip to content

Commit 16bd3c3

Browse files
ttaylorrderrickstolee
authored andcommitted
path-walk: support combine filter
The `combine` filter takes the intersection of its children, that is: objects are shown only when all child filters would admit the object. The preceding patches added support for many individual filter types. Enable users to compose these filters by implementing support for the `combine` filter type. Mapping intersection onto path_walk_info works because every supported child filter is a monotonic restriction: - `blob:none`, `tree:0` unconditionally clear `info->blobs` and (for `tree:0`) `info->trees`; clearing an already-cleared flag is a no-op. - `object:type=X` is now expressed as an AND of each type flag with the filtered type, so applying multiple such filters only refines the existing set rather than overwrites it. - `blob:limit=N` has to compose too: the intersection of "size < L1" and "size < L2" is "size < min(L1, L2)". Update the `LOFC_BLOB_LIMIT` handler to take the running minimum when `info->blob_limit` is already set, so a combined filter with, e.g., both "blob:limit=10" and "blob:limit=5" produces a limit of 5 regardless of ordering. - `sparse:oid` is left unchanged. A `combine` filter that includes a `sparse:oid` is allowed at most once, since the existing handler refuses to overwrite `info->pl`. Two `sparse:oid` filters in a single `combine` would be unusual and are rejected with a warning, matching the standalone `sparse:oid` behavior. Implementation-wise, the existing `prepare_filters()` called `list_objects_filter_release()` inside each case branch. That works fine for top-level filters, but `combine` filters need to recurse over its child filters without releasing each one in turn (since the parent's release iterates the sub array). Split `prepare_filters()` into a recursive helper that performs only the mutation, plus a thin wrapper that calls the helper and then releases the top-level filter once. The `LOFC_COMBINE` case in the helper just walks `sub_nr` and recurses; child filters are released by the wrapper's single `list_objects_filter_release()` call on the parent (which itself recursively releases each sub-filter, the same way it always has). If any sub-filter is unsupported (e.g. "tree:1", "sparse:<path>", or a not-yet-supported choice), the recursion bubbles a failure up and the existing pack-objects/backfill fallback paths kick in. Add coverage in t6601: - "combine:blob:none+tree:0" collapses to "tree:0" - "combine:object:type=blob+blob:limit=3" yields only the blobs smaller than three bytes - "combine:object:type=blob+object:type=tree" intersects to empty - "combine:tree:1+blob:none" reports the "tree:1" error. Update Documentation/git-pack-objects.adoc to add combine to the list of supported --filter forms. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Derrick Stolee <stolee@gmail.com>
1 parent b221ea4 commit 16bd3c3

3 files changed

Lines changed: 93 additions & 6 deletions

File tree

Documentation/git-pack-objects.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,8 @@ will be automatically changed to version `1`.
405405
Incompatible with `--delta-islands`. The `--use-bitmap-index` option is
406406
ignored in the presence of `--path-walk`. Whe `--path-walk` option
407407
supports the `--filter=<spec>` forms `blob:none`, `blob:limit=<n>`,
408-
`tree:0`, `object:type=<type>`, and `sparse:<oid>`.
408+
`tree:0`, `object:type=<type>`, and `sparse:<oid>`. These supported filter
409+
types can be combined with the `combine:<spec>+<spec>` form.
409410
410411
411412
DELTA ISLANDS

path-walk.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -573,8 +573,8 @@ static int setup_pending_objects(struct path_walk_info *info,
573573
return 0;
574574
}
575575

576-
static int prepare_filters(struct path_walk_info *info,
577-
struct list_objects_filter_options *options)
576+
static int prepare_filters_one(struct path_walk_info *info,
577+
struct list_objects_filter_options *options)
578578
{
579579
switch (options->choice) {
580580
case LOFC_DISABLED:
@@ -591,7 +591,8 @@ static int prepare_filters(struct path_walk_info *info,
591591
if (info) {
592592
if (!options->blob_limit_value)
593593
info->blobs = 0;
594-
else
594+
else if (!info->blob_limit ||
595+
info->blob_limit > options->blob_limit_value)
595596
info->blob_limit = options->blob_limit_value;
596597
list_objects_filter_release(options);
597598
}
@@ -606,7 +607,6 @@ static int prepare_filters(struct path_walk_info *info,
606607
if (info) {
607608
info->trees = 0;
608609
info->blobs = 0;
609-
list_objects_filter_release(options);
610610
}
611611
return 1;
612612

@@ -658,8 +658,13 @@ static int prepare_filters(struct path_walk_info *info,
658658
warning(_("sparse filter is not cone-mode compatible"));
659659
return 0;
660660
}
661+
}
662+
return 1;
661663

662-
list_objects_filter_release(options);
664+
case LOFC_COMBINE:
665+
for (size_t i = 0; i < options->sub_nr; i++) {
666+
if (!prepare_filters_one(info, &options->sub[i]))
667+
return 0;
663668
}
664669
return 1;
665670

@@ -670,6 +675,16 @@ static int prepare_filters(struct path_walk_info *info,
670675
}
671676
}
672677

678+
static int prepare_filters(struct path_walk_info *info,
679+
struct list_objects_filter_options *options)
680+
{
681+
if (!prepare_filters_one(info, options))
682+
return 0;
683+
if (info)
684+
list_objects_filter_release(options);
685+
return 1;
686+
}
687+
673688
int path_walk_filter_compatible(struct list_objects_filter_options *options)
674689
{
675690
return prepare_filters(NULL, options);

t/t6601-path-walk.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,77 @@ test_expect_success 'all, object:type=blob filter' '
729729
test_cmp_sorted expect out
730730
'
731731

732+
test_expect_success 'all, combine:blob:none+tree:0 filter' '
733+
test-tool path-walk \
734+
--filter=combine:blob:none+tree:0 -- --all >out &&
735+
736+
cat >expect <<-EOF &&
737+
0:commit::$(git rev-parse topic)
738+
0:commit::$(git rev-parse base)
739+
0:commit::$(git rev-parse base~1)
740+
0:commit::$(git rev-parse base~2)
741+
1:tag:/tags:$(git rev-parse refs/tags/first)
742+
1:tag:/tags:$(git rev-parse refs/tags/second.1)
743+
1:tag:/tags:$(git rev-parse refs/tags/second.2)
744+
1:tag:/tags:$(git rev-parse refs/tags/third)
745+
1:tag:/tags:$(git rev-parse refs/tags/fourth)
746+
1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
747+
1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
748+
2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
749+
2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
750+
3:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{tree})
751+
3:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2)
752+
blobs:2
753+
commits:4
754+
tags:7
755+
trees:2
756+
EOF
757+
758+
test_cmp_sorted expect out
759+
'
760+
761+
test_expect_success 'all, combine:object:type=blob+blob:limit=3 filter' '
762+
test-tool path-walk \
763+
--filter=combine:object:type=blob+blob:limit=3 \
764+
-- --all >out &&
765+
766+
cat >expect <<-EOF &&
767+
0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
768+
0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
769+
1:blob:a:$(git rev-parse base~2:a)
770+
2:blob:left/b:$(git rev-parse base~2:left/b)
771+
3:blob:right/c:$(git rev-parse base~2:right/c)
772+
4:blob:right/d:$(git rev-parse base~1:right/d)
773+
blobs:6
774+
commits:0
775+
tags:0
776+
trees:0
777+
EOF
778+
779+
test_cmp_sorted expect out
780+
'
781+
782+
test_expect_success 'all, combine of disjoint object:types is empty' '
783+
test-tool path-walk \
784+
--filter=combine:object:type=blob+object:type=tree \
785+
-- --all >out &&
786+
787+
cat >expect <<-EOF &&
788+
blobs:0
789+
commits:0
790+
tags:0
791+
trees:0
792+
EOF
793+
794+
test_cmp_sorted expect out
795+
'
796+
797+
test_expect_success 'combine: rejects unsupported subfilters' '
798+
test_must_fail test-tool path-walk \
799+
--filter=combine:tree:1+blob:none -- --all 2>err &&
800+
test_grep "tree:1 filter not supported by the path-walk API" err
801+
'
802+
732803
test_expect_success 'setup sparse filter blob' '
733804
# Cone-mode patterns: include root, exclude all dirs, include left/
734805
cat >patterns <<-\EOF &&

0 commit comments

Comments
 (0)