mirror of
https://github.com/git/git.git
synced 2026-03-08 08:12:34 +01:00
Merge branch 'ab/clone-default-object-filter' into seen
"git clone" learns to pay attention to "clone.<url>.defaultObjectFilter" configuration and behave as if the "--filter=<filter-spec>" option was given on the command line. Comments? * ab/clone-default-object-filter: clone: add clone.<url>.defaultObjectFilter config
This commit is contained in:
@@ -21,3 +21,37 @@ endif::[]
|
||||
If a partial clone filter is provided (see `--filter` in
|
||||
linkgit:git-rev-list[1]) and `--recurse-submodules` is used, also apply
|
||||
the filter to submodules.
|
||||
|
||||
`clone.defaultObjectFilter`::
|
||||
`clone.<url>.defaultObjectFilter`::
|
||||
When set to a filter spec string (e.g., `blob:limit=1m`,
|
||||
`blob:none`, `tree:0`), linkgit:git-clone[1] will automatically
|
||||
use `--filter=<value>` to enable partial clone behavior.
|
||||
Objects matching the filter are excluded from the initial
|
||||
transfer and lazily fetched on demand (e.g., during checkout).
|
||||
Subsequent fetches inherit the filter via the per-remote config
|
||||
that is written during the clone.
|
||||
+
|
||||
The bare `clone.defaultObjectFilter` applies to all clones. The
|
||||
URL-qualified form `clone.<url>.defaultObjectFilter` restricts the
|
||||
setting to clones whose URL matches `<url>`, following the same
|
||||
rules as `http.<url>.*` (see linkgit:git-config[1]). The most
|
||||
specific URL match wins. You can match a domain, a namespace, or a
|
||||
specific project:
|
||||
+
|
||||
----
|
||||
[clone]
|
||||
defaultObjectFilter = blob:limit=1m
|
||||
|
||||
[clone "https://github.com/"]
|
||||
defaultObjectFilter = blob:limit=5m
|
||||
|
||||
[clone "https://internal.corp.com/large-project/"]
|
||||
defaultObjectFilter = blob:none
|
||||
----
|
||||
+
|
||||
An explicit `--filter` option on the command line takes precedence
|
||||
over this config, and `--no-filter` defeats it entirely to force a
|
||||
full clone. Only affects the initial clone; it has no effect on
|
||||
later fetches into an existing repository. If the server does not
|
||||
support object filtering, the setting is silently ignored.
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "path.h"
|
||||
#include "pkt-line.h"
|
||||
#include "list-objects-filter-options.h"
|
||||
#include "urlmatch.h"
|
||||
#include "hook.h"
|
||||
#include "bundle.h"
|
||||
#include "bundle-uri.h"
|
||||
@@ -759,6 +760,47 @@ static int git_clone_config(const char *k, const char *v,
|
||||
return git_default_config(k, v, ctx, cb);
|
||||
}
|
||||
|
||||
static int clone_filter_collect(const char *var, const char *value,
|
||||
const struct config_context *ctx UNUSED,
|
||||
void *cb)
|
||||
{
|
||||
char **filter_spec_p = cb;
|
||||
|
||||
if (!strcmp(var, "clone.defaultobjectfilter")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
free(*filter_spec_p);
|
||||
*filter_spec_p = xstrdup(value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up clone.defaultObjectFilter or clone.<url>.defaultObjectFilter
|
||||
* using the urlmatch infrastructure. A URL-qualified entry that matches
|
||||
* the clone URL takes precedence over the bare form, following the same
|
||||
* rules as http.<url>.* configuration variables.
|
||||
*/
|
||||
static char *get_default_object_filter(const char *url)
|
||||
{
|
||||
struct urlmatch_config config = URLMATCH_CONFIG_INIT;
|
||||
char *filter_spec = NULL;
|
||||
char *normalized_url;
|
||||
|
||||
config.section = "clone";
|
||||
config.key = "defaultobjectfilter";
|
||||
config.collect_fn = clone_filter_collect;
|
||||
config.cb = &filter_spec;
|
||||
|
||||
normalized_url = url_normalize(url, &config.url);
|
||||
|
||||
repo_config(the_repository, urlmatch_config_entry, &config);
|
||||
free(normalized_url);
|
||||
urlmatch_config_release(&config);
|
||||
|
||||
return filter_spec;
|
||||
}
|
||||
|
||||
static int write_one_config(const char *key, const char *value,
|
||||
const struct config_context *ctx,
|
||||
void *data)
|
||||
@@ -1059,6 +1101,14 @@ int cmd_clone(int argc,
|
||||
} else
|
||||
die(_("repository '%s' does not exist"), repo_name);
|
||||
|
||||
if (!filter_options.choice && !filter_options.no_filter) {
|
||||
char *config_filter = get_default_object_filter(repo);
|
||||
if (config_filter) {
|
||||
parse_list_objects_filter(&filter_options, config_filter);
|
||||
free(config_filter);
|
||||
}
|
||||
}
|
||||
|
||||
/* no need to be strict, transport_set_option() will validate it again */
|
||||
if (option_depth && atoi(option_depth) < 1)
|
||||
die(_("depth %s is not a positive number"), option_depth);
|
||||
|
||||
@@ -723,6 +723,98 @@ test_expect_success 'after fetching descendants of non-promisor commits, gc work
|
||||
git -C partial gc --prune=now
|
||||
'
|
||||
|
||||
# Test clone.<url>.defaultObjectFilter config
|
||||
|
||||
test_expect_success 'setup for clone.defaultObjectFilter tests' '
|
||||
git init default-filter-src &&
|
||||
echo "small" >default-filter-src/small.txt &&
|
||||
dd if=/dev/zero of=default-filter-src/large.bin bs=1024 count=100 2>/dev/null &&
|
||||
git -C default-filter-src add . &&
|
||||
git -C default-filter-src commit -m "initial" &&
|
||||
|
||||
git clone --bare "file://$(pwd)/default-filter-src" default-filter-srv.bare &&
|
||||
git -C default-filter-srv.bare config --local uploadpack.allowfilter 1 &&
|
||||
git -C default-filter-srv.bare config --local uploadpack.allowanysha1inwant 1
|
||||
'
|
||||
|
||||
test_expect_success 'clone with clone.<url>.defaultObjectFilter applies filter' '
|
||||
SERVER_URL="file://$(pwd)/default-filter-srv.bare" &&
|
||||
git -c "clone.$SERVER_URL.defaultObjectFilter=blob:limit=1k" clone \
|
||||
"$SERVER_URL" default-filter-clone &&
|
||||
|
||||
test "$(git -C default-filter-clone config --local remote.origin.promisor)" = "true" &&
|
||||
test "$(git -C default-filter-clone config --local remote.origin.partialclonefilter)" = "blob:limit=1024"
|
||||
'
|
||||
|
||||
test_expect_success 'clone with --filter overrides clone.<url>.defaultObjectFilter' '
|
||||
SERVER_URL="file://$(pwd)/default-filter-srv.bare" &&
|
||||
git -c "clone.$SERVER_URL.defaultObjectFilter=blob:limit=1k" \
|
||||
clone --filter=blob:none "$SERVER_URL" default-filter-override &&
|
||||
|
||||
test "$(git -C default-filter-override config --local remote.origin.partialclonefilter)" = "blob:none"
|
||||
'
|
||||
|
||||
test_expect_success 'clone with clone.<url>.defaultObjectFilter=blob:none works' '
|
||||
SERVER_URL="file://$(pwd)/default-filter-srv.bare" &&
|
||||
git -c "clone.$SERVER_URL.defaultObjectFilter=blob:none" clone \
|
||||
"$SERVER_URL" default-filter-blobnone &&
|
||||
|
||||
test "$(git -C default-filter-blobnone config --local remote.origin.promisor)" = "true" &&
|
||||
test "$(git -C default-filter-blobnone config --local remote.origin.partialclonefilter)" = "blob:none"
|
||||
'
|
||||
|
||||
test_expect_success 'clone.<url>.defaultObjectFilter with tree:0 works' '
|
||||
SERVER_URL="file://$(pwd)/default-filter-srv.bare" &&
|
||||
git -c "clone.$SERVER_URL.defaultObjectFilter=tree:0" clone \
|
||||
"$SERVER_URL" default-filter-tree0 &&
|
||||
|
||||
test "$(git -C default-filter-tree0 config --local remote.origin.promisor)" = "true" &&
|
||||
test "$(git -C default-filter-tree0 config --local remote.origin.partialclonefilter)" = "tree:0"
|
||||
'
|
||||
|
||||
test_expect_success 'most specific URL match wins for clone.defaultObjectFilter' '
|
||||
SERVER_URL="file://$(pwd)/default-filter-srv.bare" &&
|
||||
git \
|
||||
-c "clone.file://.defaultObjectFilter=blob:limit=1k" \
|
||||
-c "clone.$SERVER_URL.defaultObjectFilter=blob:none" \
|
||||
clone "$SERVER_URL" default-filter-url-specific &&
|
||||
|
||||
test "$(git -C default-filter-url-specific config --local remote.origin.partialclonefilter)" = "blob:none"
|
||||
'
|
||||
|
||||
test_expect_success 'non-matching URL does not apply clone.defaultObjectFilter' '
|
||||
git \
|
||||
-c "clone.https://other.example.com/.defaultObjectFilter=blob:none" \
|
||||
clone "file://$(pwd)/default-filter-srv.bare" default-filter-url-nomatch &&
|
||||
|
||||
test_must_fail git -C default-filter-url-nomatch config --local remote.origin.promisor
|
||||
'
|
||||
|
||||
test_expect_success 'bare clone.defaultObjectFilter applies to all clones' '
|
||||
git -c clone.defaultObjectFilter=blob:none \
|
||||
clone "file://$(pwd)/default-filter-srv.bare" default-filter-bare-key &&
|
||||
|
||||
test "$(git -C default-filter-bare-key config --local remote.origin.promisor)" = "true" &&
|
||||
test "$(git -C default-filter-bare-key config --local remote.origin.partialclonefilter)" = "blob:none"
|
||||
'
|
||||
|
||||
test_expect_success 'URL-specific clone.defaultObjectFilter overrides bare form' '
|
||||
SERVER_URL="file://$(pwd)/default-filter-srv.bare" &&
|
||||
git \
|
||||
-c clone.defaultObjectFilter=blob:limit=1k \
|
||||
-c "clone.$SERVER_URL.defaultObjectFilter=blob:none" \
|
||||
clone "$SERVER_URL" default-filter-url-over-bare &&
|
||||
|
||||
test "$(git -C default-filter-url-over-bare config --local remote.origin.partialclonefilter)" = "blob:none"
|
||||
'
|
||||
|
||||
test_expect_success '--no-filter defeats clone.defaultObjectFilter' '
|
||||
SERVER_URL="file://$(pwd)/default-filter-srv.bare" &&
|
||||
git -c "clone.$SERVER_URL.defaultObjectFilter=blob:none" \
|
||||
clone --no-filter "$SERVER_URL" default-filter-no-filter &&
|
||||
|
||||
test_must_fail git -C default-filter-no-filter config --local remote.origin.promisor
|
||||
'
|
||||
|
||||
. "$TEST_DIRECTORY"/lib-httpd.sh
|
||||
start_httpd
|
||||
|
||||
Reference in New Issue
Block a user