threads / discuss / 34295

git clone -b

Subject: git clone -b

## tl;dr

10 messages between Jun 28, 2013 and Jul 3, 2013.

replies: 9people: 5as markdown or json

Stefan Näwe· Jun 28, 2013, 11:59 UTC · lore
Hi there!

Is there any reason why 'git clone -b' only takes a branch (from refs/heads/) or a tag (from refs/tags/) ?

Background: At $dayjob we're using some kind of 'hidden' refs (in refs/releases/)
to communicate between the 'branch integrator' (who creates the ref in refs/releases/)
and the 'build master' who wants to build that ref. 
It would be a little easier if the build master could simply say
  git clone -b refs/releases/the-release-for-today URL
instead of: git clone... ; cd ... ; git fetch... ; git checkout....
Any answer or even a better idea to solve that is appreciated.
Stefan
-- 
----------------------------------------------------------------
/dev/random says: Second star to the right & straight on till morning...
python -c "print '73746566616e2e6e616577654061746c61732d656c656b74726f6e696b2e636f6d'.decode('hex')"
Stefan Näwe· Jun 28, 2013, 12:15 UTC · re: Stefan Näwe · lore

Re: git clone -b

Am 28.06.2013 13:59, schrieb Stefan Näwe:
Show 19 quoted lines
> Hi there!
> 
> Is there any reason why 'git clone -b' only takes a branch (from refs/heads/)
> or a tag (from refs/tags/) ?
> 
> Background: At $dayjob we're using some kind of 'hidden' refs (in refs/releases/)
> to communicate between the 'branch integrator' (who creates the ref in refs/releases/)
> and the 'build master' who wants to build that ref. 
> 
> It would be a little easier if the build master could simply say
> 
>   git clone -b refs/releases/the-release-for-today URL
> 
> instead of: git clone... ; cd ... ; git fetch... ; git checkout....
> 
> Any answer or even a better idea to solve that is appreciated.
> 
> Stefan
> 
Oh, and while at it:
This doesn't look/feel right:
  $ git clone -b refs/heads/master git/.git other-git
  Cloning into 'other-git'...
  fatal: Remote branch refs/heads/master not found in upstream origin
  fatal: The remote end hung up unexpectedly
