Subject: Re: [PATCH] glossary: describe "worktree"

From: Junio C Hamano <[email-masked]>
Date: Thu, 10 Feb 2022 10:28:31 -0800

Han-Wen Nienhuys <[email-masked]> writes:

> On Thu, Feb 10, 2022 at 5:36 PM Junio C Hamano <[email-masked]> wrote:
>> >>    One thing that makes me worried somewhat is what I did not touch,
>> >>    namely, how pseudo refs are defined.  I know MERGE_HEAD is very
>> >>    special and it may be impossible to coax it into refs API for
>> >>    writing, so the text there makes sense for it, but there are
>> >>    other all-caps-and-directly-under-dot-git-directory files like
>> >>    ORIG_HEAD and CHERRY_PICK_HEAD that are written using the refs
>> >>    API, so the description would have to be updated there.
>> >
>> > I'm not quite following; why would the description need to be updated?
>> >  Sure MERGE_HEAD is written without using the refs API, but we didn't
>> > mention how the pseduorefs were written in the description, and all of
>> > MERGE_HEAD, CHERRY_PICK_HEAD, ORIG_HEAD, REVERT_HEAD get written
>> > per-worktree so doesn't "pseudorefs like MERGE_HEAD" cover it as far
>> > as the reader is concerned?
>>
>> Here is how pseudo refs are defined.
>>
>> [[def_pseudoref]]pseudoref::
>>         Pseudorefs are a class of files under `$GIT_DIR` which behave
>>         like refs for the purposes of rev-parse, but which are treated
>>         specially by git.  Pseudorefs both have names that are all-caps,
>>         and always start with a line consisting of a
>>         <<def_SHA1,SHA-1>> followed by whitespace.  So, HEAD is not a
>>         pseudoref, because it is sometimes a symbolic ref.  They might
>
> refs.c says
>
>         if (is_pseudoref_syntax(refname))
>                 return REF_TYPE_PSEUDOREF;
>
> Ie. ref_type("HEAD") == REF_TYPE_PSEUDOREF
>
> This may be partly my fault (commit 55dd8b910 "Make HEAD a PSEUDOREF
> rather than PER_WORKTREE.").
>
> From the source code I had only understood that pseudorefs are ALLCAPS
> names and are in the toplevel namespace.
> (HEAD, FETCH_HEAD and MERGE_HEAD have special-cased support in various places).
>
> Is this glossary the official definition of what things are? If so,
> the source code should refer to there. If not -except for confusion-
> how bad is it if the info in the glossary is inaccurate?

Developer and end-user confusion ensues.

>> What worries me the most is that we cannot simply say "all-caps
>> names that end with '_HEAD' all behave like refs except that they
>> will not be symrefs without reflog." MERGE_HEAD is the only known
>> exception if I am not mistaken, and I am OK to single it out as an
>> oddball.  The current description however gives that there are a lot
>> more differences _among_ pseudorefs.
>
> It might be possible to add this extra info the reftable format as a
> further subtype of the ref record.  We'd have to update the JGit
> implementation, though.

As you said earlier, the true oddball is FETCH_HEAD X-<.  I actually
think in all the discussion in this thread around pseudoref, I meant
that one when I mentioned MERGE_HEAD, and I suspect the glossary
entry also made the same mistake of not mentioning it.  MERGE_HEAD
is also different in that it can list more than one commit, but
FETCH_HEAD has a lot more information per commit.

The format was invented solely for the purpose of passing
information from "git fetch" to "git merge" as an implementation
detail of "git pull" to describe each commit/tag that are being
merged, so that it can in turn pass the extra info to drive "git
fmt-merge-msg" internally to prepare merge template.

"git pull" did have to use such a special format temporary file
(which is what FETCH_HEAD really is, rather than a ref that records
more than one commits), but we didn't have to treat such an oddball
temporary file as if it were a ref.  But we allowed "git rev-parse"
to read only the first object name in the file and ignore the rest
as if nothing strange happened, which probably was a mistake made
out of my sloppyness when we did "pull is fetch followed by merge"
callchain.

For backward compatibility, "git merge FETCH_HEAD" still may have to
work the way it does (i.e. if FETCH_HEAD has multiple lines, the
resulting merge would become an octopus merge, and merge message
will say not just the commit but mention where they came from).  But
I am not sure if it is essential for us to keep treating these
oddball temporary files as if they are (sort of) refs.