{"thread":{"id":"48480","subject":"[PATCH v1 0/8] Introducing odb remote","startedAt":"2018-05-13T10:32:58Z","lastAt":"2018-06-25T18:06:50Z","messageCount":15,"participants":["Christian Couder","Junio C Hamano","Ævar Arnfjörð Bjarmason"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"347537","messageId":"20180513103232.17514-1-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":null,"subject":"[PATCH v1 0/8] Introducing odb remote","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:24Z","receivedAt":"2018-05-13T10:32:58Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This is a follow up from the patch series called \"Promisor remotes and\nexternal ODB support\" that I sent earlier this year.\n\nFollowing discussions of these patch series, where Junio said \"a\nminimum s/ext/remote/ would clarify what it is\", I decided to rename\n\"external odb\" to \"odb remote\". I am still open to another name, but I\nthink that \"odb remote\" works well with \"odb helper\" that was already\nused in the series and is as good or perhaps better than \"remote odb\",\nas a \"remote odb\" I think would be easier to confuse with a regular\n\"remote\".\n\nAnother obvious difference with the previous series is that this\nseries is only about integrating with the promisor/narrow clone work\nand showing that it makes it possible to use more than one promisor\nremote. Everything that is not necessary for that integration has been\nremoved for now (though you can still find it in one of my branches on\nGitHub if you want).\n\nThis makes this patch series much shorter than the previous ones and\nalready useful. So hopefully this will make it possible to start\nreviewing and merging it.\n\nThere is one test in patch 8/8 that shows that more than one promisor\nremote can now be used, but I feel that it could be interesting to add\nother such tests, so I am open to ideas in this area.\n\nHigh level overview of this patch series\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n  - Patch 1/8:\n\nThis makes functions in fetch-object.c return an error code, which is\nnecessary to later tell that they failed and try another odb remote\nwhen there is more than one. This could also just be seen as a fix to\nthese functions.\n\n  - Patch 2/8:\n\nThis introduces the minimum infrastructure for odb remotes.\n\n  - Patches 3/8 and 4/8:\n\nThese patches implement odb_remote_get_direct() and\nodb_remote_get_many_direct() using the functions from fetch-object.c.\nThese new functions will be used in following patches to replace the\nfunctions from fetch-object.c.\n\n  - Patch 5/8:\n\nThis implement odb_remote_reinit() which will be needed to reparse the\nodb remote configuration.\n\n  - Patches 6/8 and 7/8:\n\nThese patches integrate the odb remote mechanism into the\npromisor/narrow clone code. The \"extensions.partialclone\" config\noption is replaced by \"odb.<name>.promisorRemote\" and\n\"core.partialclonefilter\" is replaced by \"odb.<name>.partialclonefilter\".\n\n  - Patch 8/8:\n\nThis adds a test case that shows that now more than one promisor\nremote can be used.\n\nLinks\n~~~~~\n\nThis patch series on GitHub:\n\nhttps://github.com/chriscool/git/commits/odb-remote\n\nVersion 1 and 2 of the \"Promisor remotes and external ODB support\" series:\n\nhttps://public-inbox.org/git/20180103163403.11303-1-chriscool@tuxfamily.org/\nhttps://public-inbox.org/git/20180319133147.15413-1-chriscool@tuxfamily.org/\n\nVersion 1 and 2 of the \"Promisor remotes and external ODB support\" series on GitHub:\n\nhttps://github.com/chriscool/git/commits/gl-small-promisor-external-odb12\nhttps://github.com/chriscool/git/commits/gl-small-promisor-external-odb71\n\n\nChristian Couder (8):\n  fetch-object: make functions return an error code\n  Add initial odb remote support\n  odb-remote: implement odb_remote_get_direct()\n  odb-remote: implement odb_remote_get_many_direct()\n  odb-remote: add odb_remote_reinit()\n  Use odb_remote_get_direct() and has_external_odb()\n  Use odb.origin.partialclonefilter instead of core.partialclonefilter\n  t0410: test fetching from many promisor remotes\n\n Makefile                      |   2 +\n builtin/cat-file.c            |   5 +-\n builtin/fetch.c               |  13 ++--\n builtin/gc.c                  |   3 +-\n builtin/repack.c              |   3 +-\n cache.h                       |   2 -\n connected.c                   |   3 +-\n environment.c                 |   1 -\n fetch-object.c                |  15 +++--\n fetch-object.h                |   6 +-\n list-objects-filter-options.c |  49 ++++++++------\n list-objects-filter-options.h |   3 +-\n odb-helper.c                  |  45 +++++++++++++\n odb-helper.h                  |  18 ++++++\n odb-remote.c                  | 118 ++++++++++++++++++++++++++++++++++\n odb-remote.h                  |  10 +++\n packfile.c                    |   3 +-\n setup.c                       |   7 +-\n sha1-file.c                   |   9 +--\n t/t0410-partial-clone.sh      |  54 +++++++++++-----\n t/t5500-fetch-pack.sh         |   4 +-\n t/t5601-clone.sh              |   2 +-\n t/t5616-partial-clone.sh      |   4 +-\n unpack-trees.c                |   6 +-\n 24 files changed, 306 insertions(+), 79 deletions(-)\n create mode 100644 odb-helper.c\n create mode 100644 odb-helper.h\n create mode 100644 odb-remote.c\n create mode 100644 odb-remote.h\n\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347538","messageId":"20180513103232.17514-2-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"[PATCH v1 1/8] fetch-object: make functions return an error code","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:25Z","receivedAt":"2018-05-13T10:33:02Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"The callers of the fetch_object() and fetch_objects() might\nbe interested in knowing if these functions succeeded or not.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n fetch-object.c | 15 +++++++++------\n fetch-object.h |  6 +++---\n sha1-file.c    |  4 ++--\n 3 files changed, 14 insertions(+), 11 deletions(-)\n\ndiff --git a/fetch-object.c b/fetch-object.c\nindex 853624f811..ccc4ea7f1a 100644\n--- a/fetch-object.c\n+++ b/fetch-object.c\n@@ -5,11 +5,12 @@\n #include \"transport.h\"\n #include \"fetch-object.h\"\n \n-static void fetch_refs(const char *remote_name, struct ref *ref)\n+static int fetch_refs(const char *remote_name, struct ref *ref)\n {\n \tstruct remote *remote;\n \tstruct transport *transport;\n \tint original_fetch_if_missing = fetch_if_missing;\n+\tint res;\n \n \tfetch_if_missing = 0;\n \tremote = remote_get(remote_name);\n@@ -19,18 +20,20 @@ static void fetch_refs(const char *remote_name, struct ref *ref)\n \n \ttransport_set_option(transport, TRANS_OPT_FROM_PROMISOR, \"1\");\n \ttransport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, \"1\");\n-\ttransport_fetch_refs(transport, ref);\n+\tres = transport_fetch_refs(transport, ref);\n \tfetch_if_missing = original_fetch_if_missing;\n+\n+\treturn res;\n }\n \n-void fetch_object(const char *remote_name, const unsigned char *sha1)\n+int fetch_object(const char *remote_name, const unsigned char *sha1)\n {\n \tstruct ref *ref = alloc_ref(sha1_to_hex(sha1));\n \thashcpy(ref->old_oid.hash, sha1);\n-\tfetch_refs(remote_name, ref);\n+\treturn fetch_refs(remote_name, ref);\n }\n \n-void fetch_objects(const char *remote_name, const struct oid_array *to_fetch)\n+int fetch_objects(const char *remote_name, const struct oid_array *to_fetch)\n {\n \tstruct ref *ref = NULL;\n \tint i;\n@@ -41,5 +44,5 @@ void fetch_objects(const char *remote_name, const struct oid_array *to_fetch)\n \t\tnew_ref->next = ref;\n \t\tref = new_ref;\n \t}\n-\tfetch_refs(remote_name, ref);\n+\treturn fetch_refs(remote_name, ref);\n }\ndiff --git a/fetch-object.h b/fetch-object.h\nindex 4b269d07ed..12e1f9ee70 100644\n--- a/fetch-object.h\n+++ b/fetch-object.h\n@@ -3,9 +3,9 @@\n \n #include \"sha1-array.h\"\n \n-extern void fetch_object(const char *remote_name, const unsigned char *sha1);\n+extern int fetch_object(const char *remote_name, const unsigned char *sha1);\n \n-extern void fetch_objects(const char *remote_name,\n-\t\t\t  const struct oid_array *to_fetch);\n+extern int fetch_objects(const char *remote_name,\n+\t\t\t const struct oid_array *to_fetch);\n \n #endif\ndiff --git a/sha1-file.c b/sha1-file.c\nindex 46072602ff..7d3c1ebd91 100644\n--- a/sha1-file.c\n+++ b/sha1-file.c\n@@ -1290,8 +1290,8 @@ int oid_object_info_extended(const struct object_id *oid, struct object_info *oi\n \t\tif (fetch_if_missing && repository_format_partial_clone &&\n \t\t    !already_retried) {\n \t\t\t/*\n-\t\t\t * TODO Investigate haveing fetch_object() return\n-\t\t\t * TODO error/success and stopping the music here.\n+\t\t\t * TODO Investigate checking fetch_object() return\n+\t\t\t * TODO value and stopping on error here.\n \t\t\t */\n \t\t\tfetch_object(repository_format_partial_clone, real->hash);\n \t\t\talready_retried = 1;\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347539","messageId":"20180513103232.17514-4-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"[PATCH v1 3/8] odb-remote: implement odb_remote_get_direct()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:27Z","receivedAt":"2018-05-13T10:33:04Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This is implemented only in the promisor remote mode\nfor now by calling fetch_object().\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n odb-helper.c | 14 ++++++++++++++\n odb-helper.h |  3 ++-\n odb-remote.c | 17 +++++++++++++++++\n odb-remote.h |  1 +\n 4 files changed, 34 insertions(+), 1 deletion(-)\n\ndiff --git a/odb-helper.c b/odb-helper.c\nindex b4d403ffa9..2851fe2657 100644\n--- a/odb-helper.c\n+++ b/odb-helper.c\n@@ -4,6 +4,7 @@\n #include \"odb-helper.h\"\n #include \"run-command.h\"\n #include \"sha1-lookup.h\"\n+#include \"fetch-object.h\"\n \n struct odb_helper *odb_helper_new(const char *name, int namelen)\n {\n@@ -14,3 +15,16 @@ struct odb_helper *odb_helper_new(const char *name, int namelen)\n \n \treturn o;\n }\n+\n+int odb_helper_get_direct(struct odb_helper *o,\n+\t\t\t  const unsigned char *sha1)\n+{\n+\tint res;\n+\tuint64_t start = getnanotime();\n+\n+\tres = fetch_object(o->dealer, sha1);\n+\n+\ttrace_performance_since(start, \"odb_helper_get_direct\");\n+\n+\treturn res;\n+}\ndiff --git a/odb-helper.h b/odb-helper.h\nindex 61d2ad082b..d21b625a7e 100644\n--- a/odb-helper.h\n+++ b/odb-helper.h\n@@ -9,5 +9,6 @@ struct odb_helper {\n };\n \n extern struct odb_helper *odb_helper_new(const char *name, int namelen);\n-\n+extern int odb_helper_get_direct(struct odb_helper *o,\n+\t\t\t\t const unsigned char *sha1);\n #endif /* ODB_HELPER_H */\ndiff --git a/odb-remote.c b/odb-remote.c\nindex e03b953ec6..dbab40c0f8 100644\n--- a/odb-remote.c\n+++ b/odb-remote.c\n@@ -70,3 +70,20 @@ int has_odb_remote(void)\n {\n \treturn !!find_odb_helper(NULL);\n }\n+\n+int odb_remote_get_direct(const unsigned char *sha1)\n+{\n+\tstruct odb_helper *o;\n+\n+\ttrace_printf(\"trace: odb_remote_get_direct: %s\", sha1_to_hex(sha1));\n+\n+\todb_remote_init();\n+\n+\tfor (o = helpers; o; o = o->next) {\n+\t\tif (odb_helper_get_direct(o, sha1) < 0)\n+\t\t\tcontinue;\n+\t\treturn 0;\n+\t}\n+\n+\treturn -1;\n+}\ndiff --git a/odb-remote.h b/odb-remote.h\nindex 68aa330244..27a480fcfe 100644\n--- a/odb-remote.h\n+++ b/odb-remote.h\n@@ -3,5 +3,6 @@\n \n extern struct odb_helper *find_odb_helper(const char *dealer);\n extern int has_odb_remote(void);\n+extern int odb_remote_get_direct(const unsigned char *sha1);\n \n #endif /* ODB_REMOTE_H */\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347540","messageId":"20180513103232.17514-6-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"[PATCH v1 5/8] odb-remote: add odb_remote_reinit()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:29Z","receivedAt":"2018-05-13T10:33:08Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"We will need to reinitialize the odb remote configuration\nas we will make some changes to it in a later commit when\nwe will detect that a remote is also an odb remote.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n odb-remote.c | 14 ++++++++++++--\n odb-remote.h |  1 +\n 2 files changed, 13 insertions(+), 2 deletions(-)\n\ndiff --git a/odb-remote.c b/odb-remote.c\nindex 9a1561430c..0a734ff379 100644\n--- a/odb-remote.c\n+++ b/odb-remote.c\n@@ -39,17 +39,27 @@ static int odb_remote_config(const char *var, const char *value, void *data)\n \treturn 0;\n }\n \n-static void odb_remote_init(void)\n+static void odb_remote_do_init(int force)\n {\n \tstatic int initialized;\n \n-\tif (initialized)\n+\tif (!force && initialized)\n \t\treturn;\n \tinitialized = 1;\n \n \tgit_config(odb_remote_config, NULL);\n }\n \n+static inline void odb_remote_init(void)\n+{\n+\todb_remote_do_init(0);\n+}\n+\n+inline void odb_remote_reinit(void)\n+{\n+\todb_remote_do_init(1);\n+}\n+\n struct odb_helper *find_odb_helper(const char *dealer)\n {\n \tstruct odb_helper *o;\ndiff --git a/odb-remote.h b/odb-remote.h\nindex e6cedde722..d862216a8f 100644\n--- a/odb-remote.h\n+++ b/odb-remote.h\n@@ -1,6 +1,7 @@\n #ifndef ODB_REMOTE_H\n #define ODB_REMOTE_H\n \n+extern void odb_remote_reinit(void);\n extern struct odb_helper *find_odb_helper(const char *dealer);\n extern int has_odb_remote(void);\n extern int odb_remote_get_direct(const unsigned char *sha1);\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347541","messageId":"20180513103232.17514-3-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"[PATCH v1 2/8] Add initial odb remote support","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:26Z","receivedAt":"2018-05-13T10:33:10Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"The odb-remote.{c,h} files will contain the functions\nthat are called by the rest of Git mostly from\n\"sha1_file.c\" to access the objects managed by the\nodb remotes.\n\nThe odb-helper.{c,h} files will contain the functions to\nactually implement communication with either the internal\nfunctions or the external scripts or processes that will\nmanage and provide remote git objects.\n\nFor now only infrastructure to create helpers from the\nconfig and to check if there are odb remotes and helpers\nis implemented.\n\nHelped-by: Jeff King <peff@peff.net>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Makefile     |  2 ++\n odb-helper.c | 16 ++++++++++++\n odb-helper.h | 13 ++++++++++\n odb-remote.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n odb-remote.h |  7 +++++\n 5 files changed, 110 insertions(+)\n create mode 100644 odb-helper.c\n create mode 100644 odb-helper.h\n create mode 100644 odb-remote.c\n create mode 100644 odb-remote.h\n\ndiff --git a/Makefile b/Makefile\nindex ad880d1fc5..f64dea287b 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -896,6 +896,8 @@ LIB_OBJS += notes-cache.o\n LIB_OBJS += notes-merge.o\n LIB_OBJS += notes-utils.o\n LIB_OBJS += object.o\n+LIB_OBJS += odb-helper.o\n+LIB_OBJS += odb-remote.o\n LIB_OBJS += oidmap.o\n LIB_OBJS += oidset.o\n LIB_OBJS += packfile.o\ndiff --git a/odb-helper.c b/odb-helper.c\nnew file mode 100644\nindex 0000000000..b4d403ffa9\n--- /dev/null\n+++ b/odb-helper.c\n@@ -0,0 +1,16 @@\n+#include \"cache.h\"\n+#include \"object.h\"\n+#include \"argv-array.h\"\n+#include \"odb-helper.h\"\n+#include \"run-command.h\"\n+#include \"sha1-lookup.h\"\n+\n+struct odb_helper *odb_helper_new(const char *name, int namelen)\n+{\n+\tstruct odb_helper *o;\n+\n+\to = xcalloc(1, sizeof(*o));\n+\to->name = xmemdupz(name, namelen);\n+\n+\treturn o;\n+}\ndiff --git a/odb-helper.h b/odb-helper.h\nnew file mode 100644\nindex 0000000000..61d2ad082b\n--- /dev/null\n+++ b/odb-helper.h\n@@ -0,0 +1,13 @@\n+#ifndef ODB_HELPER_H\n+#define ODB_HELPER_H\n+\n+struct odb_helper {\n+\tconst char *name;\n+\tconst char *dealer;\n+\n+\tstruct odb_helper *next;\n+};\n+\n+extern struct odb_helper *odb_helper_new(const char *name, int namelen);\n+\n+#endif /* ODB_HELPER_H */\ndiff --git a/odb-remote.c b/odb-remote.c\nnew file mode 100644\nindex 0000000000..e03b953ec6\n--- /dev/null\n+++ b/odb-remote.c\n@@ -0,0 +1,72 @@\n+#include \"cache.h\"\n+#include \"odb-remote.h\"\n+#include \"odb-helper.h\"\n+#include \"config.h\"\n+\n+static struct odb_helper *helpers;\n+static struct odb_helper **helpers_tail = &helpers;\n+\n+static struct odb_helper *find_or_create_helper(const char *name, int len)\n+{\n+\tstruct odb_helper *o;\n+\n+\tfor (o = helpers; o; o = o->next)\n+\t\tif (!strncmp(o->name, name, len) && !o->name[len])\n+\t\t\treturn o;\n+\n+\to = odb_helper_new(name, len);\n+\t*helpers_tail = o;\n+\thelpers_tail = &o->next;\n+\n+\treturn o;\n+}\n+\n+static int odb_remote_config(const char *var, const char *value, void *data)\n+{\n+\tstruct odb_helper *o;\n+\tconst char *name;\n+\tint namelen;\n+\tconst char *subkey;\n+\n+\tif (parse_config_key(var, \"odb\", &name, &namelen, &subkey) < 0)\n+\t\treturn 0;\n+\n+\to = find_or_create_helper(name, namelen);\n+\n+\tif (!strcmp(subkey, \"promisorremote\"))\n+\t\treturn git_config_string(&o->dealer, var, value);\n+\n+\treturn 0;\n+}\n+\n+static void odb_remote_init(void)\n+{\n+\tstatic int initialized;\n+\n+\tif (initialized)\n+\t\treturn;\n+\tinitialized = 1;\n+\n+\tgit_config(odb_remote_config, NULL);\n+}\n+\n+struct odb_helper *find_odb_helper(const char *dealer)\n+{\n+\tstruct odb_helper *o;\n+\n+\todb_remote_init();\n+\n+\tif (!dealer)\n+\t\treturn helpers;\n+\n+\tfor (o = helpers; o; o = o->next)\n+\t\tif (!strcmp(o->dealer, dealer))\n+\t\t\treturn o;\n+\n+\treturn NULL;\n+}\n+\n+int has_odb_remote(void)\n+{\n+\treturn !!find_odb_helper(NULL);\n+}\ndiff --git a/odb-remote.h b/odb-remote.h\nnew file mode 100644\nindex 0000000000..68aa330244\n--- /dev/null\n+++ b/odb-remote.h\n@@ -0,0 +1,7 @@\n+#ifndef ODB_REMOTE_H\n+#define ODB_REMOTE_H\n+\n+extern struct odb_helper *find_odb_helper(const char *dealer);\n+extern int has_odb_remote(void);\n+\n+#endif /* ODB_REMOTE_H */\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347542","messageId":"20180513103232.17514-8-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"[PATCH v1 7/8] Use odb.origin.partialclonefilter instead of core.partialclonefilter","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:31Z","receivedAt":"2018-05-13T10:33:14Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Let's make the partial clone filter specific to one odb\ninstead of general to all the odbs.\n\nThis makes it possible to have different partial clone\nfilters for different odbs.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin/fetch.c               |  2 +-\n list-objects-filter-options.c | 26 ++++++++++++++++----------\n list-objects-filter-options.h |  3 ++-\n odb-helper.h                  |  1 +\n odb-remote.c                  |  2 ++\n t/t5616-partial-clone.sh      |  2 +-\n 6 files changed, 23 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 82a3e655ba..288d58c0c5 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -1350,7 +1350,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)\n \t * the config.\n \t */\n \tif (!filter_options.choice)\n-\t\tpartial_clone_get_default_filter_spec(&filter_options);\n+\t\tpartial_clone_get_default_filter_spec(&filter_options, remote->name);\n \treturn;\n }\n \ndiff --git a/list-objects-filter-options.c b/list-objects-filter-options.c\nindex f8a4642d17..59378dfb0a 100644\n--- a/list-objects-filter-options.c\n+++ b/list-objects-filter-options.c\n@@ -7,6 +7,7 @@\n #include \"list-objects-filter.h\"\n #include \"list-objects-filter-options.h\"\n #include \"odb-remote.h\"\n+#include \"odb-helper.h\"\n \n /*\n  * Parse value of the argument to the \"filter\" keyword.\n@@ -29,6 +30,9 @@ static int gently_parse_list_objects_filter(\n {\n \tconst char *v0;\n \n+\tif (!arg)\n+\t\treturn 0;\n+\n \tif (filter_options->choice) {\n \t\tif (errbuf) {\n \t\t\tstrbuf_init(errbuf, 0);\n@@ -116,6 +120,7 @@ void partial_clone_register(\n \tconst struct list_objects_filter_options *filter_options)\n {\n \tchar *cfg_name;\n+\tchar *filter_name;\n \n \t/* Check if it is already registered */\n \tif (find_odb_helper(remote))\n@@ -131,25 +136,26 @@ void partial_clone_register(\n \t/*\n \t * Record the initial filter-spec in the config as\n \t * the default for subsequent fetches from this remote.\n-\t *\n-\t * TODO: move core.partialclonefilter into odb.<name>\n \t */\n-\tcore_partial_clone_filter_default =\n-\t\txstrdup(filter_options->filter_spec);\n-\tgit_config_set(\"core.partialclonefilter\",\n-\t\t       core_partial_clone_filter_default);\n+\tfilter_name = xstrfmt(\"odb.%s.partialclonefilter\", remote);\n+\tgit_config_set(filter_name, filter_options->filter_spec);\n+\tfree(filter_name);\n \n \t/* Make sure the config info are reset */\n \todb_remote_reinit();\n }\n \n void partial_clone_get_default_filter_spec(\n-\tstruct list_objects_filter_options *filter_options)\n+\tstruct list_objects_filter_options *filter_options,\n+\tconst char *remote)\n {\n+\tstruct odb_helper *helper = find_odb_helper(remote);\n+\n \t/*\n \t * Parse default value, but silently ignore it if it is invalid.\n \t */\n-\tgently_parse_list_objects_filter(filter_options,\n-\t\t\t\t\t core_partial_clone_filter_default,\n-\t\t\t\t\t NULL);\n+\tif (helper)\n+\t\tgently_parse_list_objects_filter(filter_options,\n+\t\t\t\t\t\t helper->partial_clone_filter,\n+\t\t\t\t\t\t NULL);\n }\ndiff --git a/list-objects-filter-options.h b/list-objects-filter-options.h\nindex 0000a61f82..12ceef3230 100644\n--- a/list-objects-filter-options.h\n+++ b/list-objects-filter-options.h\n@@ -74,6 +74,7 @@ void partial_clone_register(\n \tconst char *remote,\n \tconst struct list_objects_filter_options *filter_options);\n void partial_clone_get_default_filter_spec(\n-\tstruct list_objects_filter_options *filter_options);\n+\tstruct list_objects_filter_options *filter_options,\n+\tconst char *remote);\n \n #endif /* LIST_OBJECTS_FILTER_OPTIONS_H */\ndiff --git a/odb-helper.h b/odb-helper.h\nindex d63210d516..02bc3dbe13 100644\n--- a/odb-helper.h\n+++ b/odb-helper.h\n@@ -4,6 +4,7 @@\n struct odb_helper {\n \tconst char *name;\n \tconst char *dealer;\n+\tconst char *partial_clone_filter;\n \n \tstruct odb_helper *next;\n };\ndiff --git a/odb-remote.c b/odb-remote.c\nindex 0a734ff379..2c7c35c763 100644\n--- a/odb-remote.c\n+++ b/odb-remote.c\n@@ -35,6 +35,8 @@ static int odb_remote_config(const char *var, const char *value, void *data)\n \n \tif (!strcmp(subkey, \"promisorremote\"))\n \t\treturn git_config_string(&o->dealer, var, value);\n+\tif (!strcmp(subkey, \"partialclonefilter\"))\n+\t\treturn git_config_string(&o->partial_clone_filter, var, value);\n \n \treturn 0;\n }\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 5ddd1e011c..4231121181 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -41,7 +41,7 @@ test_expect_success 'do partial clone 1' '\n \ttest_cmp expect_1.oids observed.oids &&\n \ttest \"$(git -C pc1 config --local core.repositoryformatversion)\" = \"1\" &&\n \ttest \"$(git -C pc1 config --local odb.origin.promisorRemote)\" = \"origin\" &&\n-\ttest \"$(git -C pc1 config --local core.partialclonefilter)\" = \"blob:none\"\n+\ttest \"$(git -C pc1 config --local odb.origin.partialclonefilter)\" = \"blob:none\"\n '\n \n # checkout master to force dynamic object fetch of blobs at HEAD.\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347543","messageId":"20180513103232.17514-7-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"[PATCH v1 6/8] Use odb_remote_get_direct() and has_external_odb()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:30Z","receivedAt":"2018-05-13T10:33:14Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Instead of using the repository_format_partial_clone global\nand fetch_object() directly, let's use has_odb_remote() and\nodb_remote_get_direct().\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin/cat-file.c            |  5 +++--\n builtin/fetch.c               | 11 ++++++-----\n builtin/gc.c                  |  3 ++-\n builtin/repack.c              |  3 ++-\n cache.h                       |  2 --\n connected.c                   |  3 ++-\n environment.c                 |  1 -\n list-objects-filter-options.c | 27 +++++++++++++++------------\n packfile.c                    |  3 ++-\n setup.c                       |  7 +------\n sha1-file.c                   |  9 +++++----\n t/t0410-partial-clone.sh      | 30 +++++++++++++++---------------\n t/t5500-fetch-pack.sh         |  4 ++--\n t/t5601-clone.sh              |  2 +-\n t/t5616-partial-clone.sh      |  2 +-\n unpack-trees.c                |  6 +++---\n 16 files changed, 60 insertions(+), 58 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 2c46d257cd..25665b206a 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -13,6 +13,7 @@\n #include \"tree-walk.h\"\n #include \"sha1-array.h\"\n #include \"packfile.h\"\n+#include \"odb-remote.h\"\n \n struct batch_options {\n \tint enabled;\n@@ -477,8 +478,8 @@ static int batch_objects(struct batch_options *opt)\n \n \t\tfor_each_loose_object(batch_loose_object, &sa, 0);\n \t\tfor_each_packed_object(batch_packed_object, &sa, 0);\n-\t\tif (repository_format_partial_clone)\n-\t\t\twarning(\"This repository has extensions.partialClone set. Some objects may not be loaded.\");\n+\t\tif (has_odb_remote())\n+\t\t\twarning(\"This repository uses an odb. Some objects may not be loaded.\");\n \n \t\tcb.opt = opt;\n \t\tcb.expand = &data;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 7ee83ac0f8..82a3e655ba 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -20,6 +20,7 @@\n #include \"utf8.h\"\n #include \"packfile.h\"\n #include \"list-objects-filter-options.h\"\n+#include \"odb-remote.h\"\n \n static const char * const builtin_fetch_usage[] = {\n \tN_(\"git fetch [<options>] [<repository> [<refspec>...]]\"),\n@@ -1320,7 +1321,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)\n \t * If no prior partial clone/fetch and the current fetch DID NOT\n \t * request a partial-fetch, do a normal fetch.\n \t */\n-\tif (!repository_format_partial_clone && !filter_options.choice)\n+\tif (!has_odb_remote() && !filter_options.choice)\n \t\treturn;\n \n \t/*\n@@ -1328,7 +1329,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)\n \t * on this repo and remember the given filter-spec as the default\n \t * for subsequent fetches to this remote.\n \t */\n-\tif (!repository_format_partial_clone && filter_options.choice) {\n+\tif (!has_odb_remote() && filter_options.choice) {\n \t\tpartial_clone_register(remote->name, &filter_options);\n \t\treturn;\n \t}\n@@ -1337,7 +1338,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)\n \t * We are currently limited to only ONE promisor remote and only\n \t * allow partial-fetches from the promisor remote.\n \t */\n-\tif (strcmp(remote->name, repository_format_partial_clone)) {\n+\tif (!find_odb_helper(remote->name)) {\n \t\tif (filter_options.choice)\n \t\t\tdie(_(\"--filter can only be used with the remote configured in core.partialClone\"));\n \t\treturn;\n@@ -1473,7 +1474,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \tif (depth || deepen_since || deepen_not.nr)\n \t\tdeepen = 1;\n \n-\tif (filter_options.choice && !repository_format_partial_clone)\n+\tif (filter_options.choice && !has_odb_remote())\n \t\tdie(\"--filter can only be used when extensions.partialClone is set\");\n \n \tif (all) {\n@@ -1507,7 +1508,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (remote) {\n-\t\tif (filter_options.choice || repository_format_partial_clone)\n+\t\tif (filter_options.choice || has_odb_remote())\n \t\t\tfetch_one_setup_partial(remote);\n \t\tresult = fetch_one(remote, argc, argv, prune_tags_ok);\n \t} else {\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex d604940bb6..418cf2f0b0 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -22,6 +22,7 @@\n #include \"commit.h\"\n #include \"packfile.h\"\n #include \"object-store.h\"\n+#include \"odb-remote.h\"\n \n #define FAILED_RUN \"failed to run %s\"\n \n@@ -466,7 +467,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \t\t\targv_array_push(&prune, prune_expire);\n \t\t\tif (quiet)\n \t\t\t\targv_array_push(&prune, \"--no-progress\");\n-\t\t\tif (repository_format_partial_clone)\n+\t\t\tif (has_odb_remote())\n \t\t\t\targv_array_push(&prune,\n \t\t\t\t\t\t\"--exclude-promisor-objects\");\n \t\t\tif (run_command_v_opt(prune.argv, RUN_GIT_CMD))\ndiff --git a/builtin/repack.c b/builtin/repack.c\nindex 7bdb40142f..8d2126087b 100644\n--- a/builtin/repack.c\n+++ b/builtin/repack.c\n@@ -8,6 +8,7 @@\n #include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"argv-array.h\"\n+#include \"odb-remote.h\"\n \n static int delta_base_offset = 1;\n static int pack_kept_objects = -1;\n@@ -234,7 +235,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)\n \targv_array_push(&cmd.args, \"--all\");\n \targv_array_push(&cmd.args, \"--reflog\");\n \targv_array_push(&cmd.args, \"--indexed-objects\");\n-\tif (repository_format_partial_clone)\n+\tif (has_odb_remote())\n \t\targv_array_push(&cmd.args, \"--exclude-promisor-objects\");\n \tif (window)\n \t\targv_array_pushf(&cmd.args, \"--window=%s\", window);\ndiff --git a/cache.h b/cache.h\nindex 0c1fb9fbcc..17263f9013 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -897,13 +897,11 @@ extern int grafts_replace_parents;\n #define GIT_REPO_VERSION 0\n #define GIT_REPO_VERSION_READ 1\n extern int repository_format_precious_objects;\n-extern char *repository_format_partial_clone;\n extern const char *core_partial_clone_filter_default;\n \n struct repository_format {\n \tint version;\n \tint precious_objects;\n-\tchar *partial_clone; /* value of extensions.partialclone */\n \tint is_bare;\n \tint hash_algo;\n \tchar *work_tree;\ndiff --git a/connected.c b/connected.c\nindex 91feb78815..5d45f833d4 100644\n--- a/connected.c\n+++ b/connected.c\n@@ -4,6 +4,7 @@\n #include \"connected.h\"\n #include \"transport.h\"\n #include \"packfile.h\"\n+#include \"odb-remote.h\"\n \n /*\n  * If we feed all the commits we want to verify to this command\n@@ -56,7 +57,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,\n \targv_array_push(&rev_list.args,\"rev-list\");\n \targv_array_push(&rev_list.args, \"--objects\");\n \targv_array_push(&rev_list.args, \"--stdin\");\n-\tif (repository_format_partial_clone)\n+\tif (has_odb_remote())\n \t\targv_array_push(&rev_list.args, \"--exclude-promisor-objects\");\n \targv_array_push(&rev_list.args, \"--not\");\n \targv_array_push(&rev_list.args, \"--all\");\ndiff --git a/environment.c b/environment.c\nindex 2a6de2330b..f8048f4a5d 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -30,7 +30,6 @@ int warn_ambiguous_refs = 1;\n int warn_on_object_refname_ambiguity = 1;\n int ref_paranoia = -1;\n int repository_format_precious_objects;\n-char *repository_format_partial_clone;\n const char *core_partial_clone_filter_default;\n const char *git_commit_encoding;\n const char *git_log_output_encoding;\ndiff --git a/list-objects-filter-options.c b/list-objects-filter-options.c\nindex 6a3cc985c4..f8a4642d17 100644\n--- a/list-objects-filter-options.c\n+++ b/list-objects-filter-options.c\n@@ -6,6 +6,7 @@\n #include \"list-objects.h\"\n #include \"list-objects-filter.h\"\n #include \"list-objects-filter-options.h\"\n+#include \"odb-remote.h\"\n \n /*\n  * Parse value of the argument to the \"filter\" keyword.\n@@ -114,30 +115,32 @@ void partial_clone_register(\n \tconst char *remote,\n \tconst struct list_objects_filter_options *filter_options)\n {\n-\t/*\n-\t * Record the name of the partial clone remote in the\n-\t * config and in the global variable -- the latter is\n-\t * used throughout to indicate that partial clone is\n-\t * enabled and to expect missing objects.\n-\t */\n-\tif (repository_format_partial_clone &&\n-\t    *repository_format_partial_clone &&\n-\t    strcmp(remote, repository_format_partial_clone))\n-\t\tdie(_(\"cannot change partial clone promisor remote\"));\n+\tchar *cfg_name;\n+\n+\t/* Check if it is already registered */\n+\tif (find_odb_helper(remote))\n+\t\treturn;\n \n \tgit_config_set(\"core.repositoryformatversion\", \"1\");\n-\tgit_config_set(\"extensions.partialclone\", remote);\n \n-\trepository_format_partial_clone = xstrdup(remote);\n+\t/* Add odb config for the remote */\n+\tcfg_name = xstrfmt(\"odb.%s.promisorRemote\", remote);\n+\tgit_config_set(cfg_name, remote);\n+\tfree(cfg_name);\n \n \t/*\n \t * Record the initial filter-spec in the config as\n \t * the default for subsequent fetches from this remote.\n+\t *\n+\t * TODO: move core.partialclonefilter into odb.<name>\n \t */\n \tcore_partial_clone_filter_default =\n \t\txstrdup(filter_options->filter_spec);\n \tgit_config_set(\"core.partialclonefilter\",\n \t\t       core_partial_clone_filter_default);\n+\n+\t/* Make sure the config info are reset */\n+\todb_remote_reinit();\n }\n \n void partial_clone_get_default_filter_spec(\ndiff --git a/packfile.c b/packfile.c\nindex 6c3ddc3c31..bf0d1e7a20 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -15,6 +15,7 @@\n #include \"tree-walk.h\"\n #include \"tree.h\"\n #include \"object-store.h\"\n+#include \"odb-remote.h\"\n \n char *odb_pack_name(struct strbuf *buf,\n \t\t    const unsigned char *sha1,\n@@ -1960,7 +1961,7 @@ int is_promisor_object(const struct object_id *oid)\n \tstatic int promisor_objects_prepared;\n \n \tif (!promisor_objects_prepared) {\n-\t\tif (repository_format_partial_clone) {\n+\t\tif (has_odb_remote()) {\n \t\t\tfor_each_packed_object(add_promisor_object,\n \t\t\t\t\t       &promisor_objects,\n \t\t\t\t\t       FOR_EACH_OBJECT_PROMISOR_ONLY);\ndiff --git a/setup.c b/setup.c\nindex 3e03d442b6..be7f45cf4b 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -419,11 +419,7 @@ static int check_repo_format(const char *var, const char *value, void *vdata)\n \t\t\t;\n \t\telse if (!strcmp(ext, \"preciousobjects\"))\n \t\t\tdata->precious_objects = git_config_bool(var, value);\n-\t\telse if (!strcmp(ext, \"partialclone\")) {\n-\t\t\tif (!value)\n-\t\t\t\treturn config_error_nonbool(var);\n-\t\t\tdata->partial_clone = xstrdup(value);\n-\t\t} else\n+\t\telse\n \t\t\tstring_list_append(&data->unknown_extensions, ext);\n \t} else if (strcmp(var, \"core.bare\") == 0) {\n \t\tdata->is_bare = git_config_bool(var, value);\n@@ -465,7 +461,6 @@ static int check_repository_format_gently(const char *gitdir, struct repository_\n \t}\n \n \trepository_format_precious_objects = candidate->precious_objects;\n-\trepository_format_partial_clone = candidate->partial_clone;\n \tstring_list_clear(&candidate->unknown_extensions, 0);\n \tif (!has_common) {\n \t\tif (candidate->is_bare != -1) {\ndiff --git a/sha1-file.c b/sha1-file.c\nindex 7d3c1ebd91..27eb3a99ac 100644\n--- a/sha1-file.c\n+++ b/sha1-file.c\n@@ -32,6 +32,7 @@\n #include \"packfile.h\"\n #include \"fetch-object.h\"\n #include \"object-store.h\"\n+#include \"odb-remote.h\"\n \n /* The maximum size for an object header. */\n #define MAX_HEADER_LEN 32\n@@ -1287,13 +1288,13 @@ int oid_object_info_extended(const struct object_id *oid, struct object_info *oi\n \t\t}\n \n \t\t/* Check if it is a missing object */\n-\t\tif (fetch_if_missing && repository_format_partial_clone &&\n+\t\tif (fetch_if_missing && has_odb_remote() &&\n \t\t    !already_retried) {\n \t\t\t/*\n-\t\t\t * TODO Investigate checking fetch_object() return\n-\t\t\t * TODO value and stopping on error here.\n+\t\t\t * TODO Investigate checking odb_remote_get_direct()\n+\t\t\t * TODO return value and stopping on error here.\n \t\t\t */\n-\t\t\tfetch_object(repository_format_partial_clone, real->hash);\n+\t\t\todb_remote_get_direct(real->hash);\n \t\t\talready_retried = 1;\n \t\t\tcontinue;\n \t\t}\ndiff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh\nindex cc18b75c03..6af4712da8 100755\n--- a/t/t0410-partial-clone.sh\n+++ b/t/t0410-partial-clone.sh\n@@ -43,7 +43,7 @@ test_expect_success 'missing reflog object, but promised by a commit, passes fsc\n \n \t# But with the extension, it succeeds\n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo fsck\n '\n \n@@ -66,7 +66,7 @@ test_expect_success 'missing reflog object, but promised by a tag, passes fsck'\n \tprintf \"$T\\n\" | pack_as_from_promisor &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo fsck\n '\n \n@@ -84,7 +84,7 @@ test_expect_success 'missing reflog object alone fails fsck, even with extension\n \tdelete_object repo \"$A\" &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \ttest_must_fail git -C repo fsck\n '\n \n@@ -100,7 +100,7 @@ test_expect_success 'missing ref object, but promised, passes fsck' '\n \tpromise_and_delete \"$A\" &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo fsck\n '\n \n@@ -123,7 +123,7 @@ test_expect_success 'missing object, but promised, passes fsck' '\n \tpromise_and_delete \"$AT\" &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo fsck\n '\n \n@@ -136,7 +136,7 @@ test_expect_success 'missing CLI object, but promised, passes fsck' '\n \tpromise_and_delete \"$A\" &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo fsck \"$A\"\n '\n \n@@ -151,7 +151,7 @@ test_expect_success 'fetching of missing objects' '\n \trm -rf repo/.git/objects/* &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"origin\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"origin\" &&\n \tgit -C repo cat-file -p \"$HASH\" &&\n \n \t# Ensure that the .promisor file is written, and check that its\n@@ -172,7 +172,7 @@ test_expect_success 'rev-list stops traversal at missing and promised commit' '\n \tpromise_and_delete \"$FOO\" &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo rev-list --exclude-promisor-objects --objects bar >out &&\n \tgrep $(git -C repo rev-parse bar) out &&\n \t! grep $FOO out\n@@ -197,7 +197,7 @@ test_expect_success 'rev-list stops traversal at missing and promised tree' '\n \tpromise_and_delete \"$TREE2\" &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&\n \tgrep $(git -C repo rev-parse foo) out &&\n \t! grep $TREE out &&\n@@ -216,7 +216,7 @@ test_expect_success 'rev-list stops traversal at missing and promised blob' '\n \tpromise_and_delete \"$BLOB\" &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&\n \tgrep $(git -C repo rev-parse HEAD) out &&\n \t! grep $BLOB out\n@@ -235,7 +235,7 @@ test_expect_success 'rev-list stops traversal at promisor commit, tree, and blob\n \tprintf \"%s\\n%s\\n%s\\n\" $COMMIT $TREE $BLOB | pack_as_from_promisor &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&\n \t! grep $COMMIT out &&\n \t! grep $TREE out &&\n@@ -259,7 +259,7 @@ test_expect_success 'rev-list accepts missing and promised objects on command li\n \tpromise_and_delete $BLOB &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo rev-list --exclude-promisor-objects --objects \"$COMMIT\" \"$TREE\" \"$BLOB\"\n '\n \n@@ -272,7 +272,7 @@ test_expect_success 'gc does not repack promisor objects' '\n \tHASH=$(printf \"$TREE_HASH\\n\" | pack_as_from_promisor) &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo gc &&\n \n \t# Ensure that the promisor packfile still exists, and remove it\n@@ -296,7 +296,7 @@ test_expect_success 'gc stops traversal when a missing but promised object is re\n \tHASH=$(promise_and_delete $TREE_HASH) &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"arbitrary string\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C repo gc &&\n \n \t# Ensure that the promisor packfile still exists, and remove it\n@@ -327,7 +327,7 @@ test_expect_success 'fetching of missing objects from an HTTP server' '\n \trm -rf repo/.git/objects/* &&\n \n \tgit -C repo config core.repositoryformatversion 1 &&\n-\tgit -C repo config extensions.partialclone \"origin\" &&\n+\tgit -C repo config odb.magic.promisorRemote \"origin\" &&\n \tgit -C repo cat-file -p \"$HASH\" &&\n \n \t# Ensure that the .promisor file is written, and check that its\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex 0680dec808..3bb20b0566 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -792,14 +792,14 @@ fetch_filter_blob_limit_zero () {\n \ttest_config -C \"$SERVER\" uploadpack.allowfilter 1 &&\n \n \tgit clone \"$URL\" client &&\n-\ttest_config -C client extensions.partialclone origin &&\n+\ttest_config -C client odb.magic.promisorRemote origin &&\n \n \ttest_commit -C \"$SERVER\" two &&\n \n \tgit -C client fetch --filter=blob:limit=0 origin HEAD:somewhere &&\n \n \t# Ensure that commit is fetched, but blob is not\n-\ttest_config -C client extensions.partialclone \"arbitrary string\" &&\n+\ttest_config -C client odb.magic.promisorRemote \"arbitrary string\" &&\n \tgit -C client cat-file -e $(git -C \"$SERVER\" rev-parse two) &&\n \ttest_must_fail git -C client cat-file -e $(git hash-object \"$SERVER/two.t\")\n }\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex 0b62037744..022c65a7ae 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -647,7 +647,7 @@ partial_clone () {\n \tgit -C client fsck &&\n \n \t# Ensure that unneeded blobs are not inadvertently fetched.\n-\ttest_config -C client extensions.partialclone \"not a remote\" &&\n+\ttest_config -C client odb.origin.promisorRemote \"not a remote\" &&\n \ttest_must_fail git -C client cat-file -e \"$HASH1\" &&\n \n \t# But this blob was fetched, because clone performs an initial checkout\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex cee5565367..5ddd1e011c 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -40,7 +40,7 @@ test_expect_success 'do partial clone 1' '\n \t\t| sort >observed.oids &&\n \ttest_cmp expect_1.oids observed.oids &&\n \ttest \"$(git -C pc1 config --local core.repositoryformatversion)\" = \"1\" &&\n-\ttest \"$(git -C pc1 config --local extensions.partialclone)\" = \"origin\" &&\n+\ttest \"$(git -C pc1 config --local odb.origin.promisorRemote)\" = \"origin\" &&\n \ttest \"$(git -C pc1 config --local core.partialclonefilter)\" = \"blob:none\"\n '\n \ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex dec37ad1e7..fde63993a9 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -16,6 +16,7 @@\n #include \"submodule-config.h\"\n #include \"fsmonitor.h\"\n #include \"fetch-object.h\"\n+#include \"odb-remote.h\"\n \n /*\n  * Error messages expected by scripts out of plumbing commands such as\n@@ -371,7 +372,7 @@ static int check_updates(struct unpack_trees_options *o)\n \t\tload_gitmodules_file(index, &state);\n \n \tenable_delayed_checkout(&state);\n-\tif (repository_format_partial_clone && o->update && !o->dry_run) {\n+\tif (has_odb_remote() && o->update && !o->dry_run) {\n \t\t/*\n \t\t * Prefetch the objects that are to be checked out in the loop\n \t\t * below.\n@@ -388,8 +389,7 @@ static int check_updates(struct unpack_trees_options *o)\n \t\t\t}\n \t\t}\n \t\tif (to_fetch.nr)\n-\t\t\tfetch_objects(repository_format_partial_clone,\n-\t\t\t\t      &to_fetch);\n+\t\t\todb_remote_get_many_direct(&to_fetch);\n \t\tfetch_if_missing = fetch_if_missing_store;\n \t\toid_array_clear(&to_fetch);\n \t}\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347544","messageId":"20180513103232.17514-9-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"[PATCH v1 8/8] t0410: test fetching from many promisor remotes","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:32Z","receivedAt":"2018-05-13T10:33:30Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t0410-partial-clone.sh | 24 +++++++++++++++++++++++-\n 1 file changed, 23 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh\nindex 6af4712da8..4a7a662512 100755\n--- a/t/t0410-partial-clone.sh\n+++ b/t/t0410-partial-clone.sh\n@@ -162,8 +162,30 @@ test_expect_success 'fetching of missing objects' '\n \tgit verify-pack --verbose \"$IDX\" | grep \"$HASH\"\n '\n \n+test_expect_success 'fetching of missing objects from another odb remote' '\n+\tgit clone \"file://$(pwd)/server\" server2 &&\n+\ttest_commit -C server2 bar &&\n+\tgit -C server2 repack -a -d --write-bitmap-index &&\n+\tHASH2=$(git -C server2 rev-parse bar) &&\n+\n+\tgit -C repo remote add server2 \"file://$(pwd)/server2\" &&\n+\tgit -C repo config odb.magic2.promisorRemote server2 &&\n+\tgit -C repo cat-file -p \"$HASH2\" &&\n+\n+\tgit -C repo fetch server2 &&\n+\trm -rf repo/.git/objects/* &&\n+\tgit -C repo cat-file -p \"$HASH2\" &&\n+\n+\t# Ensure that the .promisor file is written, and check that its\n+\t# associated packfile contains the object\n+\tls repo/.git/objects/pack/pack-*.promisor >promisorlist &&\n+\ttest_line_count = 1 promisorlist &&\n+\tIDX=$(cat promisorlist | sed \"s/promisor$/idx/\") &&\n+\tgit verify-pack --verbose \"$IDX\" | grep \"$HASH2\"\n+'\n+\n test_expect_success 'rev-list stops traversal at missing and promised commit' '\n-\trm -rf repo &&\n+\trm -rf repo server server2 &&\n \ttest_create_repo repo &&\n \ttest_commit -C repo foo &&\n \ttest_commit -C repo bar &&\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347545","messageId":"20180513103232.17514-5-chriscool@tuxfamily.org","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"[PATCH v1 4/8] odb-remote: implement odb_remote_get_many_direct()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-05-13T10:32:28Z","receivedAt":"2018-05-13T10:33:35Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This function will be used to get many objects from a promisor\nremote.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n odb-helper.c | 15 +++++++++++++++\n odb-helper.h |  3 +++\n odb-remote.c | 17 +++++++++++++++++\n odb-remote.h |  1 +\n 4 files changed, 36 insertions(+)\n\ndiff --git a/odb-helper.c b/odb-helper.c\nindex 2851fe2657..5fe37e6fe5 100644\n--- a/odb-helper.c\n+++ b/odb-helper.c\n@@ -28,3 +28,18 @@ int odb_helper_get_direct(struct odb_helper *o,\n \n \treturn res;\n }\n+\n+int odb_helper_get_many_direct(struct odb_helper *o,\n+\t\t\t       const struct oid_array *to_get)\n+{\n+\tint res;\n+\tuint64_t start;\n+\n+\tstart = getnanotime();\n+\n+\tres = fetch_objects(o->dealer, to_get);\n+\n+\ttrace_performance_since(start, \"odb_helper_get_many_direct\");\n+\n+\treturn res;\n+}\ndiff --git a/odb-helper.h b/odb-helper.h\nindex d21b625a7e..d63210d516 100644\n--- a/odb-helper.h\n+++ b/odb-helper.h\n@@ -11,4 +11,7 @@ struct odb_helper {\n extern struct odb_helper *odb_helper_new(const char *name, int namelen);\n extern int odb_helper_get_direct(struct odb_helper *o,\n \t\t\t\t const unsigned char *sha1);\n+extern int odb_helper_get_many_direct(struct odb_helper *o,\n+\t\t\t\t      const struct oid_array *to_get);\n+\n #endif /* ODB_HELPER_H */\ndiff --git a/odb-remote.c b/odb-remote.c\nindex dbab40c0f8..9a1561430c 100644\n--- a/odb-remote.c\n+++ b/odb-remote.c\n@@ -87,3 +87,20 @@ int odb_remote_get_direct(const unsigned char *sha1)\n \n \treturn -1;\n }\n+\n+int odb_remote_get_many_direct(const struct oid_array *to_get)\n+{\n+\tstruct odb_helper *o;\n+\n+\ttrace_printf(\"trace: odb_remote_get_many_direct: nr: %d\", to_get->nr);\n+\n+\todb_remote_init();\n+\n+\tfor (o = helpers; o; o = o->next) {\n+\t\tif (odb_helper_get_many_direct(o, to_get) < 0)\n+\t\t\tcontinue;\n+\t\treturn 0;\n+\t}\n+\n+\treturn -1;\n+}\ndiff --git a/odb-remote.h b/odb-remote.h\nindex 27a480fcfe..e6cedde722 100644\n--- a/odb-remote.h\n+++ b/odb-remote.h\n@@ -4,5 +4,6 @@\n extern struct odb_helper *find_odb_helper(const char *dealer);\n extern int has_odb_remote(void);\n extern int odb_remote_get_direct(const unsigned char *sha1);\n+extern int odb_remote_get_many_direct(const struct oid_array *to_get);\n \n #endif /* ODB_REMOTE_H */\n-- \n2.17.0.590.gbd05bfcafd\n\n"},{"id":"347574","messageId":"xmqqr2mebqph.fsf@gitster-ct.c.googlers.com","threadId":"48480","inReplyTo":"20180513103232.17514-1-chriscool@tuxfamily.org","subject":"Re: [PATCH v1 0/8] Introducing odb remote","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-14T08:12:58Z","receivedAt":"2018-05-14T08:13:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> This is a follow up from the patch series called \"Promisor remotes and\n> external ODB support\" that I sent earlier this year.\n>\n> Following discussions of these patch series, where Junio said \"a\n> minimum s/ext/remote/ would clarify what it is\", I decided to rename\n> \"external odb\" to \"odb remote\".\n\nIn \"external odb\", \"odb\" is a noun, decorated by adjective\n\"external\".  I would expect the same would apply to \"remote\" and\n\"odb\".\n\n> I am still open to another name, but I\n> think that \"odb remote\" works well with \"odb helper\" that was already\n> used in the series and is as good or perhaps better than \"remote odb\",\n> as a \"remote odb\" I think would be easier to confuse with a regular\n> \"remote\".\n\nAs long as our use of \"remote\" as a noun is understood as omitting\n(an obvious) \"repository\" from a noun phrase \"remote repository\", I\ndo not think there is any confusion.\n\n\n\"odb remote\" sounds like the phrase is about a noun \"remote\" (we do\nuse \"remote\" as a noun when talking about fetching and pushing, as a\nshort hand for \"remote repository\") that uses \"odb\" as an adjective\nsomehow (e.g. \"this is one of those remotes defined but not for the\nusual fetching and pushing, but for accessing its odb\", or something\nilke that), which somehow does not sit well on my tongue nor in ears.\nPerhaps that is because I am not well versed in languages whose natural\nword order in a noun phrase is noun followed by adjective, but I dunno.\n\n> Another obvious difference with the previous series is that this\n> series is only about integrating with the promisor/narrow clone work\n> and showing that it makes it possible to use more than one promisor\n> remote.\n\nSounds like a sensible \"incremental\" approach.\n\nWill read the patches and commet on them in another sitting.\nThanks.\n"},{"id":"347674","messageId":"xmqqmux1aes7.fsf@gitster-ct.c.googlers.com","threadId":"48480","inReplyTo":"20180513103232.17514-2-chriscool@tuxfamily.org","subject":"Re: [PATCH v1 1/8] fetch-object: make functions return an error code","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-15T01:28:08Z","receivedAt":"2018-05-15T01:28:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> The callers of the fetch_object() and fetch_objects() might\n> be interested in knowing if these functions succeeded or not.\n>\n> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n> ---\n>  fetch-object.c | 15 +++++++++------\n>  fetch-object.h |  6 +++---\n>  sha1-file.c    |  4 ++--\n>  3 files changed, 14 insertions(+), 11 deletions(-)\n\n\"might\", but nobody pays attention to the return value, as the\nlocal availablity of the object at the end is the only thing that\nmatters, so at this step, it is not all that impactful a change.\n\nLet's see how it plays out.\n\n>  \t\t\t/*\n> -\t\t\t * TODO Investigate haveing fetch_object() return\n> -\t\t\t * TODO error/success and stopping the music here.\n> +\t\t\t * TODO Investigate checking fetch_object() return\n> +\t\t\t * TODO value and stopping on error here.\n>  \t\t\t */\n>  \t\t\tfetch_object(repository_format_partial_clone, real->hash);\n>  \t\t\talready_retried = 1;\n"},{"id":"347676","messageId":"xmqqh8n9ae17.fsf@gitster-ct.c.googlers.com","threadId":"48480","inReplyTo":"20180513103232.17514-3-chriscool@tuxfamily.org","subject":"Re: [PATCH v1 2/8] Add initial odb remote support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-15T01:44:20Z","receivedAt":"2018-05-15T01:44:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> diff --git a/odb-helper.h b/odb-helper.h\n> new file mode 100644\n> index 0000000000..61d2ad082b\n> --- /dev/null\n> +++ b/odb-helper.h\n> @@ -0,0 +1,13 @@\n> +#ifndef ODB_HELPER_H\n> +#define ODB_HELPER_H\n> +\n\nHere is a good space to write a comment on what this structure and\nits fields are about.  Who are the dealers of helpers anyway?\n\n> +struct odb_helper {\n> +\tconst char *name;\n> +\tconst char *dealer;\n> +\n> +\tstruct odb_helper *next;\n> +};\n> +\n> +extern struct odb_helper *odb_helper_new(const char *name, int namelen);\n> +\n> +#endif /* ODB_HELPER_H */\n> diff --git a/odb-remote.c b/odb-remote.c\n> new file mode 100644\n> index 0000000000..e03b953ec6\n> --- /dev/null\n> +++ b/odb-remote.c\n> @@ -0,0 +1,72 @@\n> +#include \"cache.h\"\n> +#include \"odb-remote.h\"\n> +#include \"odb-helper.h\"\n> +#include \"config.h\"\n> +\n> +static struct odb_helper *helpers;\n> +static struct odb_helper **helpers_tail = &helpers;\n> +\n> +static struct odb_helper *find_or_create_helper(const char *name, int len)\n> +{\n> +\tstruct odb_helper *o;\n> +\n> +\tfor (o = helpers; o; o = o->next)\n> +\t\tif (!strncmp(o->name, name, len) && !o->name[len])\n> +\t\t\treturn o;\n> +\n> +\to = odb_helper_new(name, len);\n> +\t*helpers_tail = o;\n> +\thelpers_tail = &o->next;\n> +\n> +\treturn o;\n> +}\n\nThis is a tangent, but I wonder if we can do better than\nhand-rolling these singly-linked list of custom structure types\nevery time we add new code.  I am just guessing (because it is not\ndescribed in the log message) that the expectation is to have only\njust a handful of helpers so looking for a helper by name is OK at\nO(n), as long as we very infrequently look up a helper by name.\n\n> +static int odb_remote_config(const char *var, const char *value, void *data)\n> +{\n> +\tstruct odb_helper *o;\n> +\tconst char *name;\n> +\tint namelen;\n> +\tconst char *subkey;\n> +\n> +\tif (parse_config_key(var, \"odb\", &name, &namelen, &subkey) < 0)\n> +\t\treturn 0;\n> +\n> +\to = find_or_create_helper(name, namelen);\n> +\n> +\tif (!strcmp(subkey, \"promisorremote\"))\n> +\t\treturn git_config_string(&o->dealer, var, value);\n\nIf the field is meant to record the name of the promisor remote,\nthen it is better to name it as such, no?\n\n> +struct odb_helper *find_odb_helper(const char *dealer)\n\nDitto.\n\n> +{\n> +\tstruct odb_helper *o;\n> +\n> +\todb_remote_init();\n> +\n> +\tif (!dealer)\n> +\t\treturn helpers;\n> +\n> +\tfor (o = helpers; o; o = o->next)\n> +\t\tif (!strcmp(o->dealer, dealer))\n> +\t\t\treturn o;\n\nThe code to create a new helper tried to avoid creating a helper\nwith duplicated name, but nobody tries to create more than one\nhelpers that point at the same promisor remote.  Yet here we try to\ngrab the first one that happens to point at the given promisor.\n\nThat somehow smells wrong.\n\n"},{"id":"347689","messageId":"87fu2t2tv1.fsf@evledraar.gmail.com","threadId":"48480","inReplyTo":"20180513103232.17514-3-chriscool@tuxfamily.org","subject":"Re: [PATCH v1 2/8] Add initial odb remote support","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-15T08:41:54Z","receivedAt":"2018-05-15T08:42:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, May 13 2018, Christian Couder wrote:\n\n> \"sha1_file.c\"[...]\n\nsha1-file.c these days :)\n"},{"id":"350777","messageId":"CAP8UFD3kMQxiViL4sUPMjmJHxVkobmTdpJ+=G827hVhPwaxarg@mail.gmail.com","threadId":"48480","inReplyTo":"xmqqh8n9ae17.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v1 2/8] Add initial odb remote support","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-06-23T12:15:09Z","receivedAt":"2018-06-23T12:15:14Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Tue, May 15, 2018 at 3:44 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Christian Couder <christian.couder@gmail.com> writes:\n\n>> --- /dev/null\n>> +++ b/odb-helper.h\n>> @@ -0,0 +1,13 @@\n>> +#ifndef ODB_HELPER_H\n>> +#define ODB_HELPER_H\n>\n> Here is a good space to write a comment on what this structure and\n> its fields are about.  Who are the dealers of helpers anyway?\n\nOk I added a few comments and renamed \"dealer\" to \"remote\".\n\n>> +static struct odb_helper *helpers;\n>> +static struct odb_helper **helpers_tail = &helpers;\n>> +\n>> +static struct odb_helper *find_or_create_helper(const char *name, int len)\n>> +{\n>> +     struct odb_helper *o;\n>> +\n>> +     for (o = helpers; o; o = o->next)\n>> +             if (!strncmp(o->name, name, len) && !o->name[len])\n>> +                     return o;\n>> +\n>> +     o = odb_helper_new(name, len);\n>> +     *helpers_tail = o;\n>> +     helpers_tail = &o->next;\n>> +\n>> +     return o;\n>> +}\n>\n> This is a tangent, but I wonder if we can do better than\n> hand-rolling these singly-linked list of custom structure types\n> every time we add new code.  I am just guessing (because it is not\n> described in the log message) that the expectation is to have only\n> just a handful of helpers so looking for a helper by name is OK at\n> O(n), as long as we very infrequently look up a helper by name.\n\nYeah, I think there will be very few helpers. I added a comment in the\nversion I will send really soon now.\n\n>> +     if (!strcmp(subkey, \"promisorremote\"))\n>> +             return git_config_string(&o->dealer, var, value);\n>\n> If the field is meant to record the name of the promisor remote,\n> then it is better to name it as such, no?\n\nYeah, it is renamed \"remote\" now.\n\n>> +     for (o = helpers; o; o = o->next)\n>> +             if (!strcmp(o->dealer, dealer))\n>> +                     return o;\n>\n> The code to create a new helper tried to avoid creating a helper\n> with duplicated name, but nobody tries to create more than one\n> helpers that point at the same promisor remote.  Yet here we try to\n> grab the first one that happens to point at the given promisor.\n>\n> That somehow smells wrong.\n\nFor each promisor remote I think it makes no sense to have more than\none remote odb pointing to it. So I am not sure what to do here.\n"},{"id":"350870","messageId":"xmqqzhzioi4r.fsf@gitster-ct.c.googlers.com","threadId":"48480","inReplyTo":"CAP8UFD3kMQxiViL4sUPMjmJHxVkobmTdpJ+=G827hVhPwaxarg@mail.gmail.com","subject":"Re: [PATCH v1 2/8] Add initial odb remote support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-25T18:06:44Z","receivedAt":"2018-06-25T18:06:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> For each promisor remote I think it makes no sense to have more than\n> one remote odb pointing to it. So I am not sure what to do here.\n\nIf it makes no sense, then detecting and erroring out would be a\nsensible thing to do, no?\n"}]}