Subject: Re: [PATCH v2] upload-pack: Fail if cloning empty namespace

From: Junio C Hamano <[email-masked]>
Date: Sun, 21 Jun 2015 11:43:43 -0700

Johannes Löthberg <[email-masked]> writes:

>>But if we made some change to the transfer to push-to-receive-pack
>>so that this can also create HEAD that points at something, what
>>would the user say, instead of that earlier
>>
>> $ git clone git://site.xz/r
>>
>>to access this new namespace?  Don't you have to be running another
>>instance of a server with GIT_NAMESPACE set to 'b'?  How do you
>>arrange that to automagically happen?
>>
>>Or do your users that clone/fetch do things differnetly from the
>>above, and if so what do they do?
>>
>>How is your server configured to support the access the existing
>>namespace 'a', and the new namespace 'b' that is automatically
>>created by pointing /usr/share/git/r.git/refs/namespaces/b/HEAD
>>to one ref inside that namespace?

Your answer to the above question marks are?

> If you want to hide the fact that you're using namespaces you'll
> probably have to either run another daemon or use a wrapper script,
> yes, but only if you want to hide it.

I would view it as segregating (not mixing refs and objects
reachable by them for 'a' and 'b') more than "hiding".  Either way,
your users' clone/fetch need a way to say which one of 'a' or 'b'
they want.  How are you arranging that to happen when you add a new
namespace 'b'?

I asked you if my understanding of your workflow to start populating
a new namespace 'b' matches what you actually do in reality, but you
omitted it from your quote in your response, which was this:

>> In order to add a new namespace 'b' next to 'a', you would somehow
>> need to populate /usr/share/git/r.git/refs/namespaces/b.  Presumably
>> you can prepare a source repository locally and then push everything
>> there manually, by doing something like this:
>> 
>>  $ git push ssh://site.xz/usr/share/git/r.git refs/*:refs/namespaces/b/*
>> 
>> but we agree that this does not create refs/namespaces/b/HEAD.

I'd assume that the answer is "yes, Junio got the 'push' to populate
correctly" and continue.

Populating refs/namespaces/b/ and the objects reachable by them by
pushing into that hierarchy is one step of doing so, and setting
HEAD there is not done by "git push", but is that the only thing
missing?

I do not view "git fetch --namespace=b" or "git clone --namespace=b
git://site.xz/r" as a usable way to do so (is there an option like
that in the first place?), and that is what I have been asking.

Note that I am not opposed to an idea to make it possible to point a
symbolic ref .git/$something/HEAD at a ref that is different from
what it is pointing at currently (or creating it if it does not
exist yet) from outside the server, i.e. without ssh-ing in and
running "git symbolic ref".

That $something may be "refs/namespaces/b" in your case, but it does
not have to be.  We do not have a good way to support more common
case of repointing ".git/HEAD" to say "now the primary branch of
this repository is not 'master' but it is called 'trunk'".

That is one reason why I do not want a patch to receive-pack that
randomly picks one ref among all refs pushed and point HEAD at it,
which is the following part from your patch in the other thread
(where we should be having this discussion ;-).

@@ -981,6 +983,14 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 		return NULL; /* good */
 	}
 	else {
+		namespace = get_git_namespace();
+		if (strcmp(namespace, "refs/namespaces/")) {
+			strbuf_addf(&namespaced_head_buf, "%s%s", namespace, "HEAD");
+			namespaced_head_path = strbuf_detach(&namespaced_head_buf, NULL);
+
+			create_symref(namespaced_head_path, namespaced_name, NULL);
+		}
+
 		struct strbuf err = STRBUF_INIT;
 		if (shallow_update && si->shallow_ref[cmd->index] &&
 		    update_shallow_ref(cmd, si))

This is part of update() function in receive-pack, which is called
for each and every ref that is pushed.  If you did the "initial
population push" I cited from earlier part of the discussion:

 $ git push ssh://site.xz/usr/share/git/r.git refs/*:refs/namespaces/b/*

the above would see updates to refs/namespaces/b/refs/heads/master,
refs/namespaces/b/refs/heads/next, refs/namespaces/b/refs/tags/v1.0,
etc., i.e. all the refs you are pushing in an unspecified order, and
the added code would run once for each and every one of them.  Where
would the final HEAD points at is not something you can control, and
once you create one, you cannot repoint to a more reasonable ref.

If we introduce a way to point any symbolic ref at a ref that is
different from what it is pointing at currently (or creating it if
it does not exist yet) from outside the server, i.e. without ssh-ing
in and running "git symbolic ref", then that would work equally well
for your use case, and also will solve longstanding "how do I change
the primary branch the server's HEAD points at?" problem.  I do not
think your patch is a good first step to introduce that solution.