refspec: let callers pass in hash algorithm when parsing items

When parsing a refspec item we need to know about the hash algorithm used by the repository so that we can decide whether or not a given string is an exact object ID. We use `the_hash_algo` for this, which makes the code implicitly depend on `the_repository`. Refactor `refspec_item_init_fetch()`, `refspec_item_init_push()` and `valid_fetch_refspec()` so that callers have to pass in the hash algorithm explicitly and adapt callers accordingly. For now, all of the callers simply pass `the_hash_algo`, so there is no change in behaviour. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jul 16, 2026 at 14:38 UTC bb71c3f19e6a693fc1d32e4448be8520132d946e
5 files changed +27 -19
builtin/fetch.c
+2 -1
@@ -601,7 +601,8 @@ static struct ref *get_ref_map(struct remote *remote,
601 struct refspec_item tag_refspec;
602
603 /* also fetch all tags */
604 - refspec_item_init_push(&tag_refspec, TAG_REFSPEC);
604 + refspec_item_init_push(&tag_refspec, TAG_REFSPEC,
605 + the_hash_algo);
606 get_fetch_map(remote_refs, &tag_refspec, &tail, 0);
607 refspec_item_clear(&tag_refspec);
608 } else if (tags == TAGS_DEFAULT && *autotags) {
builtin/pull.c
+1 -1
@@ -612,7 +612,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
612 const char *spec_src;
613 const char *merge_branch;
614
615 - if (!refspec_item_init_fetch(&spec, refspec))
615 + if (!refspec_item_init_fetch(&spec, refspec, the_hash_algo))
616 die(_("invalid refspec '%s'"), refspec);
617 spec_src = spec.src;
618 if (!*spec_src || !strcmp(spec_src, "HEAD"))
refspec.c
+17 -13
@@ -16,7 +16,8 @@
16 * Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
17 * Returns 1 if successful and 0 if the refspec is invalid.
18 */
19 -static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch)
19 +static int parse_refspec(struct refspec_item *item, const char *refspec,
20 + const struct git_hash_algo *algo, int fetch)
21 {
22 size_t llen;
23 int is_glob;
@@ -84,7 +85,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
85 */
86 if (!*item->src)
87 return 0; /* negative refspecs must not be empty */
87 - else if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))
88 + else if (llen == algo->hexsz && !get_oid_hex_algop(item->src, &unused, algo))
89 return 0; /* negative refspecs cannot be exact sha1 */
90 else if (!check_refname_format(item->src, flags))
91 ; /* valid looking ref is ok */
@@ -101,7 +102,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
102 /* LHS */
103 if (!*item->src)
104 ; /* empty is ok; it means "HEAD" */
104 - else if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))
105 + else if (llen == algo->hexsz && !get_oid_hex_algop(item->src, &unused, algo))
106 item->exact_sha1 = 1; /* ok */
107 else if (!check_refname_format(item->src, flags))
108 ; /* valid looking ref is ok */
@@ -154,21 +155,23 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
155 }
156
157 static int refspec_item_init(struct refspec_item *item, const char *refspec,
157 - int fetch)
158 + const struct git_hash_algo *algo, int fetch)
159 {
160 memset(item, 0, sizeof(*item));
161 item->raw = xstrdup(refspec);
161 - return parse_refspec(item, refspec, fetch);
162 + return parse_refspec(item, refspec, algo, fetch);
163 }
164
164 -int refspec_item_init_fetch(struct refspec_item *item, const char *refspec)
165 +int refspec_item_init_fetch(struct refspec_item *item, const char *refspec,
166 + const struct git_hash_algo *algo)
167 {
166 - return refspec_item_init(item, refspec, 1);
168 + return refspec_item_init(item, refspec, algo, 1);
169 }
170
169 -int refspec_item_init_push(struct refspec_item *item, const char *refspec)
171 +int refspec_item_init_push(struct refspec_item *item, const char *refspec,
172 + const struct git_hash_algo *algo)
173 {
171 - return refspec_item_init(item, refspec, 0);
174 + return refspec_item_init(item, refspec, algo, 0);
175 }
176
177 void refspec_item_clear(struct refspec_item *item)
@@ -200,9 +203,9 @@ void refspec_append(struct refspec *rs, const char *refspec)
203 int ret;
204
205 if (rs->fetch)
203 - ret = refspec_item_init_fetch(&item, refspec);
206 + ret = refspec_item_init_fetch(&item, refspec, the_hash_algo);
207 else
205 - ret = refspec_item_init_push(&item, refspec);
208 + ret = refspec_item_init_push(&item, refspec, the_hash_algo);
209 if (!ret)
210 die(_("invalid refspec '%s'"), refspec);
211
@@ -246,10 +249,11 @@ void refspec_clear(struct refspec *rs)
249 rs->fetch = 0;
250 }
251
249 -int valid_fetch_refspec(const char *fetch_refspec_str)
252 +int valid_fetch_refspec(const char *fetch_refspec_str,
253 + const struct git_hash_algo *algo)
254 {
255 struct refspec_item refspec;
252 - int ret = refspec_item_init_fetch(&refspec, fetch_refspec_str);
256 + int ret = refspec_item_init_fetch(&refspec, fetch_refspec_str, algo);
257 refspec_item_clear(&refspec);
258 return ret;
259 }
refspec.h
+6 -3
@@ -1,6 +1,7 @@
1 #ifndef REFSPEC_H
2 #define REFSPEC_H
3
4 +struct git_hash_algo;
5 struct string_list;
6 struct strvec;
7
@@ -33,8 +34,10 @@ struct refspec_item {
34 char *raw;
35 };
36
36 -int refspec_item_init_fetch(struct refspec_item *item, const char *refspec);
37 -int refspec_item_init_push(struct refspec_item *item, const char *refspec);
37 +int refspec_item_init_fetch(struct refspec_item *item, const char *refspec,
38 + const struct git_hash_algo *algo);
39 +int refspec_item_init_push(struct refspec_item *item, const char *refspec,
40 + const struct git_hash_algo *algo);
41 void refspec_item_clear(struct refspec_item *item);
42
43 /**
@@ -61,7 +64,7 @@ __attribute__((format (printf,2,3)))
64 void refspec_appendf(struct refspec *rs, const char *fmt, ...);
65 void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
66
64 -int valid_fetch_refspec(const char *refspec);
67 +int valid_fetch_refspec(const char *refspec, const struct git_hash_algo *algo);
68
69 /*
70 * Determine what <prefix> values to pass to the peer in ref-prefix lines
remote.c
+1 -1
@@ -3039,7 +3039,7 @@ int valid_remote_name(const char *name)
3039 int result;
3040 struct strbuf refspec = STRBUF_INIT;
3041 strbuf_addf(&refspec, "refs/heads/test:refs/remotes/%s/test", name);
3042 - result = valid_fetch_refspec(refspec.buf);
3042 + result = valid_fetch_refspec(refspec.buf, the_hash_algo);
3043 strbuf_release(&refspec);
3044 return result;
3045 }