Subject: Re: [PATCH v7 2/8] cherry-pick: treat CHERRY_PICK_HEAD and REVERT_HEAD as refs

From: David Turner <[email-masked]>
Date: Thu, 09 Jul 2015 17:53:20 -0400

On Wed, 2015-07-08 at 22:55 -0700, Junio C Hamano wrote:
> David Turner <[email-masked]> writes:
> 
> > I didn't see this until after I had sent my previous message.  I think
> > the "multiple working trees" argument is strong enough that I will
> > change the code (and tests). 
> 
> Not just code, but we probably should step back a bit and clearly
> define what we are trying to achieve.  I _think_ what we want are:
> 
>  - Everything under refs/* and their associated logs would be handed
>    off to the "pluggable ref backend" when one is in use.
> 
>  - All ref-like things with one-level ALL_CAPS names are per working
>    tree.
> 
>    - They do not participate in "prunable?" reachability
>      computation.
>
>    - They (typically) do not want "logs".

Except HEAD definitely does. 

>    - Each may have extra information specific to it.
>    - You can however read an object name off of them.
> 
> One possible and straight-forward implementation to achieve
> "ref-like things with one-level ALL_CAPS names are per working tree"
> is to declare that they will not be handed off to the backend, but
> will always be implemented as files immediately under $GIT_DIR/.
> 
> But note that there is no fundamental reason we have to do it that
> way; an alternative would be to allow backends to store these things
> per working tree, but then the interface to drive backends need to
> tell them which working tree we are working from.
> 
> Unlike branches, HEAD must be per working tree; the "pluggable ref
> backend" needs to be able handle HEAD when you introduce it.

I actually punted on this in my implementation, because at the time,
git-new-workdir was only in contrib.  But since the new worktree stuff,
multiple worktrees have first-class support, so I'll have to update the
code to handle it.

> So
> from that point of view, "multiple working tree" is *not* a valid
> argument why they *have* to be implemented as files under $GIT_DIR/.
> If you plan to let the pluggable ref backend to handle HEAD, you
> must have a solution for per working tree ref-like things anyway.

OK, here's my current best idea:

1. A "pseudoref" is an all-caps file in $GIT_DIR/ that always contains
at least a SHA1.  CHERRY_PICK_HEAD and REVERT_HEAD are examples. Because
HEAD might be a symbolic ref, it is not a pseudoref. 

Refs backends do not manage pseudorefs.  Instead, when a pseudoref (an
all-caps ref containing no slashes) is requested (e.g. git rev-parse
FETCH_HEAD) the generic refs code checks for the existence of that
file and if it exists, returns immediately without hitting the backend.
The generic code will refuse to allow updates to pseudorefs.

2. The pluggable refs backend manages all refs other than HEAD.

3. The "files" backend always manages HEAD.  This allows for a reflog
and for HEAD to be a symbolic ref.

The major complication here is ref transactions -- what if there's a
transaction that wants to update e.g. both HEAD and refs/heads/master?

It may be the case that this never happens; I have not actually audited
the code to figure it out.  If someone knows for sure that it does not
happen, please say so. But assuming it does happen, here's my idea:

If the refs backend is the files backend, we can simply treat HEAD like
any other ref.

If the refs backend is different, then the refs code needs to hold a
files-backend transaction for HEAD, which it will commit immediately
after the other transaction succeeds.  We can stick a pointer to the
extra transaction in the generic struct ref_transaction, which (as
Michael Haggerty suggests) specific backends will extend.

A failure to commit either transaction will be reported as a failure,
and we'll give an additional inconsistent state warning if the main
transaction succeeds but the HEAD transaction fails.

I don't love this idea -- it seems like kind of a hack.  But it's the
best I can come up with.

What do other folks think?

> As to J6t's "no excessive plumbing invocations", I think the right
> approach is to have a single "git prompt--helper" command that does
> what the current script does to compute $r.  "we want to keep
> peeking into files under $GIT_DIR/" alone is not a valid enough
> reason to constrain us (I am fine if the solution we find
> appropriate for the 'multiple working trees' and other issues ends
> up being "we solve it by having them as files in $GIT_DIR" for other
> reasons, though).

Agree.