(where git is git's git which definitely has refs/heads/master...)
Stefan
-- 
----------------------------------------------------------------
/dev/random says: In God we trust; all else we walk through.
python -c "print '73746566616e2e6e616577654061746c61732d656c656b74726f6e696b2e636f6d'.decode('hex')"
Fredrik Gustafsson· Jun 28, 2013, 12:18 UTC · re: Stefan Näwe · lore

Re: git clone -b

On Fri, Jun 28, 2013 at 01:59:51PM +0200, Stefan Näwe wrote:
Show 18 quoted lines
> Hi there!
> 
> Is there any reason why 'git clone -b' only takes a branch (from refs/heads/)
> or a tag (from refs/tags/) ?
> 
> Background: At $dayjob we're using some kind of 'hidden' refs (in refs/releases/)
> to communicate between the 'branch integrator' (who creates the ref in refs/releases/)
> and the 'build master' who wants to build that ref. 
> 
> It would be a little easier if the build master could simply say
> 
>   git clone -b refs/releases/the-release-for-today URL
> 
> instead of: git clone... ; cd ... ; git fetch... ; git checkout....
> 
> Any answer or even a better idea to solve that is appreciated.
> 
> Stefan

I don't understand what the alternative should be. You can't look in /refs/* because there's a lot of other stuff like bisect/remotes etc. there.

Of course you could add to also look in /refs/releases/ but as I understand you that a special solution for your company. Why should all git users have that addition?

Two questions about your setup:
	1. Why do you always clone your repository? To me clone is a one
	time operation.
	2. Why don't you tag your releases with an ordinary tag?
-- 
Med vänliga hälsningar
Fredrik Gustafsson

tel: 0733-608274
e-post: iveqy@iveqy.com
Stefan Näwe· Jun 28, 2013, 12:27 UTC · re: Fredrik Gustafsson · lore

Re: git clone -b

Am 28.06.2013 14:18, schrieb Fredrik Gustafsson:
Show 23 quoted lines
> On Fri, Jun 28, 2013 at 01:59:51PM +0200, Stefan Näwe wrote:
>> Hi there!
>>
>> Is there any reason why 'git clone -b' only takes a branch (from refs/heads/)
>> or a tag (from refs/tags/) ?
>>
>> Background: At $dayjob we're using some kind of 'hidden' refs (in refs/releases/)
>> to communicate between the 'branch integrator' (who creates the ref in refs/releases/)
>> and the 'build master' who wants to build that ref. 
>>
>> It would be a little easier if the build master could simply say
>>
>>   git clone -b refs/releases/the-release-for-today URL
>>
>> instead of: git clone... ; cd ... ; git fetch... ; git checkout....
>>
>> Any answer or even a better idea to solve that is appreciated.
>>
>> Stefan
> 
> I don't understand what the alternative should be. You can't look in
> /refs/* because there's a lot of other stuff like bisect/remotes etc.
> there.
Well, I tell clone exactly what I want. There is no reason try something
from refs/*.
 
> Of course you could add to also look in /refs/releases/ but as I
> understand you that a special solution for your company. Why should all
> git users have that addition?
It wouldn't hurt, IMHO. Maybe it would even make sense to allow any SHA-1
to be passed to '-b'.
 
> Two questions about your setup:
> 
> 	1. Why do you always clone your repository? To me clone is a one
> 	time operation.
We would use 'git archive' if that would be submodule-aware...
> 	2. Why don't you tag your releases with an ordinary tag?

Because we use that 'refs/release' thing as a hidden ref that other developers will not see when they fetch (unless they are told to checkout that particular ref).

Think of using this similar to the way github uses refs/pull/*/{head,merge} for their pull request mechanism.

Stefan
-- 
----------------------------------------------------------------
/dev/random says: The Definition of an Upgrade: Take old bugs out, put new ones in.
python -c "print '73746566616e2e6e616577654061746c61732d656c656b74726f6e696b2e636f6d'.decode('hex')"
Stefan Näwe· Jul 1, 2013, 07:04 UTC · re: Stefan Näwe · lore

Re: git clone -b

Am 28.06.2013 13:59, schrieb Stefan Näwe:
Show 19 quoted lines
> Hi there!
> 
> Is there any reason why 'git clone -b' only takes a branch (from refs/heads/)
> or a tag (from refs/tags/) ?
> 
> Background: At $dayjob we're using some kind of 'hidden' refs (in refs/releases/)
> to communicate between the 'branch integrator' (who creates the ref in refs/releases/)
> and the 'build master' who wants to build that ref. 
> 
> It would be a little easier if the build master could simply say
> 
>   git clone -b refs/releases/the-release-for-today URL
> 
> instead of: git clone... ; cd ... ; git fetch... ; git checkout....
> 
> Any answer or even a better idea to solve that is appreciated.
> 
> Stefan
> 
Anyone?
Thanks,
  Stefan
-- 
----------------------------------------------------------------
/dev/random says: Some people like learning Eskimo, but I can't get Inuit.
python -c "print '73746566616e2e6e616577654061746c61732d656c656b74726f6e696b2e636f6d'.decode('hex')"
Junio C Hamano· Jul 1, 2013, 16:46 UTC · re: Stefan Näwe · lore

Re: git clone -b

Stefan Näwe <stefan.naewe@atlas-elektronik.com> writes:
>> Is there any reason why 'git clone -b' only takes a branch (from refs/heads/)
>> or a tag (from refs/tags/) ?

Because they are common enough, and doing the same for an arbitrary object is just as easy to do something like:

	git clone -n
        git checkout $an_arbitrary_commit_object_name^0
>> Background: At $dayjob we're using some kind of 'hidden' refs (in refs/releases/)
>> to communicate between the 'branch integrator' (who creates the ref in refs/releases/)
>> and the 'build master' who wants to build that ref. 

While I wasn't paying much attention to this, I vaguely recall that people pointed out that using a fresh clone every time may not be what you want to do in the first place, and I happen to agree with them (and that is why I am not very much interested in this topic).

Stefan Näwe· Jul 2, 2013, 06:35 UTC · re: Junio C Hamano · lore

Re: git clone -b

Am 01.07.2013 18:46, schrieb Junio C Hamano:
Show 10 quoted lines
> Stefan Näwe <stefan.naewe@atlas-elektronik.com> writes:
> 
>>> Is there any reason why 'git clone -b' only takes a branch (from refs/heads/)
>>> or a tag (from refs/tags/) ?
> 
> Because they are common enough, and doing the same for an arbitrary
> object is just as easy to do something like:
> 
> 	git clone -n
>         git checkout $an_arbitrary_commit_object_name^0
OK. I wasn't aware of '-n' for 'git clone'. Thanks.
Show 9 quoted lines
> 
>>> Background: At $dayjob we're using some kind of 'hidden' refs (in refs/releases/)
>>> to communicate between the 'branch integrator' (who creates the ref in refs/releases/)
>>> and the 'build master' who wants to build that ref. 
> 
> While I wasn't paying much attention to this, I vaguely recall that
> people pointed out that using a fresh clone every time may not be
> what you want to do in the first place, and I happen to agree with
> them (and that is why I am not very much interested in this topic).
 
As I said: We'd be using 'git archive --remote...' if that was
submodule-aware.
Thanks,
  Stefan
-- 
----------------------------------------------------------------
/dev/random says: Circular Definition: see Definition, Circular.
python -c "print '73746566616e2e6e616577654061746c61732d656c656b74726f6e696b2e636f6d'.decode('hex')"
Junio C Hamano· Jul 2, 2013, 18:21 UTC · re: Stefan Näwe · lore

Re: git clone -b

Stefan Näwe <stefan.naewe@atlas-elektronik.com> writes:
Show 7 quoted lines
>> While I wasn't paying much attention to this, I vaguely recall that
>> people pointed out that using a fresh clone every time may not be
>> what you want to do in the first place, and I happen to agree with
>> them (and that is why I am not very much interested in this topic).
>  
> As I said: We'd be using 'git archive --remote...' if that was
> submodule-aware.

That would still have to transfer full material enough to populate the working tree for a single revision. I was wondering why "clone once, and then update incrementally with 'fetch && reset --hard' && clean'" is not used, if the tree is for a build-bot.

Phil Hord· Jul 1, 2013, 17:49 UTC · re: Stefan Näwe · lore

Re: git clone -b

It would be nice to support more generic specs for the --branch switch. But it is complicated because the refs have not been fetched yet during the clone, and so normal refs operations -- which expect to work on a local repository -- do not work. So, the ref is looked up locally from a list in expected locations after fetching the remote refs but before the clone occurs. The remote refs which are fetched is not configurable during clone, and so only 'refs/heads/*' is fetched for non-mirrors.

I was able to tweak git-clone to fetch the remote ref when I hacked builtin/clone.c to check in 'refs' and also to extend the refspec to something more broad ("+refs/*:refs/remotes/origin/*"), but this is not a workable solution. But there probably is a more correct way than the hack I tried.

Phil
Jeff King· Jul 3, 2013, 10:01 UTC · re: Phil Hord · lore

Re: git clone -b

On Mon, Jul 01, 2013 at 01:49:37PM -0400, Phil Hord wrote:
Show 8 quoted lines
> It would be nice to support more generic specs for the --branch
> switch. But it is complicated because the refs have not been fetched
> yet during the clone, and so normal refs operations -- which expect to
> work on a local repository -- do not work.  So, the ref is looked up
> locally from a list in expected locations after fetching the remote
> refs but before the clone occurs.  The remote refs which are fetched
> is not configurable during clone, and so only 'refs/heads/*' is
> fetched for non-mirrors.
I think there are two problems:
  1. Our find_remote_branch function implements only half of the regular
     ref_rev_parse_rules (heads and tags). Fixing that to make "-b
     refs/heads/master" work is pretty easy. Patch is below.
  2. When we give a ref that is not going to be fetched, we should
     fetch it explicitly. It looks like --single-branch tries to do
     this, but only handles tags. I am not sure what a non-single-branch
     would want to do (since you are effectively overriding the
     default refspecs).
     So even with the patch, doing "clone -b refs/foo/bar" does not
     quite work.
diff --git a/builtin/clone.c b/builtin/clone.c
index 14b1323..5984303 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -433,24 +433,24 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch
 	raise(signo);
 }
 
-static struct ref *find_remote_branch(const struct ref *refs, const char *branch)
+static struct ref *find_remote_branch(const struct ref *refs, const char *name)
 {
-	struct ref *ref;
-	struct strbuf head = STRBUF_INIT;
-	strbuf_addstr(&head, "refs/heads/");
-	strbuf_addstr(&head, branch);
-	ref = find_ref_by_name(refs, head.buf);
-	strbuf_release(&head);
-
-	if (ref)
-		return ref;
-
-	strbuf_addstr(&head, "refs/tags/");
-	strbuf_addstr(&head, branch);
-	ref = find_ref_by_name(refs, head.buf);
-	strbuf_release(&head);
-
-	return ref;
+	int len = strlen(name);
+	const char **p;
+
+	for (p = ref_rev_parse_rules; *p; p++) {
+		struct ref *ref;
+
+		ref = find_ref_by_name(refs, mkpath(*p, len, name));
+		if (ref)
+			/*
+			 * optionally check for and complain about ambiguity
+			 * here, like dwim_ref does
+			 */
+			return ref;
+	}
+
+	return NULL;
 }
 
 static struct ref *wanted_peer_refs(const struct ref *refs,

← back to recent threads