Thread (3 messages) 3 messages, 2 authors, 2023-12-28

Re: reftable: How to represent deleted referees of symrefs in the reflog?

From: Patrick Steinhardt <hidden>
Date: 2023-12-28 08:14:59

On Wed, Dec 20, 2023 at 08:03:00PM +0100, Han-Wen Nienhuys wrote:
On Tue, Nov 21, 2023 at 2:46 PM Patrick Steinhardt [off-list ref] wrote:
quoted
To me it seems like deletions in this case only delete a particular log
entry instead of the complete log for a particular reference. And some
older discussion [1] seems to confirm my hunch that a complete reflog is
deleted not with `log_type = 0x0`, but instead by writing the null
object ID as new ID.
No, writing a null OID (more precisely a transition from $SHA1 =>
$ZERO) means that a branch was at $SHA1, and then was deleted. The
reflog continues to exist, and new entries may be added by reviving
the branch. That would add a $ZERO => $NEWSHA transition, but the
history of the branch prior to its deletion is retained.
quoted
 # This behaviour is a bit more on the weird side. We delete the
 # referee, and that causes the files backend to claim that the reflog
 # for HEAD is gone, as well. The reflog still exists though, as
 # demonstrated in the next command.
 $ git update-ref -m delete-main -d refs/heads/main
 $ git reflog show HEAD
fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree.
This looks wrong to me. HEAD has a history, and that history didn't go
away because the current branch happened to be deleted.
quoted
It kind of feels like the second step in the files backend where the
reflog is claimed to not exist is buggy -- I'd have expected to still
right, I agree.
quoted
see the reflog, as the HEAD reference exists quite alright and has never
stopped to exist. And in the third step, I'd have expected to see three
reflog entries, including the deletion that is indeed still present in
the on-disk logfile.

But with the reftable backend the problem becomes worse: we cannot even
represent the fact that the reflog still exists, but that the deletion
of the referee has caused the HEAD to point to the null OID, because the
null OID indicates complete deletion of the reflog.
This doesn't match my recollection. See
https://github.com/git/git/pull/1215, or more precisely
https://github.com/git/git/blob/3b2c5ddb28fa42a8c944373bea2ca756b1723908/refs/reftable-backend.c#L1582

Removing the entire reflog means removing all the individual entries
using tombstones.
Yeah, indeed. I was misinterpreting older discussions here, and now use
individual tombstones which does work as expected. It's a bit
unfortunate that deletion of the reflog thus scales with its size, but
for now I think that's okay. We can still iterate on this if this ever
proves to become a problem.
quoted
Consequentially, if
we wrote the null OID, we'd only be able to see the last log entry here.

It may totally be that I'm missing something obvious here. But if not,
it leaves us with a couple of options for how to fix it:

    1. Disregard this edge case and accept that the reftable backend
       does not do exactly the same thing as the files backend in very
       specific situations like this.
I remember discussing with Jun that it would be acceptable to have
slight semantic differences if unavoidable for the reflogs, and there
should be a record of this in the list.  I think there will always be
some differences: for example, dropping reflogs because of a dir/file
conflict seems like a bug rather than a feature.
Initially I'm aiming for matching semantics, because this will make it a
ton easier to land the initial implementation of the backend. But I do
agree that eventually we may want to iterate and allow for diverging
behaviour between the backends.

Thanks!

Patrick

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help