{"thread":{"id":"66018","subject":"[PATCH 0/3] refspec: remove dependency on `the_repository`","startedAt":"2026-07-16T12:38:13Z","lastAt":"2026-07-17T06:02:24Z","messageCount":6,"participants":["Patrick Steinhardt","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"548398","messageId":"20260716-pks-refspec-wo-the-repository-v1-0-aa40844d067f@pks.im","threadId":"66018","inReplyTo":null,"subject":"[PATCH 0/3] refspec: remove dependency on `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-07-16T12:38:01Z","receivedAt":"2026-07-16T12:38:13Z","isPatch":true,"body":"Hi,\n\nthis small patch series removes the dependency on `the_repository` in\n\"refspec.c\". Thanks!\n\nPatrick\n\n---\nPatrick Steinhardt (3):\n      refspec: group related structures and functions\n      refspec: let callers pass in hash algorithm when parsing items\n      refspec: stop depending on `the_repository`\n\n builtin/fast-export.c       |  4 +++-\n builtin/fetch.c             |  9 ++++++---\n builtin/pull.c              |  2 +-\n builtin/push.c              |  6 ++++--\n builtin/send-pack.c         |  5 ++++-\n builtin/submodule--helper.c |  2 +-\n http-push.c                 |  2 +-\n refspec.c                   | 39 +++++++++++++++++++++------------------\n refspec.h                   | 42 +++++++++++++++++++++++++++---------------\n remote.c                    |  6 +++---\n transport-helper.c          |  2 +-\n 11 files changed, 72 insertions(+), 47 deletions(-)\n\n\n---\nbase-commit: d35c5399e3e54ac277bb391fc2f6be3e816d312b\nchange-id: 20260716-pks-refspec-wo-the-repository-24a6fd303548\n\n"},{"id":"548399","messageId":"20260716-pks-refspec-wo-the-repository-v1-1-aa40844d067f@pks.im","threadId":"66018","inReplyTo":"20260716-pks-refspec-wo-the-repository-v1-0-aa40844d067f@pks.im","subject":"[PATCH 1/3] refspec: group related structures and functions","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-07-16T12:38:02Z","receivedAt":"2026-07-16T12:38:14Z","isPatch":true,"body":"Reorganize the refspec header a bit so that structures and their related\nfunctions are grouped closer together. While at it, fix a couple of\nstyle violations.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refspec.h | 26 ++++++++++++++------------\n 1 file changed, 14 insertions(+), 12 deletions(-)\n\ndiff --git a/refspec.h b/refspec.h\nindex 8b04f9995e..832d6f923c 100644\n--- a/refspec.h\n+++ b/refspec.h\n@@ -1,6 +1,9 @@\n #ifndef REFSPEC_H\n #define REFSPEC_H\n \n+struct string_list;\n+struct strvec;\n+\n #define TAG_REFSPEC \"refs/tags/*:refs/tags/*\"\n \n /**\n@@ -30,10 +33,9 @@ struct refspec_item {\n \tchar *raw;\n };\n \n-struct string_list;\n-\n-#define REFSPEC_INIT_FETCH { .fetch = 1 }\n-#define REFSPEC_INIT_PUSH { .fetch = 0 }\n+int refspec_item_init_fetch(struct refspec_item *item, const char *refspec);\n+int refspec_item_init_push(struct refspec_item *item, const char *refspec);\n+void refspec_item_clear(struct refspec_item *item);\n \n /**\n  * An array of strings can be parsed into a struct refspec using\n@@ -47,20 +49,20 @@ struct refspec {\n \tunsigned fetch : 1;\n };\n \n-int refspec_item_init_fetch(struct refspec_item *item, const char *refspec);\n-int refspec_item_init_push(struct refspec_item *item, const char *refspec);\n-void refspec_item_clear(struct refspec_item *item);\n+#define REFSPEC_INIT_FETCH { .fetch = 1 }\n+#define REFSPEC_INIT_PUSH { .fetch = 0 }\n+\n void refspec_init_fetch(struct refspec *rs);\n void refspec_init_push(struct refspec *rs);\n+void refspec_clear(struct refspec *rs);\n+\n void refspec_append(struct refspec *rs, const char *refspec);\n __attribute__((format (printf,2,3)))\n void refspec_appendf(struct refspec *rs, const char *fmt, ...);\n void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);\n-void refspec_clear(struct refspec *rs);\n \n int valid_fetch_refspec(const char *refspec);\n \n-struct strvec;\n /*\n  * Determine what <prefix> values to pass to the peer in ref-prefix lines\n  * (see linkgit:gitprotocol-v2[5]).\n@@ -76,7 +78,7 @@ int refname_matches_negative_refspec_item(const char *refname, struct refspec *r\n  * Returns 1 if refname matches pattern, 0 otherwise.\n  */\n int match_refname_with_pattern(const char *pattern, const char *refname,\n-\t\t\t\t   const char *replacement, char **result);\n+\t\t\t       const char *replacement, char **result);\n \n /*\n  * Queries a refspec for a match and updates the query item.\n@@ -89,8 +91,8 @@ int refspec_find_match(struct refspec *rs, struct refspec_item *query);\n  * list.\n  */\n void refspec_find_all_matches(struct refspec *rs,\n-\t\t\t\t    struct refspec_item *query,\n-\t\t\t\t    struct string_list *results);\n+\t\t\t      struct refspec_item *query,\n+\t\t\t      struct string_list *results);\n \n /*\n  * Remove all entries in the input list which match any negative refspec in\n\n-- \n2.55.0.313.g8d093f411d.dirty\n\n"},{"id":"548400","messageId":"20260716-pks-refspec-wo-the-repository-v1-2-aa40844d067f@pks.im","threadId":"66018","inReplyTo":"20260716-pks-refspec-wo-the-repository-v1-0-aa40844d067f@pks.im","subject":"[PATCH 2/3] refspec: let callers pass in hash algorithm when parsing items","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-07-16T12:38:03Z","receivedAt":"2026-07-16T12:38:17Z","isPatch":true,"body":"When parsing a refspec item we need to know about the hash algorithm\nused by the repository so that we can decide whether or not a given\nstring is an exact object ID. We use `the_hash_algo` for this, which\nmakes the code implicitly depend on `the_repository`.\n\nRefactor `refspec_item_init_fetch()`, `refspec_item_init_push()` and\n`valid_fetch_refspec()` so that callers have to pass in the hash\nalgorithm explicitly and adapt callers accordingly. For now, all of\nthe callers simply pass `the_hash_algo`, so there is no change in\nbehaviour.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fetch.c |  3 ++-\n builtin/pull.c  |  2 +-\n refspec.c       | 30 +++++++++++++++++-------------\n refspec.h       |  9 ++++++---\n remote.c        |  2 +-\n 5 files changed, 27 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 8e676b79ba..1d4a129039 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -601,7 +601,8 @@ static struct ref *get_ref_map(struct remote *remote,\n \t\tstruct refspec_item tag_refspec;\n \n \t\t/* also fetch all tags */\n-\t\trefspec_item_init_push(&tag_refspec, TAG_REFSPEC);\n+\t\trefspec_item_init_push(&tag_refspec, TAG_REFSPEC,\n+\t\t\t\t       the_hash_algo);\n \t\tget_fetch_map(remote_refs, &tag_refspec, &tail, 0);\n \t\trefspec_item_clear(&tag_refspec);\n \t} else if (tags == TAGS_DEFAULT && *autotags) {\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex d49b09114a..db3ee0aab3 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -612,7 +612,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)\n \tconst char *spec_src;\n \tconst char *merge_branch;\n \n-\tif (!refspec_item_init_fetch(&spec, refspec))\n+\tif (!refspec_item_init_fetch(&spec, refspec, the_hash_algo))\n \t\tdie(_(\"invalid refspec '%s'\"), refspec);\n \tspec_src = spec.src;\n \tif (!*spec_src || !strcmp(spec_src, \"HEAD\"))\ndiff --git a/refspec.c b/refspec.c\nindex fb89bce1db..33a6fb8e45 100644\n--- a/refspec.c\n+++ b/refspec.c\n@@ -16,7 +16,8 @@\n  * Parses the provided refspec 'refspec' and populates the refspec_item 'item'.\n  * Returns 1 if successful and 0 if the refspec is invalid.\n  */\n-static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch)\n+static int parse_refspec(struct refspec_item *item, const char *refspec,\n+\t\t\t const struct git_hash_algo *algo, int fetch)\n {\n \tsize_t llen;\n \tint is_glob;\n@@ -84,7 +85,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet\n \t\t */\n \t\tif (!*item->src)\n \t\t\treturn 0; /* negative refspecs must not be empty */\n-\t\telse if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))\n+\t\telse if (llen == algo->hexsz && !get_oid_hex_algop(item->src, &unused, algo))\n \t\t\treturn 0; /* negative refspecs cannot be exact sha1 */\n \t\telse if (!check_refname_format(item->src, flags))\n \t\t\t; /* valid looking ref is ok */\n@@ -101,7 +102,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet\n \t\t/* LHS */\n \t\tif (!*item->src)\n \t\t\t; /* empty is ok; it means \"HEAD\" */\n-\t\telse if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))\n+\t\telse if (llen == algo->hexsz && !get_oid_hex_algop(item->src, &unused, algo))\n \t\t\titem->exact_sha1 = 1; /* ok */\n \t\telse if (!check_refname_format(item->src, flags))\n \t\t\t; /* valid looking ref is ok */\n@@ -154,21 +155,23 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet\n }\n \n static int refspec_item_init(struct refspec_item *item, const char *refspec,\n-\t\t\t     int fetch)\n+\t\t\t     const struct git_hash_algo *algo, int fetch)\n {\n \tmemset(item, 0, sizeof(*item));\n \titem->raw = xstrdup(refspec);\n-\treturn parse_refspec(item, refspec, fetch);\n+\treturn parse_refspec(item, refspec, algo, fetch);\n }\n \n-int refspec_item_init_fetch(struct refspec_item *item, const char *refspec)\n+int refspec_item_init_fetch(struct refspec_item *item, const char *refspec,\n+\t\t\t    const struct git_hash_algo *algo)\n {\n-\treturn refspec_item_init(item, refspec, 1);\n+\treturn refspec_item_init(item, refspec, algo, 1);\n }\n \n-int refspec_item_init_push(struct refspec_item *item, const char *refspec)\n+int refspec_item_init_push(struct refspec_item *item, const char *refspec,\n+\t\t\t   const struct git_hash_algo *algo)\n {\n-\treturn refspec_item_init(item, refspec, 0);\n+\treturn refspec_item_init(item, refspec, algo, 0);\n }\n \n void refspec_item_clear(struct refspec_item *item)\n@@ -200,9 +203,9 @@ void refspec_append(struct refspec *rs, const char *refspec)\n \tint ret;\n \n \tif (rs->fetch)\n-\t\tret = refspec_item_init_fetch(&item, refspec);\n+\t\tret = refspec_item_init_fetch(&item, refspec, the_hash_algo);\n \telse\n-\t\tret = refspec_item_init_push(&item, refspec);\n+\t\tret = refspec_item_init_push(&item, refspec, the_hash_algo);\n \tif (!ret)\n \t\tdie(_(\"invalid refspec '%s'\"), refspec);\n \n@@ -246,10 +249,11 @@ void refspec_clear(struct refspec *rs)\n \trs->fetch = 0;\n }\n \n-int valid_fetch_refspec(const char *fetch_refspec_str)\n+int valid_fetch_refspec(const char *fetch_refspec_str,\n+\t\t\tconst struct git_hash_algo *algo)\n {\n \tstruct refspec_item refspec;\n-\tint ret = refspec_item_init_fetch(&refspec, fetch_refspec_str);\n+\tint ret = refspec_item_init_fetch(&refspec, fetch_refspec_str, algo);\n \trefspec_item_clear(&refspec);\n \treturn ret;\n }\ndiff --git a/refspec.h b/refspec.h\nindex 832d6f923c..e482b720a8 100644\n--- a/refspec.h\n+++ b/refspec.h\n@@ -1,6 +1,7 @@\n #ifndef REFSPEC_H\n #define REFSPEC_H\n \n+struct git_hash_algo;\n struct string_list;\n struct strvec;\n \n@@ -33,8 +34,10 @@ struct refspec_item {\n \tchar *raw;\n };\n \n-int refspec_item_init_fetch(struct refspec_item *item, const char *refspec);\n-int refspec_item_init_push(struct refspec_item *item, const char *refspec);\n+int refspec_item_init_fetch(struct refspec_item *item, const char *refspec,\n+\t\t\t    const struct git_hash_algo *algo);\n+int refspec_item_init_push(struct refspec_item *item, const char *refspec,\n+\t\t\t   const struct git_hash_algo *algo);\n void refspec_item_clear(struct refspec_item *item);\n \n /**\n@@ -61,7 +64,7 @@ __attribute__((format (printf,2,3)))\n void refspec_appendf(struct refspec *rs, const char *fmt, ...);\n void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);\n \n-int valid_fetch_refspec(const char *refspec);\n+int valid_fetch_refspec(const char *refspec, const struct git_hash_algo *algo);\n \n /*\n  * Determine what <prefix> values to pass to the peer in ref-prefix lines\ndiff --git a/remote.c b/remote.c\nindex e6c52c850c..b4dff1e5f9 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -3039,7 +3039,7 @@ int valid_remote_name(const char *name)\n \tint result;\n \tstruct strbuf refspec = STRBUF_INIT;\n \tstrbuf_addf(&refspec, \"refs/heads/test:refs/remotes/%s/test\", name);\n-\tresult = valid_fetch_refspec(refspec.buf);\n+\tresult = valid_fetch_refspec(refspec.buf, the_hash_algo);\n \tstrbuf_release(&refspec);\n \treturn result;\n }\n\n-- \n2.55.0.313.g8d093f411d.dirty\n\n"},{"id":"548401","messageId":"20260716-pks-refspec-wo-the-repository-v1-3-aa40844d067f@pks.im","threadId":"66018","inReplyTo":"20260716-pks-refspec-wo-the-repository-v1-0-aa40844d067f@pks.im","subject":"[PATCH 3/3] refspec: stop depending on `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-07-16T12:38:04Z","receivedAt":"2026-07-16T12:38:19Z","isPatch":true,"body":"The only remaining user of `the_hash_algo` in \"refspec.c\" is\n`refspec_append()`, which needs to know the hash algorithm so that it\ncan parse the appended refspec item. In contrast to the functions\nadapted in the preceding commit, this function always operates on a\n`struct refspec`. As that structure is expected to only ever contain\nrefspecs that all use the same hash function it doesn't make sense\nthough to adapt each caller.\n\nInstead, adapt the structure itself so that it gets initialized with a\nhash function and use that hash function to parse new refspec items.\nAdapt callers accordingly.\n\nThis removes the final dependency on the global repository variable in\n\"refspec.c\", so we can drop `USE_THE_REPOSITORY_VARIABLE`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fast-export.c       |  4 +++-\n builtin/fetch.c             |  6 ++++--\n builtin/push.c              |  6 ++++--\n builtin/send-pack.c         |  5 ++++-\n builtin/submodule--helper.c |  2 +-\n http-push.c                 |  2 +-\n refspec.c                   | 13 ++++++-------\n refspec.h                   | 17 ++++++++++++-----\n remote.c                    |  4 ++--\n transport-helper.c          |  2 +-\n 10 files changed, 38 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 0be43104dc..8f4da4cfac 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -51,7 +51,7 @@ static int show_original_ids;\n static int mark_tags;\n static struct string_list extra_refs = STRING_LIST_INIT_DUP;\n static struct string_list tag_refs = STRING_LIST_INIT_DUP;\n-static struct refspec refspecs = REFSPEC_INIT_FETCH;\n+static struct refspec refspecs;\n static int anonymize;\n static struct hashmap anonymized_seeds;\n static struct revision_sources revision_sources;\n@@ -1372,6 +1372,8 @@ int cmd_fast_export(int argc,\n \t/* we handle encodings */\n \trepo_config(the_repository, git_default_config, NULL);\n \n+\trefspec_init_fetch(&refspecs, the_hash_algo);\n+\n \trepo_init_revisions(the_repository, &revs, prefix);\n \tinit_revision_sources(&revision_sources);\n \trevs.topo_order = 1;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 1d4a129039..6e1a224553 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -96,7 +96,7 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;\n static struct strbuf default_rla = STRBUF_INIT;\n static struct transport *gtransport;\n static struct transport *gsecondary;\n-static struct refspec refmap = REFSPEC_INIT_FETCH;\n+static struct refspec refmap;\n static struct string_list server_options = STRING_LIST_INIT_DUP;\n static struct string_list negotiation_restrict = STRING_LIST_INIT_NODUP;\n static struct string_list negotiation_include = STRING_LIST_INIT_NODUP;\n@@ -2429,7 +2429,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,\n \t\t     const struct fetch_config *config,\n \t\t     struct list_objects_filter_options *filter_options)\n {\n-\tstruct refspec rs = REFSPEC_INIT_FETCH;\n+\tstruct refspec rs = REFSPEC_INIT_FETCH(the_hash_algo);\n \tint i;\n \tint exit_code;\n \tint maybe_prune_tags;\n@@ -2631,6 +2631,8 @@ int cmd_fetch(int argc,\n \n \tfilter_options.allow_auto_filter = 1;\n \n+\trefspec_init_fetch(&refmap, the_hash_algo);\n+\n \tpacket_trace_identity(\"fetch\");\n \n \t/* Record the command line for the reflog */\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 1b2ad3b8df..8ccdb07c40 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -66,7 +66,7 @@ static enum transport_family family;\n \n static struct push_cas_option cas;\n \n-static struct refspec rs = REFSPEC_INIT_PUSH;\n+static struct refspec rs;\n \n static struct string_list push_options_config = STRING_LIST_INIT_DUP;\n \n@@ -749,6 +749,8 @@ int cmd_push(int argc,\n \t\t: &push_options_config);\n \tset_push_cert_flags(&flags, push_cert);\n \n+\trefspec_init_push(&rs, the_hash_algo);\n+\n \tdie_for_incompatible_opt4(deleterefs, \"--delete\",\n \t\t\t\t  tags, \"--tags\",\n \t\t\t\t  flags & TRANSPORT_PUSH_ALL, \"--all/--branches\",\n@@ -855,7 +857,7 @@ int cmd_push(int argc,\n \t\t\t}\n \n \t\t\trefspec_clear(&rs);\n-\t\t\trs = (struct refspec) REFSPEC_INIT_PUSH;\n+\t\t\trs = (struct refspec) REFSPEC_INIT_PUSH(the_hash_algo);\n \n \t\t\tif (tags)\n \t\t\t\trefspec_append(&rs, \"refs/tags/*\");\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex 1412b49bc8..d6cdbae472 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -153,7 +153,7 @@ int cmd_send_pack(int argc,\n \t\t  const char *prefix,\n \t\t  struct repository *repo)\n {\n-\tstruct refspec rs = REFSPEC_INIT_PUSH;\n+\tstruct refspec rs;\n \tconst char *remote_name = NULL;\n \tstruct remote *remote = NULL;\n \tconst char *dest = NULL;\n@@ -214,6 +214,9 @@ int cmd_send_pack(int argc,\n \n \trepo_config(repo, send_pack_config, NULL);\n \targc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);\n+\n+\trefspec_init_push(&rs, repo->hash_algo);\n+\n \tif (argc > 0) {\n \t\tdest = argv[0];\n \t\trefspec_appendn(&rs, argv + 1, argc - 1);\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1cc82a134d..c396b826ba 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -3150,7 +3150,7 @@ static int push_check(int argc, const char **argv, const char *prefix UNUSED,\n \tif (argc > 2) {\n \t\tint i;\n \t\tstruct ref *local_refs = get_local_heads();\n-\t\tstruct refspec refspec = REFSPEC_INIT_PUSH;\n+\t\tstruct refspec refspec = REFSPEC_INIT_PUSH(the_hash_algo);\n \n \t\trefspec_appendn(&refspec, argv + 2, argc - 2);\n \ndiff --git a/http-push.c b/http-push.c\nindex 3c23cbba27..969d984cb9 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1716,7 +1716,7 @@ int cmd_main(int argc, const char **argv)\n {\n \tstruct transfer_request *request;\n \tstruct transfer_request *next_request;\n-\tstruct refspec rs = REFSPEC_INIT_PUSH;\n+\tstruct refspec rs = REFSPEC_INIT_PUSH(the_hash_algo);\n \tstruct remote_lock *ref_lock = NULL;\n \tstruct remote_lock *info_ref_lock = NULL;\n \tint delete_branch = 0;\ndiff --git a/refspec.c b/refspec.c\nindex 33a6fb8e45..7cb479983b 100644\n--- a/refspec.c\n+++ b/refspec.c\n@@ -1,4 +1,3 @@\n-#define USE_THE_REPOSITORY_VARIABLE\n #define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"git-compat-util.h\"\n@@ -185,15 +184,15 @@ void refspec_item_clear(struct refspec_item *item)\n \titem->exact_sha1 = 0;\n }\n \n-void refspec_init_fetch(struct refspec *rs)\n+void refspec_init_fetch(struct refspec *rs, const struct git_hash_algo *algo)\n {\n-\tstruct refspec blank = REFSPEC_INIT_FETCH;\n+\tstruct refspec blank = REFSPEC_INIT_FETCH(algo);\n \tmemcpy(rs, &blank, sizeof(*rs));\n }\n \n-void refspec_init_push(struct refspec *rs)\n+void refspec_init_push(struct refspec *rs, const struct git_hash_algo *algo)\n {\n-\tstruct refspec blank = REFSPEC_INIT_PUSH;\n+\tstruct refspec blank = REFSPEC_INIT_PUSH(algo);\n \tmemcpy(rs, &blank, sizeof(*rs));\n }\n \n@@ -203,9 +202,9 @@ void refspec_append(struct refspec *rs, const char *refspec)\n \tint ret;\n \n \tif (rs->fetch)\n-\t\tret = refspec_item_init_fetch(&item, refspec, the_hash_algo);\n+\t\tret = refspec_item_init_fetch(&item, refspec, rs->hash_algo);\n \telse\n-\t\tret = refspec_item_init_push(&item, refspec, the_hash_algo);\n+\t\tret = refspec_item_init_push(&item, refspec, rs->hash_algo);\n \tif (!ret)\n \t\tdie(_(\"invalid refspec '%s'\"), refspec);\n \ndiff --git a/refspec.h b/refspec.h\nindex e482b720a8..fadef67933 100644\n--- a/refspec.h\n+++ b/refspec.h\n@@ -49,14 +49,21 @@ struct refspec {\n \tint alloc;\n \tint nr;\n \n+\tconst struct git_hash_algo *hash_algo;\n \tunsigned fetch : 1;\n };\n \n-#define REFSPEC_INIT_FETCH { .fetch = 1 }\n-#define REFSPEC_INIT_PUSH { .fetch = 0 }\n-\n-void refspec_init_fetch(struct refspec *rs);\n-void refspec_init_push(struct refspec *rs);\n+#define REFSPEC_INIT_FETCH(algo) { \\\n+\t.fetch = 1, \\\n+\t.hash_algo = (algo), \\\n+}\n+#define REFSPEC_INIT_PUSH(algo) { \\\n+\t.fetch = 0, \\\n+\t.hash_algo = (algo), \\\n+}\n+\n+void refspec_init_fetch(struct refspec *rs, const struct git_hash_algo *hash_algo);\n+void refspec_init_push(struct refspec *rs, const struct git_hash_algo *hash_algo);\n void refspec_clear(struct refspec *rs);\n \n void refspec_append(struct refspec *rs, const char *refspec);\ndiff --git a/remote.c b/remote.c\nindex b4dff1e5f9..d151b1f9d9 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -150,8 +150,8 @@ static struct remote *make_remote(struct remote_state *remote_state,\n \tret->prune = -1;  /* unspecified */\n \tret->prune_tags = -1;  /* unspecified */\n \tret->name = xstrndup(name, len);\n-\trefspec_init_push(&ret->push);\n-\trefspec_init_fetch(&ret->fetch);\n+\trefspec_init_push(&ret->push, the_hash_algo);\n+\trefspec_init_fetch(&ret->fetch, the_hash_algo);\n \tstring_list_init_dup(&ret->server_options);\n \tstring_list_init_dup(&ret->negotiation_restrict);\n \tstring_list_init_dup(&ret->negotiation_include);\ndiff --git a/transport-helper.c b/transport-helper.c\nindex 80f90eb7ba..8a25707b03 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -162,7 +162,7 @@ static struct child_process *get_helper(struct transport *transport)\n \n \tdata->helper = helper;\n \tdata->no_disconnect_req = 0;\n-\trefspec_init_fetch(&data->rs);\n+\trefspec_init_fetch(&data->rs, the_hash_algo);\n \n \t/*\n \t * Open the output as FILE* so strbuf_getline_*() family of\n\n-- \n2.55.0.313.g8d093f411d.dirty\n\n"},{"id":"548456","messageId":"xmqqpl0mejlc.fsf@gitster.g","threadId":"66018","inReplyTo":"20260716-pks-refspec-wo-the-repository-v1-3-aa40844d067f@pks.im","subject":"Re: [PATCH 3/3] refspec: stop depending on `the_repository`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-07-16T20:59:59Z","receivedAt":"2026-07-16T21:00:02Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The only remaining user of `the_hash_algo` in \"refspec.c\" is\n> `refspec_append()`, which needs to know the hash algorithm so that it\n> can parse the appended refspec item. In contrast to the functions\n> adapted in the preceding commit, this function always operates on a\n> `struct refspec`. As that structure is expected to only ever contain\n> refspecs that all use the same hash function it doesn't make sense\n> though to adapt each caller.\n>\n> Instead, adapt the structure itself so that it gets initialized with a\n> hash function and use that hash function to parse new refspec items.\n> Adapt callers accordingly.\n>\n> This removes the final dependency on the global repository variable in\n> \"refspec.c\", so we can drop `USE_THE_REPOSITORY_VARIABLE`.\n\nWhile we lost some references to the_repository, we gained\nmore references to the_hash_algo in exchange.  Because\nthe_hash_algo is defined in terms of the_repository->hash_algo,\nit is only available when the_repository is still in use.\nSo these changes do not really help callers, and only leave\nmore for them to clean up later.\n\nWhich is probably fine.  We have to start somewhere, and\nrefspec parsing is a fairly well-isolated corner of the\nuniverse that serves as a good starting point.\n\nThanks.\n"},{"id":"548471","messageId":"alnFZe5jqvFdHQdh@pks.im","threadId":"66018","inReplyTo":"xmqqpl0mejlc.fsf@gitster.g","subject":"Re: [PATCH 3/3] refspec: stop depending on `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-07-17T06:02:13Z","receivedAt":"2026-07-17T06:02:24Z","isPatch":true,"body":"On Thu, Jul 16, 2026 at 01:59:59PM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > The only remaining user of `the_hash_algo` in \"refspec.c\" is\n> > `refspec_append()`, which needs to know the hash algorithm so that it\n> > can parse the appended refspec item. In contrast to the functions\n> > adapted in the preceding commit, this function always operates on a\n> > `struct refspec`. As that structure is expected to only ever contain\n> > refspecs that all use the same hash function it doesn't make sense\n> > though to adapt each caller.\n> >\n> > Instead, adapt the structure itself so that it gets initialized with a\n> > hash function and use that hash function to parse new refspec items.\n> > Adapt callers accordingly.\n> >\n> > This removes the final dependency on the global repository variable in\n> > \"refspec.c\", so we can drop `USE_THE_REPOSITORY_VARIABLE`.\n> \n> While we lost some references to the_repository, we gained\n> more references to the_hash_algo in exchange.  Because\n> the_hash_algo is defined in terms of the_repository->hash_algo,\n> it is only available when the_repository is still in use.\n> So these changes do not really help callers, and only leave\n> more for them to clean up later.\n> \n> Which is probably fine.  We have to start somewhere, and\n> refspec parsing is a fairly well-isolated corner of the\n> universe that serves as a good starting point.\n\nYup, this patch series follows our typical approach of making one\nsubsystem `the_repository`-clean, but bumping that dependency up into\nthe next-higher level.\n\nI've got a bunch of follow-up patch series that'll also convert some of\nthose higher-up dependencies. Most importantly, I'm converting all\nsubsystems that relate to the transport layer, as I'm on a very naive\nquest to try and get git-clone(1) working without `the_repository`.\nLet's see how far I get.\n\nPatrick\n"}]}