From: Jonathan Tan <hidden> Date: 2021-06-01 21:34:26
This is a preliminary step towards supporting partial clone submodules
(e.g., by cloning with --recurse-submodules and having the given filter
propagate to submodules). Even with this patch set, we won't be there
yet (notably, some code in Git access objects in submodules by adding
them as alternates - so lazy-fetching missing objects in submodules
wouldn't work here), but at least this is a first step.
This patch set would also be useful if Git needed to operate on
other repositories (other than in the submodule case), but I can't think
of such a situation right now.
As mentioned, there is still more work that needs to be done. Any help
is appreciated, and as for me, I hope to get back to this in the 3rd
quarter of the year.
Jonathan Tan (4):
promisor-remote: read partialClone config here
promisor-remote: support per-repository config
run-command: move envvar-resetting function
promisor-remote: teach lazy-fetch in any repo
Makefile | 1 +
cache.h | 1 -
object-file.c | 7 +-
promisor-remote.c | 119 +++++++++++++++++++---------------
promisor-remote.h | 26 +++++---
repository.h | 4 ++
run-command.c | 10 +++
run-command.h | 7 ++
setup.c | 10 ++-
submodule.c | 14 +---
t/helper/test-partial-clone.c | 34 ++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 24 +++++++
14 files changed, 177 insertions(+), 82 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
--
2.32.0.rc0.204.g9fa02ecfa5-goog
From: Jonathan Tan <hidden> Date: 2021-06-01 21:34:28
Currently, the reading of config related to promisor remotes is done in
two places: once in setup.c (which sets the global variable
repository_format_partial_clone, to be read by the code in
promisor-remote.c), and once in promisor-remote.c. This means that care
must be taken to ensure that repository_format_partial_clone is set
before any code in promisor-remote.c accesses it.
To simplify the code, move all such config reading to promisor-remote.c.
By doing this, it will be easier to see when
repository_format_partial_clone is written and, thus, to reason about
the code. This will be especially helpful in a subsequent commit, which
modifies this code.
Signed-off-by: Jonathan Tan <redacted>
---
cache.h | 1 -
promisor-remote.c | 10 +++++-----
promisor-remote.h | 6 ------
setup.c | 10 +++++++---
4 files changed, 12 insertions(+), 15 deletions(-)
@@ -1061,7 +1061,6 @@ extern int repository_format_worktree_config;structrepository_format{intversion;intprecious_objects;-char*partial_clone;/* value of extensions.partialclone */intworktree_config;intis_bare;inthash_algo;
From: Jonathan Tan <hidden> Date: 2021-06-01 21:34:32
Instead of using global variables to store promisor remote information,
store this config in struct repository instead, and add
repository-agnostic non-static functions corresponding to the existing
non-static functions that only work on the_repository.
The actual lazy-fetching of missing objects currently does not work on
repositories other than the_repository, and will still not work after
this commit, so add a BUG message explaining this. A subsequent commit
will remove this limitation.
Signed-off-by: Jonathan Tan <redacted>
---
promisor-remote.c | 101 +++++++++++++++++++++++++---------------------
promisor-remote.h | 20 +++++++--
repository.h | 4 ++
3 files changed, 77 insertions(+), 48 deletions(-)
@@ -235,9 +244,11 @@ int promisor_remote_get_direct(struct repository *repo,if(oid_nr==0)return0;-promisor_remote_init();+promisor_remote_init(repo);-for(r=promisors;r;r=r->next){+if(repo!=the_repository)+BUG("only the_repository is supported for now");+for(r=repo->promisor_remote_config->promisors;r;r=r->next){if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;
@@ -139,6 +140,9 @@ struct repository {/* True if commit-graph has been disabled within this process. */intcommit_graph_disabled;+/* Configurations related to promisor remotes. */+structpromisor_remote_config*promisor_remote_config;+/* Configurations *//* Indicate if a repository has a different 'commondir' from 'gitdir' */
From: Jonathan Tan <hidden> Date: 2021-06-01 21:34:35
There is a function that resets environment variables, used when
invoking a sub-process in a submodule. The lazy-fetching code (used in
partial clones) will need this function in a subsequent commit, so move
it to a more central location.
Signed-off-by: Jonathan Tan <redacted>
---
run-command.c | 10 ++++++++++
run-command.h | 7 +++++++
submodule.c | 14 ++------------
3 files changed, 19 insertions(+), 12 deletions(-)
@@ -483,4 +483,11 @@ int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn,task_finished_fn,void*pp_cb,constchar*tr2_category,constchar*tr2_label);+/**+*Conveniencefunctionthataddsentriestoenv_arraythatresetsall+*repo-specificenvironmentvariablesexceptforCONFIG_DATA_ENVIRONMENT.See+*local_repo_envincache.hformoreinformation.+*/+voidprepare_other_repo_env(structstrvec*env_array);+#endif
From: Jonathan Tan <hidden> Date: 2021-06-01 21:34:36
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
Signed-off-by: Jonathan Tan <redacted>
---
Makefile | 1 +
object-file.c | 7 ++-----
promisor-remote.c | 14 +++++++++-----
t/helper/test-partial-clone.c | 34 ++++++++++++++++++++++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 24 ++++++++++++++++++++++++
7 files changed, 72 insertions(+), 10 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&!(flags&OBJECT_INFO_SKIP_FETCH_OBJECT)){/**TODOInvestigatecheckingpromisor_remote_get_direct()*TODOreturnvalueandstoppingonerrorhere.-*TODOPassarepositorystructthrough-*promisor_remote_get_direct(),suchthatarbitrary-*repositorieswork.*/promisor_remote_get_direct(r,real,1);already_retried=1;
@@ -246,10 +252,8 @@ int promisor_remote_get_direct(struct repository *repo,promisor_remote_init(repo);-if(repo!=the_repository)-BUG("only the_repository is supported for now");for(r=repo->promisor_remote_config->promisors;r;r=r->next){-if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){+if(fetch_objects(repo,r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;remaining_nr=remove_fetched_oids(repo,&remaining_oids,
@@ -0,0 +1,34 @@+#include"cache.h"+#include"test-tool.h"+#include"repository.h"+#include"object-store.h"++staticvoidobject_info(constchar*gitdir,constchar*oid_hex)+{+structrepositoryr;+structobject_idoid;+unsignedlongsize;+structobject_infooi={.sizep=&size};+constchar*p;++if(repo_init(&r,gitdir,NULL))+die("could not init repo");+if(parse_oid_hex(oid_hex,&oid,&p))+die("could not parse oid");+if(oid_object_info_extended(&r,&oid,&oi,0))+die("could not obtain object info");+printf("%d\n",(int)size);+}++intcmd__partial_clone(intargc,constchar**argv)+{+if(argc<4)+die("too few arguments");++if(!strcmp(argv[1],"object-info"))+object_info(argv[2],argv[3]);+else+die("invalid argument '%s'",argv[1]);++return0;+}
@@ -604,6 +604,30 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+printf12345>full/file.txt&&+git-Cfulladdfile.txt&&+git-Cfullcommit-m"first commit"&&++test_config-Cfulluploadpack.allowfilter1&&+test_config-Cfulluploadpack.allowanysha1inwant1&&+gitclone--filter=blob:none--bare"file://$(pwd)/full"partial.git&&+FILE_HASH=$(githash-object--stdin<full/file.txt)&&++# Sanity check that the file is missing+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+grep"[?]$FILE_HASH"out&&++OUT=$(test-toolpartial-cloneobject-infopartial.git"$FILE_HASH")&&+test"$OUT"-eq5&&++# Sanity check that the file is now present+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+!grep"[?]$FILE_HASH"out+'+ ."$TEST_DIRECTORY"/lib-httpd.sh start_httpd
Can value ever be NULL here? I think the answer is "no, because we check
earlier in setup.c:handle_extension_v0()", but there is an implicit
conversion from xstrdup_or_null() to just xstrdup(), which would fault
if value were to be NULL.
Looking deeper, this path is a little confusing to me, since (in the
pre-image), handle_extension_v0() makes a copy of value and binds it to
data->partial_clone. But then check_repository_format_gently() makes
another copy of canidate->partial_clone (which is the same location as
data->partial_clone).
So, the extra copy is a little strange to me, because even though the
copy in handle_extension_v0() is definitely necessary, I'm not certain
that the one in set_repository_format_partial_clone() is. And this patch
removes the latter one, which I think is good. But we never free
repository_format_partial_clone.
Maybe that is added in a later patch, let's see...
Thanks,
Taylor
From: Taylor Blau <hidden> Date: 2021-06-04 20:12:39
On Tue, Jun 01, 2021 at 02:34:17PM -0700, Jonathan Tan wrote:
Instead of using global variables to store promisor remote information,
store this config in struct repository instead, and add
repository-agnostic non-static functions corresponding to the existing
non-static functions that only work on the_repository.
The actual lazy-fetching of missing objects currently does not work on
repositories other than the_repository, and will still not work after
this commit, so add a BUG message explaining this. A subsequent commit
will remove this limitation.
Makes sense to me. I found my answer to the question that I raised
during my review of the previous patch, and I think it would make sense
to address in an amended version of this patch.
Other than that, the translation all looked very faithful to me.
Ah, this is probably where I would have expected to see
r->promisor_remote_config->repository_format_partial_clone freed as
well.
I wondered whether or not that should have been freed, since on first
read it seemed that this function was mostly concerned with the list of
promisor remotes rather than the structure containing them. But on a
closer look, we are re-initializing the whole structure with
promisor_remote_init(), which runs the whole promisor_remote_config
callback again.
So I do think we want to free that part of the structure, too, before
reinitializing it. I would probably do it in promisor_remote_clear().
quoted hunk
@@ -235,9 +244,11 @@ int promisor_remote_get_direct(struct repository *repo, if (oid_nr == 0) return 0;- promisor_remote_init();+ promisor_remote_init(repo);- for (r = promisors; r; r = r->next) {+ if (repo != the_repository)+ BUG("only the_repository is supported for now");
I could go either way on whether this is worthy of a BUG() or not, but I
don't really have much of a strong feeling about it.
Thanks,
Taylor
From: Taylor Blau <hidden> Date: 2021-06-04 20:19:57
On Tue, Jun 01, 2021 at 02:34:18PM -0700, Jonathan Tan wrote:
There is a function that resets environment variables, used when
invoking a sub-process in a submodule. The lazy-fetching code (used in
partial clones) will need this function in a subsequent commit, so move
it to a more central location.
Signed-off-by: Jonathan Tan <redacted>
All seems pretty normal to me. I did have one question, though:
+/**
+ * Convenience function that adds entries to env_array that resets all
Hmm. Why "resets"? IIUC local_repo_env is the array of environment
variables that change behavior. With that understanding in mind, I
probably would have written something more like:
Convenience function which adds all GIT_* environment variables to
env_array with the exception of GIT_CONFIG_PARAMETERS. See
local_repo_env in cache.h for more information.
(Confusingly, cache.h calls this variable CONFIG_DATA_ENVIRONMENT, but
binds it to GIT_CONFIG_PARAMETERS. I think it probably makes more sense
to use the environment variable's name rather than our #define, since
we're saying "all GIT_* variables, except this one", so it would be
weird for "this one" not to start with "GIT_".
Otherwise the movement looks fine to me.
Thanks,
Taylor
On Tue, Jun 1, 2021 at 2:38 PM Jonathan Tan [off-list ref] wrote:
quoted hunk
Instead of using global variables to store promisor remote information,
store this config in struct repository instead, and add
repository-agnostic non-static functions corresponding to the existing
non-static functions that only work on the_repository.
The actual lazy-fetching of missing objects currently does not work on
repositories other than the_repository, and will still not work after
this commit, so add a BUG message explaining this. A subsequent commit
will remove this limitation.
Signed-off-by: Jonathan Tan <redacted>
---
promisor-remote.c | 101 +++++++++++++++++++++++++---------------------
promisor-remote.h | 20 +++++++--
repository.h | 4 ++
3 files changed, 77 insertions(+), 48 deletions(-)
@@ -235,9 +244,11 @@ int promisor_remote_get_direct(struct repository *repo,if(oid_nr==0)return0;-promisor_remote_init();+promisor_remote_init(repo);-for(r=promisors;r;r=r->next){+if(repo!=the_repository)+BUG("only the_repository is supported for now");+for(r=repo->promisor_remote_config->promisors;r;r=r->next){if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;
Is part of the plan for supporting partial clones within submodules to
audit the code for use of these inline wrappers and convert them over
to the repo_* variants? I'm particularly interested in the
has_promisor_remote() function, since there are calls in
diffcore-rename at least that protect that call with a check against r
== the_repository.
quoted hunk
/*
* Fetches all requested objects from all promisor remotes, trying them one at
@@ -139,6 +140,9 @@ struct repository {/* True if commit-graph has been disabled within this process. */intcommit_graph_disabled;+/* Configurations related to promisor remotes. */+structpromisor_remote_config*promisor_remote_config;+/* Configurations *//* Indicate if a repository has a different 'commondir' from 'gitdir' */--
2.32.0.rc0.204.g9fa02ecfa5-goog
Looks like a reasonable step in moving away from globals and have
repository-specific variants of these functions; I didn't spot any
problems, just one question about additional plans.
From: Taylor Blau <hidden> Date: 2021-06-04 21:26:05
On Tue, Jun 01, 2021 at 02:34:19PM -0700, Jonathan Tan wrote:
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
OK. Everything you wrote seemed reasonable to me, but I did have a
couple of questions on the test you added:
@@ -0,0 +1,34 @@+#include"cache.h"+#include"test-tool.h"+#include"repository.h"+#include"object-store.h"++staticvoidobject_info(constchar*gitdir,constchar*oid_hex)+{+structrepositoryr;+structobject_idoid;+unsignedlongsize;+structobject_infooi={.sizep=&size};+constchar*p;++if(repo_init(&r,gitdir,NULL))+die("could not init repo");+if(parse_oid_hex(oid_hex,&oid,&p))+die("could not parse oid");+if(oid_object_info_extended(&r,&oid,&oi,0))+die("could not obtain object info");+printf("%d\n",(int)size);+}
Hmm. Is there a reason that the same couldn't be implemented by calling "git
cat-file -s" from the partial clone?
@@ -604,6 +604,30 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+printf12345>full/file.txt&&+git-Cfulladdfile.txt&&+git-Cfullcommit-m"first commit"&&
This is a stylistic nit, but I think using test_commit is better here
for a non-superficial reason. My guess is that you wanted to avoid
specifying a message and file (which are required positional arguments
to test_commit before you can specify the contents). But I think there
are two good reasons to use test_commit here:
- It saves three lines of test script here.
- You don't have to make the expected size a magic number (i.e.,
because you knew ahead of time that the contents was "12345").
I probably would have expected this test to end with:
git -C full cat-file -s $FILE_HASH >expect &&
git -C partial.git cat-file -s $FILE_HASH >actual &&
test_cmp expect actual
which reads more clearly to me (although I think the much more important
test is that $FILE_HASH doesn't show up in the output of the rev-list
--missing=print that is run in the partial clone).
This works for me, although I wouldn't have been sad to see the
sub-shell contain "git -C full rev-parse HEAD:file.txt" instead.
+ # Sanity check that the file is missing
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ grep "[?]$FILE_HASH" out &&
+
+ OUT=$(test-tool partial-clone object-info partial.git "$FILE_HASH") &&
Coming back to my point about the utility of the partial-clone helper,
could this be replaced by saying just OUT="$(git -C partial.git cat-file
-s "$FILE_HASH")" instead?
Thanks,
Taylor
On Tue, Jun 1, 2021 at 2:38 PM Jonathan Tan [off-list ref] wrote:
quoted hunk
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
Signed-off-by: Jonathan Tan <redacted>
---
Makefile | 1 +
object-file.c | 7 ++-----
promisor-remote.c | 14 +++++++++-----
t/helper/test-partial-clone.c | 34 ++++++++++++++++++++++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 24 ++++++++++++++++++++++++
7 files changed, 72 insertions(+), 10 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&
So here you removed the special check against the_repository while
looking for promisor_remotes. There are other such special checks in
the code; I also see:
diff.c: if (options->repo == the_repository && has_promisor_remote() &&
diffcore-break.c: if (r == the_repository && has_promisor_remote()) {
diffcore-rename.c: if (r == the_repository && has_promisor_remote()) {
and a series I'm planning to submit soon will add another to merge.ort.c.
Do these need to all be fixed as part of the partial clone submodule
support as well? Do I need to change anything about my series? I
guess since I'm asking that, I should probably submit it first so you
can actually see it and answer my question. (And the timing may be
good since the area is fresh in your memory...)
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
/*
* TODO Investigate checking promisor_remote_get_direct()
* TODO return value and stopping on error here.
- * TODO Pass a repository struct through
- * promisor_remote_get_direct(), such that arbitrary
- * repositories work.
Odd, it appears that when this comment was added (in commit b14ed5adaf
("Use promisor_remote_get_direct() and has_promisor_remote()",
2019-06-25)), a repository was passed to promisor_remote_get_direct().
Sure, it was just a transliteration of the comment that was there
before when fetch_objects() was the function being called, but since
the code was being changed and the comment being updated, it seems the
TODO should have been removed back then.
Oh, well, good to update it now at least.
@@ -246,10 +252,8 @@ int promisor_remote_get_direct(struct repository *repo,promisor_remote_init(repo);-if(repo!=the_repository)-BUG("only the_repository is supported for now");for(r=repo->promisor_remote_config->promisors;r;r=r->next){-if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){+if(fetch_objects(repo,r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;remaining_nr=remove_fetched_oids(repo,&remaining_oids,
@@ -0,0 +1,34 @@+#include"cache.h"+#include"test-tool.h"+#include"repository.h"+#include"object-store.h"++staticvoidobject_info(constchar*gitdir,constchar*oid_hex)+{+structrepositoryr;+structobject_idoid;+unsignedlongsize;+structobject_infooi={.sizep=&size};+constchar*p;++if(repo_init(&r,gitdir,NULL))+die("could not init repo");+if(parse_oid_hex(oid_hex,&oid,&p))+die("could not parse oid");+if(oid_object_info_extended(&r,&oid,&oi,0))+die("could not obtain object info");+printf("%d\n",(int)size);+}++intcmd__partial_clone(intargc,constchar**argv)+{+if(argc<4)+die("too few arguments");++if(!strcmp(argv[1],"object-info"))+object_info(argv[2],argv[3]);+else+die("invalid argument '%s'",argv[1]);++return0;+}
@@ -604,6 +604,30 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+printf12345>full/file.txt&&+git-Cfulladdfile.txt&&+git-Cfullcommit-m"first commit"&&++test_config-Cfulluploadpack.allowfilter1&&+test_config-Cfulluploadpack.allowanysha1inwant1&&+gitclone--filter=blob:none--bare"file://$(pwd)/full"partial.git&&+FILE_HASH=$(githash-object--stdin<full/file.txt)&&++# Sanity check that the file is missing+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+grep"[?]$FILE_HASH"out&&++OUT=$(test-toolpartial-cloneobject-infopartial.git"$FILE_HASH")&&+test"$OUT"-eq5&&++# Sanity check that the file is now present+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+!grep"[?]$FILE_HASH"out+'+ ."$TEST_DIRECTORY"/lib-httpd.sh start_httpd--
Hi,
On Tue, Jun 1, 2021 at 2:38 PM Jonathan Tan [off-list ref] wrote:
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
@@ -0,0 +1,34 @@+#include"cache.h"+#include"test-tool.h"+#include"repository.h"+#include"object-store.h"++staticvoidobject_info(constchar*gitdir,constchar*oid_hex)+{+structrepositoryr;+structobject_idoid;+unsignedlongsize;+structobject_infooi={.sizep=&size};+constchar*p;++if(repo_init(&r,gitdir,NULL))+die("could not init repo");+if(parse_oid_hex(oid_hex,&oid,&p))+die("could not parse oid");+if(oid_object_info_extended(&r,&oid,&oi,0))+die("could not obtain object info");+printf("%d\n",(int)size);+}++intcmd__partial_clone(intargc,constchar**argv)+{+if(argc<4)+die("too few arguments");++if(!strcmp(argv[1],"object-info"))+object_info(argv[2],argv[3]);+else+die("invalid argument '%s'",argv[1]);++return0;+}
@@ -604,6 +604,30 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+printf12345>full/file.txt&&+git-Cfulladdfile.txt&&+git-Cfullcommit-m"first commit"&&++test_config-Cfulluploadpack.allowfilter1&&+test_config-Cfulluploadpack.allowanysha1inwant1&&+gitclone--filter=blob:none--bare"file://$(pwd)/full"partial.git&&+FILE_HASH=$(githash-object--stdin<full/file.txt)&&++# Sanity check that the file is missing+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+grep"[?]$FILE_HASH"out&&++OUT=$(test-toolpartial-cloneobject-infopartial.git"$FILE_HASH")&&+test"$OUT"-eq5&&++# Sanity check that the file is now present+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+!grep"[?]$FILE_HASH"out+'+
Turns out that this test fails under GIT_TEST_DEFAULT_HASH=sha256; output:
error: wrong index v2 file size in /home/newren/floss/git/t/trash
directory.t0410-partial-clone/partial.git/objects/pack/pack-66a15be115d740341216938fb7abb31902e960bd6d464829d85164d1a4a25bec.idx
error: wrong index v2 file size in /home/newren/floss/git/t/trash
directory.t0410-partial-clone/partial.git/objects/pack/pack-66a15be115d740341216938fb7abb31902e960bd6d464829d85164d1a4a25bec.idx
fatal: couldn't find remote ref 74242c6e4a0d89f454d89d3496a1f7cb3f1f39f0
error: wrong index v2 file size in /home/newren/floss/git/t/trash
directory.t0410-partial-clone/partial.git/objects/pack/pack-66a15be115d740341216938fb7abb31902e960bd6d464829d85164d1a4a25bec.idx
error: wrong index v2 file size in /home/newren/floss/git/t/trash
directory.t0410-partial-clone/partial.git/objects/pack/pack-66a15be115d740341216938fb7abb31902e960bd6d464829d85164d1a4a25bec.idx
fatal: could not obtain object info
Can value ever be NULL here? I think the answer is "no, because we check
earlier in setup.c:handle_extension_v0()", but there is an implicit
conversion from xstrdup_or_null() to just xstrdup(), which would fault
if value were to be NULL.
Ah, good catch. I think you're right, but it's better to be defensive
here. I'll add that check and also say that this will be caught by
setup.c.
Looking deeper, this path is a little confusing to me, since (in the
pre-image), handle_extension_v0() makes a copy of value and binds it to
data->partial_clone. But then check_repository_format_gently() makes
another copy of canidate->partial_clone (which is the same location as
data->partial_clone).
So, the extra copy is a little strange to me, because even though the
copy in handle_extension_v0() is definitely necessary, I'm not certain
that the one in set_repository_format_partial_clone() is. And this patch
removes the latter one, which I think is good. But we never free
repository_format_partial_clone.
Yes, it's also a simplification that we go straight from config to
variable here, instead of going through the candidate struct. As for
freeing repository_format_partial_clone, this is run once and never
again (guarded by "initialized" check) so there is no prior value to
free, and I don't think this variable needs to be freed.
Maybe that is added in a later patch, let's see...
So I think things are fine here, but in a later patch,
repository_format_partial_clone is moved to the struct repository, which
can be cleared with repo_clear(). I'll need to add a free there :-)
From: Jonathan Tan <hidden> Date: 2021-06-05 01:44:59
On Tue, Jun 01, 2021 at 02:34:17PM -0700, Jonathan Tan wrote:
quoted
Instead of using global variables to store promisor remote information,
store this config in struct repository instead, and add
repository-agnostic non-static functions corresponding to the existing
non-static functions that only work on the_repository.
The actual lazy-fetching of missing objects currently does not work on
repositories other than the_repository, and will still not work after
this commit, so add a BUG message explaining this. A subsequent commit
will remove this limitation.
Makes sense to me. I found my answer to the question that I raised
during my review of the previous patch, and I think it would make sense
to address in an amended version of this patch.
Just to clarify, what is the question and what is the answer?
Other than that, the translation all looked very faithful to me.
Ah, this is probably where I would have expected to see
r->promisor_remote_config->repository_format_partial_clone freed as
well.
I wondered whether or not that should have been freed, since on first
read it seemed that this function was mostly concerned with the list of
promisor remotes rather than the structure containing them. But on a
closer look, we are re-initializing the whole structure with
promisor_remote_init(), which runs the whole promisor_remote_config
callback again.
So I do think we want to free that part of the structure, too, before
reinitializing it. I would probably do it in promisor_remote_clear().
I'll add that in the next version.
quoted
@@ -235,9 +244,11 @@ int promisor_remote_get_direct(struct repository *repo, if (oid_nr == 0) return 0;- promisor_remote_init();+ promisor_remote_init(repo);- for (r = promisors; r; r = r->next) {+ if (repo != the_repository)+ BUG("only the_repository is supported for now");
I could go either way on whether this is worthy of a BUG() or not, but I
don't really have much of a strong feeling about it.
This BUG() will be removed in patch 4. I'm OK either way (adding BUG()
here and removing it in patch 4, or never adding BUG() in the first
place).
Is part of the plan for supporting partial clones within submodules to
audit the code for use of these inline wrappers and convert them over
to the repo_* variants? I'm particularly interested in the
has_promisor_remote() function, since there are calls in
diffcore-rename at least that protect that call with a check against r
== the_repository.
Good point. Yes, that should be part of the plan - at least, we should
see what those invocations are for.
quoted
@@ -139,6 +140,9 @@ struct repository { /* True if commit-graph has been disabled within this process. */ int commit_graph_disabled;+ /* Configurations related to promisor remotes. */+ struct promisor_remote_config *promisor_remote_config;+ /* Configurations */ /* Indicate if a repository has a different 'commondir' from 'gitdir' */--
2.32.0.rc0.204.g9fa02ecfa5-goog
Looks like a reasonable step in moving away from globals and have
repository-specific variants of these functions; I didn't spot any
problems, just one question about additional plans.
From: Jonathan Tan <hidden> Date: 2021-06-05 01:57:46
On Tue, Jun 01, 2021 at 02:34:18PM -0700, Jonathan Tan wrote:
quoted
There is a function that resets environment variables, used when
invoking a sub-process in a submodule. The lazy-fetching code (used in
partial clones) will need this function in a subsequent commit, so move
it to a more central location.
Signed-off-by: Jonathan Tan <redacted>
All seems pretty normal to me. I did have one question, though:
quoted
+/**
+ * Convenience function that adds entries to env_array that resets all
Hmm. Why "resets"? IIUC local_repo_env is the array of environment
variables that change behavior. With that understanding in mind, I
probably would have written something more like:
Convenience function which adds all GIT_* environment variables to
env_array with the exception of GIT_CONFIG_PARAMETERS. See
local_repo_env in cache.h for more information.
I mentioned "reset" because the effect of adding the name without any
value makes the environment variable of that name unset in the
subprocess. I'll word it as you say, and add "When used as the env_array
of a subprocess, these entries cause the corresponding environment
variables to be unset in the subprocess." after the first sentence.
(Confusingly, cache.h calls this variable CONFIG_DATA_ENVIRONMENT, but
binds it to GIT_CONFIG_PARAMETERS. I think it probably makes more sense
to use the environment variable's name rather than our #define, since
we're saying "all GIT_* variables, except this one", so it would be
weird for "this one" not to start with "GIT_".
OK, that makes sense.
Otherwise the movement looks fine to me.
Thanks,
Taylor
From: Jonathan Tan <hidden> Date: 2021-06-05 02:11:15
quoted
+static void object_info(const char *gitdir, const char *oid_hex)
+{
+ struct repository r;
+ struct object_id oid;
+ unsigned long size;
+ struct object_info oi = {.sizep = &size};
+ const char *p;
+
+ if (repo_init(&r, gitdir, NULL))
+ die("could not init repo");
+ if (parse_oid_hex(oid_hex, &oid, &p))
+ die("could not parse oid");
+ if (oid_object_info_extended(&r, &oid, &oi, 0))
+ die("could not obtain object info");
+ printf("%d\n", (int) size);
+}
Hmm. Is there a reason that the same couldn't be implemented by calling "git
cat-file -s" from the partial clone?
I don't think "git cat-file" (when run in the superproject) by itself
can access an object from a submodule. "git -C name_of_submodule
cat-file $HASH" would access that object, but I specifically want to
test oid_object_info_extended() on a repo that is not the_repository
(which would not work with -C, because the_repository would then be the
submodule).
quoted
+test_expect_success 'lazy-fetch when accessing object not in the_repository' '
+ rm -rf full partial.git &&
+ test_create_repo full &&
+ printf 12345 >full/file.txt &&
+ git -C full add file.txt &&
+ git -C full commit -m "first commit" &&
This is a stylistic nit, but I think using test_commit is better here
for a non-superficial reason. My guess is that you wanted to avoid
specifying a message and file (which are required positional arguments
to test_commit before you can specify the contents). But I think there
are two good reasons to use test_commit here:
- It saves three lines of test script here.
- You don't have to make the expected size a magic number (i.e.,
because you knew ahead of time that the contents was "12345").
I probably would have expected this test to end with:
git -C full cat-file -s $FILE_HASH >expect &&
git -C partial.git cat-file -s $FILE_HASH >actual &&
test_cmp expect actual
which reads more clearly to me (although I think the much more important
test is that $FILE_HASH doesn't show up in the output of the rev-list
--missing=print that is run in the partial clone).
This works for me, although I wouldn't have been sad to see the
sub-shell contain "git -C full rev-parse HEAD:file.txt" instead.
I'll do this too.
quoted
+ # Sanity check that the file is missing
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ grep "[?]$FILE_HASH" out &&
+
+ OUT=$(test-tool partial-clone object-info partial.git "$FILE_HASH") &&
Coming back to my point about the utility of the partial-clone helper,
could this be replaced by saying just OUT="$(git -C partial.git cat-file
-s "$FILE_HASH")" instead?
Thanks,
Taylor
Same answer as above - I specifically want to test accessing (and
thereby lazy-fetching) an object when the object is not in
the_repository. I'll add some documentation to explain what it does and
that it's equivalent to using "git -C repo cat-file -s", except that
this specifically tests another code path.
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&
So here you removed the special check against the_repository while
looking for promisor_remotes. There are other such special checks in
the code; I also see:
diff.c: if (options->repo == the_repository && has_promisor_remote() &&
diffcore-break.c: if (r == the_repository && has_promisor_remote()) {
diffcore-rename.c: if (r == the_repository && has_promisor_remote()) {
and a series I'm planning to submit soon will add another to merge.ort.c.
Do these need to all be fixed as part of the partial clone submodule
support as well? Do I need to change anything about my series? I
guess since I'm asking that, I should probably submit it first so you
can actually see it and answer my question. (And the timing may be
good since the area is fresh in your memory...)
Thanks for raising this. Looking at the 3 you listed, they all have to
do with prefetching. This is fine both now and later. Now, since partial
clones in submodules still don't work, any fetching of any sort (pre- or
not) will not work. Later, since this prefetching is just an
optimization. (Of course, we should come back and add prefetching for
submodule partial clones, but that is an optimization, not a correctness
issue.)
quoted
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
/*
* TODO Investigate checking promisor_remote_get_direct()
* TODO return value and stopping on error here.
- * TODO Pass a repository struct through
- * promisor_remote_get_direct(), such that arbitrary
- * repositories work.
Odd, it appears that when this comment was added (in commit b14ed5adaf
("Use promisor_remote_get_direct() and has_promisor_remote()",
2019-06-25)), a repository was passed to promisor_remote_get_direct().
Sure, it was just a transliteration of the comment that was there
before when fetch_objects() was the function being called, but since
the code was being changed and the comment being updated, it seems the
TODO should have been removed back then.
Oh, well, good to update it now at least.
Yes - perhaps the comment was emphasizing the "such that arbitrary
repositories work" part. But anyway, yes, it is now removed.
[snip]
From: Jonathan Tan <hidden> Date: 2021-06-05 02:17:15
Turns out that this test fails under GIT_TEST_DEFAULT_HASH=sha256; output:
error: wrong index v2 file size in /home/newren/floss/git/t/trash
directory.t0410-partial-clone/partial.git/objects/pack/pack-66a15be115d740341216938fb7abb31902e960bd6d464829d85164d1a4a25bec.idx
error: wrong index v2 file size in /home/newren/floss/git/t/trash
directory.t0410-partial-clone/partial.git/objects/pack/pack-66a15be115d740341216938fb7abb31902e960bd6d464829d85164d1a4a25bec.idx
fatal: couldn't find remote ref 74242c6e4a0d89f454d89d3496a1f7cb3f1f39f0
error: wrong index v2 file size in /home/newren/floss/git/t/trash
directory.t0410-partial-clone/partial.git/objects/pack/pack-66a15be115d740341216938fb7abb31902e960bd6d464829d85164d1a4a25bec.idx
error: wrong index v2 file size in /home/newren/floss/git/t/trash
directory.t0410-partial-clone/partial.git/objects/pack/pack-66a15be115d740341216938fb7abb31902e960bd6d464829d85164d1a4a25bec.idx
fatal: could not obtain object info
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&
So here you removed the special check against the_repository while
looking for promisor_remotes. There are other such special checks in
the code; I also see:
diff.c: if (options->repo == the_repository && has_promisor_remote() &&
diffcore-break.c: if (r == the_repository && has_promisor_remote()) {
diffcore-rename.c: if (r == the_repository && has_promisor_remote()) {
and a series I'm planning to submit soon will add another to merge.ort.c.
Do these need to all be fixed as part of the partial clone submodule
support as well? Do I need to change anything about my series? I
guess since I'm asking that, I should probably submit it first so you
can actually see it and answer my question. (And the timing may be
good since the area is fresh in your memory...)
On Tue, Jun 01, 2021 at 02:34:16PM -0700, Jonathan Tan wrote:
Currently, the reading of config related to promisor remotes is done in
two places: once in setup.c (which sets the global variable
repository_format_partial_clone, to be read by the code in
promisor-remote.c), and once in promisor-remote.c. This means that care
must be taken to ensure that repository_format_partial_clone is set
before any code in promisor-remote.c accesses it.
To simplify the code, move all such config reading to promisor-remote.c.
By doing this, it will be easier to see when
repository_format_partial_clone is written and, thus, to reason about
the code. This will be especially helpful in a subsequent commit, which
modifies this code.
Do we reliably call promisor-remote.c:promisor_remote_config()? It's
called only during promisor_remote_init(), which happens if we call
something like promisor_remote_get_direct(), and I guess we call that
one unconditionally (e.g. there's no "if (partial_clone)
promisor_remote_get_direct();" that I saw in a brief glance) then it's
OK.
quoted hunk
@@ -1061,7 +1061,6 @@ extern int repository_format_worktree_config; struct repository_format { int version; int precious_objects;- char *partial_clone; /* value of extensions.partialclone */
I also don't see that this repository_format.partial_clone value gets
checked anywhere anyways - I only see where it's set and freed in a
brief grep - so this seems fine to me.
I saw Taylor's comment about NULL-ness and other than that, this patch
looks good to me.
Reviewed-by: Emily Shaffer <redacted>
From: Jonathan Tan <hidden> Date: 2021-06-08 00:26:24
There is a function that resets environment variables, used when
invoking a sub-process in a submodule. The lazy-fetching code (used in
partial clones) will need this function in a subsequent commit, so move
it to a more central location.
Signed-off-by: Jonathan Tan <redacted>
---
run-command.c | 10 ++++++++++
run-command.h | 9 +++++++++
submodule.c | 14 ++------------
3 files changed, 21 insertions(+), 12 deletions(-)
@@ -483,4 +483,13 @@ int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn,task_finished_fn,void*pp_cb,constchar*tr2_category,constchar*tr2_label);+/**+*ConveniencefunctionwhichaddsallGIT_*environmentvariablestoenv_array+*withtheexceptionofGIT_CONFIG_PARAMETERS.Whenusedastheenv_arrayofa+*subprocess,theseentriescausethecorrespondingenvironmentvariablesto+*beunsetinthesubprocess.Seelocal_repo_envincache.hformore+*information.+*/+voidprepare_other_repo_env(structstrvec*env_array);+#endif
From: Jonathan Tan <hidden> Date: 2021-06-08 00:26:24
Instead of using global variables to store promisor remote information,
store this config in struct repository instead, and add
repository-agnostic non-static functions corresponding to the existing
non-static functions that only work on the_repository.
The actual lazy-fetching of missing objects currently does not work on
repositories other than the_repository, and will still not work after
this commit, so add a BUG message explaining this. A subsequent commit
will remove this limitation.
Signed-off-by: Jonathan Tan <redacted>
---
promisor-remote.c | 103 ++++++++++++++++++++++++++--------------------
promisor-remote.h | 22 ++++++++--
repository.c | 6 +++
repository.h | 4 ++
4 files changed, 87 insertions(+), 48 deletions(-)
@@ -239,9 +250,11 @@ int promisor_remote_get_direct(struct repository *repo,if(oid_nr==0)return0;-promisor_remote_init();+promisor_remote_init(repo);-for(r=promisors;r;r=r->next){+if(repo!=the_repository)+BUG("only the_repository is supported for now");+for(r=repo->promisor_remote_config->promisors;r;r=r->next){if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;
@@ -11,6 +11,7 @@#include"lockfile.h"#include"submodule-config.h"#include"sparse-index.h"+#include"promisor-remote.h"/* The main repository */staticstructrepositorythe_repo;
@@ -139,6 +140,9 @@ struct repository {/* True if commit-graph has been disabled within this process. */intcommit_graph_disabled;+/* Configurations related to promisor remotes. */+structpromisor_remote_config*promisor_remote_config;+/* Configurations *//* Indicate if a repository has a different 'commondir' from 'gitdir' */
From: Jonathan Tan <hidden> Date: 2021-06-08 00:26:25
Currently, the reading of config related to promisor remotes is done in
two places: once in setup.c (which sets the global variable
repository_format_partial_clone, to be read by the code in
promisor-remote.c), and once in promisor-remote.c. This means that care
must be taken to ensure that repository_format_partial_clone is set
before any code in promisor-remote.c accesses it.
To simplify the code, move all such config reading to promisor-remote.c.
By doing this, it will be easier to see when
repository_format_partial_clone is written and, thus, to reason about
the code. This will be especially helpful in a subsequent commit, which
modifies this code.
Signed-off-by: Jonathan Tan <redacted>
---
cache.h | 1 -
promisor-remote.c | 14 +++++++++-----
promisor-remote.h | 6 ------
setup.c | 10 +++++++---
4 files changed, 16 insertions(+), 15 deletions(-)
@@ -1061,7 +1061,6 @@ extern int repository_format_worktree_config;structrepository_format{intversion;intprecious_objects;-char*partial_clone;/* value of extensions.partialclone */intworktree_config;intis_bare;inthash_algo;
From: Jonathan Tan <hidden> Date: 2021-06-08 00:27:23
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
Signed-off-by: Jonathan Tan <redacted>
---
Makefile | 1 +
object-file.c | 7 ++----
promisor-remote.c | 14 ++++++++----
t/helper/test-partial-clone.c | 43 +++++++++++++++++++++++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 23 +++++++++++++++++++
7 files changed, 80 insertions(+), 10 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&!(flags&OBJECT_INFO_SKIP_FETCH_OBJECT)){/**TODOInvestigatecheckingpromisor_remote_get_direct()*TODOreturnvalueandstoppingonerrorhere.-*TODOPassarepositorystructthrough-*promisor_remote_get_direct(),suchthatarbitrary-*repositorieswork.*/promisor_remote_get_direct(r,real,1);already_retried=1;
@@ -252,10 +258,8 @@ int promisor_remote_get_direct(struct repository *repo,promisor_remote_init(repo);-if(repo!=the_repository)-BUG("only the_repository is supported for now");for(r=repo->promisor_remote_config->promisors;r;r=r->next){-if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){+if(fetch_objects(repo,r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;remaining_nr=remove_fetched_oids(repo,&remaining_oids,
@@ -604,6 +604,29 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+test_commit-Cfullcreate-a-filefile.txt&&++test_config-Cfulluploadpack.allowfilter1&&+test_config-Cfulluploadpack.allowanysha1inwant1&&+gitclone--filter=blob:none--bare"file://$(pwd)/full"partial.git&&+FILE_HASH=$(git-Cfullrev-parseHEAD:file.txt)&&++# Sanity check that the file is missing+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+grep"[?]$FILE_HASH"out&&++git-Cfullcat-file-s"$FILE_HASH">expect&&+test-toolpartial-cloneobject-infopartial.git"$FILE_HASH">actual&&+test_cmpexpectactual&&++# Sanity check that the file is now present+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+!grep"[?]$FILE_HASH"out+'+ ."$TEST_DIRECTORY"/lib-httpd.sh start_httpd
On Tue, Jun 01, 2021 at 02:34:17PM -0700, Jonathan Tan wrote:
Instead of using global variables to store promisor remote information,
store this config in struct repository instead, and add
repository-agnostic non-static functions corresponding to the existing
non-static functions that only work on the_repository.
Hm. Am I the only one who doesn't like assigning from the result of an
assignment like this? ...Based on 'git grep "=[^=]\+=[^=]"' yes, I am the
only one :)
Overall this patch looks OK to me, but I see that there are some changes
suggested for the next version, so I'll hold off on a reviewed-by so I
can have a look at those too.
- Emily
On Tue, Jun 01, 2021 at 02:34:18PM -0700, Jonathan Tan wrote:
quoted hunk
There is a function that resets environment variables, used when
invoking a sub-process in a submodule. The lazy-fetching code (used in
partial clones) will need this function in a subsequent commit, so move
it to a more central location.
Signed-off-by: Jonathan Tan <redacted>
---
run-command.c | 10 ++++++++++
run-command.h | 7 +++++++
submodule.c | 14 ++------------
3 files changed, 19 insertions(+), 12 deletions(-)
@@ -483,4 +483,11 @@ int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn,task_finished_fn,void*pp_cb,constchar*tr2_category,constchar*tr2_label);+/**+*Conveniencefunctionthataddsentriestoenv_arraythatresetsall+*repo-specificenvironmentvariablesexceptforCONFIG_DATA_ENVIRONMENT.See+*local_repo_envincache.hformoreinformation.+*/+voidprepare_other_repo_env(structstrvec*env_array);
This call was used in less places than I thought (I guess that's part of
why you're making it more public/central), so my worry about having some
large scale change was for nothing.
As for Taylor's comment about the CONFIG_DATA_ENVIRONMENT variable, it
was named like that before you got here, so I am not too worried whether
or not you change it.
Reviewed-by: Emily Shaffer <redacted>
On Tue, Jun 01, 2021 at 02:34:19PM -0700, Jonathan Tan wrote:
quoted hunk
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
Signed-off-by: Jonathan Tan <redacted>
---
Makefile | 1 +
object-file.c | 7 ++-----
promisor-remote.c | 14 +++++++++-----
t/helper/test-partial-clone.c | 34 ++++++++++++++++++++++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 24 ++++++++++++++++++++++++
7 files changed, 72 insertions(+), 10 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&
So we remove the explicit "if we've got promisors and are operating on
the repo we launched in" and instead ask "if the repo we're operating on
has promisors" - definitely a step towards in-process submodule
happiness :)
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
/*
* TODO Investigate checking promisor_remote_get_direct()
* TODO return value and stopping on error here.
- * TODO Pass a repository struct through
- * promisor_remote_get_direct(), such that arbitrary
- * repositories work.
*/
promisor_remote_get_direct(r, real, 1);
And this seems like a stale comment, since I see we were already passing
'r' here. But arbitrary repositories still don't just work, right? Or, I
guess your point was "partial clone + submodules don't just work,
because of the alternates thing" - so maybe this part is OK?
Should this change have happened when we added 'r' to
promisor_remote_init? If r==the_repository then there's no difference
between these two calls, right?
@@ -0,0 +1,34 @@+#include"cache.h"+#include"test-tool.h"+#include"repository.h"+#include"object-store.h"++staticvoidobject_info(constchar*gitdir,constchar*oid_hex)+{+structrepositoryr;+structobject_idoid;+unsignedlongsize;+structobject_infooi={.sizep=&size};+constchar*p;++if(repo_init(&r,gitdir,NULL))+die("could not init repo");+if(parse_oid_hex(oid_hex,&oid,&p))+die("could not parse oid");+if(oid_object_info_extended(&r,&oid,&oi,0))+die("could not obtain object info");+printf("%d\n",(int)size);+}++intcmd__partial_clone(intargc,constchar**argv)+{+if(argc<4)+die("too few arguments");++if(!strcmp(argv[1],"object-info"))+object_info(argv[2],argv[3]);+else+die("invalid argument '%s'",argv[1]);++return0;+}
@@ -604,6 +604,30 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+printf12345>full/file.txt&&+git-Cfulladdfile.txt&&+git-Cfullcommit-m"first commit"&&
I think there is some test_commit or similar function here that's more
commonly used, right?
+
+ test_config -C full uploadpack.allowfilter 1 &&
+ test_config -C full uploadpack.allowanysha1inwant 1 &&
I wasn't sure what these configs are for, but it looks like .allowfilter
is to allow 'full' to serve as a remote to a partial clone. But what do
you need .allowAnySha1InWant for here? Are we expecting to ask for SHAs
that 'full' doesn't have?
+ git clone --filter=blob:none --bare "file://$(pwd)/full" partial.git &&
+ FILE_HASH=$(git hash-object --stdin <full/file.txt) &&
+
+ # Sanity check that the file is missing
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ grep "[?]$FILE_HASH" out &&
+
+ OUT=$(test-tool partial-clone object-info partial.git "$FILE_HASH") &&
+ test "$OUT" -eq 5 &&
Hm. I guess I am confused about why this fetches the desired object into
partial.git. Maybe the test-helper needs a comment (and maybe here too)
on the line where fetch will be triggered?
+
+ # Sanity check that the file is now present
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ ! grep "[?]$FILE_HASH" out
On Tue, Jun 01, 2021 at 02:34:15PM -0700, Jonathan Tan wrote:
This is a preliminary step towards supporting partial clone submodules
(e.g., by cloning with --recurse-submodules and having the given filter
propagate to submodules). Even with this patch set, we won't be there
yet (notably, some code in Git access objects in submodules by adding
them as alternates - so lazy-fetching missing objects in submodules
wouldn't work here), but at least this is a first step.
This patch set would also be useful if Git needed to operate on
other repositories (other than in the submodule case), but I can't think
of such a situation right now.
As mentioned, there is still more work that needs to be done. Any help
is appreciated, and as for me, I hope to get back to this in the 3rd
quarter of the year.
I see there's a v2 that came while I was still reviewing, oops. But
overall I like this series:
- It's small
- It does reasonable code cleanup which benefits the codebase on its
own
- It paves the way for a series later on without being part of that
series, meaning that the later series will be slightly smaller
because of it (a lesson I should learn for myself)
Thanks. I'll try and review v2 later in the week.
- Emily
On Mon, Jun 7, 2021 at 5:26 PM Jonathan Tan [off-list ref] wrote:
quoted hunk
Currently, the reading of config related to promisor remotes is done in
two places: once in setup.c (which sets the global variable
repository_format_partial_clone, to be read by the code in
promisor-remote.c), and once in promisor-remote.c. This means that care
must be taken to ensure that repository_format_partial_clone is set
before any code in promisor-remote.c accesses it.
To simplify the code, move all such config reading to promisor-remote.c.
By doing this, it will be easier to see when
repository_format_partial_clone is written and, thus, to reason about
the code. This will be especially helpful in a subsequent commit, which
modifies this code.
Signed-off-by: Jonathan Tan <redacted>
---
cache.h | 1 -
promisor-remote.c | 14 +++++++++-----
promisor-remote.h | 6 ------
setup.c | 10 +++++++---
4 files changed, 16 insertions(+), 15 deletions(-)
@@ -1061,7 +1061,6 @@ extern int repository_format_worktree_config;structrepository_format{intversion;intprecious_objects;-char*partial_clone;/* value of extensions.partialclone */intworktree_config;intis_bare;inthash_algo;
This is actually slightly hard to parse out. I was trying to figure
out where repository_format_partial_clone was initialized, and it's
not handled when value is NULL in handle_extension_v0; it's the fact
that repository_format_partial_clone is declared a static global
variable.
But in the next patch you make it a member of struct
promisor_remote_config, and instead rely on the xcalloc call in
promisor_remote_init().
That means everything is properly initialized and you haven't made any
mistakes here, but the logic is a bit hard to follow. Perhaps it'd be
nicer to just write this as
+ if (!strcmp(var, "extensions.partialclone")) {
+ repository_format_partial_clone = xstrdup_or_null(value);
+ return 0;
+ }
which makes the code shorter and easier to follow, at least for me.
On Mon, Jun 7, 2021 at 5:26 PM Jonathan Tan [off-list ref] wrote:
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
I wonder if this commit message is a good place to call out that we
also want to eventually audit codepaths using the old
has_promisor_remote() wrapper function (particularly the ones
protected by a repo == the_repository check) as well.
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&!(flags&OBJECT_INFO_SKIP_FETCH_OBJECT)){/**TODOInvestigatecheckingpromisor_remote_get_direct()*TODOreturnvalueandstoppingonerrorhere.-*TODOPassarepositorystructthrough-*promisor_remote_get_direct(),suchthatarbitrary-*repositorieswork.*/promisor_remote_get_direct(r,real,1);already_retried=1;
@@ -252,10 +258,8 @@ int promisor_remote_get_direct(struct repository *repo,promisor_remote_init(repo);-if(repo!=the_repository)-BUG("only the_repository is supported for now");for(r=repo->promisor_remote_config->promisors;r;r=r->next){-if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){+if(fetch_objects(repo,r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;remaining_nr=remove_fetched_oids(repo,&remaining_oids,
@@ -604,6 +604,29 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+test_commit-Cfullcreate-a-filefile.txt&&++test_config-Cfulluploadpack.allowfilter1&&+test_config-Cfulluploadpack.allowanysha1inwant1&&+gitclone--filter=blob:none--bare"file://$(pwd)/full"partial.git&&+FILE_HASH=$(git-Cfullrev-parseHEAD:file.txt)&&++# Sanity check that the file is missing+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+grep"[?]$FILE_HASH"out&&++git-Cfullcat-file-s"$FILE_HASH">expect&&+test-toolpartial-cloneobject-infopartial.git"$FILE_HASH">actual&&+test_cmpexpectactual&&++# Sanity check that the file is now present+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+!grep"[?]$FILE_HASH"out+'+ ."$TEST_DIRECTORY"/lib-httpd.sh start_httpd--
On Mon, Jun 7, 2021 at 5:26 PM Jonathan Tan [off-list ref] wrote:
Thanks everyone for your reviews. I believe I've addressed all review
comments, including the one from Elijah about the test failing with
sha256 (which turns out to be because I didn't add a call to
setup_git_directory(), which the other test helpers do).
Thanks for fixing those up. I spotted some minor nits/questions, but
nothing big.
Looks like Junio did spot some bigger items...which raises a question
for me. I have a series
(https://lore.kernel.org/git/pull.969.git.1622856485.gitgitgadget@gmail.com/)
that also touches partial clones. Our series are semantically
independent, but we both add a repository parameter to
fetch_objects(). So we both make the same change, but you also make
additional nearby changes, resulting in two trivial conflicts. So,
should I rebase my series on yours, should you rebase on mine, or
should we just let both proceed independently and double-check Junio
resolves the trivial conflicts in favor of your side?
Thoughts?
From: Jonathan Tan <hidden> Date: 2021-06-09 04:44:47
quoted
@@ -99,6 +94,15 @@ static int promisor_remote_config(const char *var, const char *value, void *data size_t namelen; const char *subkey;+ if (!strcmp(var, "extensions.partialclone")) {+ /*+ * NULL value is handled in handle_extension_v0 in setup.c.+ */+ if (value)+ repository_format_partial_clone = xstrdup(value);+ return 0;+ }
This is actually slightly hard to parse out. I was trying to figure
out where repository_format_partial_clone was initialized, and it's
not handled when value is NULL in handle_extension_v0; it's the fact
that repository_format_partial_clone is declared a static global
variable.
But in the next patch you make it a member of struct
promisor_remote_config, and instead rely on the xcalloc call in
promisor_remote_init().
That means everything is properly initialized and you haven't made any
mistakes here, but the logic is a bit hard to follow. Perhaps it'd be
nicer to just write this as
+ if (!strcmp(var, "extensions.partialclone")) {
+ repository_format_partial_clone = xstrdup_or_null(value);
+ return 0;
+ }
which makes the code shorter and easier to follow, at least for me.
Hmm...is your concern about the case in which
repository_format_partial_clone is uninitialized, or about ignoring a
potential NULL value? If the former, I don't see how your suggestion
fixes things, since extensions.partialclone may never have been in the
config in the first place (and would thus leave
repository_format_partial_clone uninitialized, if it weren't for the
fact that it is in static storage and thus initialized to 0). If the
latter, I guess I should be more detailed about how it's being handled
in setup.c (or maybe just leave out the comment altogether - the code
here can handle a NULL repository_format_partial_clone for some reason).
From: Jonathan Tan <hidden> Date: 2021-06-09 04:46:09
On Mon, Jun 7, 2021 at 5:26 PM Jonathan Tan [off-list ref] wrote:
quoted
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
I wonder if this commit message is a good place to call out that we
also want to eventually audit codepaths using the old
has_promisor_remote() wrapper function (particularly the ones
protected by a repo == the_repository check) as well.
Sounds good. I think we will need to check uses of all wrappers.
From: Jonathan Tan <hidden> Date: 2021-06-09 04:52:28
quoted
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
/*
* TODO Investigate checking promisor_remote_get_direct()
* TODO return value and stopping on error here.
- * TODO Pass a repository struct through
- * promisor_remote_get_direct(), such that arbitrary
- * repositories work.
*/
promisor_remote_get_direct(r, real, 1);
And this seems like a stale comment, since I see we were already passing
'r' here. But arbitrary repositories still don't just work, right? Or, I
guess your point was "partial clone + submodules don't just work,
because of the alternates thing" - so maybe this part is OK?
This part is OK (arbitrary repositories work here), yes.
Should this change have happened when we added 'r' to
promisor_remote_init? If r==the_repository then there's no difference
between these two calls, right?
Good point - yes, it should have. I'll change it.
quoted
+test_expect_success 'lazy-fetch when accessing object not in the_repository' '
+ rm -rf full partial.git &&
+ test_create_repo full &&
+ printf 12345 >full/file.txt &&
+ git -C full add file.txt &&
+ git -C full commit -m "first commit" &&
I think there is some test_commit or similar function here that's more
commonly used, right?
Taylor Blau suggested a similar thing, and I have changed it in v2.
quoted
+
+ test_config -C full uploadpack.allowfilter 1 &&
+ test_config -C full uploadpack.allowanysha1inwant 1 &&
I wasn't sure what these configs are for, but it looks like .allowfilter
is to allow 'full' to serve as a remote to a partial clone. But what do
you need .allowAnySha1InWant for here? Are we expecting to ask for SHAs
that 'full' doesn't have?
We are expecting to ask for SHAs that 'full' doesn't *advertise*, yes (namely,
the hash of a certain blob).
quoted
+ git clone --filter=blob:none --bare "file://$(pwd)/full" partial.git &&
+ FILE_HASH=$(git hash-object --stdin <full/file.txt) &&
+
+ # Sanity check that the file is missing
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ grep "[?]$FILE_HASH" out &&
+
+ OUT=$(test-tool partial-clone object-info partial.git "$FILE_HASH") &&
+ test "$OUT" -eq 5 &&
Hm. I guess I am confused about why this fetches the desired object into
partial.git. Maybe the test-helper needs a comment (and maybe here too)
on the line where fetch will be triggered?
I've added a comment to the test-helper code in v2 - could you take a
look and see if that clarifies things? But in any case, the answer is
that this test-tool invocation attempts to read an object in the
submodule while running as a process in the superproject. The read
attempt is a read of a missing object, so that object is lazily fetched.
From: Jonathan Tan <hidden> Date: 2021-06-09 04:59:28
Looks like Junio did spot some bigger items...which raises a question
for me. I have a series
(https://lore.kernel.org/git/pull.969.git.1622856485.gitgitgadget@gmail.com/)
that also touches partial clones. Our series are semantically
independent, but we both add a repository parameter to
fetch_objects(). So we both make the same change, but you also make
additional nearby changes, resulting in two trivial conflicts. So,
should I rebase my series on yours, should you rebase on mine, or
should we just let both proceed independently and double-check Junio
resolves the trivial conflicts in favor of your side?
Thoughts?
From [1], looks like this is already resolved, but in any case I think
we can just let both proceed independently since the conflicts are
relatively trivial. If it turns out to be not so trivial, I think Junio
can just let one of us know on-list and whoever it is can rebase on the
other's.
[1] https://lore.kernel.org/git/xmqqlf7jnb5u.fsf@gitster.g/
On Tue, Jun 8, 2021 at 9:44 PM Jonathan Tan [off-list ref] wrote:
quoted
quoted
@@ -99,6 +94,15 @@ static int promisor_remote_config(const char *var, const char *value, void *data size_t namelen; const char *subkey;+ if (!strcmp(var, "extensions.partialclone")) {+ /*+ * NULL value is handled in handle_extension_v0 in setup.c.+ */+ if (value)+ repository_format_partial_clone = xstrdup(value);+ return 0;+ }
This is actually slightly hard to parse out. I was trying to figure
out where repository_format_partial_clone was initialized, and it's
not handled when value is NULL in handle_extension_v0; it's the fact
that repository_format_partial_clone is declared a static global
variable.
But in the next patch you make it a member of struct
promisor_remote_config, and instead rely on the xcalloc call in
promisor_remote_init().
That means everything is properly initialized and you haven't made any
mistakes here, but the logic is a bit hard to follow. Perhaps it'd be
nicer to just write this as
+ if (!strcmp(var, "extensions.partialclone")) {
+ repository_format_partial_clone = xstrdup_or_null(value);
+ return 0;
+ }
which makes the code shorter and easier to follow, at least for me.
Hmm...is your concern about the case in which
repository_format_partial_clone is uninitialized, or about ignoring a
potential NULL value? If the former, I don't see how your suggestion
fixes things, since extensions.partialclone may never have been in the
config in the first place (and would thus leave
repository_format_partial_clone uninitialized, if it weren't for the
fact that it is in static storage and thus initialized to 0). If the
latter, I guess I should be more detailed about how it's being handled
in setup.c (or maybe just leave out the comment altogether - the code
here can handle a NULL repository_format_partial_clone for some reason).
My comment was about the latter; I was trying to understand what the
comment meant relative to that case, and how and where that case would
be handled in the code. With that frame of reference, the comment
seemed misleading to me...though perhaps the comment was intended to
answer some other question entirely.
From: Jonathan Tan <hidden> Date: 2021-06-10 17:26:53
quoted
Hmm...is your concern about the case in which
repository_format_partial_clone is uninitialized, or about ignoring a
potential NULL value? If the former, I don't see how your suggestion
fixes things, since extensions.partialclone may never have been in the
config in the first place (and would thus leave
repository_format_partial_clone uninitialized, if it weren't for the
fact that it is in static storage and thus initialized to 0). If the
latter, I guess I should be more detailed about how it's being handled
in setup.c (or maybe just leave out the comment altogether - the code
here can handle a NULL repository_format_partial_clone for some reason).
My comment was about the latter; I was trying to understand what the
comment meant relative to that case, and how and where that case would
be handled in the code. With that frame of reference, the comment
seemed misleading to me...though perhaps the comment was intended to
answer some other question entirely.
Junio suggested [1] that repository_format_partial_clone be handled when
the repo format is validated, so this part of the code can just make use
of the repository_format_partial_clone value in struct repository and
not read the config itself. So I believe that this part is now
obsolete (but you can take a look at patches 1 and 2 to verify, if you
want).
[1] https://lore.kernel.org/git/xmqqeedbidvy.fsf@gitster.g/
From: Jonathan Tan <hidden> Date: 2021-06-10 17:35:52
Instead of using global variables to store promisor remote information,
store this config in struct repository instead, and add
repository-agnostic non-static functions corresponding to the existing
non-static functions that only work on the_repository.
The actual lazy-fetching of missing objects currently does not work on
repositories other than the_repository, and will still not work after
this commit, so add a BUG message explaining this. A subsequent commit
will remove this limitation.
Signed-off-by: Jonathan Tan <redacted>
---
promisor-remote.c | 98 ++++++++++++++++++++++++++---------------------
promisor-remote.h | 22 +++++++++--
repository.c | 6 +++
repository.h | 2 +
4 files changed, 82 insertions(+), 46 deletions(-)
@@ -228,9 +238,11 @@ int promisor_remote_get_direct(struct repository *repo,if(oid_nr==0)return0;-promisor_remote_init();+promisor_remote_init(repo);-for(r=promisors;r;r=r->next){+if(repo!=the_repository)+BUG("only the_repository is supported for now");+for(r=repo->promisor_remote_config->promisors;r;r=r->next){if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;
@@ -11,6 +11,7 @@#include"lockfile.h"#include"submodule-config.h"#include"sparse-index.h"+#include"promisor-remote.h"/* The main repository */staticstructrepositorythe_repo;
From: Jonathan Tan <hidden> Date: 2021-06-10 17:36:11
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
Besides that, there is some code that uses the wrapper functions
like has_promisor_remote(). Those will need to be checked to see if they
could support the non-wrapper functions instead (and thus support any
repository, not just the_repository).
Signed-off-by: Jonathan Tan <redacted>
---
Makefile | 1 +
object-file.c | 7 ++----
promisor-remote.c | 9 ++++----
t/helper/test-partial-clone.c | 43 +++++++++++++++++++++++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 23 +++++++++++++++++++
7 files changed, 76 insertions(+), 9 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&!(flags&OBJECT_INFO_SKIP_FETCH_OBJECT)){/**TODOInvestigatecheckingpromisor_remote_get_direct()*TODOreturnvalueandstoppingonerrorhere.-*TODOPassarepositorystructthrough-*promisor_remote_get_direct(),suchthatarbitrary-*repositorieswork.*/promisor_remote_get_direct(r,real,1);already_retried=1;
@@ -20,6 +21,8 @@ static int fetch_objects(const char *remote_name,child.git_cmd=1;child.in=-1;+if(repo!=the_repository)+prepare_other_repo_env(&child.env_array,repo->gitdir);strvec_pushl(&child.args,"-c","fetch.negotiationAlgorithm=noop","fetch",remote_name,"--no-tags","--no-write-fetch-head","--recurse-submodules=no",
@@ -240,10 +243,8 @@ int promisor_remote_get_direct(struct repository *repo,promisor_remote_init(repo);-if(repo!=the_repository)-BUG("only the_repository is supported for now");for(r=repo->promisor_remote_config->promisors;r;r=r->next){-if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){+if(fetch_objects(repo,r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;remaining_nr=remove_fetched_oids(repo,&remaining_oids,
@@ -604,6 +604,29 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+test_commit-Cfullcreate-a-filefile.txt&&++test_config-Cfulluploadpack.allowfilter1&&+test_config-Cfulluploadpack.allowanysha1inwant1&&+gitclone--filter=blob:none--bare"file://$(pwd)/full"partial.git&&+FILE_HASH=$(git-Cfullrev-parseHEAD:file.txt)&&++# Sanity check that the file is missing+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+grep"[?]$FILE_HASH"out&&++git-Cfullcat-file-s"$FILE_HASH">expect&&+test-toolpartial-cloneobject-infopartial.git"$FILE_HASH">actual&&+test_cmpexpectactual&&++# Sanity check that the file is now present+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+!grep"[?]$FILE_HASH"out+'+ ."$TEST_DIRECTORY"/lib-httpd.sh start_httpd
From: Jonathan Tan <hidden> Date: 2021-06-10 17:36:48
I think I've addressed all review comments. As for Junio's suggestion
about also printing the type in the former patch 4 (now patch 5) [1], I
decided to just leave the code as-is and not also print the type.
The main changes are that patch 1 is somewhat rewritten - we still
remove the global variable, but we no longer read the
extensions.partialClone config directly from promisor-remote.c. Instead,
we store it in struct repository when the format of a repository is
being verified, and promisor-remote.c merely reads it from there. Patch
3 is a new patch that updates the environment variable preparation
before it is moved in patch 4 (formerly patch 3).
[1] https://lore.kernel.org/git/xmqq7dj2ik7k.fsf@gitster.g/
Jonathan Tan (5):
repository: move global r_f_p_c to repo struct
promisor-remote: support per-repository config
submodule: refrain from filtering GIT_CONFIG_COUNT
run-command: refactor subprocess env preparation
promisor-remote: teach lazy-fetch in any repo
Makefile | 1 +
object-file.c | 7 +--
promisor-remote.c | 108 ++++++++++++++++++----------------
promisor-remote.h | 28 ++++++---
repository.c | 9 +++
repository.h | 5 ++
run-command.c | 12 ++++
run-command.h | 10 ++++
setup.c | 16 +++--
submodule.c | 17 +-----
t/helper/test-partial-clone.c | 43 ++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 23 ++++++++
14 files changed, 196 insertions(+), 85 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
Range-diff against v2:
1: d99598ca50 < -: ---------- promisor-remote: read partialClone config here
-: ---------- > 1: 255d112256 repository: move global r_f_p_c to repo struct
2: 5a1ccae335 ! 2: a52448cff2 promisor-remote: support per-repository config
@@ promisor-remote.c
#include "transport.h"
#include "strvec.h"
--static char *repository_format_partial_clone;
+struct promisor_remote_config {
-+ char *repository_format_partial_clone;
+ struct promisor_remote *promisors;
+ struct promisor_remote **promisors_tail;
+};
-
++
static int fetch_objects(const char *remote_name,
const struct object_id *oids,
+ int oid_nr)
@@ promisor-remote.c: static int fetch_objects(const char *remote_name,
return finish_command(&child) ? -1 : 0;
}
@@ promisor-remote.c: static void promisor_remote_move_to_tail(struct promisor_remo
const char *name;
size_t namelen;
const char *subkey;
-@@ promisor-remote.c: static int promisor_remote_config(const char *var, const char *value, void *data
- * NULL value is handled in handle_extension_v0 in setup.c.
- */
- if (value)
-- repository_format_partial_clone = xstrdup(value);
-+ config->repository_format_partial_clone = xstrdup(value);
- return 0;
- }
-
@@ promisor-remote.c: static int promisor_remote_config(const char *var, const char *value, void *data
remote_name = xmemdupz(name, namelen);
@@ promisor-remote.c: static int promisor_remote_config(const char *var, const char
+ config->promisors_tail = &config->promisors;
- git_config(promisor_remote_config, NULL);
-+ git_config(promisor_remote_config, config);
++ repo_config(r, promisor_remote_config, config);
-- if (repository_format_partial_clone) {
-+ if (config->repository_format_partial_clone) {
+- if (the_repository->repository_format_partial_clone) {
++ if (r->repository_format_partial_clone) {
struct promisor_remote *o, *previous;
-- o = promisor_remote_lookup(repository_format_partial_clone,
+- o = promisor_remote_lookup(the_repository->repository_format_partial_clone,
+ o = promisor_remote_lookup(config,
-+ config->repository_format_partial_clone,
++ r->repository_format_partial_clone,
&previous);
if (o)
- promisor_remote_move_to_tail(o, previous);
+ promisor_remote_move_to_tail(config, o, previous);
else
-- promisor_remote_new(repository_format_partial_clone);
-+ promisor_remote_new(config, config->repository_format_partial_clone);
+- promisor_remote_new(the_repository->repository_format_partial_clone);
++ promisor_remote_new(config, r->repository_format_partial_clone);
}
}
@@ promisor-remote.c: static int promisor_remote_config(const char *var, const char
- while (promisors) {
- struct promisor_remote *r = promisors;
- promisors = promisors->next;
-+ FREE_AND_NULL(config->repository_format_partial_clone);
-+
+ while (config->promisors) {
+ struct promisor_remote *r = config->promisors;
+ config->promisors = config->promisors->next;
@@ repository.h: struct lock_file;
enum untracked_cache_setting {
UNTRACKED_CACHE_UNSET = -1,
@@ repository.h: struct repository {
- /* True if commit-graph has been disabled within this process. */
- int commit_graph_disabled;
-+ /* Configurations related to promisor remotes. */
+ /* Configurations related to promisor remotes. */
+ char *repository_format_partial_clone;
+ struct promisor_remote_config *promisor_remote_config;
-+
+
/* Configurations */
- /* Indicate if a repository has a different 'commondir' from 'gitdir' */
-: ---------- > 3: e1a40108f4 submodule: refrain from filtering GIT_CONFIG_COUNT
3: 3f7c4e6e67 ! 4: fd6907822c run-command: move envvar-resetting function
@@ Metadata
Author: Jonathan Tan [off-list ref]
## Commit message ##
- run-command: move envvar-resetting function
+ run-command: refactor subprocess env preparation
- There is a function that resets environment variables, used when
- invoking a sub-process in a submodule. The lazy-fetching code (used in
- partial clones) will need this function in a subsequent commit, so move
- it to a more central location.
+ submodule.c has functionality that prepares the environment for running
+ a subprocess in a new repo. The lazy-fetching code (used in partial
+ clones) will need this in a subsequent commit, so move it to a more
+ central location.
Signed-off-by: Jonathan Tan [off-list ref]
@@ run-command.c: int run_auto_maintenance(int quiet)
return run_command(&maint);
}
+
-+void prepare_other_repo_env(struct strvec *env_array)
++void prepare_other_repo_env(struct strvec *env_array, const char *new_git_dir)
+{
+ const char * const *var;
+
+ for (var = local_repo_env; *var; var++) {
-+ if (strcmp(*var, CONFIG_DATA_ENVIRONMENT))
++ if (strcmp(*var, CONFIG_DATA_ENVIRONMENT) &&
++ strcmp(*var, CONFIG_COUNT_ENVIRONMENT))
+ strvec_push(env_array, *var);
+ }
++ strvec_pushf(env_array, "%s=%s", GIT_DIR_ENVIRONMENT, new_git_dir);
+}
## run-command.h ##
@@ run-command.h: int run_processes_parallel_tr2(int n, get_next_task_fn, start_fai
const char *tr2_category, const char *tr2_label);
+/**
-+ * Convenience function which adds all GIT_* environment variables to env_array
-+ * with the exception of GIT_CONFIG_PARAMETERS. When used as the env_array of a
-+ * subprocess, these entries cause the corresponding environment variables to
-+ * be unset in the subprocess. See local_repo_env in cache.h for more
++ * Convenience function which prepares env_array for a command to be run in a
++ * new repo. This adds all GIT_* environment variables to env_array with the
++ * exception of GIT_CONFIG_PARAMETERS (which cause the corresponding
++ * environment variables to be unset in the subprocess) and adds an environment
++ * variable pointing to new_git_dir. See local_repo_env in cache.h for more
+ * information.
+ */
-+void prepare_other_repo_env(struct strvec *env_array);
++void prepare_other_repo_env(struct strvec *env_array, const char *new_git_dir);
+
#endif
@@ submodule.c: static void print_submodule_diff_summary(struct repository *r, stru
- const char * const *var;
-
- for (var = local_repo_env; *var; var++) {
-- if (strcmp(*var, CONFIG_DATA_ENVIRONMENT))
+- if (strcmp(*var, CONFIG_DATA_ENVIRONMENT) &&
+- strcmp(*var, CONFIG_COUNT_ENVIRONMENT))
- strvec_push(out, *var);
- }
-}
@@ submodule.c: static void print_submodule_diff_summary(struct repository *r, stru
void prepare_submodule_repo_env(struct strvec *out)
{
- prepare_submodule_repo_env_no_git_dir(out);
-+ prepare_other_repo_env(out);
- strvec_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT,
- DEFAULT_GIT_DIR_ENVIRONMENT);
+- strvec_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT,
+- DEFAULT_GIT_DIR_ENVIRONMENT);
++ prepare_other_repo_env(out, DEFAULT_GIT_DIR_ENVIRONMENT);
}
static void prepare_submodule_repo_env_in_gitdir(struct strvec *out)
{
- prepare_submodule_repo_env_no_git_dir(out);
-+ prepare_other_repo_env(out);
- strvec_pushf(out, "%s=.", GIT_DIR_ENVIRONMENT);
+- strvec_pushf(out, "%s=.", GIT_DIR_ENVIRONMENT);
++ prepare_other_repo_env(out, ".");
}
+ /*
4: 655607d575 ! 5: a6d73662b1 promisor-remote: teach lazy-fetch in any repo
@@ Commit message
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
+ Besides that, there is some code that uses the wrapper functions
+ like has_promisor_remote(). Those will need to be checked to see if they
+ could support the non-wrapper functions instead (and thus support any
+ repository, not just the_repository).
+
Signed-off-by: Jonathan Tan [off-list ref]
## Makefile ##
@@ promisor-remote.c: static int fetch_objects(const char *remote_name,
child.git_cmd = 1;
child.in = -1;
-+ if (repo != the_repository) {
-+ prepare_other_repo_env(&child.env_array);
-+ strvec_pushf(&child.env_array, "%s=%s", GIT_DIR_ENVIRONMENT,
-+ repo->gitdir);
-+ }
++ if (repo != the_repository)
++ prepare_other_repo_env(&child.env_array, repo->gitdir);
strvec_pushl(&child.args, "-c", "fetch.negotiationAlgorithm=noop",
"fetch", remote_name, "--no-tags",
"--no-write-fetch-head", "--recurse-submodules=no",
-@@ promisor-remote.c: static void promisor_remote_init(struct repository *r)
- xcalloc(sizeof(*r->promisor_remote_config), 1);
- config->promisors_tail = &config->promisors;
-
-- git_config(promisor_remote_config, config);
-+ repo_config(r, promisor_remote_config, config);
-
- if (config->repository_format_partial_clone) {
- struct promisor_remote *o, *previous;
@@ promisor-remote.c: int promisor_remote_get_direct(struct repository *repo,
promisor_remote_init(repo);
--
2.32.0.rc1.229.g3e70b5a671-goog
From: Jonathan Tan <hidden> Date: 2021-06-10 17:36:49
Move repository_format_partial_clone, which is currently a global
variable, into struct repository. (Full support for per-repository
partial clone config will be done in a subsequent commit - this is split
into its own commit because of the extent of the changes needed.)
The new repo-specific variable cannot be set in
check_repository_format_gently() (as is currently), because that
function does not know which repo it is operating on (or even whether
the value is important); therefore this responsibility is delegated to
the outermost caller that knows. Of all the outermost callers that know
(found by looking at all functions that call clear_repository_format()),
I looked at those that either read from the main Git directory or write
into a struct repository. These callers have been modified accordingly
(write to the_repository in the former case and write to the given
struct repository in the latter case).
Signed-off-by: Jonathan Tan <redacted>
---
promisor-remote.c | 13 +++----------
promisor-remote.h | 6 ------
repository.c | 3 +++
repository.h | 3 +++
setup.c | 16 +++++++++++-----
5 files changed, 20 insertions(+), 21 deletions(-)
@@ -139,6 +139,9 @@ struct repository {/* True if commit-graph has been disabled within this process. */intcommit_graph_disabled;+/* Configurations related to promisor remotes. */+char*repository_format_partial_clone;+/* Configurations *//* Indicate if a repository has a different 'commondir' from 'gitdir' */
From: Jonathan Tan <hidden> Date: 2021-06-10 17:37:07
14111fc492 ("git: submodule honor -c credential.* from command line",
2016-03-01) taught Git to pass through the GIT_CONFIG_PARAMETERS
environment variable when invoking a subprocess on behalf of a
submodule. But when d8d77153ea ("config: allow specifying config entries
via envvar pairs", 2021-01-15) introduced support for GIT_CONFIG_COUNT
(and its associated GIT_CONFIG_KEY_? and GIT_CONFIG_VALUE_?), the
subprocess mechanism wasn't updated to also pass through these
variables.
Since they are conceptually the same (d8d77153ea was written to address
a shortcoming of GIT_CONFIG_PARAMETERS), update the submodule subprocess
mechanism to also pass through GIT_CONFIG_COUNT.
Signed-off-by: Jonathan Tan <redacted>
---
submodule.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Jonathan Tan <hidden> Date: 2021-06-10 17:37:08
submodule.c has functionality that prepares the environment for running
a subprocess in a new repo. The lazy-fetching code (used in partial
clones) will need this in a subsequent commit, so move it to a more
central location.
Signed-off-by: Jonathan Tan <redacted>
---
run-command.c | 12 ++++++++++++
run-command.h | 10 ++++++++++
submodule.c | 18 ++----------------
3 files changed, 24 insertions(+), 16 deletions(-)
@@ -483,4 +483,14 @@ int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn,task_finished_fn,void*pp_cb,constchar*tr2_category,constchar*tr2_label);+/**+*Conveniencefunctionwhichpreparesenv_arrayforacommandtoberunina+*newrepo.ThisaddsallGIT_*environmentvariablestoenv_arraywiththe+*exceptionofGIT_CONFIG_PARAMETERS(whichcausethecorresponding+*environmentvariablestobeunsetinthesubprocess)andaddsanenvironment+*variablepointingtonew_git_dir.Seelocal_repo_envincache.hformore+*information.+*/+voidprepare_other_repo_env(structstrvec*env_array,constchar*new_git_dir);+#endif
On Thu, Jun 10, 2021 at 10:35 AM Jonathan Tan [off-list ref] wrote:
quoted hunk
Move repository_format_partial_clone, which is currently a global
variable, into struct repository. (Full support for per-repository
partial clone config will be done in a subsequent commit - this is split
into its own commit because of the extent of the changes needed.)
The new repo-specific variable cannot be set in
check_repository_format_gently() (as is currently), because that
function does not know which repo it is operating on (or even whether
the value is important); therefore this responsibility is delegated to
the outermost caller that knows. Of all the outermost callers that know
(found by looking at all functions that call clear_repository_format()),
I looked at those that either read from the main Git directory or write
into a struct repository. These callers have been modified accordingly
(write to the_repository in the former case and write to the given
struct repository in the latter case).
Signed-off-by: Jonathan Tan <redacted>
---
promisor-remote.c | 13 +++----------
promisor-remote.h | 6 ------
repository.c | 3 +++
repository.h | 3 +++
setup.c | 16 +++++++++++-----
5 files changed, 20 insertions(+), 21 deletions(-)
@@ -172,6 +172,9 @@ int repo_init(struct repository *repo,repo_set_hash_algo(repo,format.hash_algo);+repo->repository_format_partial_clone=format.partial_clone;+format.partial_clone=NULL;
This was surprising to me, and I tried to dig around to find out why
you set it to NULL. AFAICT, you're trying to avoid the need to do a
xstrdup(), so you take over ownership in the first line and set to
NULL in the second to avoid a double-free. So, it makes sense, but
given how surprising it was and it took me a while to figure it out,
perhaps it's worth adding a comment that this is what you're doing
here? The same comment would also apply in a few other places in this
patch...
quoted hunk
+
if (worktree)
repo_set_worktree(repo, worktree);
@@ -139,6 +139,9 @@ struct repository {/* True if commit-graph has been disabled within this process. */intcommit_graph_disabled;+/* Configurations related to promisor remotes. */+char*repository_format_partial_clone;+/* Configurations *//* Indicate if a repository has a different 'commondir' from 'gitdir' */
Adding Peff to cc as per comments about 89044baa8b ("submodule: stop
sanitizing config options", 2016-05-04) below.
On Thu, Jun 10, 2021 at 10:35 AM Jonathan Tan [off-list ref] wrote:
quoted hunk
14111fc492 ("git: submodule honor -c credential.* from command line",
2016-03-01) taught Git to pass through the GIT_CONFIG_PARAMETERS
environment variable when invoking a subprocess on behalf of a
submodule. But when d8d77153ea ("config: allow specifying config entries
via envvar pairs", 2021-01-15) introduced support for GIT_CONFIG_COUNT
(and its associated GIT_CONFIG_KEY_? and GIT_CONFIG_VALUE_?), the
subprocess mechanism wasn't updated to also pass through these
variables.
Since they are conceptually the same (d8d77153ea was written to address
a shortcoming of GIT_CONFIG_PARAMETERS), update the submodule subprocess
mechanism to also pass through GIT_CONFIG_COUNT.
Signed-off-by: Jonathan Tan <redacted>
---
submodule.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
I'm super confused. It appears that
prepare_submodule_repo_env_no_git_dir() is filtering out
"GIT_CONFIG_PARAMETERS" (CONFIG_DATA_ENVIRONMENT) and
"GIT_CONFIG_COUNT" (CONFIG_COUNT_ENVIRONMENT), using all environment
variables other than these ones. But the commit message talks about
adding an extra environment variable, rather than filtering another
out. I must be mis-reading something somewhere, but I'm struggling to
figure it out.
Digging around for a while led me to commit 89044baa8b ("submodule:
stop sanitizing config options", 2016-05-04), which suggests that the
passing of GIT_CONFIG_PARAMETERS is not done here but in
git-submodule.sh. It still didn't make it clear to me why it's
stripped out here, but something makes me thing that git-submodule.sh
should be affected by your change as well.
Also, from looking at the other commit messages you reference, it
appears GIT_CONFIG_PARAMETERS was just one big environment variable,
whereas GIT_CONFIG_COUNT is closely associated with 2*N other
environment variables...so shouldn't your loop (and perhaps also
git-submodule.sh) also be checking GIT_CONFIG_KEY_\d+ and
GIT_CONFIG_VALUE_\d+ ?
I've been looking at this patch longer than I care to admit and I
still feel like I don't have a clue what's going on.
On Thu, Jun 10, 2021 at 10:35 AM Jonathan Tan [off-list ref] wrote:
quoted hunk
submodule.c has functionality that prepares the environment for running
a subprocess in a new repo. The lazy-fetching code (used in partial
clones) will need this in a subsequent commit, so move it to a more
central location.
Signed-off-by: Jonathan Tan <redacted>
---
run-command.c | 12 ++++++++++++
run-command.h | 10 ++++++++++
submodule.c | 18 ++----------------
3 files changed, 24 insertions(+), 16 deletions(-)
@@ -483,4 +483,14 @@ int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn,task_finished_fn,void*pp_cb,constchar*tr2_category,constchar*tr2_label);+/**+*Conveniencefunctionwhichpreparesenv_arrayforacommandtoberunina+*newrepo.ThisaddsallGIT_*environmentvariablestoenv_arraywiththe+*exceptionofGIT_CONFIG_PARAMETERS(whichcausethecorresponding+*environmentvariablestobeunsetinthesubprocess)andaddsanenvironment+*variablepointingtonew_git_dir.Seelocal_repo_envincache.hformore+*information.
This comment is out-of-date as of your previous patch. There's (at
least) one more variable that is also excluded.
On Thu, Jun 10, 2021 at 10:35 AM Jonathan Tan [off-list ref] wrote:
I think I've addressed all review comments. As for Junio's suggestion
about also printing the type in the former patch 4 (now patch 5) [1], I
decided to just leave the code as-is and not also print the type.
The main changes are that patch 1 is somewhat rewritten - we still
remove the global variable, but we no longer read the
extensions.partialClone config directly from promisor-remote.c. Instead,
we store it in struct repository when the format of a repository is
being verified, and promisor-remote.c merely reads it from there. Patch
3 is a new patch that updates the environment variable preparation
before it is moved in patch 4 (formerly patch 3).
I've read through all the patches. 2 & 5 look good to me, I had small
nitpicks on 1 & 4, and I'm totally lost on patch 3. Patch 3 is just a
one-liner and it might be fine, but for some reason I can't figure out
the code before or after the patch even after digging around into
other commits and other files to try to get my bearings. Hopefully
someone else can comment on that one.
[1] https://lore.kernel.org/git/xmqq7dj2ik7k.fsf@gitster.g/
Jonathan Tan (5):
repository: move global r_f_p_c to repo struct
promisor-remote: support per-repository config
submodule: refrain from filtering GIT_CONFIG_COUNT
run-command: refactor subprocess env preparation
promisor-remote: teach lazy-fetch in any repo
Makefile | 1 +
object-file.c | 7 +--
promisor-remote.c | 108 ++++++++++++++++++----------------
promisor-remote.h | 28 ++++++---
repository.c | 9 +++
repository.h | 5 ++
run-command.c | 12 ++++
run-command.h | 10 ++++
setup.c | 16 +++--
submodule.c | 17 +-----
t/helper/test-partial-clone.c | 43 ++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 23 ++++++++
14 files changed, 196 insertions(+), 85 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
Range-diff against v2:
1: d99598ca50 < -: ---------- promisor-remote: read partialClone config here
-: ---------- > 1: 255d112256 repository: move global r_f_p_c to repo struct
2: 5a1ccae335 ! 2: a52448cff2 promisor-remote: support per-repository config
@@ promisor-remote.c
#include "transport.h"
#include "strvec.h"
--static char *repository_format_partial_clone;
+struct promisor_remote_config {
-+ char *repository_format_partial_clone;
+ struct promisor_remote *promisors;
+ struct promisor_remote **promisors_tail;
+};
-
++
static int fetch_objects(const char *remote_name,
const struct object_id *oids,
+ int oid_nr)
@@ promisor-remote.c: static int fetch_objects(const char *remote_name,
return finish_command(&child) ? -1 : 0;
}
@@ promisor-remote.c: static void promisor_remote_move_to_tail(struct promisor_remo
const char *name;
size_t namelen;
const char *subkey;
-@@ promisor-remote.c: static int promisor_remote_config(const char *var, const char *value, void *data
- * NULL value is handled in handle_extension_v0 in setup.c.
- */
- if (value)
-- repository_format_partial_clone = xstrdup(value);
-+ config->repository_format_partial_clone = xstrdup(value);
- return 0;
- }
-
@@ promisor-remote.c: static int promisor_remote_config(const char *var, const char *value, void *data
remote_name = xmemdupz(name, namelen);
@@ promisor-remote.c: static int promisor_remote_config(const char *var, const char
+ config->promisors_tail = &config->promisors;
- git_config(promisor_remote_config, NULL);
-+ git_config(promisor_remote_config, config);
++ repo_config(r, promisor_remote_config, config);
-- if (repository_format_partial_clone) {
-+ if (config->repository_format_partial_clone) {
+- if (the_repository->repository_format_partial_clone) {
++ if (r->repository_format_partial_clone) {
struct promisor_remote *o, *previous;
-- o = promisor_remote_lookup(repository_format_partial_clone,
+- o = promisor_remote_lookup(the_repository->repository_format_partial_clone,
+ o = promisor_remote_lookup(config,
-+ config->repository_format_partial_clone,
++ r->repository_format_partial_clone,
&previous);
if (o)
- promisor_remote_move_to_tail(o, previous);
+ promisor_remote_move_to_tail(config, o, previous);
else
-- promisor_remote_new(repository_format_partial_clone);
-+ promisor_remote_new(config, config->repository_format_partial_clone);
+- promisor_remote_new(the_repository->repository_format_partial_clone);
++ promisor_remote_new(config, r->repository_format_partial_clone);
}
}
@@ promisor-remote.c: static int promisor_remote_config(const char *var, const char
- while (promisors) {
- struct promisor_remote *r = promisors;
- promisors = promisors->next;
-+ FREE_AND_NULL(config->repository_format_partial_clone);
-+
+ while (config->promisors) {
+ struct promisor_remote *r = config->promisors;
+ config->promisors = config->promisors->next;
@@ repository.h: struct lock_file;
enum untracked_cache_setting {
UNTRACKED_CACHE_UNSET = -1,
@@ repository.h: struct repository {
- /* True if commit-graph has been disabled within this process. */
- int commit_graph_disabled;
-+ /* Configurations related to promisor remotes. */
+ /* Configurations related to promisor remotes. */
+ char *repository_format_partial_clone;
+ struct promisor_remote_config *promisor_remote_config;
-+
+
/* Configurations */
- /* Indicate if a repository has a different 'commondir' from 'gitdir' */
-: ---------- > 3: e1a40108f4 submodule: refrain from filtering GIT_CONFIG_COUNT
3: 3f7c4e6e67 ! 4: fd6907822c run-command: move envvar-resetting function
@@ Metadata
Author: Jonathan Tan [off-list ref]
## Commit message ##
- run-command: move envvar-resetting function
+ run-command: refactor subprocess env preparation
- There is a function that resets environment variables, used when
- invoking a sub-process in a submodule. The lazy-fetching code (used in
- partial clones) will need this function in a subsequent commit, so move
- it to a more central location.
+ submodule.c has functionality that prepares the environment for running
+ a subprocess in a new repo. The lazy-fetching code (used in partial
+ clones) will need this in a subsequent commit, so move it to a more
+ central location.
Signed-off-by: Jonathan Tan [off-list ref]
@@ run-command.c: int run_auto_maintenance(int quiet)
return run_command(&maint);
}
+
-+void prepare_other_repo_env(struct strvec *env_array)
++void prepare_other_repo_env(struct strvec *env_array, const char *new_git_dir)
+{
+ const char * const *var;
+
+ for (var = local_repo_env; *var; var++) {
-+ if (strcmp(*var, CONFIG_DATA_ENVIRONMENT))
++ if (strcmp(*var, CONFIG_DATA_ENVIRONMENT) &&
++ strcmp(*var, CONFIG_COUNT_ENVIRONMENT))
+ strvec_push(env_array, *var);
+ }
++ strvec_pushf(env_array, "%s=%s", GIT_DIR_ENVIRONMENT, new_git_dir);
+}
## run-command.h ##
@@ run-command.h: int run_processes_parallel_tr2(int n, get_next_task_fn, start_fai
const char *tr2_category, const char *tr2_label);
+/**
-+ * Convenience function which adds all GIT_* environment variables to env_array
-+ * with the exception of GIT_CONFIG_PARAMETERS. When used as the env_array of a
-+ * subprocess, these entries cause the corresponding environment variables to
-+ * be unset in the subprocess. See local_repo_env in cache.h for more
++ * Convenience function which prepares env_array for a command to be run in a
++ * new repo. This adds all GIT_* environment variables to env_array with the
++ * exception of GIT_CONFIG_PARAMETERS (which cause the corresponding
++ * environment variables to be unset in the subprocess) and adds an environment
++ * variable pointing to new_git_dir. See local_repo_env in cache.h for more
+ * information.
+ */
-+void prepare_other_repo_env(struct strvec *env_array);
++void prepare_other_repo_env(struct strvec *env_array, const char *new_git_dir);
+
#endif
@@ submodule.c: static void print_submodule_diff_summary(struct repository *r, stru
- const char * const *var;
-
- for (var = local_repo_env; *var; var++) {
-- if (strcmp(*var, CONFIG_DATA_ENVIRONMENT))
+- if (strcmp(*var, CONFIG_DATA_ENVIRONMENT) &&
+- strcmp(*var, CONFIG_COUNT_ENVIRONMENT))
- strvec_push(out, *var);
- }
-}
@@ submodule.c: static void print_submodule_diff_summary(struct repository *r, stru
void prepare_submodule_repo_env(struct strvec *out)
{
- prepare_submodule_repo_env_no_git_dir(out);
-+ prepare_other_repo_env(out);
- strvec_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT,
- DEFAULT_GIT_DIR_ENVIRONMENT);
+- strvec_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT,
+- DEFAULT_GIT_DIR_ENVIRONMENT);
++ prepare_other_repo_env(out, DEFAULT_GIT_DIR_ENVIRONMENT);
}
static void prepare_submodule_repo_env_in_gitdir(struct strvec *out)
{
- prepare_submodule_repo_env_no_git_dir(out);
-+ prepare_other_repo_env(out);
- strvec_pushf(out, "%s=.", GIT_DIR_ENVIRONMENT);
+- strvec_pushf(out, "%s=.", GIT_DIR_ENVIRONMENT);
++ prepare_other_repo_env(out, ".");
}
+ /*
4: 655607d575 ! 5: a6d73662b1 promisor-remote: teach lazy-fetch in any repo
@@ Commit message
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
+ Besides that, there is some code that uses the wrapper functions
+ like has_promisor_remote(). Those will need to be checked to see if they
+ could support the non-wrapper functions instead (and thus support any
+ repository, not just the_repository).
+
Signed-off-by: Jonathan Tan [off-list ref]
## Makefile ##
@@ promisor-remote.c: static int fetch_objects(const char *remote_name,
child.git_cmd = 1;
child.in = -1;
-+ if (repo != the_repository) {
-+ prepare_other_repo_env(&child.env_array);
-+ strvec_pushf(&child.env_array, "%s=%s", GIT_DIR_ENVIRONMENT,
-+ repo->gitdir);
-+ }
++ if (repo != the_repository)
++ prepare_other_repo_env(&child.env_array, repo->gitdir);
strvec_pushl(&child.args, "-c", "fetch.negotiationAlgorithm=noop",
"fetch", remote_name, "--no-tags",
"--no-write-fetch-head", "--recurse-submodules=no",
-@@ promisor-remote.c: static void promisor_remote_init(struct repository *r)
- xcalloc(sizeof(*r->promisor_remote_config), 1);
- config->promisors_tail = &config->promisors;
-
-- git_config(promisor_remote_config, config);
-+ repo_config(r, promisor_remote_config, config);
-
- if (config->repository_format_partial_clone) {
- struct promisor_remote *o, *previous;
@@ promisor-remote.c: int promisor_remote_get_direct(struct repository *repo,
promisor_remote_init(repo);
--
2.32.0.rc1.229.g3e70b5a671-goog
I'm super confused. It appears that
prepare_submodule_repo_env_no_git_dir() is filtering out
"GIT_CONFIG_PARAMETERS" (CONFIG_DATA_ENVIRONMENT) and
"GIT_CONFIG_COUNT" (CONFIG_COUNT_ENVIRONMENT), using all environment
variables other than these ones. But the commit message talks about
adding an extra environment variable, rather than filtering another
out. I must be mis-reading something somewhere, but I'm struggling to
figure it out.
I think there might be a double (triple?) negative here:
- we want to pass through the config parameters variable, but not
other local repo env variables;
- so we _don't_ want the config variable to appear in the "out"
strvec, because its presence would cause it to be cleared
from the child process environment;
- so we go through the list adding everything _except_ that variable;
- and we match using strcmp(), so a true value means "did not match",
so we should add it to the list
Also, from looking at the other commit messages you reference, it
appears GIT_CONFIG_PARAMETERS was just one big environment variable,
whereas GIT_CONFIG_COUNT is closely associated with 2*N other
environment variables...so shouldn't your loop (and perhaps also
git-submodule.sh) also be checking GIT_CONFIG_KEY_\d+ and
GIT_CONFIG_VALUE_\d+ ?
We definitely could clean out those GIT_CONFIG_KEY_* values. But the
COUNT serves as a master parameter. Anybody who sets COUNT would then
also set the individual key/value parameters, too (and even it only sets
it to "5", and there is a crufty GIT_CONFIG_KEY_6 in the environment,
that is not wrong).
-Peff
From: Jonathan Tan <hidden> Date: 2021-06-11 17:03:06
quoted
I'm super confused. It appears that
prepare_submodule_repo_env_no_git_dir() is filtering out
"GIT_CONFIG_PARAMETERS" (CONFIG_DATA_ENVIRONMENT) and
"GIT_CONFIG_COUNT" (CONFIG_COUNT_ENVIRONMENT), using all environment
variables other than these ones. But the commit message talks about
adding an extra environment variable, rather than filtering another
out. I must be mis-reading something somewhere, but I'm struggling to
figure it out.
I think there might be a double (triple?) negative here:
- we want to pass through the config parameters variable, but not
other local repo env variables;
- so we _don't_ want the config variable to appear in the "out"
strvec, because its presence would cause it to be cleared
from the child process environment;
- so we go through the list adding everything _except_ that variable;
- and we match using strcmp(), so a true value means "did not match",
so we should add it to the list
quoted
Also, from looking at the other commit messages you reference, it
appears GIT_CONFIG_PARAMETERS was just one big environment variable,
whereas GIT_CONFIG_COUNT is closely associated with 2*N other
environment variables...so shouldn't your loop (and perhaps also
git-submodule.sh) also be checking GIT_CONFIG_KEY_\d+ and
GIT_CONFIG_VALUE_\d+ ?
We definitely could clean out those GIT_CONFIG_KEY_* values. But the
COUNT serves as a master parameter. Anybody who sets COUNT would then
also set the individual key/value parameters, too (and even it only sets
it to "5", and there is a crufty GIT_CONFIG_KEY_6 in the environment,
that is not wrong).
-Peff
As Peff describes, if an envvar is present in the list, it becomes
unset. (Perhaps confusingly, if an string of the form "ENVVAR=VALUE"
(note the "=") is present in the list, it becomes set to the given
value.) So in order to *not* filter out the envvar from the subprocess,
we need to filter out the envvar from env_array.
If you can think of a better way to document this, please let me know.
One way I thought of that might reduce confusion is for this function to
take the struct child_process directly. I don't like taking the whole
struct when we're just modifying env_array, but I think that this
becomes easier to document (just say that we're unsetting all these
envvars from the child process, and in the function body, say that to
unset a variable, we need to make it appear without a "=" in env_array).
Saw this series mentioned in "What's cooking" and remembered I didn't
give an update.
On Thu, Jun 10, 2021 at 2:29 PM Elijah Newren [off-list ref] wrote:
On Thu, Jun 10, 2021 at 10:35 AM Jonathan Tan [off-list ref] wrote:
quoted
I think I've addressed all review comments. As for Junio's suggestion
about also printing the type in the former patch 4 (now patch 5) [1], I
decided to just leave the code as-is and not also print the type.
The main changes are that patch 1 is somewhat rewritten - we still
remove the global variable, but we no longer read the
extensions.partialClone config directly from promisor-remote.c. Instead,
we store it in struct repository when the format of a repository is
being verified, and promisor-remote.c merely reads it from there. Patch
3 is a new patch that updates the environment variable preparation
before it is moved in patch 4 (formerly patch 3).
I've read through all the patches. 2 & 5 look good to me, I had small
nitpicks on 1 & 4, and I'm totally lost on patch 3. Patch 3 is just a
one-liner and it might be fine, but for some reason I can't figure out
the code before or after the patch even after digging around into
other commits and other files to try to get my bearings. Hopefully
someone else can comment on that one.
I'm happy with Jonathan and Peff's responses on patch 3; as I
mentioned above I just didn't understand the original code before
Jonathan's changes. (Perhaps some comments could be added to clarify
that code area, but again that's clarifying the code that existed
before Jonathan's patch so it doesn't need to be part of his series.)
So that only leaves my nitpicks on patches 1 & 4; otherwise the series
looks good to me.
From: Jonathan Tan <hidden> Date: 2021-06-17 17:13:33
Quoting from [1]:
I'm happy with Jonathan and Peff's responses on patch 3; as I
mentioned above I just didn't understand the original code before
Jonathan's changes. (Perhaps some comments could be added to clarify
that code area, but again that's clarifying the code that existed
before Jonathan's patch so it doesn't need to be part of his series.)
So that only leaves my nitpicks on patches 1 & 4; otherwise the series
looks good to me.
I've addressed Elijah's comments on patches 1 and 4.
[1] https://lore.kernel.org/git/CABPp-BFD5=98C0+WnfK=+s7twZ960ORiZzUSP94GD2A4bXJ69Q@mail.gmail.com/
Jonathan Tan (5):
repository: move global r_f_p_c to repo struct
promisor-remote: support per-repository config
submodule: refrain from filtering GIT_CONFIG_COUNT
run-command: refactor subprocess env preparation
promisor-remote: teach lazy-fetch in any repo
Makefile | 1 +
object-file.c | 7 +--
promisor-remote.c | 108 ++++++++++++++++++----------------
promisor-remote.h | 28 ++++++---
repository.c | 10 ++++
repository.h | 5 ++
run-command.c | 12 ++++
run-command.h | 10 ++++
setup.c | 17 ++++--
submodule.c | 17 +-----
t/helper/test-partial-clone.c | 43 ++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 23 ++++++++
14 files changed, 199 insertions(+), 84 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
Range-diff against v3:
1: e8e6a95951 ! 1: 0bd009597d repository: move global r_f_p_c to repo struct
@@ repository.c: int repo_init(struct repository *repo,
repo_set_hash_algo(repo, format.hash_algo);
++ /* take ownership of format.partial_clone */
+ repo->repository_format_partial_clone = format.partial_clone;
+ format.partial_clone = NULL;
+
@@ setup.c: int discover_git_directory(struct strbuf *commondir,
return -1;
}
++ /* take ownership of candidate.partial_clone */
+ the_repository->repository_format_partial_clone =
+ candidate.partial_clone;
+ candidate.partial_clone = NULL;
@@ setup.c: const char *setup_git_directory_gently(int *nongit_ok)
- if (startup_info->have_repository)
+ if (startup_info->have_repository) {
repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
++ /* take ownership of repo_fmt.partial_clone */
+ the_repository->repository_format_partial_clone =
+ repo_fmt.partial_clone;
+ repo_fmt.partial_clone = NULL;
@@ setup.c: const char *setup_git_directory_gently(int *nongit_ok)
}
/*
* Since precompose_string_if_needed() needs to look at
-@@ setup.c: const char *setup_git_directory_gently(int *nongit_ok)
- setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
- }
-
--
- strbuf_release(&dir);
- strbuf_release(&gitdir);
- clear_repository_format(&repo_fmt);
@@ setup.c: void check_repository_format(struct repository_format *fmt)
check_repository_format_gently(get_git_dir(), fmt, NULL);
startup_info->have_repository = 1;
2: 07eb0a0f39 = 2: 8a478b46bf promisor-remote: support per-repository config
3: 004ac92e9b = 3: 78b4108ae1 submodule: refrain from filtering GIT_CONFIG_COUNT
4: ce0454f442 ! 4: 1778cbf878 run-command: refactor subprocess env preparation
@@ run-command.h: int run_processes_parallel_tr2(int n, get_next_task_fn, start_fai
+/**
+ * Convenience function which prepares env_array for a command to be run in a
+ * new repo. This adds all GIT_* environment variables to env_array with the
-+ * exception of GIT_CONFIG_PARAMETERS (which cause the corresponding
-+ * environment variables to be unset in the subprocess) and adds an environment
-+ * variable pointing to new_git_dir. See local_repo_env in cache.h for more
-+ * information.
++ * exception of GIT_CONFIG_PARAMETERS and GIT_CONFIG_COUNT (which cause the
++ * corresponding environment variables to be unset in the subprocess) and adds
++ * an environment variable pointing to new_git_dir. See local_repo_env in
++ * cache.h for more information.
+ */
+void prepare_other_repo_env(struct strvec *env_array, const char *new_git_dir);
+
5: a3278d61f0 = 5: dbba426b6a promisor-remote: teach lazy-fetch in any repo
--
2.32.0.272.g935e593368-goog
From: Jonathan Tan <hidden> Date: 2021-06-17 17:13:39
Move repository_format_partial_clone, which is currently a global
variable, into struct repository. (Full support for per-repository
partial clone config will be done in a subsequent commit - this is split
into its own commit because of the extent of the changes needed.)
The new repo-specific variable cannot be set in
check_repository_format_gently() (as is currently), because that
function does not know which repo it is operating on (or even whether
the value is important); therefore this responsibility is delegated to
the outermost caller that knows. Of all the outermost callers that know
(found by looking at all functions that call clear_repository_format()),
I looked at those that either read from the main Git directory or write
into a struct repository. These callers have been modified accordingly
(write to the_repository in the former case and write to the given
struct repository in the latter case).
Signed-off-by: Jonathan Tan <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
promisor-remote.c | 13 +++----------
promisor-remote.h | 6 ------
repository.c | 4 ++++
repository.h | 3 +++
setup.c | 17 +++++++++++++----
5 files changed, 23 insertions(+), 20 deletions(-)
@@ -172,6 +172,10 @@ int repo_init(struct repository *repo,repo_set_hash_algo(repo,format.hash_algo);+/* take ownership of format.partial_clone */+repo->repository_format_partial_clone=format.partial_clone;+format.partial_clone=NULL;+if(worktree)repo_set_worktree(repo,worktree);
@@ -139,6 +139,9 @@ struct repository {/* True if commit-graph has been disabled within this process. */intcommit_graph_disabled;+/* Configurations related to promisor remotes. */+char*repository_format_partial_clone;+/* Configurations *//* Indicate if a repository has a different 'commondir' from 'gitdir' */
@@ -1197,6 +1194,11 @@ int discover_git_directory(struct strbuf *commondir,return-1;}+/* take ownership of candidate.partial_clone */+the_repository->repository_format_partial_clone=+candidate.partial_clone;+candidate.partial_clone=NULL;+clear_repository_format(&candidate);return0;}
@@ -1304,8 +1306,13 @@ const char *setup_git_directory_gently(int *nongit_ok)gitdir=DEFAULT_GIT_DIR_ENVIRONMENT;setup_git_env(gitdir);}-if(startup_info->have_repository)+if(startup_info->have_repository){repo_set_hash_algo(the_repository,repo_fmt.hash_algo);+/* take ownership of repo_fmt.partial_clone */+the_repository->repository_format_partial_clone=+repo_fmt.partial_clone;+repo_fmt.partial_clone=NULL;+}}/**Sinceprecompose_string_if_needed()needstolookat
From: Jonathan Tan <hidden> Date: 2021-06-17 17:13:41
Instead of using global variables to store promisor remote information,
store this config in struct repository instead, and add
repository-agnostic non-static functions corresponding to the existing
non-static functions that only work on the_repository.
The actual lazy-fetching of missing objects currently does not work on
repositories other than the_repository, and will still not work after
this commit, so add a BUG message explaining this. A subsequent commit
will remove this limitation.
Signed-off-by: Jonathan Tan <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
promisor-remote.c | 98 ++++++++++++++++++++++++++---------------------
promisor-remote.h | 22 +++++++++--
repository.c | 6 +++
repository.h | 2 +
4 files changed, 82 insertions(+), 46 deletions(-)
@@ -228,9 +238,11 @@ int promisor_remote_get_direct(struct repository *repo,if(oid_nr==0)return0;-promisor_remote_init();+promisor_remote_init(repo);-for(r=promisors;r;r=r->next){+if(repo!=the_repository)+BUG("only the_repository is supported for now");+for(r=repo->promisor_remote_config->promisors;r;r=r->next){if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;
@@ -11,6 +11,7 @@#include"lockfile.h"#include"submodule-config.h"#include"sparse-index.h"+#include"promisor-remote.h"/* The main repository */staticstructrepositorythe_repo;
From: Jonathan Tan <hidden> Date: 2021-06-17 17:13:42
14111fc492 ("git: submodule honor -c credential.* from command line",
2016-03-01) taught Git to pass through the GIT_CONFIG_PARAMETERS
environment variable when invoking a subprocess on behalf of a
submodule. But when d8d77153ea ("config: allow specifying config entries
via envvar pairs", 2021-01-15) introduced support for GIT_CONFIG_COUNT
(and its associated GIT_CONFIG_KEY_? and GIT_CONFIG_VALUE_?), the
subprocess mechanism wasn't updated to also pass through these
variables.
Since they are conceptually the same (d8d77153ea was written to address
a shortcoming of GIT_CONFIG_PARAMETERS), update the submodule subprocess
mechanism to also pass through GIT_CONFIG_COUNT.
Signed-off-by: Jonathan Tan <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
submodule.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Jonathan Tan <hidden> Date: 2021-06-17 17:13:43
submodule.c has functionality that prepares the environment for running
a subprocess in a new repo. The lazy-fetching code (used in partial
clones) will need this in a subsequent commit, so move it to a more
central location.
Signed-off-by: Jonathan Tan <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
run-command.c | 12 ++++++++++++
run-command.h | 10 ++++++++++
submodule.c | 18 ++----------------
3 files changed, 24 insertions(+), 16 deletions(-)
@@ -483,4 +483,14 @@ int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn,task_finished_fn,void*pp_cb,constchar*tr2_category,constchar*tr2_label);+/**+*Conveniencefunctionwhichpreparesenv_arrayforacommandtoberunina+*newrepo.ThisaddsallGIT_*environmentvariablestoenv_arraywiththe+*exceptionofGIT_CONFIG_PARAMETERSandGIT_CONFIG_COUNT(whichcausethe+*correspondingenvironmentvariablestobeunsetinthesubprocess)andadds+*anenvironmentvariablepointingtonew_git_dir.Seelocal_repo_envin+*cache.hformoreinformation.+*/+voidprepare_other_repo_env(structstrvec*env_array,constchar*new_git_dir);+#endif
From: Jonathan Tan <hidden> Date: 2021-06-17 17:13:44
This is one step towards supporting partial clone submodules.
Even after this patch, we will still lack partial clone submodules
support, primarily because a lot of Git code that accesses submodule
objects does so by adding their object stores as alternates, meaning
that any lazy fetches that would occur in the submodule would be done
based on the config of the superproject, not of the submodule. This also
prevents testing of the functionality in this patch by user-facing
commands. So for now, test this mechanism using a test helper.
Besides that, there is some code that uses the wrapper functions
like has_promisor_remote(). Those will need to be checked to see if they
could support the non-wrapper functions instead (and thus support any
repository, not just the_repository).
Signed-off-by: Jonathan Tan <redacted>
Signed-off-by: Junio C Hamano <redacted>
---
Makefile | 1 +
object-file.c | 7 ++----
promisor-remote.c | 9 ++++----
t/helper/test-partial-clone.c | 43 +++++++++++++++++++++++++++++++++++
t/helper/test-tool.c | 1 +
t/helper/test-tool.h | 1 +
t/t0410-partial-clone.sh | 23 +++++++++++++++++++
7 files changed, 76 insertions(+), 9 deletions(-)
create mode 100644 t/helper/test-partial-clone.c
@@ -1570,15 +1570,12 @@ static int do_oid_object_info_extended(struct repository *r,}/* Check if it is a missing object */-if(fetch_if_missing&&has_promisor_remote()&&-!already_retried&&r==the_repository&&+if(fetch_if_missing&&repo_has_promisor_remote(r)&&+!already_retried&&!(flags&OBJECT_INFO_SKIP_FETCH_OBJECT)){/**TODOInvestigatecheckingpromisor_remote_get_direct()*TODOreturnvalueandstoppingonerrorhere.-*TODOPassarepositorystructthrough-*promisor_remote_get_direct(),suchthatarbitrary-*repositorieswork.*/promisor_remote_get_direct(r,real,1);already_retried=1;
@@ -20,6 +21,8 @@ static int fetch_objects(const char *remote_name,child.git_cmd=1;child.in=-1;+if(repo!=the_repository)+prepare_other_repo_env(&child.env_array,repo->gitdir);strvec_pushl(&child.args,"-c","fetch.negotiationAlgorithm=noop","fetch",remote_name,"--no-tags","--no-write-fetch-head","--recurse-submodules=no",
@@ -240,10 +243,8 @@ int promisor_remote_get_direct(struct repository *repo,promisor_remote_init(repo);-if(repo!=the_repository)-BUG("only the_repository is supported for now");for(r=repo->promisor_remote_config->promisors;r;r=r->next){-if(fetch_objects(r->name,remaining_oids,remaining_nr)<0){+if(fetch_objects(repo,r->name,remaining_oids,remaining_nr)<0){if(remaining_nr==1)continue;remaining_nr=remove_fetched_oids(repo,&remaining_oids,
@@ -604,6 +604,29 @@ test_expect_success 'do not fetch when checking existence of tree we construct ogit-Crepocherry-pickside1'+test_expect_success'lazy-fetch when accessing object not in the_repository''+rm-rffullpartial.git&&+test_create_repofull&&+test_commit-Cfullcreate-a-filefile.txt&&++test_config-Cfulluploadpack.allowfilter1&&+test_config-Cfulluploadpack.allowanysha1inwant1&&+gitclone--filter=blob:none--bare"file://$(pwd)/full"partial.git&&+FILE_HASH=$(git-Cfullrev-parseHEAD:file.txt)&&++# Sanity check that the file is missing+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+grep"[?]$FILE_HASH"out&&++git-Cfullcat-file-s"$FILE_HASH">expect&&+test-toolpartial-cloneobject-infopartial.git"$FILE_HASH">actual&&+test_cmpexpectactual&&++# Sanity check that the file is now present+git-Cpartial.gitrev-list--objects--missing=printHEAD>out&&+!grep"[?]$FILE_HASH"out+'+ ."$TEST_DIRECTORY"/lib-httpd.sh start_httpd
On Thu, Jun 17, 2021 at 10:13 AM Jonathan Tan [off-list ref] wrote:
Quoting from [1]:
quoted
I'm happy with Jonathan and Peff's responses on patch 3; as I
mentioned above I just didn't understand the original code before
Jonathan's changes. (Perhaps some comments could be added to clarify
that code area, but again that's clarifying the code that existed
before Jonathan's patch so it doesn't need to be part of his series.)
So that only leaves my nitpicks on patches 1 & 4; otherwise the series
looks good to me.
I've addressed Elijah's comments on patches 1 and 4.
Yep, patches 1, 2, 4, and 5 are Reviewed-by me. While I looked over
Patch 3, I made Peff explain it to me, so he's the one who reviewed
that one. ;-)