Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show-ref: add --symbolic-name option #1684

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion builtin/submodule--helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static int repo_get_default_remote(struct repository *repo, char **default_remot
char *dest = NULL;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

> diff --git a/refs.h b/refs.h
> index 298caf6c618..2e740c692ac 100644
> --- a/refs.h
> +++ b/refs.h
> @@ -71,9 +71,10 @@ struct pack_refs_opts {
>  	struct ref_exclusions *exclusions;
>  	struct string_list *includes;
>  };
> -
>  const char *refs_resolve_ref_unsafe(struct ref_store *refs,
> +
>  				    const char *refname,
> +				    char **referent,
>  				    int resolve_flags,
>  				    struct object_id *oid,
>  				    int *flags);

If referent is meant to be an out-parameter, it should sit next to
oid that is also an out-parameter.  And as a late-comer sibling, it
should sit after its elder brother.

Also, I do not see the reason for the shuffling of blank lines.
Shouldn't it be the other way around, even?  After an unrelated
definition of "struct pack_refs_opts", there is (and should be)
a blank line, then the first line of the declaration of function.

Perhaps some fat-fingering.

> @@ -1928,6 +1928,7 @@ int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
>  
>  const char *refs_resolve_ref_unsafe(struct ref_store *refs,
>  				    const char *refname,
> +				    char **referent,
>  				    int resolve_flags,
>  				    struct object_id *oid,
>  				    int *flags)
> @@ -1989,6 +1990,8 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
>  		}
>  
>  		*flags |= read_flags;
> +		if (referent && read_flags & REF_ISSYMREF && sb_refname.len > 0)
> +			*referent = sb_refname.buf;

Is this safe?  After this assignment, which "return" in this loop
are you expecting to return from this function?  If you fail to
return from the function during this iteration, you'll clobber the
same strbuf with the next refs_read_raw_ref(), but I do not see how
you are ensuring that you'll return from the function without such
corruption happening.

This assignment happens only when read_flags has REF_ISSYMREF set,
so the next "if it is not, then return refname" would not even
trigger.  If RESOLVE_REF_NO_RECURSE bit is on in resolve_flags,
then we'd return without further dereferencing, but if that is the
only safe exit from the function, shouldn't you be guarding the
function with something like

	if (referent && !(resolve_flags & RESOLVE_REF_NO_RECURSE))
		BUG("recursive dereference can will clobber *referent");

to protect its callers from their own mistakes?

Another return before we start the next iteration of the loop and
clobber sb_refname with another call to refs_read_raw_ref() is the
error return codepath at the end of the loop, but that is a totally
uninteresting case.

Or am I totally confused?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, John Cai wrote (reply to this):

Hi Junio

On 8 Apr 2024, at 19:02, Junio C Hamano wrote:

>> diff --git a/refs.h b/refs.h
>> index 298caf6c618..2e740c692ac 100644
>> --- a/refs.h
>> +++ b/refs.h
>> @@ -71,9 +71,10 @@ struct pack_refs_opts {
>>  	struct ref_exclusions *exclusions;
>>  	struct string_list *includes;
>>  };
>> -
>>  const char *refs_resolve_ref_unsafe(struct ref_store *refs,
>> +
>>  				    const char *refname,
>> +				    char **referent,
>>  				    int resolve_flags,
>>  				    struct object_id *oid,
>>  				    int *flags);
>
> If referent is meant to be an out-parameter, it should sit next to
> oid that is also an out-parameter.  And as a late-comer sibling, it
> should sit after its elder brother.
>
> Also, I do not see the reason for the shuffling of blank lines.
> Shouldn't it be the other way around, even?  After an unrelated
> definition of "struct pack_refs_opts", there is (and should be)
> a blank line, then the first line of the declaration of function.
>
> Perhaps some fat-fingering.

This was indeed a case of fat-fingering.

