bundle: parse filter capability

The v3 bundle format has capabilities, allowing newer versions of Git to
create bundles with newer features. Older versions that do not
understand these new capabilities will fail with a helpful warning.

Create a new capability allowing Git to understand that the contained
pack-file is filtered according to some object filter. Typically, this
filter will be "blob:none" for a blobless partial clone.

This change teaches Git to parse this capability, place its value in the
bundle header, and demonstrate this understanding by adding a message to
'git bundle verify'.

Since we will use gently_parse_list_objects_filter() outside of
list-objects-filter-options.c, make it an external method and move its
API documentation to before its declaration.

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Derrick Stolee 2022-03-09 16:01:39 +00:00 коммит произвёл Junio C Hamano
Родитель 4f33a6345f
Коммит 105c6f14ad
6 изменённых файлов: 50 добавлений и 22 удалений

Просмотреть файл

@ -75,8 +75,11 @@ verify <file>::
cleanly to the current repository. This includes checks on the cleanly to the current repository. This includes checks on the
bundle format itself as well as checking that the prerequisite bundle format itself as well as checking that the prerequisite
commits exist and are fully linked in the current repository. commits exist and are fully linked in the current repository.
'git bundle' prints a list of missing commits, if any, and exits Information about additional capabilities, such as "object filter",
with a non-zero status. is printed. See "Capabilities" in link:technical/bundle-format.html
for more information. Finally, 'git bundle' prints a list of
missing commits, if any. The exit code is zero for success, but
will be nonzero if the bundle file is invalid.
list-heads <file>:: list-heads <file>::
Lists the references defined in the bundle. If followed by a Lists the references defined in the bundle. If followed by a

Просмотреть файл

@ -71,6 +71,11 @@ and the Git bundle v2 format cannot represent a shallow clone repository.
== Capabilities == Capabilities
Because there is no opportunity for negotiation, unknown capabilities cause 'git Because there is no opportunity for negotiation, unknown capabilities cause 'git
bundle' to abort. The only known capability is `object-format`, which specifies bundle' to abort.
the hash algorithm in use, and can take the same values as the
`extensions.objectFormat` configuration value. * `object-format` specifies the hash algorithm in use, and can take the same
values as the `extensions.objectFormat` configuration value.
* `filter` specifies an object filter as in the `--filter` option in
linkgit:git-rev-list[1]. The resulting pack-file must be marked as a
`.promisor` pack-file after it is unbundled.

Просмотреть файл

@ -11,7 +11,7 @@
#include "run-command.h" #include "run-command.h"
#include "refs.h" #include "refs.h"
#include "strvec.h" #include "strvec.h"
#include "list-objects-filter-options.h"
static const char v2_bundle_signature[] = "# v2 git bundle\n"; static const char v2_bundle_signature[] = "# v2 git bundle\n";
static const char v3_bundle_signature[] = "# v3 git bundle\n"; static const char v3_bundle_signature[] = "# v3 git bundle\n";
@ -33,6 +33,7 @@ void bundle_header_release(struct bundle_header *header)
{ {
string_list_clear(&header->prerequisites, 1); string_list_clear(&header->prerequisites, 1);
string_list_clear(&header->references, 1); string_list_clear(&header->references, 1);
list_objects_filter_release(&header->filter);
} }
static int parse_capability(struct bundle_header *header, const char *capability) static int parse_capability(struct bundle_header *header, const char *capability)
@ -45,6 +46,10 @@ static int parse_capability(struct bundle_header *header, const char *capability
header->hash_algo = &hash_algos[algo]; header->hash_algo = &hash_algos[algo];
return 0; return 0;
} }
if (skip_prefix(capability, "filter=", &arg)) {
parse_list_objects_filter(&header->filter, arg);
return 0;
}
return error(_("unknown capability '%s'"), capability); return error(_("unknown capability '%s'"), capability);
} }
@ -220,6 +225,8 @@ int verify_bundle(struct repository *r,
req_nr = revs.pending.nr; req_nr = revs.pending.nr;
setup_revisions(2, argv, &revs, NULL); setup_revisions(2, argv, &revs, NULL);
list_objects_filter_copy(&revs.filter, &header->filter);
if (prepare_revision_walk(&revs)) if (prepare_revision_walk(&revs))
die(_("revision walk setup failed")); die(_("revision walk setup failed"));
@ -259,6 +266,12 @@ int verify_bundle(struct repository *r,
r->nr), r->nr),
r->nr); r->nr);
list_refs(r, 0, NULL); list_refs(r, 0, NULL);
if (header->filter.choice) {
printf_ln("The bundle uses this filter: %s",
list_objects_filter_spec(&header->filter));
}
r = &header->prerequisites; r = &header->prerequisites;
if (!r->nr) { if (!r->nr) {
printf_ln(_("The bundle records a complete history.")); printf_ln(_("The bundle records a complete history."));

Просмотреть файл

@ -4,12 +4,14 @@
#include "strvec.h" #include "strvec.h"
#include "cache.h" #include "cache.h"
#include "string-list.h" #include "string-list.h"
#include "list-objects-filter-options.h"
struct bundle_header { struct bundle_header {
unsigned version; unsigned version;
struct string_list prerequisites; struct string_list prerequisites;
struct string_list references; struct string_list references;
const struct git_hash_algo *hash_algo; const struct git_hash_algo *hash_algo;
struct list_objects_filter_options filter;
}; };
#define BUNDLE_HEADER_INIT \ #define BUNDLE_HEADER_INIT \

Просмотреть файл

@ -40,22 +40,7 @@ const char *list_object_filter_config_name(enum list_objects_filter_choice c)
BUG("list_object_filter_config_name: invalid argument '%d'", c); BUG("list_object_filter_config_name: invalid argument '%d'", c);
} }
/* int gently_parse_list_objects_filter(
* Parse value of the argument to the "filter" keyword.
* On the command line this looks like:
* --filter=<arg>
* and in the pack protocol as:
* "filter" SP <arg>
*
* The filter keyword will be used by many commands.
* See Documentation/rev-list-options.txt for allowed values for <arg>.
*
* Capture the given arg as the "filter_spec". This can be forwarded to
* subordinate commands when necessary (although it's better to pass it through
* expand_list_objects_filter_spec() first). We also "intern" the arg for the
* convenience of the current command.
*/
static int gently_parse_list_objects_filter(
struct list_objects_filter_options *filter_options, struct list_objects_filter_options *filter_options,
const char *arg, const char *arg,
struct strbuf *errbuf) struct strbuf *errbuf)

Просмотреть файл

@ -72,6 +72,26 @@ struct list_objects_filter_options {
/* Normalized command line arguments */ /* Normalized command line arguments */
#define CL_ARG__FILTER "filter" #define CL_ARG__FILTER "filter"
/*
* Parse value of the argument to the "filter" keyword.
* On the command line this looks like:
* --filter=<arg>
* and in the pack protocol as:
* "filter" SP <arg>
*
* The filter keyword will be used by many commands.
* See Documentation/rev-list-options.txt for allowed values for <arg>.
*
* Capture the given arg as the "filter_spec". This can be forwarded to
* subordinate commands when necessary (although it's better to pass it through
* expand_list_objects_filter_spec() first). We also "intern" the arg for the
* convenience of the current command.
*/
int gently_parse_list_objects_filter(
struct list_objects_filter_options *filter_options,
const char *arg,
struct strbuf *errbuf);
void list_objects_filter_die_if_populated( void list_objects_filter_die_if_populated(
struct list_objects_filter_options *filter_options); struct list_objects_filter_options *filter_options);