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>
This commit is contained in:
Patrick Steinhardt
2026-07-16 14:38:03 +02:00
committed by Junio C Hamano
parent 991ec2741d
commit bb71c3f19e
5 changed files with 27 additions and 19 deletions

View File

@@ -601,7 +601,8 @@ static struct ref *get_ref_map(struct remote *remote,
struct refspec_item tag_refspec;
/* also fetch all tags */
refspec_item_init_push(&tag_refspec, TAG_REFSPEC);
refspec_item_init_push(&tag_refspec, TAG_REFSPEC,
the_hash_algo);
get_fetch_map(remote_refs, &tag_refspec, &tail, 0);
refspec_item_clear(&tag_refspec);
} else if (tags == TAGS_DEFAULT && *autotags) {

View File

@@ -612,7 +612,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
const char *spec_src;
const char *merge_branch;
if (!refspec_item_init_fetch(&spec, refspec))
if (!refspec_item_init_fetch(&spec, refspec, the_hash_algo))
die(_("invalid refspec '%s'"), refspec);
spec_src = spec.src;
if (!*spec_src || !strcmp(spec_src, "HEAD"))

View File

@@ -16,7 +16,8 @@
* Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
* Returns 1 if successful and 0 if the refspec is invalid.
*/
static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch)
static int parse_refspec(struct refspec_item *item, const char *refspec,
const struct git_hash_algo *algo, int fetch)
{
size_t llen;
int is_glob;
@@ -84,7 +85,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
*/
if (!*item->src)
return 0; /* negative refspecs must not be empty */
else if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))
else if (llen == algo->hexsz && !get_oid_hex_algop(item->src, &unused, algo))
return 0; /* negative refspecs cannot be exact sha1 */
else if (!check_refname_format(item->src, flags))
; /* valid looking ref is ok */
@@ -101,7 +102,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
/* LHS */
if (!*item->src)
; /* empty is ok; it means "HEAD" */
else if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))
else if (llen == algo->hexsz && !get_oid_hex_algop(item->src, &unused, algo))
item->exact_sha1 = 1; /* ok */
else if (!check_refname_format(item->src, flags))
; /* valid looking ref is ok */
@@ -154,21 +155,23 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
}
static int refspec_item_init(struct refspec_item *item, const char *refspec,
int fetch)
const struct git_hash_algo *algo, int fetch)
{
memset(item, 0, sizeof(*item));
item->raw = xstrdup(refspec);
return parse_refspec(item, refspec, fetch);
return parse_refspec(item, refspec, algo, fetch);
}
int refspec_item_init_fetch(struct refspec_item *item, const char *refspec)
int refspec_item_init_fetch(struct refspec_item *item, const char *refspec,
const struct git_hash_algo *algo)
{
return refspec_item_init(item, refspec, 1);
return refspec_item_init(item, refspec, algo, 1);
}
int refspec_item_init_push(struct refspec_item *item, const char *refspec)
int refspec_item_init_push(struct refspec_item *item, const char *refspec,
const struct git_hash_algo *algo)
{
return refspec_item_init(item, refspec, 0);
return refspec_item_init(item, refspec, algo, 0);
}
void refspec_item_clear(struct refspec_item *item)
@@ -200,9 +203,9 @@ void refspec_append(struct refspec *rs, const char *refspec)
int ret;
if (rs->fetch)
ret = refspec_item_init_fetch(&item, refspec);
ret = refspec_item_init_fetch(&item, refspec, the_hash_algo);
else
ret = refspec_item_init_push(&item, refspec);
ret = refspec_item_init_push(&item, refspec, the_hash_algo);
if (!ret)
die(_("invalid refspec '%s'"), refspec);
@@ -246,10 +249,11 @@ void refspec_clear(struct refspec *rs)
rs->fetch = 0;
}
int valid_fetch_refspec(const char *fetch_refspec_str)
int valid_fetch_refspec(const char *fetch_refspec_str,
const struct git_hash_algo *algo)
{
struct refspec_item refspec;
int ret = refspec_item_init_fetch(&refspec, fetch_refspec_str);
int ret = refspec_item_init_fetch(&refspec, fetch_refspec_str, algo);
refspec_item_clear(&refspec);
return ret;
}

View File

@@ -1,6 +1,7 @@
#ifndef REFSPEC_H
#define REFSPEC_H
struct git_hash_algo;
struct string_list;
struct strvec;
@@ -33,8 +34,10 @@ struct refspec_item {
char *raw;
};
int refspec_item_init_fetch(struct refspec_item *item, const char *refspec);
int refspec_item_init_push(struct refspec_item *item, const char *refspec);
int refspec_item_init_fetch(struct refspec_item *item, const char *refspec,
const struct git_hash_algo *algo);
int refspec_item_init_push(struct refspec_item *item, const char *refspec,
const struct git_hash_algo *algo);
void refspec_item_clear(struct refspec_item *item);
/**
@@ -61,7 +64,7 @@ __attribute__((format (printf,2,3)))
void refspec_appendf(struct refspec *rs, const char *fmt, ...);
void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
int valid_fetch_refspec(const char *refspec);
int valid_fetch_refspec(const char *refspec, const struct git_hash_algo *algo);
/*
* Determine what <prefix> values to pass to the peer in ref-prefix lines

View File

@@ -3039,7 +3039,7 @@ int valid_remote_name(const char *name)
int result;
struct strbuf refspec = STRBUF_INIT;
strbuf_addf(&refspec, "refs/heads/test:refs/remotes/%s/test", name);
result = valid_fetch_refspec(refspec.buf);
result = valid_fetch_refspec(refspec.buf, the_hash_algo);
strbuf_release(&refspec);
return result;
}