Subject: Re: [PATCH 7/8] refs: add 'update-symref' command to 'update-ref'

From: Junio C Hamano <[email-masked]>
Date: Wed, 10 Apr 2024 09:06:45 -0700

Patrick Steinhardt <[email-masked]> writes:

>> > I might have missed it while scanning through this thread, but why
>> > exactly is the zero OID not a good enough placeholder here to say that
>> > the ref must not exist? A symref cannot point to a ref named after the
>> > zero OID anyway.
>
>> > In my opinion, "update-symref" with an old-value must be able to accept
>> > both object IDs and symrefs as old value. Like this it would be possible
>> > to update a proper ref to a symref in a race-free way. So you can say:
>> >
>> >     git update-ref SYMREF refs/heads/main 19981daefd7c147444462739375462b49412ce33
>
>> > To update "SYRMEF" to "refs/heads/main", but only in case it currently
>> > is a proper ref that points to 19981daefd7c147444462739375462b49412ce33.
>> > Similarly...
>> >
>> >     git update-ref SYMREF refs/heads/main refs/heads/master
>
>> > would update "SYMREF" to "refs/heads/main", but only if it currently
>> > points to the symref "refs/heads/master".

I think that would work well.  We need to explicitly forbid a file
$GIT_DIR/[0-9a-f]{40} to be used as a pseudoref, which I think that
is an improvement.  I do not know how the transition to move to a
world with a stricter rule would look like, though.

>> > And by extension I think that
>> > the zero OID should retain its established meaning of "This ref must not
>> > exist":
>> >
>> >     git update-ref SYMREF refs/heads/main 0000000000000000000000000000000000000000
>> >
>> > This would only update "SYMREF" to "refs/heads/main" if it does not yet
>> > exist.

We express "SYMREF must currently be a symref" by naming an old-ref,
and we say "SYMREF can currently be either a ref or symref, but it
must point at this object" by naming an old-oid.  The looseness of
the latter (i.e. we cannot express "Before making HEAD point at ref
X, ensure that it is detached at OID") looks a bit disturbing, but
otherwise looks good.  I offhand do not know how expressive we would
want the "old" requirement to be.

>> On a side-note: This would also mean that we should somehow support
>> moving from symrefs to a regular ref via a transaction, so that means we
>> should allow
>> 
>>     update SP <ref> SP <new-oid> [SP (<old-oid> | <old-rev>)] LF
>> 
>> too, but I'm not going to tackle that in my patches.
>
> Yes, I think that would be a sensible idea, even though we have to be
> careful with backwards compatibility here. In any case, I think it makes
> sense to not extend the scope of your patch series and leave this for
> the future.

Likewise, we may want to be able to express "Before making HEAD
detached at commit X, ensure that HEAD points at ref Y that points
at commit Z".  IOW, the "old" part might have to be not

	[SP (<old-oid> | <old-ref>)]

but

	[SP <old-oid> SP <old-ref>]

to specify both, perhaps?