>
>> @@ -1928,6 +1928,7 @@ int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
>>
>>  const char *refs_resolve_ref_unsafe(struct ref_store *refs,
>>  				    const char *refname,
>> +				    char **referent,
>>  				    int resolve_flags,
>>  				    struct object_id *oid,
>>  				    int *flags)
>> @@ -1989,6 +1990,8 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
>>  		}
>>
>>  		*flags |= read_flags;
>> +		if (referent && read_flags & REF_ISSYMREF && sb_refname.len > 0)
>> +			*referent = sb_refname.buf;
>
> Is this safe?  After this assignment, which "return" in this loop
> are you expecting to return from this function?  If you fail to
> return from the function during this iteration, you'll clobber the
> same strbuf with the next refs_read_raw_ref(), but I do not see how
> you are ensuring that you'll return from the function without such
> corruption happening.
>
> This assignment happens only when read_flags has REF_ISSYMREF set,
> so the next "if it is not, then return refname" would not even
> trigger.  If RESOLVE_REF_NO_RECURSE bit is on in resolve_flags,
> then we'd return without further dereferencing, but if that is the
> only safe exit from the function, shouldn't you be guarding the
> function with something like
>
> 	if (referent && !(resolve_flags & RESOLVE_REF_NO_RECURSE))
> 		BUG("recursive dereference can will clobber *referent");
>
> to protect its callers from their own mistakes?
>
> Another return before we start the next iteration of the loop and
> clobber sb_refname with another call to refs_read_raw_ref() is the
> error return codepath at the end of the loop, but that is a totally
> uninteresting case.
>
> Or am I totally confused?

Yeah good point. This probably not a good idea. In fact, perhaps adding another
argument to this function is unnecessary. We already have refs_read_symbolic_ref
and we can just make a separate call to that once we know that a ref is a
symbolic reference. Though a separate call is less efficient, I'm not sure it's
worth adding this parameter.

thanks
John

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Patrick Steinhardt wrote (reply to this):

On Mon, Apr 08, 2024 at 05:38:11PM +0000, John Cai via GitGitGadget wrote:
> From: John Cai <johncai86@gmail.com>
[snip]
> @@ -1928,6 +1928,7 @@ int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
>  
>  const char *refs_resolve_ref_unsafe(struct ref_store *refs,
>  				    const char *refname,
> +				    char **referent,
>  				    int resolve_flags,
>  				    struct object_id *oid,
>  				    int *flags)

I wonder whether this really should be a `char **`. You don't seem to be
free'ing returned pointers anywhere, so this should probably at least be
`const char **` to indicate that memory is owned by the ref store. But
that would require the ref store to inevitably release it, which may
easily lead to bugs when the caller expects a different lifetime.

So how about we instead make this a `struct strbuf *referent`? This
makes it quite clear who owns the memory. Furthermore, if the caller
wants to resolve multiple refs, it would allow them to reuse the buffer
for better-optimized allocation patterns.

[snip]
> diff --git a/refs/ref-cache.c b/refs/ref-cache.c
> index 9f9797209a4..4c23b92414a 100644
> --- a/refs/ref-cache.c
> +++ b/refs/ref-cache.c
> @@ -34,12 +34,14 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
>  }
>  
>  struct ref_entry *create_ref_entry(const char *refname,
> +				   const char *referent,
>  				   const struct object_id *oid, int flag)
>  {
>  	struct ref_entry *ref;
>  
>  	FLEX_ALLOC_STR(ref, name, refname);
>  	oidcpy(&ref->u.value.oid, oid);
> +	ref->u.value.referent = referent;
>  	ref->flag = flag;
>  	return ref;
>  }

It's kind of hard to spot the actual changes inbetween all those changes
to callsites. Is it possible to split the patch up such that we have one
patch that changes all the callsites and one patch that does the actual
changes to implement this?

Patrick

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

Patrick Steinhardt <ps@pks.im> writes:

>>  const char *refs_resolve_ref_unsafe(struct ref_store *refs,
>>  				    const char *refname,
>> +				    char **referent,
>>  				    int resolve_flags,
>>  				    struct object_id *oid,
>>  				    int *flags)
>
> I wonder whether this really should be a `char **`. You don't seem to be
> free'ing returned pointers anywhere, so this should probably at least be
> `const char **` to indicate that memory is owned by the ref store. But
> that would require the ref store to inevitably release it, which may
> easily lead to bugs when the caller expects a different lifetime.
>
> So how about we instead make this a `struct strbuf *referent`? This
> makes it quite clear who owns the memory. Furthermore, if the caller
> wants to resolve multiple refs, it would allow them to reuse the buffer
> for better-optimized allocation patterns.

Or return an allocated piece of memory via "char **".  I think an
interface that _requires_ the caller to use strbuf is not nice, if
the caller is not expected to further _edit_ the returned contents
using the strbuf API.  If it is likely that the caller would want to
perform further post-processing on the result, an interface based on
strbuf is nice, but I do not think it applies to this case.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Patrick Steinhardt wrote (reply to this):

