Skip to content

Commit b221ea4

Browse files
ttaylorrderrickstolee
authored andcommitted
path-walk: support object:type filter
The `object:type` filter accepts only objects of a single type; it is the second member of the object-info-only filter family that bitmap traversal already supports. Like `blob:none` and `tree:0`, it can be evaluated with nothing more than the object's type, which is exactly the granularity path-walk's existing info->{commits,trees,blobs,tags} flags already control. Map `LOFC_OBJECT_TYPE` in `prepare_filters()` by AND-ing each flag against the filtered type. A single `object:type=X` filter applied to the default info (all flags = 1) leaves `info->X = 1` and all the others 0, which is what we want. Using an AND rather than straight assignment prepares us for a subsequent change to implement combined object filters. The path-walk machinery is mostly already wired for the per-type distinction: - `walk_path()` calls `path_fn` for a batch only when the corresponding `info->X` flag is set, so unwanted types are silently not reported. - `add_tree_entries()` skips tree entries of type `OBJ_BLOB` when `info->blobs` is unset, so we don't even allocate paths for them. - The commit-walk loop short-circuits the root-tree fetch when `!info->trees && !info->blobs`, so commit-only filters don't descend into trees at all. But there are a couple of side effects of the "trees off, blobs on" case that need fixing: 1. 'setup_pending_objects()' previously skipped pending trees as soon as `info->trees` was zero. For 'object:type=blob' the call site needs those pending trees: a lightweight tag pointing to a tree, or an annotated tag whose peeled target is a tree, can both reach blobs that are otherwise unreachable from any commit's root tree. Loosen the gate to "if (!info->trees && !info->blobs) continue" and similarly retrieve the root_tree_list whenever either trees or blobs are wanted. 2. The revision machinery's `handle_commit()` drops pending trees when `revs->tree_objects` is zero (see the 'OBJ_TREE' handler in revision.c), so by the time path-walk sees the pending list after `prepare_revision_walk()` the tree-bearing pendings would already be gone. Fix this by setting revs->tree_objects = info->trees || info->blobs so pending trees survive `prepare_revision_walk()` whenever we need to walk into them. Path-walk still resets tree_objects to zero immediately after `prepare_revision_walk()` returns, so the rev-walk itself never enumerates trees redundantly with path-walk's own descent. Add coverage in t6601 for each of the four `object:type` values. The 'object:type=blob' test in particular asserts that file2 and child/file (both reachable only through tag-pointed trees) show up in the output, exercising the pending-tree fix. Update Documentation/git-pack-objects.adoc to add object:type 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 c9efff0 commit b221ea4

4 files changed

Lines changed: 103 additions & 2 deletions

File tree

