diff --git a/Documentation/git-pack-objects.adoc b/Documentation/git-pack-objects.adoc index c86219be91..f2852ebd31 100644 --- a/Documentation/git-pack-objects.adoc +++ b/Documentation/git-pack-objects.adoc @@ -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=` forms `blob:none`, `blob:limit=`, -`tree:0`, and `sparse:`. +`tree:0`, `object:type=`, and `sparse:`. DELTA ISLANDS diff --git a/path-walk.c b/path-walk.c index cb67b8ce86..418972e753 100644 --- a/path-walk.c +++ b/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; diff --git a/path-walk.h b/path-walk.h index 7e57ae5f65..a2652b2d46 100644 --- a/path-walk.h +++ b/path-walk.h @@ -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 diff --git a/t/t6601-path-walk.sh b/t/t6601-path-walk.sh index 566db7c7e3..0fd8e61c76 100755 --- a/t/t6601-path-walk.sh +++ b/t/t6601-path-walk.sh @@ -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 &&