On Wed, Apr 10, 2024 at 08:26:13AM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
> 
> >>  const char *refs_resolve_ref_unsafe(struct ref_store *refs,
> >>  				    const char *refname,
> >> +				    char **referent,
> >>  				    int resolve_flags,
> >>  				    struct object_id *oid,
> >>  				    int *flags)
> >
> > I wonder whether this really should be a `char **`. You don't seem to be
> > free'ing returned pointers anywhere, so this should probably at least be
> > `const char **` to indicate that memory is owned by the ref store. But
> > that would require the ref store to inevitably release it, which may
> > easily lead to bugs when the caller expects a different lifetime.
> >
> > So how about we instead make this a `struct strbuf *referent`? This
> > makes it quite clear who owns the memory. Furthermore, if the caller
> > wants to resolve multiple refs, it would allow them to reuse the buffer
> > for better-optimized allocation patterns.
> 
> Or return an allocated piece of memory via "char **".  I think an
> interface that _requires_ the caller to use strbuf is not nice, if
> the caller is not expected to further _edit_ the returned contents
> using the strbuf API.  If it is likely that the caller would want to
> perform further post-processing on the result, an interface based on
> strbuf is nice, but I do not think it applies to this case.

When iterating through refs this would incur one allocation per ref
though, whereas using a `struct strbuf` would only require a single one.

Patrick

struct strbuf sb = STRBUF_INIT;
struct ref_store *store = get_main_ref_store(repo);
const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
const char *refname = refs_resolve_ref_unsafe(store, "HEAD", NULL, 0, NULL,
NULL);

