Re: [PATCH v6 06/10] fast-export: add new --refspec option

4 messages, 2 authors, 2016-06-15 · open the first message on its own page

Re: [PATCH v6 06/10] fast-export: add new --refspec option

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:59:14

Junio C Hamano [off-list ref] writes:
Felipe Contreras [off-list ref] writes:
quoted
Does it?

 % git config remote.origin.fetch '+refs/heads/*:refs/remotes-test/origin/*'
 % git fetch origin master
 From /home/felipec/dev/git
  * branch            master     -> FETCH_HEAD
  * [new branch]      master     -> refs/remotes-test/origin/master

In this case remote.origin.fetch is determining how to translate ref names, not
what gets transferred, *exactly* the same as we are doing with --refspec. And
as far as I know, remote.origin.fetch is a refspec.
If you had 'next' and 'pu' branches at the remote, do they get
fetched with that command line?
More interestingly, if you have

	[remote "mothership"]
		push = +refs/heads/*:refs/remotes/satellite/*

in your configuration and then said

	$ git push mothership master

then configured remote.mothership.push is not even used (I bring
this up because "export" is more closely related to "push" than
"fetch").

This (and why 'next' and 'pu' are not fetched in the "fetch"
example) is because traditionally, refspecs that are explicitly
given on the command line overrides configured ones (in other words,
configured ones are used as a fallback default).

This is a bit of tangent, but since the recent discussion on the
triangular workflows, I've been wondering if we may want to have a
new way to configure things so that we can say "When I push to
mothership any one of my local branches, I want it to go to the ref
with the same name at the mothership under refs/remotes/satellite/
hierarchy (because I am emulating 'git fetch' that is run on the
mothership to get updates from this satellite)", somewhat similar to
what you added to "fast-export" via the option in question.

But we cannot achieve that mapping by changing the meaning of the
configured refspecs remote.mothership.push without having to worry
about breaking existing practices of people.  When they say "git
push mothership master", they do mean to push refs/heads/master to
refs/heads/master, and it will break the expectation in their
existing repositories if we change the semantics under them.

A possible way to achieve that mapping "When I push to mothership
any one of my local branches,..." could be to introduce a _new_
configuration (so that existing repositories will not suddenly
change their behaviour):

	[remote "mothership"]
		pushmap = +refs/heads/*:refs/remotes/satellite/*

And then we can allow this command line

	$ git push mothership master

to be affected by the mapping when expanding the short-hand refspecs
given on the command line.  Traditionally, anything without colon
stood as a short-hand for "push to the same name", e.g. 'master' is
for 'refs/heads/master:refs/heads/master' in this example, and
'v1.0' would be for 'refs/tags/v1.0:refs/tags/v1.0'.

But it does not have to stay that way.  In order to move things
forward in that direction, this new configuration has to be
distinguishable from the traditional "refspec", as it embodies a
different concept.

Re: [PATCH v6 06/10] fast-export: add new --refspec option

From: Felipe Contreras <hidden>
Date: 2016-06-15 22:59:24

Junio C Hamano wrote:
Junio C Hamano [off-list ref] writes:
quoted
Felipe Contreras [off-list ref] writes:
But it does not have to stay that way.  In order to move things
forward in that direction, this new configuration has to be
distinguishable from the traditional "refspec", as it embodies a
different concept.
Is it a different concept?

 % git config remote.origin.fetch '+refs/heads/*:refs/remotes-test/origin/*'
 % git fetch origin master

What do you call this thing? ------^

-- 
Felipe Contreras

Re: [PATCH v6 06/10] fast-export: add new --refspec option

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:59:25

Felipe Contreras [off-list ref] writes:
Junio C Hamano wrote:
quoted
Junio C Hamano [off-list ref] writes:
quoted
Felipe Contreras [off-list ref] writes:
quoted
But it does not have to stay that way.  In order to move things
forward in that direction, this new configuration has to be
distinguishable from the traditional "refspec", as it embodies a
different concept.
Is it a different concept?

 % git config remote.origin.fetch '+refs/heads/*:refs/remotes-test/origin/*'
 % git fetch origin master

What do you call this thing? ------^
The answer to that question is the "value of the 'remote.*.fetch'
configuration variable".

The refspec mechanism and syntax used in "fetch" and "push" were
invented and designed to express two things [*1*]:

 1) what is the set of objects that are necessary and sufficient to
    complete some histories need to be transferred; what are the
    tips of these histories that are being completed?

 2) after the object transfer, some refs on the side that receive
    the objects are optionally to be updated;

    2-a) which refs are they?
    2-b) what objects are they updated to point at?

A refspec consists of one or more elements, each of which has
right and left hand side separated by a colon, i.e. RHS:LHS, and

 1) is determined by the RHS
 2-a) is determined by the LHS
 2-b) is determined by the correspondence between RHS-to-LHS.

A wildcarded "refs/heads/*:refs/remotes/origin/*" dynamically
expands to what the side that sends objects have, e.g. if fetching
from a repository with 'master' and 'next' branches, it becomes

	refs/heads/master:refs/remotes/origin/master
        refs/heads/next:refs/remotes/origin/next

So with

	$ refspec='refs/heads/master:refs/remotes/origin/master
	        refs/heads/next:refs/remotes/origin/next'
	$ git fetch origin $refspec

we transfer objects to allow us to have complete histories leading
to 'master' and 'next' from the origin repository.  And we update
our refs/remotes/origin/{next,master} refs.

Traditionally, when there is _no_ refspec on the command line, the
value of 'remote.*.fetch' configuration variable is used as the
fallback default, and that usage is still true.  When used in that
way, the value of the variable _is taken as_ a refspec.

However, we can no longer say that the variable _is_ a refspec with
the modern Git, and here is why.

"git fetch origin master" used to ignore the 'remote.*.fetch'
configuration variable completely, but since f2690487 (which is a
fairly recent invention), the variable participates in the "fetch"
process in a different way [*2*].  With this in the config:

    [remote "origin"]
    	fetch = refs/heads/master:refs/remotes/origin/master
        fetch = refs/heads/next:refs/remotes/origin/next

the command with 'master' refspec on the command line transfers the
objects required to complete the history only for the 'master', and
not 'next':

	$ git fetch origin master

In this usage, 'master' on the command line is the only thing that
determines what histories are completed (because it does not say
'next', the objects necessary to complete its history are not
transferred unless they are needed to complete 'master').  The value
of the 'remote.*.fetch' configuration does not participate in the
determination of the history being transferred at all.  It is not
used as a refspec.

But unlike Git of the last year, we do map this 'master' using the
'remote.*.fetch' configuration variable, in order to decide 2)
above.  We find that the given remote ref, 'master', has an element
that corresopnds to it in the 'remote.*.fetch' configuration, and
that element tells us to update refs/remotes/origin/master to point
at the object they call 'master', effectively turning the above
command line into this form (using "refspec" that has only one
element, refs/heads/master:refs/remotes/origin/master):

	$ git fetch origin refs/heads/master:refs/remotes/origin/master

There is no "refs/heads/next:refs/remotes/origin/next" here, because
the 'fetch' configuration is not used as a refspec, but as something
else.

My understanding of the added option parameter to "git fast-export"
is that it is not about specifying the history being transferred,
but is about mapping the name of the destination.  For example, does
object between 'master' and 'next' participate in the datastream
produced with this?

	fast-export \
            --refspec=refs/heads/master:refs/remotes/origin/master \
            --refspec=refs/heads/next:refs/remotes/origin/next \
            master

If this parameter were a refspec, as we have discussed already in
previous rounds [*3*], we should be able to give it on the command line,
like any normal refspec, instead of repeating the same thing
(i.e. up to what commit should the history be transported) as in:

	fast-export --refspec=refs/heads/master:refs/remotes/origin/master master

but just

	fast-export refs/heads/master:refs/remotes/origin/master


[Footnote]

 *1* Note that readers are hearing the authoritative definition
     given by the person who invented and designed it back in August
     2005.

 *2* And a recent $gmane/238832 moves "push" in the direction to be
     in line with "fetch" in this regard.

 *3* And I think I even outlined the code to do so.

Re: [PATCH v6 06/10] fast-export: add new --refspec option

From: Felipe Contreras <hidden>
Date: 2016-06-15 23:00:48

Hi,

Sorry it took too long to reply to this.

Junio C Hamano wrote:
Felipe Contreras [off-list ref] writes:
quoted
Junio C Hamano wrote:
quoted
Junio C Hamano [off-list ref] writes:
quoted
Felipe Contreras [off-list ref] writes:
quoted
But it does not have to stay that way.  In order to move things
forward in that direction, this new configuration has to be
distinguishable from the traditional "refspec", as it embodies a
different concept.
Is it a different concept?

 % git config remote.origin.fetch '+refs/heads/*:refs/remotes-test/origin/*'
 % git fetch origin master

What do you call this thing? ------^
The answer to that question is the "value of the 'remote.*.fetch'
configuration variable".
You are avoiding the question: it's a refspec.
There is no "refs/heads/next:refs/remotes/origin/next" here, because
the 'fetch' configuration is not used as a refspec, but as something
else.
Yet both remote.fetch and remote.push are a 'struct refspec', and the
documentation says they are a "refspec".
My understanding of the added option parameter to "git fast-export"
is that it is not about specifying the history being transferred,
but is about mapping the name of the destination.  For example, does
object between 'master' and 'next' participate in the datastream
produced with this?

	fast-export \
            --refspec=refs/heads/master:refs/remotes/origin/master \
            --refspec=refs/heads/next:refs/remotes/origin/next \
            master

If this parameter were a refspec, as we have discussed already in
previous rounds [*3*], we should be able to give it on the command line,
like any normal refspec, instead of repeating the same thing
(i.e. up to what commit should the history be transported) as in:

	fast-export --refspec=refs/heads/master:refs/remotes/origin/master master

but just

	fast-export refs/heads/master:refs/remotes/origin/master
Maybe in an ideal world, which we don't live in.

My guess is that trying to accomplish such a goal would result in an
unbelievable mess of the code that I wouldn't even want to think about where
to start to code this.

Moreover, `git grep refmap` returns me the following:

  t/t5516-fetch-push.sh:test_expect_success 'pushing a specific ref applies remote.$name.push as refmap' '
  t/t5516-fetch-push.sh:test_expect_success 'with no remote.$name.push, it is not used as refmap' '

I'd say with --refspec is the simplest and most sensible way this can be
implemented.

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