diff --git a/Documentation/scalar.adoc b/Documentation/scalar.adoc index e08f22607f0267..966373cac6fcdb 100644 --- a/Documentation/scalar.adoc +++ b/Documentation/scalar.adoc @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] scalar clone [--single-branch] [--branch ] [--full-clone] - [--[no-]src] [--[no-]tags] [--[no-]maintenance] + [--[no-]src] [--[no-]tags] [--[no-]maintenance] [--[no-]prefetch] [--cache-server-url ] [--[verb]-cache-server-url ] [--local-cache-path ] [] scalar list @@ -110,6 +110,20 @@ cloning. If the HEAD at the remote did not point at any branch when background maintenance feature. Use the `--no-maintenance` to skip this configuration. +--prefetch:: +--no-prefetch:: + By default, when cloning with the GVFS Protocol, `scalar clone` + issues a `/gvfs/prefetch` request to hydrate the local object cache + with the commits and trees that back the checked-out branch. Use + `--no-prefetch` to skip that request during the clone so that the + initial worktree becomes ready as quickly as possible. ++ +This only affects the initial fetch performed by `scalar clone`: the +prefetched data is still downloaded by the next `git fetch` (including the +background maintenance `prefetch` task), so the object cache is populated +shortly afterwards. This option has no effect when the GVFS Protocol is not +in use. + --local-cache-path :: Override the path to the local cache root directory; Pre-fetched objects are stored into a repository-dependent subdirectory of that path. diff --git a/scalar.c b/scalar.c index 017ce4a23a16ef..742e4e3436ac9f 100644 --- a/scalar.c +++ b/scalar.c @@ -25,9 +25,19 @@ #include "trace2.h" #include "path.h" #include "json-parser.h" +#include "gvfs.h" #include "remote.h" #include "path.h" +/* + * The `core.gvfs` bitmask that `scalar clone` configures for enlistments + * that use the GVFS Protocol (historically the value `150`). See gvfs.h + * for the meaning of the individual bits. + */ +#define SCALAR_GVFS_MODE (GVFS_BLOCK_COMMANDS | GVFS_MISSING_OK | \ + GVFS_FETCH_SKIP_REACHABILITY_AND_UPLOADPACK | \ + GVFS_PREFETCH_DURING_FETCH) + static int is_unattended(void) { return git_env_bool("Scalar_UNATTENDED", 0); } @@ -780,7 +790,7 @@ static int cmd_clone(int argc, const char **argv) const char *branch = NULL; char *branch_to_free = NULL; int full_clone = 0, single_branch = 0, show_progress = isatty(2); - int src = 1, tags = 1, maintenance = 1; + int src = 1, tags = 1, maintenance = 1, prefetch = 1; const char *cache_server_url = NULL, *local_cache_root = NULL; char *default_cache_server_url = NULL, *local_cache_root_abs = NULL; const char *prefetch_server = NULL, *get_server = NULL, *post_server = NULL; @@ -801,6 +811,9 @@ static int cmd_clone(int argc, const char **argv) N_("specify if tags should be fetched during clone")), OPT_BOOL(0, "maintenance", &maintenance, N_("specify if background maintenance should be enabled")), + OPT_BOOL(0, "prefetch", &prefetch, + N_("specify if commits and trees should be prefetched " + "during clone when using the GVFS Protocol")), OPT_BOOL(0, "gvfs-protocol", &gvfs_protocol, N_("force enable (or disable) the GVFS Protocol")), OPT_STRING(0, "cache-server-url", &cache_server_url, @@ -826,7 +839,8 @@ static int cmd_clone(int argc, const char **argv) }; const char * const clone_usage[] = { N_("scalar clone [--single-branch] [--branch ] [--full-clone]\n" - "\t[--[no-]src] [--[no-]tags] [--[no-]maintenance] [--ref-format ]\n" + "\t[--[no-]src] [--[no-]tags] [--[no-]maintenance] [--[no-]prefetch]\n" + "\t[--ref-format ]\n" "\t[--cache-server-url ] [--[verb]-cache-server-url ]\n" "\t[--local-cache-path ] []"), NULL @@ -977,7 +991,7 @@ static int cmd_clone(int argc, const char **argv) if (!cache_server_url) cache_server_url = default_cache_server_url; if (set_config("core.useGVFSHelper=true") || - set_config("core.gvfs=150") || + set_config("core.gvfs=%d", SCALAR_GVFS_MODE) || set_config("http.%s.version=HTTP/1.1", url)) { res = error(_("could not turn on GVFS helper")); goto cleanup; @@ -1034,11 +1048,29 @@ static int cmd_clone(int argc, const char **argv) if (set_recommended_config(0)) return error(_("could not configure '%s'"), dir); - if ((res = run_git("fetch", "--quiet", - show_progress ? "--progress" : "--no-progress", - "origin", - (tags ? NULL : "--no-tags"), - NULL))) { + strvec_clear(&init_argv); + /* + * When cloning with the GVFS Protocol, the `core.gvfs` value set + * above enables the GVFS_PREFETCH_DURING_FETCH bit, so the `git fetch` + * below issues a `/gvfs/prefetch` request to hydrate the local object + * cache. With `--no-prefetch`, skip that request for this initial + * fetch only (by clearing that bit for this invocation) so the + * worktree becomes ready sooner. The persisted `core.gvfs` value is + * left untouched, so subsequent fetches -- including background + * maintenance -- still prefetch as usual. + */ + if (gvfs_protocol && !prefetch) { + strvec_push(&init_argv, "-c"); + strvec_pushf(&init_argv, "core.gvfs=%d", + SCALAR_GVFS_MODE & ~GVFS_PREFETCH_DURING_FETCH); + } + strvec_pushl(&init_argv, "fetch", "--quiet", + show_progress ? "--progress" : "--no-progress", + "origin", NULL); + if (!tags) + strvec_push(&init_argv, "--no-tags"); + + if ((res = run_git_argv(&init_argv))) { if (gvfs_protocol) { res = error(_("failed to prefetch commits and trees")); goto cleanup; diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh index 75105baa9ec4e5..f190423912ad7d 100755 --- a/t/t9210-scalar.sh +++ b/t/t9210-scalar.sh @@ -461,6 +461,35 @@ test_expect_success '`scalar clone` with GVFS-enabled server' ' ) ' +test_expect_success '`scalar clone --no-prefetch` skips the initial prefetch' ' + git config --global core.askPass true && + + # A normal GVFS-enabled clone issues a "/gvfs/prefetch" request, + # which shows up in the trace as a "prefetch/since" data event. + GIT_TRACE2_EVENT="$(pwd)/with-prefetch-trace" scalar \ + -c credential.interactive=true \ + clone --gvfs-protocol --single-branch \ + -- http://$ORIGIN_HOST_PORT/ with-prefetch && + grep "prefetch/since" with-prefetch-trace && + + # ... but "--no-prefetch" skips that request during the clone. + GIT_TRACE2_EVENT="$(pwd)/no-prefetch-trace" scalar \ + -c credential.interactive=true \ + clone --no-prefetch --gvfs-protocol --single-branch \ + -- http://$ORIGIN_HOST_PORT/ no-prefetch && + ! grep "prefetch/since" no-prefetch-trace && + + : the persisted core.gvfs still enables prefetch during fetch && + echo 150 >expect && + git -C no-prefetch/src config core.gvfs >actual && + test_cmp expect actual && + + : and a subsequent git fetch performs the deferred prefetch && + GIT_TRACE2_EVENT="$(pwd)/fetch-trace" \ + git -C no-prefetch/src fetch origin && + grep "prefetch/since" fetch-trace +' + test_expect_success '`scalar clone` with GVFS-enabled server; local cache path' ' : the fake cache server requires fake authentication && git config --global core.askPass true &&