if (!refname)
Expand Down
23 changes: 13 additions & 10 deletions refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ char *refs_resolve_refdup(struct ref_store *refs,
{
const char *result;

result = refs_resolve_ref_unsafe(refs, refname, resolve_flags,
result = refs_resolve_ref_unsafe(refs, refname, NULL, resolve_flags,
oid, flags);
return xstrdup_or_null(result);
}
Expand All @@ -404,7 +404,7 @@ int read_ref_full(const char *refname, int resolve_flags, struct object_id *oid,
{
struct ref_store *refs = get_main_ref_store(the_repository);

if (refs_resolve_ref_unsafe(refs, refname, resolve_flags,
if (refs_resolve_ref_unsafe(refs, refname, NULL, resolve_flags,
oid, flags))
return 0;
return -1;
Expand All @@ -417,7 +417,7 @@ int read_ref(const char *refname, struct object_id *oid)

int refs_ref_exists(struct ref_store *refs, const char *refname)
{
return !!refs_resolve_ref_unsafe(refs, refname, RESOLVE_REF_READING,
return !!refs_resolve_ref_unsafe(refs, refname, NULL, RESOLVE_REF_READING,
NULL, NULL);
}

Expand Down Expand Up @@ -773,7 +773,7 @@ int expand_ref(struct repository *repo, const char *str, int len,
this_result = refs_found ? &oid_from_ref : oid;
strbuf_reset(&fullref);
strbuf_addf(&fullref, *p, len, str);
r = refs_resolve_ref_unsafe(refs, fullref.buf,
r = refs_resolve_ref_unsafe(refs, fullref.buf, NULL,
RESOLVE_REF_READING,
this_result, &flag);
if (r) {
Expand Down Expand Up @@ -807,7 +807,7 @@ int repo_dwim_log(struct repository *r, const char *str, int len,

strbuf_reset(&path);
strbuf_addf(&path, *p, len, str);
ref = refs_resolve_ref_unsafe(refs, path.buf,
ref = refs_resolve_ref_unsafe(refs, path.buf, NULL,
RESOLVE_REF_READING,
oid ? &hash : NULL, NULL);
if (!ref)
Expand Down Expand Up @@ -876,15 +876,15 @@ int is_pseudoref(struct ref_store *refs, const char *refname)
return 0;

if (ends_with(refname, "_HEAD")) {
refs_resolve_ref_unsafe(refs, refname,
refs_resolve_ref_unsafe(refs, refname, NULL,
RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
&oid, NULL);
return !is_null_oid(&oid);
}

for (i = 0; i < ARRAY_SIZE(irregular_pseudorefs); i++)
if (!strcmp(refname, irregular_pseudorefs[i])) {
refs_resolve_ref_unsafe(refs, refname,
refs_resolve_ref_unsafe(refs, refname, NULL,
RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
&oid, NULL);
return !is_null_oid(&oid);
Expand Down Expand Up @@ -1590,7 +1590,7 @@ int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
struct object_id oid;
int flag;

if (refs_resolve_ref_unsafe(refs, "HEAD", RESOLVE_REF_READING,
if (refs_resolve_ref_unsafe(refs, "HEAD", NULL, RESOLVE_REF_READING,
&oid, &flag))
return fn("HEAD", &oid, flag, cb_data);

Expand Down Expand Up @@ -1928,6 +1928,7 @@ int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,

const char *refs_resolve_ref_unsafe(struct ref_store *refs,
const char *refname,
char **referent,
int resolve_flags,
struct object_id *oid,
int *flags)
Expand Down Expand Up @@ -1989,6 +1990,8 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
}

*flags |= read_flags;
if (referent && read_flags & REF_ISSYMREF && sb_refname.len > 0)
*referent = sb_refname.buf;

if (!(read_flags & REF_ISSYMREF)) {
if (*flags & REF_BAD_NAME) {
Expand Down Expand Up @@ -2024,7 +2027,7 @@ int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)
const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
struct object_id *oid, int *flags)
{
return refs_resolve_ref_unsafe(get_main_ref_store(the_repository), refname,
return refs_resolve_ref_unsafe(get_main_ref_store(the_repository), refname, NULL,
resolve_flags, oid, flags);
}

Expand All @@ -2039,7 +2042,7 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,
if (!refs)
return -1;

if (!refs_resolve_ref_unsafe(refs, refname, 0, oid, &flags) ||
if (!refs_resolve_ref_unsafe(refs, refname, NULL, 0, oid, &flags) ||
is_null_oid(oid))
return -1;
return 0;
Expand Down
3 changes: 2 additions & 1 deletion refs.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ struct pack_refs_opts {
struct ref_exclusions *exclusions;
struct string_list *includes;
};

const char *refs_resolve_ref_unsafe(struct ref_store *refs,

const char *refname,
char **referent,
int resolve_flags,
struct object_id *oid,
int *flags);
Expand Down
20 changes: 11 additions & 9 deletions refs/files-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,9 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
{
struct object_id oid;
int flag;
char *referent;

if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_READING,
if (!refs_resolve_ref_unsafe(&refs->base, refname, &referent, RESOLVE_REF_READING,
&oid, &flag)) {
oidclr(&oid);
flag |= REF_ISBROKEN;
Expand All @@ -258,7 +259,7 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
oidclr(&oid);
flag |= REF_BAD_NAME | REF_ISBROKEN;
}
add_entry_to_dir(dir, create_ref_entry(refname, &oid, flag));
add_entry_to_dir(dir, create_ref_entry(refname, referent, &oid, flag));
}

/*
Expand Down Expand Up @@ -843,6 +844,7 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
continue;

iter->base.refname = iter->iter0->refname;
iter->base.referent = iter->iter0->referent;
iter->base.oid = iter->iter0->oid;
iter->base.flags = iter->iter0->flags;
return ITER_OK;
Expand Down Expand Up @@ -1109,7 +1111,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
goto error_return;
}

if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, 0,
if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, NULL, 0,
&lock->old_oid, NULL))
oidclr(&lock->old_oid);
goto out;
Expand Down Expand Up @@ -1444,7 +1446,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
goto out;
}

if (!refs_resolve_ref_unsafe(&refs->base, oldrefname,
if (!refs_resolve_ref_unsafe(&refs->base, oldrefname, NULL,
RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
&orig_oid, &flag)) {
ret = error("refname %s not found", oldrefname);
Expand Down Expand Up @@ -1490,7 +1492,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
* the safety anyway; we want to delete the reference whatever
* its current value.
*/
if (!copy && refs_resolve_ref_unsafe(&refs->base, newrefname,
if (!copy && refs_resolve_ref_unsafe(&refs->base, newrefname, NULL,
RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
NULL, NULL) &&
refs_delete_ref(&refs->base, NULL, newrefname,
Expand Down Expand Up @@ -1863,7 +1865,7 @@ static int commit_ref_update(struct files_ref_store *refs,
int head_flag;
const char *head_ref;

head_ref = refs_resolve_ref_unsafe(&refs->base, "HEAD",
head_ref = refs_resolve_ref_unsafe(&refs->base, "HEAD", NULL,
RESOLVE_REF_READING,
NULL, &head_flag);
if (head_ref && (head_flag & REF_ISSYMREF) &&
Expand Down Expand Up @@ -1911,7 +1913,7 @@ static void update_symref_reflog(struct files_ref_store *refs,
struct object_id new_oid;

if (logmsg &&
refs_resolve_ref_unsafe(&refs->base, target,
refs_resolve_ref_unsafe(&refs->base, target, NULL,
RESOLVE_REF_READING, &new_oid, NULL) &&
files_log_ref_write(refs, refname, &lock->old_oid,
&new_oid, logmsg, 0, &err)) {
Expand Down Expand Up @@ -2505,7 +2507,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
* to record and possibly check old_oid:
*/
if (!refs_resolve_ref_unsafe(&refs->base,
referent.buf, 0,
referent.buf, NULL, 0,
&lock->old_oid, NULL)) {
if (update->flags & REF_HAVE_OLD) {
strbuf_addf(err, "cannot lock ref '%s': "
Expand Down Expand Up @@ -3200,7 +3202,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
int type;
const char *ref;

ref = refs_resolve_ref_unsafe(&refs->base, refname,
ref = refs_resolve_ref_unsafe(&refs->base, refname, NULL,
RESOLVE_REF_NO_RECURSE,
NULL, &type);
update = !!(ref && !(type & REF_ISSYMREF));
Expand Down
1 change: 1 addition & 0 deletions refs/iterator.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
}

if (selection & ITER_YIELD_CURRENT) {
iter->base.referent = (*iter->current)->referent;
iter->base.refname = (*iter->current)->refname;
iter->base.oid = (*iter->current)->oid;
iter->base.flags = (*iter->current)->flags;
Expand Down
3 changes: 3 additions & 0 deletions refs/ref-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
}

struct ref_entry *create_ref_entry(const char *refname,
const char *referent,
const struct object_id *oid, int flag)
{
struct ref_entry *ref;

FLEX_ALLOC_STR(ref, name, refname);
oidcpy(&ref->u.value.oid, oid);
ref->u.value.referent = referent;
ref->flag = flag;
return ref;
}
Expand Down Expand Up @@ -428,6 +430,7 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
level->prefix_state = entry_prefix_state;
level->index = -1;
} else {
iter->base.referent = entry->u.value.referent;
iter->base.refname = entry->name;
iter->base.oid = &entry->u.value.oid;
iter->base.flags = entry->flag;
Expand Down
2 changes: 2 additions & 0 deletions refs/ref-cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct ref_value {
* referred to by the last reference in the symlink chain.
*/
struct object_id oid;
const char *referent;
};

/*
Expand Down Expand Up @@ -173,6 +174,7 @@ struct ref_entry *create_dir_entry(struct ref_cache *cache,
const char *dirname, size_t len);

struct ref_entry *create_ref_entry(const char *refname,
const char *referent,
const struct object_id *oid, int flag);

/*
Expand Down
1 change: 1 addition & 0 deletions refs/refs-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ enum do_for_each_ref_flags {
struct ref_iterator {
struct ref_iterator_vtable *vtable;
const char *refname;
const char *referent;
const struct object_id *oid;
unsigned int flags;
};
Expand Down
13 changes: 9 additions & 4 deletions refs/reftable-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)

while (!iter->err) {
int flags = 0;
char **symref = NULL;

iter->err = reftable_iterator_next_ref(&iter->iter, &iter->ref);
if (iter->err)
Expand Down Expand Up @@ -377,7 +378,10 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
oidread(&iter->oid, iter->ref.value.val2.value);
break;
case REFTABLE_REF_SYMREF:
if (!refs_resolve_ref_unsafe(&iter->refs->base, iter->ref.refname,
if (!iter->ref.value.symref)
symref = &iter->ref.value.symref;

if (!refs_resolve_ref_unsafe(&iter->refs->base, iter->ref.refname, symref,
RESOLVE_REF_READING, &iter->oid, &flags))
oidclr(&iter->oid);
break;
Expand Down Expand Up @@ -406,6 +410,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
continue;

iter->base.refname = iter->ref.refname;
iter->base.referent = iter->ref.value.symref;
iter->base.oid = &iter->oid;
iter->base.flags = flags;

Expand Down Expand Up @@ -877,7 +882,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
* so it is safe to call `refs_resolve_ref_unsafe()`
* here without causing races.
*/
const char *resolved = refs_resolve_ref_unsafe(&refs->base, u->refname, 0,
const char *resolved = refs_resolve_ref_unsafe(&refs->base, u->refname, NULL, 0,
&current_oid, NULL);

if (u->flags & REF_NO_DEREF) {
Expand Down Expand Up @@ -1252,7 +1257,7 @@ static int write_create_symref_table(struct reftable_writer *writer, void *cb_da
* never happens.
*/
if (!create->logmsg ||
!refs_resolve_ref_unsafe(&create->refs->base, create->target,
!refs_resolve_ref_unsafe(&create->refs->base, create->target, NULL,
RESOLVE_REF_READING, &new_oid, NULL) ||
!should_write_log(&create->refs->base, create->refname))
return 0;
Expand All @@ -1263,7 +1268,7 @@ static int write_create_symref_table(struct reftable_writer *writer, void *cb_da
log.value.update.message = xstrndup(create->logmsg,
create->refs->write_options.block_size / 2);
memcpy(log.value.update.new_hash, new_oid.hash, GIT_MAX_RAWSZ);
if (refs_resolve_ref_unsafe(&create->refs->base, create->refname,
if (refs_resolve_ref_unsafe(&create->refs->base, create->refname, NULL,
RESOLVE_REF_READING, &old_oid, NULL))
memcpy(log.value.update.old_hash, old_oid.hash, GIT_MAX_RAWSZ);

Expand Down
2 changes: 1 addition & 1 deletion remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ static void read_config(struct repository *repo, int early)
repo->remote_state->current_branch = NULL;
if (startup_info->have_repository && !early) {
const char *head_ref = refs_resolve_ref_unsafe(
get_main_ref_store(repo), "HEAD", 0, NULL, &flag);
get_main_ref_store(repo), "HEAD", NULL, 0, NULL, &flag);
if (head_ref && (flag & REF_ISSYMREF) &&
skip_prefix(head_ref, "refs/heads/", &head_ref)) {
repo->remote_state->current_branch = make_branch(
Expand Down
4 changes: 2 additions & 2 deletions sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ void print_commit_summary(struct repository *r,
diff_setup_done(&rev.diffopt);

refs = get_main_ref_store(r);
head = refs_resolve_ref_unsafe(refs, "HEAD", 0, NULL, NULL);
head = refs_resolve_ref_unsafe(refs, "HEAD", NULL, 0, NULL, NULL);
if (!head)
die(_("unable to resolve HEAD after creating commit"));
if (!strcmp(head, "HEAD"))
Expand Down Expand Up @@ -4651,7 +4651,7 @@ static int apply_save_autostash_ref(struct repository *r, const char *refname,
if (!refs_ref_exists(get_main_ref_store(r), refname))
return 0;

if (!refs_resolve_ref_unsafe(get_main_ref_store(r), refname,
if (!refs_resolve_ref_unsafe(get_main_ref_store(r), refname, NULL,
RESOLVE_REF_READING, &stash_oid, &flag))
return -1;
if (flag & REF_ISSYMREF)
Expand Down
2 changes: 1 addition & 1 deletion t/helper/test-ref-store.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ static int cmd_resolve_ref(struct ref_store *refs, const char **argv)
int flags;
const char *ref;

ref = refs_resolve_ref_unsafe(refs, refname, resolve_flags,
ref = refs_resolve_ref_unsafe(refs, refname, NULL, resolve_flags,
&oid, &flags);
printf("%s %s 0x%x\n", oid_to_hex(&oid), ref ? ref : "(null)", flags);
return ref ? 0 : 1;
Expand Down
4 changes: 3 additions & 1 deletion worktree.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ static void add_head_info(struct worktree *wt)

target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt),
"HEAD",
NULL,
0,
&wt->head_oid, &flags);
if (!target)
Expand Down Expand Up @@ -446,7 +447,7 @@ int is_shared_symref(const struct worktree *wt, const char *symref,
}

refs = get_worktree_ref_store(wt);
symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
symref_target = refs_resolve_ref_unsafe(refs, symref, NULL, 0,
NULL, &flags);
if ((flags & REF_ISSYMREF) &&
symref_target && !strcmp(symref_target, target))
Expand Down Expand Up @@ -547,6 +548,7 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
strbuf_worktree_ref(wt, &refname, "HEAD");
if (refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
refname.buf,
NULL,
RESOLVE_REF_READING,
&oid, &flag))
ret = fn(refname.buf, &oid, flag, cb_data);
Expand Down