From c784b0a5b991cc8ee179b8f3a8fc0b762708947d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 8 Feb 2024 15:17:31 -0800 Subject: [PATCH 1/3] git: --no-lazy-fetch option Sometimes, especially during tests of low level machinery, it is handy to have a way to disable lazy fetching of objects. This allows us to say, for example, "git cat-file -e ", to see if the object is locally available. Signed-off-by: Junio C Hamano --- Documentation/git.txt | 5 +++++ git.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Documentation/git.txt b/Documentation/git.txt index 2535a30194..95f451b22b 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -177,6 +177,11 @@ If you just want to run git as if it was started in `` then use Do not use replacement refs to replace Git objects. See linkgit:git-replace[1] for more information. +--no-lazy-fetch:: + Do not fetch missing objects from the promisor remote on + demand. Useful together with `git cat-file -e ` to + see if the object is locally available. + --literal-pathspecs:: Treat pathspecs literally (i.e. no globbing, no pathspec magic). This is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment diff --git a/git.c b/git.c index c67e44dd82..28e8bf7497 100644 --- a/git.c +++ b/git.c @@ -4,6 +4,7 @@ #include "exec-cmd.h" #include "gettext.h" #include "help.h" +#include "object-file.h" #include "pager.h" #include "read-cache-ll.h" #include "run-command.h" @@ -186,6 +187,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) use_pager = 0; if (envchanged) *envchanged = 1; + } else if (!strcmp(cmd, "--no-lazy-fetch")) { + fetch_if_missing = 0; } else if (!strcmp(cmd, "--no-replace-objects")) { disable_replace_refs(); setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1); From b3806f7633f69d44a2ade95b92ba21fb59362f4e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 16 Feb 2024 09:22:20 -0800 Subject: [PATCH 2/3] git: document GIT_NO_REPLACE_OBJECTS environment variable This variable is used as the primary way to disable the object replacement mechanism, with the "--no-replace-objects" command line option as an end-user visible way to set it, but has not been documented. The original reason why it was left undocumented might be because it was meant as an internal implementation detail, but the thing is, that our tests use the environment variable directly without the command line option, and there certainly are folks who learned its use from there, making it impossible to deprecate or change its behaviour by now. Add documentation and note that for this variable, unlike many boolean-looking environment variables, only the presence matters, not what value it is set to. Signed-off-by: Junio C Hamano --- Documentation/git.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index 95f451b22b..b1f754e84b 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -174,8 +174,10 @@ If you just want to run git as if it was started in `` then use directory. --no-replace-objects:: - Do not use replacement refs to replace Git objects. See - linkgit:git-replace[1] for more information. + Do not use replacement refs to replace Git objects. + This is equivalent to exporting the `GIT_NO_REPLACE_OBJECTS` + environment variable with any value. + See linkgit:git-replace[1] for more information. --no-lazy-fetch:: Do not fetch missing objects from the promisor remote on @@ -873,6 +875,10 @@ for full details. header and packfile URIs. Set this Boolean environment variable to false to prevent this redaction. +`GIT_NO_REPLACE_OBJECTS`:: + Setting and exporting this environment variable tells Git to + ignore replacement refs and do not replace Git objects. + `GIT_LITERAL_PATHSPECS`:: Setting this Boolean environment variable to true will cause Git to treat all pathspecs literally, rather than as glob patterns. For example, From e6d5479e7ac301ae8d11daa3d8ef748e891c91c3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 27 Feb 2024 08:48:29 -0800 Subject: [PATCH 3/3] git: extend --no-lazy-fetch to work across subprocesses Modeling after how the `--no-replace-objects` option is made usable across subprocess spawning (e.g., cURL based remote helpers are spawned as a separate process while running "git fetch"), allow the `--no-lazy-fetch` option to be passed across process boundaries. Do not model how the value of GIT_NO_REPLACE_OBJECTS environment variable is ignored, though. Just use the usual git_env_bool() to allow "export GIT_NO_LAZY_FETCH=0" and "unset GIT_NO_LAZY_FETCH" to be equivalents. Also do not model how the request is not propagated to subprocesses we spawn (e.g. "git clone --local" that spawns a new process to work in the origin repository, while the original one working in the newly created one) by the "--no-replace-objects" option, as this "do not lazily fetch from the promisor" is more about a per-request debugging aid, not "this repository's promisor should not be relied upon" property specific to a repository. Signed-off-by: Junio C Hamano --- Documentation/git.txt | 7 +++++++ environment.c | 3 +++ environment.h | 1 + git.c | 3 +++ t/t0410-partial-clone.sh | 15 +++++++++++++++ 5 files changed, 29 insertions(+) diff --git a/Documentation/git.txt b/Documentation/git.txt index b1f754e84b..a517d94a7a 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -183,6 +183,8 @@ If you just want to run git as if it was started in `` then use Do not fetch missing objects from the promisor remote on demand. Useful together with `git cat-file -e ` to see if the object is locally available. + This is equivalent to setting the `GIT_NO_LAZY_FETCH` + environment variable to `1`. --literal-pathspecs:: Treat pathspecs literally (i.e. no globbing, no pathspec magic). @@ -900,6 +902,11 @@ for full details. Setting this Boolean environment variable to true will cause Git to treat all pathspecs as case-insensitive. +`GIT_NO_LAZY_FETCH`:: + Setting this Boolean environment variable to true tells Git + not to lazily fetch missing objects from the promisor remote + on demand. + `GIT_REFLOG_ACTION`:: When a ref is updated, reflog entries are created to keep track of the reason why the ref was updated (which is diff --git a/environment.c b/environment.c index 9e37bf58c0..0ae5bbd4a1 100644 --- a/environment.c +++ b/environment.c @@ -207,6 +207,9 @@ void setup_git_env(const char *git_dir) shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT); if (shallow_file) set_alternate_shallow_file(the_repository, shallow_file, 0); + + if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0)) + fetch_if_missing = 0; } int is_bare_repository(void) diff --git a/environment.h b/environment.h index e5351c9dd9..5cec19cecc 100644 --- a/environment.h +++ b/environment.h @@ -36,6 +36,7 @@ const char *getenv_safe(struct strvec *argv, const char *name); #define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES" #define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS" #define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE" +#define NO_LAZY_FETCH_ENVIRONMENT "GIT_NO_LAZY_FETCH" #define GITATTRIBUTES_FILE ".gitattributes" #define INFOATTRIBUTES_FILE "info/attributes" #define ATTRIBUTE_MACRO_PREFIX "[attr]" diff --git a/git.c b/git.c index 28e8bf7497..d11d4dc77b 100644 --- a/git.c +++ b/git.c @@ -189,6 +189,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--no-lazy-fetch")) { fetch_if_missing = 0; + setenv(NO_LAZY_FETCH_ENVIRONMENT, "1", 1); + if (envchanged) + *envchanged = 1; } else if (!strcmp(cmd, "--no-replace-objects")) { disable_replace_refs(); setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1); diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index 5b7bee888d..c282851af7 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -665,6 +665,21 @@ test_expect_success 'lazy-fetch when accessing object not in the_repository' ' git -C partial.git rev-list --objects --missing=print HEAD >out && grep "[?]$FILE_HASH" out && + # The no-lazy-fetch mechanism prevents Git from fetching + test_must_fail env GIT_NO_LAZY_FETCH=1 \ + git -C partial.git cat-file -e "$FILE_HASH" && + + # The same with command line option to "git" + test_must_fail git --no-lazy-fetch -C partial.git cat-file -e "$FILE_HASH" && + + # The same, forcing a subprocess via an alias + test_must_fail git --no-lazy-fetch -C partial.git \ + -c alias.foo="!git cat-file" foo -e "$FILE_HASH" && + + # Sanity check that the file is still missing + git -C partial.git rev-list --objects --missing=print HEAD >out && + grep "[?]$FILE_HASH" out && + git -C full cat-file -s "$FILE_HASH" >expect && test-tool partial-clone object-info partial.git "$FILE_HASH" >actual && test_cmp expect actual &&