Documentation/git-pack-objects.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ 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`, and `sparse:<oid>`.
408+
`tree:0`, `object:type=<type>`, and `sparse:<oid>`.
409409
410410
411411
DELTA ISLANDS

path-walk.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ static int walk_path(struct path_walk_context *ctx,
381381
ret = ctx->info->path_fn(path, &filtered, list->type,
382382
ctx->info->path_fn_data);
383383
oid_array_clear(&filtered);
384-
} else if (path_is_for_direct_objects(path) ||
384+
} else if ((!ctx->info->strict_types && path_is_for_direct_objects(path)) ||
385385
(list->type == OBJ_TREE && ctx->info->trees) ||
386386
(list->type == OBJ_BLOB && ctx->info->blobs) ||
387387
(list->type == OBJ_TAG && ctx->info->tags)) {
@@ -610,6 +610,17 @@ static int prepare_filters(struct path_walk_info *info,
610610
}
611611
return 1;
612612

613+
case LOFC_OBJECT_TYPE:
614+
if (info) {
615+
info->commits &= options->object_type == OBJ_COMMIT;
616+
info->tags &= options->object_type == OBJ_TAG;
617+
info->trees &= options->object_type == OBJ_TREE;
618+
info->blobs &= options->object_type == OBJ_BLOB;
619+
info->strict_types = 1;
620+
list_objects_filter_release(options);
621+
}
622+
return 1;
623+
613624
case LOFC_SPARSE_OID:
614625
if (info) {
615626
struct object_id sparse_oid;

path-walk.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ struct path_walk_info {
4747
int blobs;
4848
int tags;
4949

50+
/**
51+
* If 'strict_types' is 0, then direct object requests will no longer
52+
* override the object type restrictions.
53+
*/
54+
int strict_types;
55+
5056
/**
5157
* If non-zero, specifies a maximum blob size. Blobs with a
5258
* size equal to or greater than this limit will not be

t/t6601-path-walk.sh

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,90 @@ test_expect_success 'tree:1 filter is rejected' '
645645
test_grep "tree:1 filter not supported by the path-walk API" err
646646
'
647647

648+
test_expect_success 'all, object:type=commit filter' '
649+
test-tool path-walk --filter=object:type=commit -- --all >out &&
650+
651+
cat >expect <<-EOF &&
652+
0:commit::$(git rev-parse topic)
653+
0:commit::$(git rev-parse base)
654+
0:commit::$(git rev-parse base~1)
655+
0:commit::$(git rev-parse base~2)
656+
blobs:0
657+
commits:4
658+
tags:0
659+
trees:0
660+
EOF
661+
662+
test_cmp_sorted expect out
663+
'
664+
665+
test_expect_success 'all, object:type=tag filter' '
666+
test-tool path-walk --filter=object:type=tag -- --all >out &&
667+
668+
cat >expect <<-EOF &&
669+
0:tag:/tags:$(git rev-parse refs/tags/first)
670+
0:tag:/tags:$(git rev-parse refs/tags/second.1)
671+
0:tag:/tags:$(git rev-parse refs/tags/second.2)
672+
0:tag:/tags:$(git rev-parse refs/tags/third)
673+
0:tag:/tags:$(git rev-parse refs/tags/fourth)
674+
0:tag:/tags:$(git rev-parse refs/tags/tree-tag)
675+
0:tag:/tags:$(git rev-parse refs/tags/blob-tag)
676+
blobs:0
677+
commits:0
678+
tags:7
679+
trees:0
680+
EOF
681+
682+
test_cmp_sorted expect out
683+
'
684+
685+
test_expect_success 'all, object:type=tree filter' '
686+
test-tool path-walk --filter=object:type=tree -- --all >out &&
687+
688+
cat >expect <<-EOF &&
689+
0:tree::$(git rev-parse topic^{tree})
690+
0:tree::$(git rev-parse base^{tree})
691+
0:tree::$(git rev-parse base~1^{tree})
692+
0:tree::$(git rev-parse base~2^{tree})
693+
0:tree::$(git rev-parse refs/tags/tree-tag^{})
694+
0:tree::$(git rev-parse refs/tags/tree-tag2^{})
695+
1:tree:a/:$(git rev-parse base:a)
696+
2:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
697+
3:tree:left/:$(git rev-parse base:left)
698+
3:tree:left/:$(git rev-parse base~2:left)
699+
4:tree:right/:$(git rev-parse topic:right)
700+
4:tree:right/:$(git rev-parse base~1:right)
701+
4:tree:right/:$(git rev-parse base~2:right)
702+
blobs:0
703+
commits:0
704+
tags:0
705+
trees:13
706+
EOF
707+
708+
test_cmp_sorted expect out
709+
'
710+
711+
test_expect_success 'all, object:type=blob filter' '
712+
test-tool path-walk --filter=object:type=blob -- --all >out &&
713+
714+
cat >expect <<-EOF &&
715+
0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
716+
0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
717+
1:blob:a:$(git rev-parse base~2:a)
718+
2:blob:left/b:$(git rev-parse base:left/b)
719+
2:blob:left/b:$(git rev-parse base~2:left/b)
720+
3:blob:right/c:$(git rev-parse base~2:right/c)
721+
3:blob:right/c:$(git rev-parse topic:right/c)
722+
4:blob:right/d:$(git rev-parse base~1:right/d)
723+
blobs:8
724+
commits:0
725+
tags:0
726+
trees:0
727+
EOF
728+
729+
test_cmp_sorted expect out
730+
'
731+
648732
test_expect_success 'setup sparse filter blob' '
649733
# Cone-mode patterns: include root, exclude all dirs, include left/
650734
cat >patterns <<-\EOF &&

0 commit comments

Comments
 (0)