This series does not add hg support, but it does do all the
refactoring that is needed to make it possible. With this series
applied actually adding full-fledged hg support is a matter of adding
the git-remote-hg file.
The reason the git-remote-hg file is not included in this series is
that while I have finished support for 'git clone hg::/path/to/hg' as
well as 'git fetch hg::/path/to/hg' and 'git fetch hgremote',
currently it does a full export on each run (that is, incremental
fetch is not supported).
Nevertheless, I think it is vital that this is included in the series
before we do anything serious with it. I hope to have the
git-remote-hg bit done tomorrow before I get on my airplane, but no
promises there.
Junio, I can try to re-roll the entire series after I finish
git-remote-hg, or I can just send it in on top of this series.
Based on abdcdc5c [More fixes to the git-remote-cvs...].
Johannes Schindelin (1):
Finally make remote helper support useful
Sverre Rabbelier (5):
.gitignore: add git-remote-cvs
Add notify and warn to util.py
Allow both url and foreign vcs in remote config
When updating refs after a fetch, resolve the symref if set
Factor ref updating out of fetch_with_import
.gitignore | 1 +
builtin-clone.c | 7 +++++++
builtin-fetch.c | 4 ++++
git_remote_helpers/util.py | 8 ++++++++
remote.c | 2 +-
transport-helper.c | 22 +++++++++++++++-------
transport.c | 10 ++++++++++
transport.h | 7 +++++--
8 files changed, 51 insertions(+), 10 deletions(-)
From: Johannes Schindelin <redacted>
The common case for remote helpers will be to import some repository which
can be specified by a single URL. Rather than supporting those who say
that Git is really complicated, let's be nice to users so that they will
be able to say:
git clone hg::https://soc.googlecode.com/hg/ soc
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Sverre Rabbelier <redacted>
--
Dscho wrote this a while back and it really does make the
series so much more useful.
transport.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
@@ -813,6 +813,16 @@ struct transport *transport_get(struct remote *remote, const char *url)url=remote->url[0];ret->url=url;+/* maybe it is a foreign URL? */+if(url){+constchar*p=url;++while(isalnum(*p))+p++;+if(!prefixcmp(p,"::"))+remote->foreign_vcs=xstrndup(url,p-url);+}+if(remote&&remote->foreign_vcs){transport_helper_init(ret,remote->foreign_vcs);returnret;
Also allow the new update_refs to actually update the refs set, this
way the remote helper can set the value of previously unknown refs.
Signed-off-by: Sverre Rabbelier <redacted>
---
This is the most important patch of the series, without it it
is truly impossible to 'git clone hg::/path/to/hg/repo' since
when we try to guess remote_head, we use
find_ref_by_name(refs, "HEAD"), which will not find anything
unless we set refs to the updated refs _after_ doing the
import. This is a result of the fact that we do not know the
value of the remote HEAD until after the import is complete.
builtin-clone.c | 7 +++++++
builtin-fetch.c | 4 ++++
transport-helper.c | 22 +++++++++++++++-------
transport.h | 7 +++++--
4 files changed, 31 insertions(+), 9 deletions(-)
@@ -154,13 +154,6 @@ static int fetch_with_import(struct transport *transport,finish_command(&fastimport);free((char*)fastimport.argv[2]);free((char*)fastimport.argv[3]);--for(i=0;i<nr_heads;i++){-posn=to_fetch[i];-if(posn->status&REF_STATUS_UPTODATE)-continue;-read_ref(posn->symref?posn->symref:posn->name,posn->old_sha1);-}return0;}
@@ -255,6 +248,20 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)returnret;}+staticintupdate_refs(structtransport*transport,structref*refs)+{+structref*ref=refs;++while(ref){+if(ref->status&REF_STATUS_UPTODATE)+continue;+read_ref(ref->symref?ref->symref:ref->name,ref->old_sha1);+ref=ref->next;+}++return0;+}+inttransport_helper_init(structtransport*transport,constchar*name){structhelper_data*data=xcalloc(sizeof(*data),1);
@@ -264,5 +271,6 @@ int transport_helper_init(struct transport *transport, const char *name)transport->get_refs_list=get_refs_list;transport->fetch=fetch;transport->disconnect=release_helper;+transport->update_refs=update_refs;return0;}
This makes it possible to return in response to 'list':
@refs/hg/origin/tip refs/heads/tip
And have HEAD resolve properly after the import completes.
Signed-off-by: Sverre Rabbelier <redacted>
---
Without this it is very hard to support 'git clone' on a
non-git repository, which I think is a very important thing
to have.
transport-helper.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
@@ -159,7 +159,7 @@ static int fetch_with_import(struct transport *transport,posn=to_fetch[i];if(posn->status&REF_STATUS_UPTODATE)continue;-read_ref(posn->name,posn->old_sha1);+read_ref(posn->symref?posn->symref:posn->name,posn->old_sha1);}return0;}
The current logic prevents both 'remote.url' and 'remote.vcs' from
being set, while that might be useful.
Signed-off-by: Sverre Rabbelier <redacted>
---
This way I can do:
remote.hgremote.url = /path/to/hg/repo
remote.hgremote.vcs = hg
As well as:
remote.hgremote.url = hg::/path/to/hg/repo
remote.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
Signed-off-by: Sverre Rabbelier <redacted>
---
These turned out to be quite useful for my git-remote-hg, if
desired this patch can move to later in the series, but I
figured that it might be useful to someone else already.
git_remote_helpers/util.py | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
@@ -15,6 +15,10 @@ import subprocess# Whether or not to show debug messagesDEBUG=False+defnotify(msg,*args):+"""Print a message to stderr."""+print>>sys.stderr,msg%args+defdebug(msg,*args):"""Print a debug message to stderr when DEBUG is enabled."""ifDEBUG:
@@ -24,6 +28,10 @@ def error (msg, *args):"""Print an error message to stderr."""print>>sys.stderr,"ERROR:",msg%args+defwarn(msg,*args):+"""Print a warning message to stderr."""+print>>sys.stderr,"warning:",msg%args+defdie(msg,*args):"""Print as error message to stderr and exit the program."""error(msg,*args)
Please define a transport_update_refs wrapper function to implement
this method invocation on the transport instance. Callers should
not be reaching into the struct transport directly.
Heya,
On Thu, Oct 29, 2009 at 07:22, Shawn O. Pearce [off-list ref] wrote:
Please define a transport_update_refs wrapper function to implement
this method invocation on the transport instance. Callers should
not be reaching into the struct transport directly.
With pleasure, should the transport_update_refs wrapper simply 'return
1' without doing anything if transport->update_refs is not set?
I certainly have to wonder... if this is done in both fetch and
clone, why isn't it just part of fetch_refs?
Because clone does not use fetch_refs, or am I missing something?
Please set this before the disconnect method (move it up one line).
From: Shawn O. Pearce <hidden> Date: 2016-06-15 22:47:38
Sverre Rabbelier [off-list ref] wrote:
On Thu, Oct 29, 2009 at 07:22, Shawn O. Pearce [off-list ref] wrote:
quoted
Please define a transport_update_refs wrapper function to implement
this method invocation on the transport instance. ?Callers should
not be reaching into the struct transport directly.
With pleasure, should the transport_update_refs wrapper simply 'return
1' without doing anything if transport->update_refs is not set?
If the function isn't defined, it should behave as though it were
defined and successfully completed.
quoted
I certainly have to wonder... if this is done in both fetch and
clone, why isn't it just part of fetch_refs?
Because clone does not use fetch_refs, or am I missing something?
Hmmph. Weird. Its been a while since I last looked at this code,
maybe I misunderstood it.
--
Shawn.
Heya,
On Thu, Oct 29, 2009 at 08:56, Shawn O. Pearce [off-list ref] wrote:
quoted
quoted
I certainly have to wonder... if this is done in both fetch and
clone, why isn't it just part of fetch_refs?
Because clone does not use fetch_refs, or am I missing something?
Hmmph. Weird. Its been a while since I last looked at this code,
maybe I misunderstood it.
Unless you mean transport_fetch_refs? It can't be done in
transport_fetch_refs because the foreign helper transport needs to
update all refs, including those that wanted_peer_refs decided not to
fetch. Otherwise the 'HEAD' ref will not be updated, and it is left at
all zeros. It is not as obvious that that is a problem in this patch,
but when Junio merges with Nico's [5bdc32d3e "make 'git clone' ask the
remote only for objects it cares about"] the code looks like this:
if (refs) {
struct ref *ref_cpy;
mapped_refs = wanted_peer_refs(refs, refspec);
ref_cpy = copy_ref_list(mapped_refs);
transport_fetch_refs(transport, ref_cpy);
if (transport->update_refs)
{
ref_cpy = copy_ref_list(refs);
transport->update_refs(transport, ref_cpy);
refs = ref_cpy;
mapped_refs = wanted_peer_refs(refs, refspec);
}
}
Does it make more sense now? transport_fetch_refs gets only a limited
view of the refs, so it cannot pass all the refs to
transport_update_refs as needed.
--
Cheers,
Sverre Rabbelier
From: Daniel Barkalow <hidden> Date: 2016-06-15 22:47:38
On Thu, 29 Oct 2009, Sverre Rabbelier wrote:
Heya,
On Thu, Oct 29, 2009 at 08:56, Shawn O. Pearce [off-list ref] wrote:
quoted
quoted
quoted
I certainly have to wonder... if this is done in both fetch and
clone, why isn't it just part of fetch_refs?
Because clone does not use fetch_refs, or am I missing something?
Hmmph. Weird. Its been a while since I last looked at this code,
maybe I misunderstood it.
Unless you mean transport_fetch_refs? It can't be done in
transport_fetch_refs because the foreign helper transport needs to
update all refs, including those that wanted_peer_refs decided not to
fetch. Otherwise the 'HEAD' ref will not be updated, and it is left at
all zeros. It is not as obvious that that is a problem in this patch,
but when Junio merges with Nico's [5bdc32d3e "make 'git clone' ask the
remote only for objects it cares about"] the code looks like this:
if (refs) {
struct ref *ref_cpy;
mapped_refs = wanted_peer_refs(refs, refspec);
ref_cpy = copy_ref_list(mapped_refs);
transport_fetch_refs(transport, ref_cpy);
if (transport->update_refs)
{
ref_cpy = copy_ref_list(refs);
transport->update_refs(transport, ref_cpy);
refs = ref_cpy;
mapped_refs = wanted_peer_refs(refs, refspec);
}
}
Does it make more sense now? transport_fetch_refs gets only a limited
view of the refs, so it cannot pass all the refs to
transport_update_refs as needed.
I think there are a bunch of bugs that you're working around:
(a) if HEAD is determined to be a symref, and we care about HEAD, we care
about whatever HEAD is a symref to; wanted_peer_refs() shouldn't be
filtering such things out.
(b) we don't want to make a whole bunch of copies of the ref list to avoid
updating the mutable ref list that we will look for updated values in; the
merge of my series with Nico's should replace my copy_ref_list with his
wanted_peer_refs, not include the copy afterwards. Correcting this should
lead to the value that matters in the list that will be used having been
updated directly by transport_fetch_refs().
-Daniel
*This .sig left intentionally blank*
Heya,
On Thu, Oct 29, 2009 at 10:22, Daniel Barkalow [off-list ref] wrote:
(a) if HEAD is determined to be a symref, and we care about HEAD, we care
about whatever HEAD is a symref to; wanted_peer_refs() shouldn't be
filtering such things out.
It seems that wanted_peer_refs filters out HEAD no matter what though?
(b) we don't want to make a whole bunch of copies of the ref list to avoid
updating the mutable ref list that we will look for updated values in; the
merge of my series with Nico's should replace my copy_ref_list with his
wanted_peer_refs, not include the copy afterwards. Correcting this should
lead to the value that matters in the list that will be used having been
updated directly by transport_fetch_refs().
This I can and will fix. Patch-bomb incoming.
--
Cheers,
Sverre Rabbelier
From: Daniel Barkalow <hidden> Date: 2016-06-15 22:47:38
On Thu, 29 Oct 2009, Sverre Rabbelier wrote:
Heya,
On Thu, Oct 29, 2009 at 10:22, Daniel Barkalow [off-list ref] wrote:
quoted
(a) if HEAD is determined to be a symref, and we care about HEAD, we care
about whatever HEAD is a symref to; wanted_peer_refs() shouldn't be
filtering such things out.
It seems that wanted_peer_refs filters out HEAD no matter what though?
It probably shouldn't. Actually, I bet Nico's clone will get extremely
confused if the remote's HEAD isn't the same as any of its branches. I'll
try to take a look tonight.
quoted
(b) we don't want to make a whole bunch of copies of the ref list to avoid
updating the mutable ref list that we will look for updated values in; the
merge of my series with Nico's should replace my copy_ref_list with his
wanted_peer_refs, not include the copy afterwards. Correcting this should
lead to the value that matters in the list that will be used having been
updated directly by transport_fetch_refs().
This I can and will fix. Patch-bomb incoming.
I'll look over it later, thanks.
-Daniel
*This .sig left intentionally blank*
Heya,
On Thu, Oct 29, 2009 at 11:43, Daniel Barkalow [off-list ref] wrote:
It probably shouldn't. Actually, I bet Nico's clone will get extremely
confused if the remote's HEAD isn't the same as any of its branches. I'll
try to take a look tonight.
I'll look over it later, thanks.