Subject: Re: [PATCH] refs: support migration with worktrees

From: "Kristoffer Haugsbakk" <[email-masked]>
Date: Wed, 29 Oct 2025 12:33:15 +0100

On Wed, Oct 29, 2025, at 11:10, Patrick Steinhardt wrote:
> On Tue, Oct 28, 2025 at 09:00:43AM -0700, Junio C Hamano wrote:
>> Patrick Steinhardt <[email-masked]> writes:
>>
>> >>  `migrate`::
>> >> -	Migrate ref store between different formats.
>> >> +	Migrate ref store between different formats. Supports repositories
>> >> +	with worktrees; migration must be run from the main worktree.
>> >
>> > It feels a bit weird to single our worktrees specifically. We don't say
>> > that the tool supports bare and non-bare repositories, either, so the
>> > only reason why we'd have the note about worktrees is historic legacy.
>> > How about this instead:
>> >
>> >     Migrate ref storage between different formats. Must be run from the
>> >     main worktree in case the repository uses worktrees.
>>
>> Two thoughts.
>>
>>  * Would it be unacceptable if the primary repository and refstore
>>    uses reftable backend, and a newly attached worktree to the
>>    repository uses ref-files only for its per-worktree refs?  If we
>>    should allow it, then "if the ref store you are migrating is in a
>>    repository with multiple worktrees, you must migrate from the
>>    primary and migrate _all_ ref store for all worktrees at once,
>>    into the same backend", which the design of this patch seems to
>>    aim at, would contradict with it, no?
>
> The problem we have here is backwards compatibility. Right now we assume
> that `extensions.refStorage` applies to all worktrees, so if we wanted
> to change it like you propose then we'd have to introduce a backwards
> incompatible change.

I don’t understand the motivation or use case for supporting different
backends for different worktrees. But Junio would have to explain that.

Maybe the motivation is this weird (from a user’s perspective) limi-
tation that you have to run a command from the main worktree?  Okay,
that’s strange but you get the error and switch to wherever the main
worktree is (that the error message hopefully helpfully provides you
with) and run the command there.  Then you forget that weird thing five
minutes later since this was a one-off command.

>
> I agree though that it would've been great if we would have said from
> the beginning that the worktree-specific configuration is allowed to
> override the ref storage format for a worktree. If so, we could easily
> convert any of the worktrees (including the main one) by without having
> any impact on all the other worktrees.

As a user I don’t understand why that is a great thing to have.

>
> But we do not live in such a world right now, and getting there would
> require some significant reworking of how we handle per-worktree
> references. Unfortunate, but I also don't think there's a strong enough
> reason to change this.
>
>>  * If "you must do so from the primary worktree and we convert all
>>    the worktrees attached to the same repository" is the only mode
>>    of operation we support (which by the way I have no problem
>>    with---the first bullet point above was asking question, not
>>    suggesting change of design), then would it be easier for the
>>    user to use if the command noticed that it is not in the primary
>>    worktree and switched to it for the user, instead of complaining
>>    and failing?
>
> I'm not sure. The question is whether the user recognizes that migrating
> references in the worktree would also migrate references in the main
> repository. It might be surprising behaviour if we did that without
> asking.

On the contrary, as a user I think it mattering what worktree I run this
command from sounds very weird.  (But again I can tolerate it requiring
me to run it from the main worktree if there are technical difficulties/
limitations.  But using different backends for different
worktrees is very weird, again.)

If I run `git gc` I don’t want it to do different things based on what
worktree I am. I want to operate on the repository, and the repository
is the same no matter what worktree I am in.  The same principle applies
to this command in my mind.

Is the “main worktree” even something that makes sense from the user’s
perspective?  It seems like it’s just a side-effect of the fact that the
repository itself has to live somewhere.  Imagine I have one main
worktree and two linked ones.  I delete the main worktree.  Imagine that
it works because the repository itself is moved to one of the linked
worktrees (arbitrary).  Which then becomes the main worktree.  But the
user does not have to care as long the user does not poke inside the
`.git` directory.  Which the user should not have to do (there should be
commands to answer whatever `.git`-poking motivations).

I am of course not suggesting such a change.  But the point is that the
“main worktree” is not such a useful end-user concept.

Sure, I happen to use a “main worktree” in the informal sense that I
often have the original path where I cloned or created the repository
and I have the other ones in satellite locations with more
pointed/topical names (e.g. `git-mine` is the basename of the Git
worktree that I use to `make install`).  But I never ever consult `git
worktree list` to remind me what the main worktree is.

Okay.  Let’s say I get tripped up by the gitlink or whatever it is kind
of file that worktrees use for `.git`.  Because I really want to poke at
the `.git` directory.  Then I think “I need to find the main worktree”
because it happens to have the repository and the link to that directory
could not be implemented using a symlink, maybe because of Windows
filesystems, I don’t know.  Again a technical limitation to my mind.
No worktree is special except because of technical limitations.

(The “main worktree” even becomes a technically contradictory concept in
the case when the “main worktree” is bare. And that is a popular
practice for some reason.)

And I wonder how many worktree users even actively think about the fact
that per-worktree refs exist.  It’s the kind of thing that you have to
logically conclude *has* to be the case:

1. `HEAD` is a ref and you need that for a worktree
2. You can have a bisect session in a worktree and that uses refs under
   the hood

But:

1. Conceptually I never really think about `HEAD` as a ref; “what
   branch/commit am I on” is what I care about. It’s the only builtin
   symref that I know of (or ref or symref depending on...). Not a usual
   ref at all.
2. I use git-bisect(1) to find a commit given a criteria.  Ones I have
   it I note the commit.  I don’t care that refs are used to store the
   bisect state while a session is active.

According to gitglossary(7) these are currently the only per-worktree
refs.  I do not know if you are allowed to use the `refs/worktree/`
hierarchy to create refs beyond that.

>
> It might of course also be surprising if you do that from the main
> working tree. But I think there's an argument to be made that it's at
> least _less_ surprising.
>
>> >> @@ -95,7 +96,7 @@ KNOWN LIMITATIONS
>> >>
>> >>  The ref format migration has several known limitations in its current form:
>> >>
>> >> -* It is not possible to migrate repositories that have worktrees.
>> >> +* Migration must be run from the main worktree.
>> >>
>> >
>> > I'd drop this bullet point entirely, as I don't really see this as a
>> > limitation anymore.
>>
>> I agree that such a limitation should be lifted, but if we have to
>> say "you must do it this way, not that way", that is still a
>> limitation ;-).
>
> So with the above reasoning I'm not sure I'd call this a limitation.
> It's rather a mechanism to protect users from unexpected consequences.