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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
main
parent
5111520e2a
commit
2b8d07ef91
|
|
@ -405,7 +405,7 @@ will be automatically changed to version `1`.
|
|||
Incompatible with `--delta-islands`. The `--use-bitmap-index` option is
|
||||
ignored in the presence of `--path-walk`. The `--path-walk` option
|
||||
supports the `--filter=<spec>` forms `blob:none`, `blob:limit=<n>`,
|
||||
`tree:0`, and `sparse:<oid>`.
|
||||
`tree:0`, `object:type=<type>`, and `sparse:<oid>`.
|
||||
|
||||
|
||||
DELTA ISLANDS
|
||||
|
|
|
|||
13
path-walk.c
13
path-walk.c
|
|
@ -382,7 +382,7 @@ static int walk_path(struct path_walk_context *ctx,
|
|||
ret = ctx->info->path_fn(path, &filtered, list->type,
|
||||
ctx->info->path_fn_data);
|
||||
oid_array_clear(&filtered);
|
||||
} else if (path_is_for_direct_objects(path) ||
|
||||
} else if ((!ctx->info->strict_types && path_is_for_direct_objects(path)) ||
|
||||
(list->type == OBJ_TREE && ctx->info->trees) ||
|
||||
(list->type == OBJ_BLOB && ctx->info->blobs) ||
|
||||
(list->type == OBJ_TAG && ctx->info->tags)) {
|
||||
|
|
@ -608,6 +608,17 @@ static int prepare_filters(struct path_walk_info *info,
|
|||
}
|
||||
return 1;
|
||||
|
||||
case LOFC_OBJECT_TYPE:
|
||||
if (info) {
|
||||
info->commits &= options->object_type == OBJ_COMMIT;
|
||||
info->tags &= options->object_type == OBJ_TAG;
|
||||
info->trees &= options->object_type == OBJ_TREE;
|
||||
info->blobs &= options->object_type == OBJ_BLOB;
|
||||
info->strict_types = 1;
|
||||
list_objects_filter_release(options);
|
||||
}
|
||||
return 1;
|
||||
|
||||
case LOFC_SPARSE_OID:
|
||||
if (info) {
|
||||
struct object_id sparse_oid;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ struct path_walk_info {
|
|||
int blobs;
|
||||
int tags;
|
||||
|
||||
/**
|
||||
* If 'strict_types' is 0, then direct object requests will no longer
|
||||
* override the object type restrictions.
|
||||
*/
|
||||
int strict_types;
|
||||
|
||||
/**
|
||||
* If non-zero, specifies a maximum blob size. Blobs with a
|
||||
* size equal to or greater than this limit will not be
|
||||
|
|
|
|||
|
|
@ -643,6 +643,90 @@ test_expect_success 'tree:1 filter is rejected' '
|
|||
test_grep "tree:1 filter not supported by the path-walk API" err
|
||||
'
|
||||
|
||||
test_expect_success 'all, object:type=commit filter' '
|
||||
test-tool path-walk --filter=object:type=commit -- --all >out &&
|
||||
|
||||
cat >expect <<-EOF &&
|
||||
0:commit::$(git rev-parse topic)
|
||||
0:commit::$(git rev-parse base)
|
||||
0:commit::$(git rev-parse base~1)
|
||||
0:commit::$(git rev-parse base~2)
|
||||
blobs:0
|
||||
commits:4
|
||||
tags:0
|
||||
trees:0
|
||||
EOF
|
||||
|
||||
test_cmp_sorted expect out
|
||||
'
|
||||
|
||||
test_expect_success 'all, object:type=tag filter' '
|
||||
test-tool path-walk --filter=object:type=tag -- --all >out &&
|
||||
|
||||
cat >expect <<-EOF &&
|
||||
0:tag:/tags:$(git rev-parse refs/tags/first)
|
||||
0:tag:/tags:$(git rev-parse refs/tags/second.1)
|
||||
0:tag:/tags:$(git rev-parse refs/tags/second.2)
|
||||
0:tag:/tags:$(git rev-parse refs/tags/third)
|
||||
0:tag:/tags:$(git rev-parse refs/tags/fourth)
|
||||
0:tag:/tags:$(git rev-parse refs/tags/tree-tag)
|
||||
0:tag:/tags:$(git rev-parse refs/tags/blob-tag)
|
||||
blobs:0
|
||||
commits:0
|
||||
tags:7
|
||||
trees:0
|
||||
EOF
|
||||
|
||||
test_cmp_sorted expect out
|
||||
'
|
||||
|
||||
test_expect_success 'all, object:type=tree filter' '
|
||||
test-tool path-walk --filter=object:type=tree -- --all >out &&
|
||||
|
||||
cat >expect <<-EOF &&
|
||||
0:tree::$(git rev-parse topic^{tree})
|
||||
0:tree::$(git rev-parse base^{tree})
|
||||
0:tree::$(git rev-parse base~1^{tree})
|
||||
0:tree::$(git rev-parse base~2^{tree})
|
||||
1:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag^{})
|
||||
1:tree:/tagged-trees:$(git rev-parse refs/tags/tree-tag2^{})
|
||||
2:tree:a/:$(git rev-parse base:a)
|
||||
3:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
|
||||
4:tree:left/:$(git rev-parse base:left)
|
||||
4:tree:left/:$(git rev-parse base~2:left)
|
||||
5:tree:right/:$(git rev-parse topic:right)
|
||||
5:tree:right/:$(git rev-parse base~1:right)
|
||||
5:tree:right/:$(git rev-parse base~2:right)
|
||||
blobs:0
|
||||
commits:0
|
||||
tags:0
|
||||
trees:13
|
||||
EOF
|
||||
|
||||
test_cmp_sorted expect out
|
||||
'
|
||||
|
||||
test_expect_success 'all, object:type=blob filter' '
|
||||
test-tool path-walk --filter=object:type=blob -- --all >out &&
|
||||
|
||||
cat >expect <<-EOF &&
|
||||
0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
|
||||
0:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
|
||||
1:blob:a:$(git rev-parse base~2:a)
|
||||
2:blob:left/b:$(git rev-parse base:left/b)
|
||||
2:blob:left/b:$(git rev-parse base~2:left/b)
|
||||
3:blob:right/c:$(git rev-parse base~2:right/c)
|
||||
3:blob:right/c:$(git rev-parse topic:right/c)
|
||||
4:blob:right/d:$(git rev-parse base~1:right/d)
|
||||
blobs:8
|
||||
commits:0
|
||||
tags:0
|
||||
trees:0
|
||||
EOF
|
||||
|
||||
test_cmp_sorted expect out
|
||||
'
|
||||
|
||||
test_expect_success 'setup sparse filter blob' '
|
||||
# Cone-mode patterns: include root, exclude all dirs, include left/
|
||||
cat >patterns <<-\EOF &&
|
||||
|
|
|
|||
Loading…
Reference in New Issue