git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* is this behaviour expected for "git clone --single-branch"?
@ 2012-09-13 18:38 Ralf Thielow
  2012-09-13 18:45 ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-13 18:38 UTC (permalink / raw)
  To: git; +Cc: pclouds, Junio C Hamano

Hi,

I know people which have a separate directory for every
branch. In this case it doesn't make sense to download
the whole repo with all branches. So I guess the
"--single-branch" option is the solution in that case!?!
But I'm wondering about it's behaviour.

# first clone the branch of the repo
$git clone --single-branch --branch master myrepo ./master
$cd master

# now calling "git branch -a" to see what I have
$git branch -a
*master
remotes/origin/HEAD -> origin/master
remotes/origin/master

# fine, now pulling from origin
$git pull
From myrepo
* [new branch]  foo  -> origin/foo
* [new branch] bar -> origin/bar
...

Hm?

# looking again to my branches
$git branch -a
*master
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/bar
remotes/origin/foo
...

After cloning (or fetching), I now have all branches which is not
what I want, because I'm only interested in the one I've cloned.
I think it's not very useful for the use-case of having one directory
for one branch.

$git version
git version 1.7.12.395.g6b149ce

Thanks

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: is this behaviour expected for "git clone --single-branch"?
  2012-09-13 18:38 is this behaviour expected for "git clone --single-branch"? Ralf Thielow
@ 2012-09-13 18:45 ` Junio C Hamano
  2012-09-13 18:48   ` Ralf Thielow
  0 siblings, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-13 18:45 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: git, pclouds

Ralf Thielow <ralf.thielow@gmail.com> writes:

> # looking again to my branches

Don't look at your branches, but look at how the refspecs are
configured by "git clone" in .git/config; I suspect we just write
the default 'refs/heads/*:refs/remotes/origin/*' pattern.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: is this behaviour expected for "git clone --single-branch"?
  2012-09-13 18:45 ` Junio C Hamano
@ 2012-09-13 18:48   ` Ralf Thielow
  2012-09-14  5:09     ` [PATCH] clone: fix refspec on "--single-branch" option Ralf Thielow
  0 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-13 18:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, pclouds

On Thu, Sep 13, 2012 at 8:45 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Ralf Thielow <ralf.thielow@gmail.com> writes:
>
>> # looking again to my branches
>
> Don't look at your branches, but look at how the refspecs are
> configured by "git clone" in .git/config; I suspect we just write
> the default 'refs/heads/*:refs/remotes/origin/*' pattern.

Indeed.

$ cat .git/config
[remote "origin"]
	fetch = +refs/heads/*:refs/remotes/origin/*

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH] clone: fix refspec on "--single-branch" option
  2012-09-13 18:48   ` Ralf Thielow
@ 2012-09-14  5:09     ` Ralf Thielow
  2012-09-14  5:35       ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-14  5:09 UTC (permalink / raw)
  To: gitster; +Cc: pclouds, git, Ralf Thielow

After using "git clone" with the "--single-branch"
option, the configured refspec for this repo was
"+refs/heads/*:refs/remotes/origin/*".
After fetching changes from this repo again, it'll
receive all refs instead of the single ref which
was used in "--single-branch". Fixing the refspec
that it just contains the ref of the branch which
was cloned.

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
 builtin/clone.c | 5 ++++-
 1 Datei geändert, 4 Zeilen hinzugefügt(+), 1 Zeile entfernt(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..3e74d55 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -754,7 +754,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 		strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
 	}
 
-	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
+	if (option_single_branch)
+		strbuf_addf(&value, "+%s%s:%s%s", src_ref_prefix, option_branch, branch_top.buf, option_branch);
+	else
+		strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
 
 	if (option_mirror || !option_bare) {
 		/* Configure the remote */
-- 
1.7.12.395.g6b149ce.dirty

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH] clone: fix refspec on "--single-branch" option
  2012-09-14  5:09     ` [PATCH] clone: fix refspec on "--single-branch" option Ralf Thielow
@ 2012-09-14  5:35       ` Junio C Hamano
  2012-09-14  6:48         ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-14  5:35 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> After using "git clone" with the "--single-branch"
> option, the configured refspec for this repo was
> "+refs/heads/*:refs/remotes/origin/*".
> After fetching changes from this repo again, it'll
> receive all refs instead of the single ref which
> was used in "--single-branch". Fixing the refspec
> that it just contains the ref of the branch which
> was cloned.
>
> Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
> ---
>  builtin/clone.c | 5 ++++-
>  1 Datei geändert, 4 Zeilen hinzugefügt(+), 1 Zeile entfernt(-)
>
> diff --git a/builtin/clone.c b/builtin/clone.c
> index 5e8f3ba..3e74d55 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -754,7 +754,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
>  		strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
>  	}
>  
> -	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
> +	if (option_single_branch)
> +		strbuf_addf(&value, "+%s%s:%s%s", src_ref_prefix, option_branch, branch_top.buf, option_branch);
> +	else
> +		strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);

Who guarantees at this point in the codepath that option_branch is
set when option_single_branch is non-zero?  Until we talk with the
remote, "clone --single-branch" without an explicit "--branch" will
not learn which branch at the remote we are going to fetch (it will
be their HEAD).

I wonder if this should be more like this:

	if (option_single_branch) {
		if (option_branch)
			Your patch "+refs/heads/foo:refs/remotes/origin/foo";
		else
			"HEAD";
        } else {
        	Original "+refs/heads/*:refs/remotes/origin/*";
	}

That is, "clone --single-branch" will continue fetching from and
integrating with their HEAD without storing any remote tracking
branch.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] clone: fix refspec on "--single-branch" option
  2012-09-14  5:35       ` Junio C Hamano
@ 2012-09-14  6:48         ` Junio C Hamano
  2012-09-14 13:10           ` Nguyen Thai Ngoc Duy
                             ` (2 more replies)
  0 siblings, 3 replies; 39+ messages in thread
From: Junio C Hamano @ 2012-09-14  6:48 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Junio C Hamano <gitster@pobox.com> writes:

> Who guarantees at this point in the codepath that option_branch is
> set when option_single_branch is non-zero?  Until we talk with the
> remote, "clone --single-branch" without an explicit "--branch" will
> not learn which branch at the remote we are going to fetch (it will
> be their HEAD).
>
> I wonder if this should be more like this:
>
> 	if (option_single_branch) {
> 		if (option_branch)
> 			Your patch "+refs/heads/foo:refs/remotes/origin/foo";
> 		else
> 			"HEAD";
>         } else {
>         	Original "+refs/heads/*:refs/remotes/origin/*";
> 	}
>
> That is, "clone --single-branch" will continue fetching from and
> integrating with their HEAD without storing any remote tracking
> branch.

Alternatively, if you can move the logic to set up this
configuration further down so that it happens after we talked to the
other side and figured out remote_head_points_at, you could instead
set it up to keep a single remote tracking branch.

Even if you did so, guess_remote_head() may not find any branch when
the other repository's HEAD is detached, so you would need to decide
what to do in such a case, and "fetch and integrate their HEAD
without using any remote tracking branch" may be a reasonable thing
to do in such a case.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] clone: fix refspec on "--single-branch" option
  2012-09-14  6:48         ` Junio C Hamano
@ 2012-09-14 13:10           ` Nguyen Thai Ngoc Duy
  2012-09-14 14:25             ` Ralf Thielow
  2012-09-14 16:02             ` Junio C Hamano
  2012-09-14 18:11           ` [PATCHv2] " Ralf Thielow
  2012-09-14 18:42           ` [PATCH] clone: fix refspec on "--single-branch" option Junio C Hamano
  2 siblings, 2 replies; 39+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-09-14 13:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Ralf Thielow, git

On Fri, Sep 14, 2012 at 1:48 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Junio C Hamano <gitster@pobox.com> writes:
>
>> Who guarantees at this point in the codepath that option_branch is
>> set when option_single_branch is non-zero?  Until we talk with the
>> remote, "clone --single-branch" without an explicit "--branch" will
>> not learn which branch at the remote we are going to fetch (it will
>> be their HEAD).
>>
>> I wonder if this should be more like this:
>>
>>       if (option_single_branch) {
>>               if (option_branch)
>>                       Your patch "+refs/heads/foo:refs/remotes/origin/foo";
>>               else
>>                       "HEAD";
>>         } else {
>>               Original "+refs/heads/*:refs/remotes/origin/*";
>>       }
>>
>> That is, "clone --single-branch" will continue fetching from and
>> integrating with their HEAD without storing any remote tracking
>> branch.
>
> Alternatively, if you can move the logic to set up this
> configuration further down so that it happens after we talked to the
> other side and figured out remote_head_points_at, you could instead
> set it up to keep a single remote tracking branch.

That sounds reasonable. I have a question though, what should a user
do when he/she want to fetch all branches again? Messing up with
refspec in config file is not something I would like to do.

Perhaps a heuristic in git-fetch to detect "single branch" situation
and ignore refspec? We could hint people that refspecs are not
followed when remote has more than one branch. They could either fetch
the another branch explicitly, which turns off the heuristic, or turn
off the advice.

> Even if you did so, guess_remote_head() may not find any branch when
> the other repository's HEAD is detached, so you would need to decide
> what to do in such a case, and "fetch and integrate their HEAD
> without using any remote tracking branch" may be a reasonable thing
> to do in such a case.
-- 
Duy

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] clone: fix refspec on "--single-branch" option
  2012-09-14 13:10           ` Nguyen Thai Ngoc Duy
@ 2012-09-14 14:25             ` Ralf Thielow
  2012-09-14 16:02             ` Junio C Hamano
  1 sibling, 0 replies; 39+ messages in thread
From: Ralf Thielow @ 2012-09-14 14:25 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: Junio C Hamano, git

On Fri, Sep 14, 2012 at 3:10 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> On Fri, Sep 14, 2012 at 1:48 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> Junio C Hamano <gitster@pobox.com> writes:
>>
>>> Who guarantees at this point in the codepath that option_branch is
>>> set when option_single_branch is non-zero?  Until we talk with the
>>> remote, "clone --single-branch" without an explicit "--branch" will
>>> not learn which branch at the remote we are going to fetch (it will
>>> be their HEAD).
>>>
>>> I wonder if this should be more like this:
>>>
>>>       if (option_single_branch) {
>>>               if (option_branch)
>>>                       Your patch "+refs/heads/foo:refs/remotes/origin/foo";
>>>               else
>>>                       "HEAD";
>>>         } else {
>>>               Original "+refs/heads/*:refs/remotes/origin/*";
>>>       }
>>>
>>> That is, "clone --single-branch" will continue fetching from and
>>> integrating with their HEAD without storing any remote tracking
>>> branch.
>>
>> Alternatively, if you can move the logic to set up this
>> configuration further down so that it happens after we talked to the
>> other side and figured out remote_head_points_at, you could instead
>> set it up to keep a single remote tracking branch.
>
> That sounds reasonable. I have a question though, what should a user
> do when he/she want to fetch all branches again? Messing up with
> refspec in config file is not something I would like to do.
>

$ git remote set-branches <remote> "*"

> Perhaps a heuristic in git-fetch to detect "single branch" situation
> and ignore refspec? We could hint people that refspecs are not
> followed when remote has more than one branch. They could either fetch
> the another branch explicitly, which turns off the heuristic, or turn
> off the advice.
>

Such an advice when using "--single-branch" is a good idea, i think.
Something like "The remote <remote> is configured to fetch only branch <branch>.
If you want to fetch all branches, use "git remote set-branches <remote> "*""
or something like that.

>> Even if you did so, guess_remote_head() may not find any branch when
>> the other repository's HEAD is detached, so you would need to decide
>> what to do in such a case, and "fetch and integrate their HEAD
>> without using any remote tracking branch" may be a reasonable thing
>> to do in such a case.
> --
> Duy

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] clone: fix refspec on "--single-branch" option
  2012-09-14 13:10           ` Nguyen Thai Ngoc Duy
  2012-09-14 14:25             ` Ralf Thielow
@ 2012-09-14 16:02             ` Junio C Hamano
  1 sibling, 0 replies; 39+ messages in thread
From: Junio C Hamano @ 2012-09-14 16:02 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: Ralf Thielow, git

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:

> On Fri, Sep 14, 2012 at 1:48 PM, Junio C Hamano <gitster@pobox.com> wrote:
>
>> Alternatively, if you can move the logic to set up this
>> configuration further down so that it happens after we talked to the
>> other side and figured out remote_head_points_at, you could instead
>> set it up to keep a single remote tracking branch.
>
> That sounds reasonable. I have a question though, what should a user
> do when he/she want to fetch all branches again? Messing up with
> refspec in config file is not something I would like to do.

You first have to think ;-).

I would say there are two kinds of users.

 - To the simplistic ones who fear the power of configuration, we
   can simply tell "You don't. Use 'single' when you want to keep
   working with the single branch. If you want full, reclone, and
   migrate your work from the single one by fetching from it to the
   full clone before discarding the single one".

 - To the ones who wants to take the full advantage of flexibility
   of configuration, we can tell "remotes.$name.fetch configuration
   is your friend. Do whatever you want to do with it, but here are
   two hints".  The hints would cover the case to revert to the
   default refspec, and the case to add another specific branch.

These days, with "git config" and "git remote" wrappers, I do not
particularly see a need to fear the power of configuration, though.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCHv2] clone: fix refspec on "--single-branch" option
  2012-09-14  6:48         ` Junio C Hamano
  2012-09-14 13:10           ` Nguyen Thai Ngoc Duy
@ 2012-09-14 18:11           ` Ralf Thielow
  2012-09-14 19:22             ` Junio C Hamano
  2012-09-14 18:42           ` [PATCH] clone: fix refspec on "--single-branch" option Junio C Hamano
  2 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-14 18:11 UTC (permalink / raw)
  To: gitster; +Cc: pclouds, git, Ralf Thielow

After a repo was cloned with the "--single-branch"
option, the configured refspec looks like
"+refs/heads/*:refs/remotes/origin/*".
After fetching from this repo again, it'll receive
all refs instead of just the ref from the single
branch. Fixing this by configure exactly the ref
of the branch the user specified in the "git clone"
command.

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---

> Alternatively, if you can move the logic to set up this
> configuration further down so that it happens after we talked to the
> other side and figured out remote_head_points_at, you could instead
> set it up to keep a single remote tracking branch.
>
> Even if you did so, guess_remote_head() may not find any branch when
> the other repository's HEAD is detached, so you would need to decide
> what to do in such a case, and "fetch and integrate their HEAD
> without using any remote tracking branch" may be a reasonable thing
> to do in such a case.

This second version now covers also the "--single-branch"
option when it was called without "--branch". It also covers
the "detached HEAD" case.
I've tested all the use-cases that have been described above and it works
as expected with this patch. But there's just one thing. It fetches
also all the tags even if they're not on this branch. I'm still in the
"learning process", perhaps someone else can fix this problem or point
me to the reason. 
I think it comes from "transport_fetch_refs(transport, mapped_refs);"
on line 813 which is called with a full "+refs/heads/*:refs/remotes/origin/*"
refspec. Thanks

 builtin/clone.c | 41 +++++++++++++++++++++++++++--------------
 1 Datei geändert, 27 Zeilen hinzugefügt(+), 14 Zeilen entfernt(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..3ddf5ab 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -755,20 +755,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	}
 
 	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
-	if (option_mirror || !option_bare) {
-		/* Configure the remote */
-		strbuf_addf(&key, "remote.%s.fetch", option_origin);
-		git_config_set_multivar(key.buf, value.buf, "^$", 0);
-		strbuf_reset(&key);
-
-		if (option_mirror) {
-			strbuf_addf(&key, "remote.%s.mirror", option_origin);
-			git_config_set(key.buf, "true");
-			strbuf_reset(&key);
-		}
-	}
-
 	strbuf_addf(&key, "remote.%s.url", option_origin);
 	git_config_set(key.buf, repo);
 	strbuf_reset(&key);
@@ -853,6 +839,33 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 					      "refs/heads/master");
 	}
 
+	if (option_mirror || !option_bare) {
+		strbuf_reset(&value);
+		if (option_single_branch) {
+			if (option_branch)
+				strbuf_addf(&value, "+%s%s:%s%s", src_ref_prefix, option_branch,
+						branch_top.buf, option_branch);
+			else if (remote_head_points_at)
+					strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+									branch_top.buf, prettify_refname(remote_head_points_at->name));
+		} else {
+			strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
+		}
+		/* Configure the remote */
+		if (value.len) {
+			strbuf_reset(&key);
+			strbuf_addf(&key, "remote.%s.fetch", option_origin);
+			git_config_set_multivar(key.buf, value.buf, "^$", 0);
+			strbuf_reset(&key);
+
+			if (option_mirror) {
+				strbuf_addf(&key, "remote.%s.mirror", option_origin);
+				git_config_set(key.buf, "true");
+				strbuf_reset(&key);
+			}
+		}
+	}
+
 	if (is_local)
 		clone_local(path, git_dir);
 	else if (refs && complete_refs_before_fetch)
-- 
1.7.12.395.g6b149ce.dirty

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH] clone: fix refspec on "--single-branch" option
  2012-09-14  6:48         ` Junio C Hamano
  2012-09-14 13:10           ` Nguyen Thai Ngoc Duy
  2012-09-14 18:11           ` [PATCHv2] " Ralf Thielow
@ 2012-09-14 18:42           ` Junio C Hamano
  2 siblings, 0 replies; 39+ messages in thread
From: Junio C Hamano @ 2012-09-14 18:42 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Junio C Hamano <gitster@pobox.com> writes:

> Alternatively, if you can move the logic to set up this
> configuration further down so that it happens after we talked to the
> other side and figured out remote_head_points_at, you could instead
> set it up to keep a single remote tracking branch.
>
> Even if you did so, guess_remote_head() may not find any branch when
> the other repository's HEAD is detached, so you would need to decide
> what to do in such a case, and "fetch and integrate their HEAD
> without using any remote tracking branch" may be a reasonable thing
> to do in such a case.

Along the lines of this, perhaps.

 builtin/clone.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git i/builtin/clone.c w/builtin/clone.c
index 5e8f3ba..c9e099d 100644
--- i/builtin/clone.c
+++ w/builtin/clone.c
@@ -853,6 +853,22 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 					      "refs/heads/master");
 	}
 
+	if (option_single_branch) {
+		/* Fix up the refspec for fetch */
+		strbuf_reset(&value);
+		if (!remote_head_points_at)
+			strbuf_addf(&value, "HEAD");
+		else
+			strbuf_addf(&value, "%s:%s%s",
+				    remote_head_points_at->name,
+				    branch_top.buf,
+				    skip_prefix(remote_head_points_at->name, "refs/heads/"));
+
+		strbuf_reset(&key);
+		strbuf_addf(&key, "remote.%s.fetch", option_origin);
+		git_config_set_multivar(key.buf, value.buf, NULL, 1);
+	}
+
 	if (is_local)
 		clone_local(path, git_dir);
 	else if (refs && complete_refs_before_fetch)

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCHv2] clone: fix refspec on "--single-branch" option
  2012-09-14 18:11           ` [PATCHv2] " Ralf Thielow
@ 2012-09-14 19:22             ` Junio C Hamano
  2012-09-14 21:13               ` [PATCHv3] " Ralf Thielow
  0 siblings, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-14 19:22 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> +			else if (remote_head_points_at)
> +					strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
> +									branch_top.buf, prettify_refname(remote_head_points_at->name));

As refspec maps names that appear on the source side to names that
appear on the destination side, and for fetch, the "soruce side"
is the remote, using "our_head_points_at" on the source side makes
it look very fishy (even though it may be a name derived from
remote_head_points_at and has the correct and appropriate value).

"prettify" also is very questionable.  It is meant to strip commonly
known prefix to make it easier to read by humans, and we can change
its result based solely on aesthetics in the future.  It is not
suitable for coming up with a value for configuration in the longer
term.

Can we make the part you moved de-dented a bit, perhaps by making it
into a small helper function or something?  It is extremely hard to
read with overly looooooong lines.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCHv3] clone: fix refspec on "--single-branch" option
  2012-09-14 19:22             ` Junio C Hamano
@ 2012-09-14 21:13               ` Ralf Thielow
  2012-09-14 22:45                 ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-14 21:13 UTC (permalink / raw)
  To: gitster; +Cc: pclouds, git, Ralf Thielow

After a repo was cloned with the "--single-branch"
option, the configured refspec looks like
"+refs/heads/*:refs/remotes/origin/*".
After fetching from this repo again, it'll receive
all refs instead of just the ref from the single
branch. Fixing this by configure exactly the ref
of the branch the user specified in the "git clone"
command.

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
> As refspec maps names that appear on the source side to names that
> appear on the destination side, and for fetch, the "soruce side"
> is the remote, using "our_head_points_at" on the source side makes
> it look very fishy (even though it may be a name derived from
> remote_head_points_at and has the correct and appropriate value).
>
> "prettify" also is very questionable.  It is meant to strip commonly
> known prefix to make it easier to read by humans, and we can change
> its result based solely on aesthetics in the future.  It is not
> suitable for coming up with a value for configuration in the longer
> term.
>

Thanks. I've fixed.

> Can we make the part you moved de-dented a bit, perhaps by making it
> into a small helper function or something?  It is extremely hard to
> read with overly looooooong lines.
>

Would be nice but the list of arguments will become too long.
I did a bit of reformating and think it now looks a bit nicer.

 builtin/clone.c | 43 +++++++++++++++++++++++++++++--------------
 1 Datei geändert, 29 Zeilen hinzugefügt(+), 14 Zeilen entfernt(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..06e3d3a 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -755,20 +755,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	}
 
 	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
-	if (option_mirror || !option_bare) {
-		/* Configure the remote */
-		strbuf_addf(&key, "remote.%s.fetch", option_origin);
-		git_config_set_multivar(key.buf, value.buf, "^$", 0);
-		strbuf_reset(&key);
-
-		if (option_mirror) {
-			strbuf_addf(&key, "remote.%s.mirror", option_origin);
-			git_config_set(key.buf, "true");
-			strbuf_reset(&key);
-		}
-	}
-
 	strbuf_addf(&key, "remote.%s.url", option_origin);
 	git_config_set(key.buf, repo);
 	strbuf_reset(&key);
@@ -853,6 +839,35 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 					      "refs/heads/master");
 	}
 
+	if (option_mirror || !option_bare) {
+		strbuf_reset(&value);
+		if (option_single_branch) {
+			if (option_branch)
+				strbuf_addf(&value, "+%s%s:%s%s",
+						src_ref_prefix, option_branch,
+						branch_top.buf, option_branch);
+			else if (remote_head_points_at)
+				strbuf_addf(&value, "+%s:%s%s",
+						remote_head_points_at->name, branch_top.buf,
+						skip_prefix(remote_head_points_at->name, "refs/heads/"));
+		} else {
+			strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
+		}
+		/* Configure the remote */
+		if (value.len) {
+			strbuf_reset(&key);
+			strbuf_addf(&key, "remote.%s.fetch", option_origin);
+			git_config_set_multivar(key.buf, value.buf, "^$", 0);
+			strbuf_reset(&key);
+
+			if (option_mirror) {
+				strbuf_addf(&key, "remote.%s.mirror", option_origin);
+				git_config_set(key.buf, "true");
+				strbuf_reset(&key);
+			}
+		}
+	}
+
 	if (is_local)
 		clone_local(path, git_dir);
 	else if (refs && complete_refs_before_fetch)
-- 
1.7.12.396.g3cff853.dirty

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCHv3] clone: fix refspec on "--single-branch" option
  2012-09-14 21:13               ` [PATCHv3] " Ralf Thielow
@ 2012-09-14 22:45                 ` Junio C Hamano
  2012-09-16  8:13                   ` [PATCHv4] clone --single: limit the fetch refspec to fetched branch Ralf Thielow
  0 siblings, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-14 22:45 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> +	if (option_mirror || !option_bare) {
> +		strbuf_reset(&value);
> +		if (option_single_branch) {
> +			if (option_branch)
> +				strbuf_addf(&value, "+%s%s:%s%s",
> +						src_ref_prefix, option_branch,
> +						branch_top.buf, option_branch);
> +			else if (remote_head_points_at)
> +				strbuf_addf(&value, "+%s:%s%s",
> +						remote_head_points_at->name, branch_top.buf,
> +						skip_prefix(remote_head_points_at->name, "refs/heads/"));

We have already set "remote.origin.url" to this repository, so the
next "git fetch" would simply fetch from "HEAD" per default.
Perhaps worth commenting that here?

Other than that, looks good.  Perhaps we would want a test or two,
too?

Thanks.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-14 22:45                 ` Junio C Hamano
@ 2012-09-16  8:13                   ` Ralf Thielow
  2012-09-17  4:48                     ` Junio C Hamano
  2012-09-17 12:06                     ` Nguyen Thai Ngoc Duy
  0 siblings, 2 replies; 39+ messages in thread
From: Ralf Thielow @ 2012-09-16  8:13 UTC (permalink / raw)
  To: gitster; +Cc: pclouds, git, Ralf Thielow

After running "git clone --single", the resulting repository has the
usual default "+refs/heads/*:refs/remotes/origin/*" wildcard fetch
refspec installed, which means that a subsequent "git fetch" will
end up grabbing all the other branches.

Update the fetch refspec to cover only the singly cloned ref instead
to correct this.

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---

Changes to v3:
- use commit message from Junio's topic branch
- add comment for the 'detached HEAD' case (also from Junio's topic branch)
(thanks for that)
- add tests for the refspec installed by the clone command

 builtin/clone.c          | 49 ++++++++++++++++++++++++++++------------
 t/t5709-clone-refspec.sh | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 Dateien geändert, 94 Zeilen hinzugefügt(+), 14 Zeilen entfernt(-)
 create mode 100755 t/t5709-clone-refspec.sh

diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..be4c62b 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -755,20 +755,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	}
 
 	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
-	if (option_mirror || !option_bare) {
-		/* Configure the remote */
-		strbuf_addf(&key, "remote.%s.fetch", option_origin);
-		git_config_set_multivar(key.buf, value.buf, "^$", 0);
-		strbuf_reset(&key);
-
-		if (option_mirror) {
-			strbuf_addf(&key, "remote.%s.mirror", option_origin);
-			git_config_set(key.buf, "true");
-			strbuf_reset(&key);
-		}
-	}
-
 	strbuf_addf(&key, "remote.%s.url", option_origin);
 	git_config_set(key.buf, repo);
 	strbuf_reset(&key);
@@ -853,6 +839,41 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 					      "refs/heads/master");
 	}
 
+	if (option_mirror || !option_bare) {
+		strbuf_reset(&value);
+		if (option_single_branch) {
+			if (option_branch)
+				strbuf_addf(&value, "+%s%s:%s%s",
+						src_ref_prefix, option_branch,
+						branch_top.buf, option_branch);
+			else if (remote_head_points_at)
+				strbuf_addf(&value, "+%s:%s%s",
+						remote_head_points_at->name, branch_top.buf,
+						skip_prefix(remote_head_points_at->name, "refs/heads/"));
+			/*
+			 * otherwise, the next "git fetch" will
+			 * simply fetch from HEAD without updating
+			 * any remote tracking branch, which is what
+			 * we want.
+			 */
+		} else {
+			strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
+		}
+		/* Configure the remote */
+		if (value.len) {
+			strbuf_reset(&key);
+			strbuf_addf(&key, "remote.%s.fetch", option_origin);
+			git_config_set_multivar(key.buf, value.buf, "^$", 0);
+			strbuf_reset(&key);
+
+			if (option_mirror) {
+				strbuf_addf(&key, "remote.%s.mirror", option_origin);
+				git_config_set(key.buf, "true");
+				strbuf_reset(&key);
+			}
+		}
+	}
+
 	if (is_local)
 		clone_local(path, git_dir);
 	else if (refs && complete_refs_before_fetch)
diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
new file mode 100755
index 0000000..f4c8e31
--- /dev/null
+++ b/t/t5709-clone-refspec.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+test_description='test refspec written by clone-command'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	echo one >file &&
+	git add file &&
+	git commit -m one &&
+	echo two >file &&
+	git commit -a -m two &&
+	git tag two &&
+	echo three >file &&
+	git commit -a -m three &&
+	git checkout -b foo &&
+	echo four >file &&
+	git commit -a -m four &&
+	git checkout master
+'
+
+test_expect_success 'refspec contains all branches by default' '
+	git clone "file://$PWD" dir_all &&
+	echo "+refs/heads/*:refs/remotes/origin/*" > expected &&
+	git --git-dir=dir_all/.git config --get remote.origin.fetch > actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'refspec contains only master with option --single-branch and remotes HEAD point to master' '
+	git clone --single-branch "file://$PWD" dir_master &&
+	echo "+refs/heads/master:refs/remotes/origin/master" > expected &&
+	git --git-dir=dir_master/.git config --get remote.origin.fetch > actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'refspec contains only foo with option --single-branch and remotes HEAD point to foo' '
+	git checkout foo &&
+	git clone --single-branch "file://$PWD" dir_foo &&
+	echo "+refs/heads/foo:refs/remotes/origin/foo" > expected &&
+	git --git-dir=dir_foo/.git config --get remote.origin.fetch > actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'refspec contains one branch after using option --single-branch with --branch' '
+	git checkout master &&
+	git clone --single-branch --branch foo "file://$PWD" dir_foo2 &&
+	echo "+refs/heads/foo:refs/remotes/origin/foo" > expected &&
+	git --git-dir=dir_foo2/.git config --get remote.origin.fetch > actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'no refspec is written if remotes HEAD is detached' '
+	git checkout two^ &&
+	git clone --single-branch "file://$PWD" dir_detached &&
+	rm expected && touch expected &&
+	git --git-dir=dir_detached/.git config --get remote.origin.fetch > actual
+	test_cmp expected actual
+'
+
+test_done
-- 
1.7.12.396.g6bea32d.dirty

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-16  8:13                   ` [PATCHv4] clone --single: limit the fetch refspec to fetched branch Ralf Thielow
@ 2012-09-17  4:48                     ` Junio C Hamano
  2012-09-17 12:06                     ` Nguyen Thai Ngoc Duy
  1 sibling, 0 replies; 39+ messages in thread
From: Junio C Hamano @ 2012-09-17  4:48 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> - add tests for the refspec installed by the clone command

Thanks.

> +test_expect_success 'refspec contains all branches by default' '
> +	git clone "file://$PWD" dir_all &&

There have been numerous "on windows which should we use, $PWD or
$(pwd)?" gotchas.  In this particular case, wouldn't the tests work
equally well with "." to avoid the uneasiness factor?

> +	echo "+refs/heads/*:refs/remotes/origin/*" > expected &&
> +	git --git-dir=dir_all/.git config --get remote.origin.fetch > actual &&
> +	test_cmp expected actual

I am a bit torn with this one.

We'd want to make sure a single clone from a repository with two
branches will not result in a repository where the next fetch will
not pull in the other branch, and the value of the
"remote.origin.fetch" is an implementation detail that happen to be
what affects the outcome.  The test is not checking the expected
outcome in a direct way (imagine how this test will break when we do
another change similar to the migration from .git/remotes/origin to
the remote.origin.fetch variables).

I'll let it pass for now, though.

> +test_expect_success 'no refspec is written if remotes HEAD is detached' '
> +	git checkout two^ &&
> +	git clone --single-branch "file://$PWD" dir_detached &&
> +	rm expected && touch expected &&

If earlier tests failed, there may not be any expected file and the
"rm expected" will fail.  You can just say

	>expected &&

instead.  "touch" is a way to update the timestamp of the file; do
not use it when you want to make sure an empty file exists.

> +	git --git-dir=dir_detached/.git config --get remote.origin.fetch > actual
> +	test_cmp expected actual
> +'

I'd feel better if the test were like this instead:

	git checkout two^ &&
        git clone --single-branch . dir_detached &&
        (
		cd dir_detached &&
                git fetch &&
                git for-each-ref refs/remotes/origin >actual
	) &&
        >expect &&
        test_cmp expect actual

That is what I would call "testing the desired results in the most
direct way".

Perhaps like this?

-- >8 -- t5709-clone-refspec.sh -- >8 --
#!/bin/sh

test_description='test refspec written by clone-command'
. ./test-lib.sh

test_expect_success 'setup' '
	# Make two branches, "master" and "side"
	echo one >file &&
	git add file &&
	git commit -m one &&
	echo two >file &&
	git commit -a -m two &&
	git tag two &&
	echo three >file &&
	git commit -a -m three &&
	git checkout -b side &&
	echo four >file &&
	git commit -a -m four &&
	git checkout master &&

	# default clone
	git clone . dir_all &&

	# default --single that follows HEAD=master
	git clone --single-branch . dir_master &&

	# default --single that follows HEAD=side
	git checkout side &&
	git clone --single-branch . dir_side &&

	# explicit --single that follows side
	git checkout master &&
	git clone --single-branch --branch side . dir_side2 &&

	# --single that does not know what branch to follow
	git checkout two^ &&
	git clone --single-branch . dir_detached &&

	# advance both "master" and "side" branches
	git checkout side &&
	echo five >file &&
	git commit -a -m five &&
	git checkout master &&
	echo six >file &&
	git commit -a -m six
'

test_expect_success 'by default all branches will be kept updated' '
	(
		cd dir_all && git fetch &&
		git for-each-ref refs/remotes/origin |
		sed -e "/HEAD$/d" \
		    -e "s|/remotes/origin/|/heads/|" >../actual
	) &&
	# follow both master and side
	git for-each-ref refs/heads >expect &&
	test_cmp expect actual
'

test_expect_success '--single-branch while HEAD pointing at master' '
	(
		cd dir_master && git fetch &&
		git for-each-ref refs/remotes/origin |
		sed -e "/HEAD$/d" \
		    -e "s|/remotes/origin/|/heads/|" >../actual
	) &&
	# only follow master
	git for-each-ref refs/heads/master >expect &&
	test_cmp expect actual
'

test_expect_success '--single-branch while HEAD pointing at side' '
	(
		cd dir_side && git fetch &&
		git for-each-ref refs/remotes/origin |
		sed -e "/HEAD$/d" \
		    -e "s|/remotes/origin/|/heads/|" >../actual
	) &&
	# only follow side
	git for-each-ref refs/heads/side >expect &&
	test_cmp expect actual
'

test_expect_success '--single-branch with explicit --branch side' '
	(
		cd dir_side2 && git fetch &&
		git for-each-ref refs/remotes/origin |
		sed -e "/HEAD$/d" \
		    -e "s|/remotes/origin/|/heads/|" >../actual
	) &&
	# only follow side
	git for-each-ref refs/heads/side >expect &&
	test_cmp expect actual
'

test_expect_success '--single-branch with detached' '
	(
		cd dir_detached && git fetch &&
		git for-each-ref refs/remotes/origin |
		sed -e "/HEAD$/d" \
		    -e "s|/remotes/origin/|/heads/|" >../actual
	)
	# nothing
	>expect &&
	test_cmp expect actual
'

test_done

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-16  8:13                   ` [PATCHv4] clone --single: limit the fetch refspec to fetched branch Ralf Thielow
  2012-09-17  4:48                     ` Junio C Hamano
@ 2012-09-17 12:06                     ` Nguyen Thai Ngoc Duy
  2012-09-17 12:11                       ` Nguyen Thai Ngoc Duy
                                         ` (2 more replies)
  1 sibling, 3 replies; 39+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-09-17 12:06 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: gitster, git

On Sun, Sep 16, 2012 at 3:13 PM, Ralf Thielow <ralf.thielow@gmail.com> wrote:
> +       if (option_mirror || !option_bare) {
> +               strbuf_reset(&value);

I think we should use a new strbuf local variable here to avoid
resetting this. At least reviewers don't have to check if this
statememt causes any effect later on because "value"'s value is gone.

> +               if (option_single_branch) {
> +                       if (option_branch)
> +                               strbuf_addf(&value, "+%s%s:%s%s",
> +                                               src_ref_prefix, option_branch,
> +                                               branch_top.buf, option_branch);
> +                       else if (remote_head_points_at)
> +                               strbuf_addf(&value, "+%s:%s%s",
> +                                               remote_head_points_at->name, branch_top.buf,
> +                                               skip_prefix(remote_head_points_at->name, "refs/heads/"));
> +                       /*
> +                        * otherwise, the next "git fetch" will
> +                        * simply fetch from HEAD without updating
> +                        * any remote tracking branch, which is what
> +                        * we want.
> +                        */

Maybe document updates too? Though if it's obvious that
--single-branch should prepare refspec so that only one branch is
fetched later on, then maybe not.

> +               } else {
> +                       strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
> +               }

--mirror --single-branch combination does not look right. The "heads/"
part is missing..

$ git branch
  master * wildmatch
$ LANG=C ./git clone --mirror --single-branch .git abc
Cloning into bare repository 'abc'...
done.
$ grep fetch abc/config
        fetch = +refs/heads/wildmatch:refs/wildmatch
$ rm -rf abc
$ LANG=C ./git clone --mirror --single-branch --branch=master .git abc
Cloning into bare repository 'abc'...
done.
$ grep fetch abc/config
        fetch = +refs/master:refs/master
-- 
Duy

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 12:06                     ` Nguyen Thai Ngoc Duy
@ 2012-09-17 12:11                       ` Nguyen Thai Ngoc Duy
  2012-09-17 19:21                         ` [PATCHv5] " Ralf Thielow
  2012-09-17 20:09                         ` [PATCHv4] " Junio C Hamano
  2012-09-17 13:25                       ` Ralf Thielow
  2012-09-17 20:08                       ` Junio C Hamano
  2 siblings, 2 replies; 39+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-09-17 12:11 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: gitster, git

On Mon, Sep 17, 2012 at 7:06 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> --mirror --single-branch combination does not look right. The "heads/"
> part is missing..

It also does not look right for cloning a tag:

$ LANG=C ./git clone --single-branch --branch=v1.7.0 .git abc
Cloning into 'abc'...
done.
Note: checking out 'e923eaeb901ff056421b9007adcbbce271caa7b6'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

$ grep fetch abc/.git/config
        fetch = +refs/heads/v1.7.0:refs/remotes/origin/v1.7.0
-- 
Duy

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 12:06                     ` Nguyen Thai Ngoc Duy
  2012-09-17 12:11                       ` Nguyen Thai Ngoc Duy
@ 2012-09-17 13:25                       ` Ralf Thielow
  2012-09-17 20:08                       ` Junio C Hamano
  2 siblings, 0 replies; 39+ messages in thread
From: Ralf Thielow @ 2012-09-17 13:25 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: gitster, git

On Mon, Sep 17, 2012 at 2:06 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> On Sun, Sep 16, 2012 at 3:13 PM, Ralf Thielow <ralf.thielow@gmail.com> wrote:
>> +       if (option_mirror || !option_bare) {
>> +               strbuf_reset(&value);
>
> I think we should use a new strbuf local variable here to avoid
> resetting this. At least reviewers don't have to check if this
> statememt causes any effect later on because "value"'s value is gone.
>

It seems that we don't need this reset here because it's already
done earlier in this function. The variable "key" is also used multiple
times so I wouldn't use a new variable.

>> +               if (option_single_branch) {
>> +                       if (option_branch)
>> +                               strbuf_addf(&value, "+%s%s:%s%s",
>> +                                               src_ref_prefix, option_branch,
>> +                                               branch_top.buf, option_branch);
>> +                       else if (remote_head_points_at)
>> +                               strbuf_addf(&value, "+%s:%s%s",
>> +                                               remote_head_points_at->name, branch_top.buf,
>> +                                               skip_prefix(remote_head_points_at->name, "refs/heads/"));
>> +                       /*
>> +                        * otherwise, the next "git fetch" will
>> +                        * simply fetch from HEAD without updating
>> +                        * any remote tracking branch, which is what
>> +                        * we want.
>> +                        */
>
> Maybe document updates too? Though if it's obvious that
> --single-branch should prepare refspec so that only one branch is
> fetched later on, then maybe not.
>

I think it's obvious.

>> +               } else {
>> +                       strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
>> +               }
>
> --mirror --single-branch combination does not look right. The "heads/"
> part is missing..
>
> $ git branch
>   master * wildmatch
> $ LANG=C ./git clone --mirror --single-branch .git abc
> Cloning into bare repository 'abc'...
> done.
> $ grep fetch abc/config
>         fetch = +refs/heads/wildmatch:refs/wildmatch
> $ rm -rf abc
> $ LANG=C ./git clone --mirror --single-branch --branch=master .git abc
> Cloning into bare repository 'abc'...
> done.
> $ grep fetch abc/config
>         fetch = +refs/master:refs/master
> --
> Duy

Thanks, I'll check this later and send a new version.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCHv5] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 12:11                       ` Nguyen Thai Ngoc Duy
@ 2012-09-17 19:21                         ` Ralf Thielow
  2012-09-17 20:18                           ` Junio C Hamano
  2012-09-18 19:14                           ` [PATCHv6] " Ralf Thielow
  2012-09-17 20:09                         ` [PATCHv4] " Junio C Hamano
  1 sibling, 2 replies; 39+ messages in thread
From: Ralf Thielow @ 2012-09-17 19:21 UTC (permalink / raw)
  To: gitster; +Cc: pclouds, git, Ralf Thielow

After running "git clone --single", the resulting repository has the
usual default "+refs/heads/*:refs/remotes/origin/*" wildcard fetch
refspec installed, which means that a subsequent "git fetch" will
end up grabbing all the other branches.

Update the fetch refspec to cover only the singly cloned ref instead
to correct this.

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---

changes in v5:
- extract a function to write refspec config
- handle --mirror option (test added)
- install correct refspec if the value of --branch is a tag (test added)
Thanks to Junio for:
- refactor tests
- add tests for created refs 

I'm not happy about using "our_head_points_to" for the remote
part of the refspec. Junio already complaint about that. As far
as I can see it's the only way of getting the information that
it's a tag. Also the condition "is this a tag" might not be the
best way.

 builtin/clone.c          |  66 +++++++++++++++-----
 t/t5709-clone-refspec.sh | 156 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 208 insertions(+), 14 deletions(-)
 create mode 100755 t/t5709-clone-refspec.sh

diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..431635c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -610,6 +610,55 @@ static void write_config(struct string_list *config)
 	}
 }
 
+static void write_refspec_config(const char* src_ref_prefix,
+		const struct ref* our_head_points_at,
+		const struct ref* remote_head_points_at, struct strbuf* branch_top)
+{
+	struct strbuf key = STRBUF_INIT;
+	struct strbuf value = STRBUF_INIT;
+
+	if (option_mirror || !option_bare) {
+		if (option_single_branch && !option_mirror) {
+			if (option_branch) {
+				if (strstr(our_head_points_at->name, "refs/tags/"))
+					strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
+						our_head_points_at->name);
+				else
+					strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+						branch_top->buf, option_branch);
+			} else if (remote_head_points_at) {
+				strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
+						branch_top->buf,
+						skip_prefix(remote_head_points_at->name, "refs/heads/"));
+			}
+			/*
+			 * otherwise, the next "git fetch" will
+			 * simply fetch from HEAD without updating
+			 * any remote tracking branch, which is what
+			 * we want.
+			 */
+		} else {
+			strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
+		}
+		/* Configure the remote */
+		if (value.len) {
+			strbuf_reset(&key);
+			strbuf_addf(&key, "remote.%s.fetch", option_origin);
+			git_config_set_multivar(key.buf, value.buf, "^$", 0);
+			strbuf_reset(&key);
+
+			if (option_mirror) {
+				strbuf_addf(&key, "remote.%s.mirror", option_origin);
+				git_config_set(key.buf, "true");
+				strbuf_reset(&key);
+			}
+		}
+	}
+
+	strbuf_release(&key);
+	strbuf_release(&value);
+}
+
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
 	int is_bundle = 0, is_local;
@@ -755,20 +804,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	}
 
 	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
-	if (option_mirror || !option_bare) {
-		/* Configure the remote */
-		strbuf_addf(&key, "remote.%s.fetch", option_origin);
-		git_config_set_multivar(key.buf, value.buf, "^$", 0);
-		strbuf_reset(&key);
-
-		if (option_mirror) {
-			strbuf_addf(&key, "remote.%s.mirror", option_origin);
-			git_config_set(key.buf, "true");
-			strbuf_reset(&key);
-		}
-	}
-
 	strbuf_addf(&key, "remote.%s.url", option_origin);
 	git_config_set(key.buf, repo);
 	strbuf_reset(&key);
@@ -853,6 +888,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 					      "refs/heads/master");
 	}
 
+	write_refspec_config(src_ref_prefix, our_head_points_at,
+			remote_head_points_at, &branch_top);
+
 	if (is_local)
 		clone_local(path, git_dir);
 	else if (refs && complete_refs_before_fetch)
diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
new file mode 100755
index 0000000..af45182
--- /dev/null
+++ b/t/t5709-clone-refspec.sh
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+test_description='test refspec written by clone-command'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	# Make two branches, "master" and "side"
+	echo one >file &&
+	git add file &&
+	git commit -m one &&
+	echo two >file &&
+	git commit -a -m two &&
+	git tag two &&
+	echo three >file &&
+	git commit -a -m three &&
+	git checkout -b side &&
+	echo four >file &&
+	git commit -a -m four &&
+	git checkout master &&
+
+	# default clone
+	git clone . dir_all &&
+
+	# default --single that follows HEAD=master
+	git clone --single-branch . dir_master &&
+
+	# default --single that follows HEAD=side
+	git checkout side &&
+	git clone --single-branch . dir_side &&
+
+	# explicit --single that follows side
+	git checkout master &&
+	git clone --single-branch --branch side . dir_side2 &&
+
+	# default --single with --mirror
+	git clone --single-branch --mirror . dir_mirror &&
+
+	# --single that does not know what branch to follow
+	git checkout two^ &&
+	git clone --single-branch . dir_detached &&
+
+	# explicit --single with tag
+	git clone --single-branch --branch two . dir_tag &&
+
+	# advance both "master" and "side" branches
+	git checkout side &&
+	echo five >file &&
+	git commit -a -m five &&
+	git checkout master &&
+	echo six >file &&
+	git commit -a -m six
+'
+
+test_expect_success 'refspec contains all branches by default' '
+	echo "+refs/heads/*:refs/remotes/origin/*" > expect &&
+	git --git-dir=dir_all/.git config --get remote.origin.fetch > actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'refspec contains all refs with option --mirror' '
+	echo "+refs/*:refs/*" > expect &&
+	git --git-dir=dir_mirror config --get remote.origin.fetch > actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'refspec contains tag ref' '
+	echo "+refs/tags/two:refs/tags/two" > expect &&
+	git --git-dir=dir_tag/.git config --get remote.origin.fetch > actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'refspec contains only master with option --single-branch and remotes HEAD point to master' '
+	echo "+refs/heads/master:refs/remotes/origin/master" > expect &&
+	git --git-dir=dir_master/.git config --get remote.origin.fetch > actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'refspec contains only foo with option --single-branch and remotes HEAD point to side' '
+	echo "+refs/heads/side:refs/remotes/origin/side" > expect &&
+	git --git-dir=dir_side/.git config --get remote.origin.fetch > actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'refspec contains one branch after using option --single-branch with --branch' '
+	echo "+refs/heads/side:refs/remotes/origin/side" > expect &&
+	git --git-dir=dir_side2/.git config --get remote.origin.fetch > actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'no refspec is written if remotes HEAD is detached' '
+	> expect &&
+	git --git-dir=dir_detached/.git config --get remote.origin.fetch > actual
+	test_cmp expect actual
+'
+
+test_expect_success 'by default all branches will be kept updated' '
+	(
+		cd dir_all && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# follow both master and side
+	git for-each-ref refs/heads >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at master' '
+	(
+		cd dir_master && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow master
+	git for-each-ref refs/heads/master >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at side' '
+	(
+		cd dir_side && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow side
+	git for-each-ref refs/heads/side >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch side' '
+	(
+		cd dir_side2 && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow side
+	git for-each-ref refs/heads/side >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with detached' '
+	(
+		cd dir_detached && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	)
+	# nothing
+	>expect &&
+	test_cmp expect actual
+'
+
+test_done
-- 
1.7.12.397.ge29f79e.dirty

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 12:06                     ` Nguyen Thai Ngoc Duy
  2012-09-17 12:11                       ` Nguyen Thai Ngoc Duy
  2012-09-17 13:25                       ` Ralf Thielow
@ 2012-09-17 20:08                       ` Junio C Hamano
  2012-09-18  1:02                         ` Nguyen Thai Ngoc Duy
  2 siblings, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-17 20:08 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: Ralf Thielow, git

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:

> --mirror --single-branch combination does not look right. The "heads/"
> part is missing..

What does it supposed to do in the first place?  "mirror" is
primarily about grabbing everything without leaving stuff out, and
"single" is about grabbing only one thing without other stuff.  It
smells like a nonsense case we didn't even bother to catch and
diagnose as an error to me.

Besides, mirror implies bare, so we would expect to see

    refs/heads/$single:refs/heads/$single

and that matches what the "single" gives us without "mirror", no?

How about explicitly forbidding that combination, or ignoring mirror
when single is given?

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 12:11                       ` Nguyen Thai Ngoc Duy
  2012-09-17 19:21                         ` [PATCHv5] " Ralf Thielow
@ 2012-09-17 20:09                         ` Junio C Hamano
  2012-09-18  1:04                           ` Nguyen Thai Ngoc Duy
  1 sibling, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-17 20:09 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: Ralf Thielow, git

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:

> On Mon, Sep 17, 2012 at 7:06 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
>> --mirror --single-branch combination does not look right. The "heads/"
>> part is missing..
>
> It also does not look right for cloning a tag:
>
> $ LANG=C ./git clone --single-branch --branch=v1.7.0 .git abc

What does it even _mean_ to clone a single branch and give a tag,
not a branch, to the --branch option?  Again, shouldn't it be
diagnosed as an error in the first place?

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv5] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 19:21                         ` [PATCHv5] " Ralf Thielow
@ 2012-09-17 20:18                           ` Junio C Hamano
  2012-09-17 21:04                             ` Ralf Thielow
  2012-09-18 19:14                           ` [PATCHv6] " Ralf Thielow
  1 sibling, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-17 20:18 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> - handle --mirror option (test added)

Handle how?  I personally think erroring out is the right way to
handle it, but if we care about people who have been misusing the
combination of single and mirror, the second best way would be to
imply "mirror" and "single" combination as "bare" and "single"
without "mirror".

> - install correct refspec if the value of --branch is a tag (test added)

What is the definition of "correct"?  I see the documentation says
"--branch can also take tags and treat them like detached HEAD", and
even though I _think_ allowing tags was a huge mistake, if we claim
we treat it like detached HEAD, we should do the same when coming up
with the refspec used for the follow-up "fetch".

Whatever we decide to do, the semantics we decided to use at least
need to be described in the commit log message, not just in the
"changes from the previous iteration".  Updating the
"Documentation/git-clone.txt" would also be necessary.

> +test_expect_success 'refspec contains all branches by default' '
> +	echo "+refs/heads/*:refs/remotes/origin/*" > expect &&
> +	git --git-dir=dir_all/.git config --get remote.origin.fetch > actual &&
> +	test_cmp expect actual
> +'

I still think these checks that know the current implementation
details (i.e. what exact configuration variables get what exact
values) are wrong thing to have in the longer term.  If the desired
behaviour (i.e. "later fetch do not screw up") can be tested
directly like the later parts of the test in this patch does, how
that desired behaviour is implemented should not have to be cast in
stone with these tests.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv5] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 20:18                           ` Junio C Hamano
@ 2012-09-17 21:04                             ` Ralf Thielow
  2012-09-17 21:39                               ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-17 21:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: pclouds, git

On Mon, Sep 17, 2012 at 10:18 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Ralf Thielow <ralf.thielow@gmail.com> writes:
>
>> - handle --mirror option (test added)
>
> Handle how?  I personally think erroring out is the right way to
> handle it, but if we care about people who have been misusing the
> combination of single and mirror, the second best way would be to
> imply "mirror" and "single" combination as "bare" and "single"
> without "mirror".
>

With this patch it would be "bare" and "single", and with the next
fetch a "mirror". However, the combination of "single" and "mirror"
doesn't really make sense so I also think we should error it out.

>> - install correct refspec if the value of --branch is a tag (test added)
>
> What is the definition of "correct"?  I see the documentation says
> "--branch can also take tags and treat them like detached HEAD", and
> even though I _think_ allowing tags was a huge mistake, if we claim
> we treat it like detached HEAD, we should do the same when coming up
> with the refspec used for the follow-up "fetch".
>

This patch would install the refspec "+refs/tags/v1.7.10:refs/tags/v1.7.10",
so we would do the same with the follow-up "fetch", not?
This can be seen as "it's not a bug, it's a feature". Why not cloning a
tag of a repo if someone just want to build a tag without having anything else.

> Whatever we decide to do, the semantics we decided to use at least
> need to be described in the commit log message, not just in the
> "changes from the previous iteration".  Updating the
> "Documentation/git-clone.txt" would also be necessary.
>

Ok.

>> +test_expect_success 'refspec contains all branches by default' '
>> +     echo "+refs/heads/*:refs/remotes/origin/*" > expect &&
>> +     git --git-dir=dir_all/.git config --get remote.origin.fetch > actual &&
>> +     test_cmp expect actual
>> +'
>
> I still think these checks that know the current implementation
> details (i.e. what exact configuration variables get what exact
> values) are wrong thing to have in the longer term.  If the desired
> behaviour (i.e. "later fetch do not screw up") can be tested
> directly like the later parts of the test in this patch does, how
> that desired behaviour is implemented should not have to be cast in
> stone with these tests.

You wrote
> I'll let it pass for now, though.
so I haven't removed them yet. I'll delete them.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv5] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 21:04                             ` Ralf Thielow
@ 2012-09-17 21:39                               ` Junio C Hamano
  2012-09-18 14:08                                 ` Ralf Thielow
  0 siblings, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-17 21:39 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

>>> - install correct refspec if the value of --branch is a tag (test added)
>>
>> What is the definition of "correct"?  I see the documentation says
>> "--branch can also take tags and treat them like detached HEAD", and
>> even though I _think_ allowing tags was a huge mistake, if we claim
>> we treat it like detached HEAD, we should do the same when coming up
>> with the refspec used for the follow-up "fetch".
>>
>
> This patch would install the refspec "+refs/tags/v1.7.10:refs/tags/v1.7.10",
> so we would do the same with the follow-up "fetch", not?
> This can be seen as "it's not a bug, it's a feature". Why not cloning a
> tag of a repo if someone just want to build a tag without having anything else.

Even though I did say I thought allowing tags was a huge mistake, I
was not suggesting to break existing users by making such a clone
into an error.

But the main point of the discussion is what should happen upon the
next "git fetch" in the repository, no?  Shouldn't the refspec be
the same as the case where you "clone --single" a repository whose
HEAD is detached at v1.7.10 in that example, instead of saying
"fetch the same tag over and over"?  After all that is the way I
expect that most people would read "treat them line detached HEAD"
in the documentation.  Subsequent "git fetch" would fetch from the
HEAD of the upstream just like a clone from a repository with a
detached HEAD.

The above is *not* a rhetorical question; I just do not think of a
sensible reason why we want a refspec that says "keep updating the
v1.7.10 tag, as it might change on the other end, and do not bother
what other things that happen in that upstream repository".  What
sensible workflow would benefit from such a refspec?

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 20:08                       ` Junio C Hamano
@ 2012-09-18  1:02                         ` Nguyen Thai Ngoc Duy
  0 siblings, 0 replies; 39+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-09-18  1:02 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Ralf Thielow, git

On Tue, Sep 18, 2012 at 3:08 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
>
>> --mirror --single-branch combination does not look right. The "heads/"
>> part is missing..
>
> What does it supposed to do in the first place?  "mirror" is
> primarily about grabbing everything without leaving stuff out, and
> "single" is about grabbing only one thing without other stuff.  It
> smells like a nonsense case we didn't even bother to catch and
> diagnose as an error to me.
>
> Besides, mirror implies bare, so we would expect to see
>
>     refs/heads/$single:refs/heads/$single
>
> and that matches what the "single" gives us without "mirror", no?

Yes that's what I think it should do too.

> How about explicitly forbidding that combination, or ignoring mirror
> when single is given?

I see nothing wrong with mirroring just one branch. But if handling it
is too complex than forbidding it is fine.
-- 
Duy

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 20:09                         ` [PATCHv4] " Junio C Hamano
@ 2012-09-18  1:04                           ` Nguyen Thai Ngoc Duy
  2012-09-18  3:56                             ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-09-18  1:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Ralf Thielow, git

On Tue, Sep 18, 2012 at 3:09 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
>
>> On Mon, Sep 17, 2012 at 7:06 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
>>> --mirror --single-branch combination does not look right. The "heads/"
>>> part is missing..
>>
>> It also does not look right for cloning a tag:
>>
>> $ LANG=C ./git clone --single-branch --branch=v1.7.0 .git abc
>
> What does it even _mean_ to clone a single branch and give a tag,
> not a branch, to the --branch option?  Again, shouldn't it be
> diagnosed as an error in the first place?

That could be misleading. The original purpose is to clone just one
ref, be it a branch or a tag. You might want to work on top of a
specific version and may not want to clone everything. For cloning a
tag, we're put in detached head state immediately.
-- 
Duy

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv4] clone --single: limit the fetch refspec to fetched branch
  2012-09-18  1:04                           ` Nguyen Thai Ngoc Duy
@ 2012-09-18  3:56                             ` Junio C Hamano
  0 siblings, 0 replies; 39+ messages in thread
From: Junio C Hamano @ 2012-09-18  3:56 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: Ralf Thielow, git

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:

> On Tue, Sep 18, 2012 at 3:09 AM, Junio C Hamano <gitster@pobox.com> wrote:
>> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
>>
>>> On Mon, Sep 17, 2012 at 7:06 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
>>>> --mirror --single-branch combination does not look right. The "heads/"
>>>> part is missing..
>>>
>>> It also does not look right for cloning a tag:
>>>
>>> $ LANG=C ./git clone --single-branch --branch=v1.7.0 .git abc
>>
>> What does it even _mean_ to clone a single branch and give a tag,
>> not a branch, to the --branch option?  Again, shouldn't it be
>> diagnosed as an error in the first place?
>
> That could be misleading. The original purpose is to clone just one
> ref, be it a branch or a tag. You might want to work on top of a
> specific version and may not want to clone everything.

Yeah, see my other comments.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv5] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 21:39                               ` Junio C Hamano
@ 2012-09-18 14:08                                 ` Ralf Thielow
  2012-09-18 16:57                                   ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-18 14:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: pclouds, git

On Mon, Sep 17, 2012 at 11:39 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Ralf Thielow <ralf.thielow@gmail.com> writes:
>
>>>> - install correct refspec if the value of --branch is a tag (test added)
>>>
>>> What is the definition of "correct"?  I see the documentation says
>>> "--branch can also take tags and treat them like detached HEAD", and
>>> even though I _think_ allowing tags was a huge mistake, if we claim
>>> we treat it like detached HEAD, we should do the same when coming up
>>> with the refspec used for the follow-up "fetch".
>>>
>>
>> This patch would install the refspec "+refs/tags/v1.7.10:refs/tags/v1.7.10",
>> so we would do the same with the follow-up "fetch", not?
>> This can be seen as "it's not a bug, it's a feature". Why not cloning a
>> tag of a repo if someone just want to build a tag without having anything else.
>
> Even though I did say I thought allowing tags was a huge mistake, I
> was not suggesting to break existing users by making such a clone
> into an error.
>
> But the main point of the discussion is what should happen upon the
> next "git fetch" in the repository, no?  Shouldn't the refspec be
> the same as the case where you "clone --single" a repository whose
> HEAD is detached at v1.7.10 in that example, instead of saying
> "fetch the same tag over and over"?  After all that is the way I
> expect that most people would read "treat them line detached HEAD"
> in the documentation.  Subsequent "git fetch" would fetch from the
> HEAD of the upstream just like a clone from a repository with a
> detached HEAD.
>

IMO if a user uses "clone --single-branch --branch <tag>", then he/she
wants to have this tag only. Why should the next "git fetch" fetching
something different?
I read "treat them like detached HEAD" in the way that the resulting
repo is in a "detached HEAD" state.

> The above is *not* a rhetorical question; I just do not think of a
> sensible reason why we want a refspec that says "keep updating the
> v1.7.10 tag, as it might change on the other end, and do not bother
> what other things that happen in that upstream repository".  What
> sensible workflow would benefit from such a refspec?
>
>

When using a tag in a different meaning than "tag this version and
do never change it", for example if someone uses a tag to describe
which revision of the project was lastly delivered to the customer, then
they could use a tag "delivered". After a new version was delivered,
someone changes this tag from "revx" to "revy". Having such a refspec,
you can fetch this tag and always get the delivered version.
This example is very theoretically.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv5] clone --single: limit the fetch refspec to fetched branch
  2012-09-18 14:08                                 ` Ralf Thielow
@ 2012-09-18 16:57                                   ` Junio C Hamano
  0 siblings, 0 replies; 39+ messages in thread
From: Junio C Hamano @ 2012-09-18 16:57 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> IMO if a user uses "clone --single-branch --branch <tag>", then he/she
> wants to have this tag only. Why should the next "git fetch" fetching
> something different?

OK, I can buy that.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCHv6] clone --single: limit the fetch refspec to fetched branch
  2012-09-17 19:21                         ` [PATCHv5] " Ralf Thielow
  2012-09-17 20:18                           ` Junio C Hamano
@ 2012-09-18 19:14                           ` Ralf Thielow
  2012-09-18 19:42                             ` Junio C Hamano
                                               ` (2 more replies)
  1 sibling, 3 replies; 39+ messages in thread
From: Ralf Thielow @ 2012-09-18 19:14 UTC (permalink / raw)
  To: gitster; +Cc: pclouds, git, Ralf Thielow

After running "git clone --single", the resulting repository has the
usual default "+refs/heads/*:refs/remotes/origin/*" wildcard fetch
refspec installed, which means that a subsequent "git fetch" will
end up grabbing all the other branches.

Update the fetch refspec to cover only the singly cloned ref instead
to correct this.

That means:
If "--single" is used without "--branch" or "--mirror", the
fetch refspec covers the branch on which remote's HEAD points to.
If "--single" is used with "--branch", it'll cover only the branch
specified in the "--branch" option.
If "--single" is combined with "--mirror", then it'll cover all
refs of the cloned repository.
If "--single" is used with "--branch" that specifies a tag, then
it'll cover only the ref for this tag.

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---

changes in v6
- remove initial created tests (they tested in a too deep level)
- add tests for "--mirror" option
- add tests for the case of cloning a tag
- update commit message

I've tried to update "Documentation/git-clone.txt", but I don't
know in which way this patch changes already described behaviour.
The resulting refspec seems only be covered in the last part of
the "--single-branch" section by describing "--no-single-branch",
but this hasn't changed. Or did I miss something?

 builtin/clone.c          |  66 ++++++++++++++++-----
 t/t5709-clone-refspec.sh | 145 +++++++++++++++++++++++++++++++++++++++++++++++
 2 Dateien geändert, 197 Zeilen hinzugefügt(+), 14 Zeilen entfernt(-)
 create mode 100755 t/t5709-clone-refspec.sh

diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..431635c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -610,6 +610,55 @@ static void write_config(struct string_list *config)
 	}
 }
 
+static void write_refspec_config(const char* src_ref_prefix,
+		const struct ref* our_head_points_at,
+		const struct ref* remote_head_points_at, struct strbuf* branch_top)
+{
+	struct strbuf key = STRBUF_INIT;
+	struct strbuf value = STRBUF_INIT;
+
+	if (option_mirror || !option_bare) {
+		if (option_single_branch && !option_mirror) {
+			if (option_branch) {
+				if (strstr(our_head_points_at->name, "refs/tags/"))
+					strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
+						our_head_points_at->name);
+				else
+					strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+						branch_top->buf, option_branch);
+			} else if (remote_head_points_at) {
+				strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
+						branch_top->buf,
+						skip_prefix(remote_head_points_at->name, "refs/heads/"));
+			}
+			/*
+			 * otherwise, the next "git fetch" will
+			 * simply fetch from HEAD without updating
+			 * any remote tracking branch, which is what
+			 * we want.
+			 */
+		} else {
+			strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
+		}
+		/* Configure the remote */
+		if (value.len) {
+			strbuf_reset(&key);
+			strbuf_addf(&key, "remote.%s.fetch", option_origin);
+			git_config_set_multivar(key.buf, value.buf, "^$", 0);
+			strbuf_reset(&key);
+
+			if (option_mirror) {
+				strbuf_addf(&key, "remote.%s.mirror", option_origin);
+				git_config_set(key.buf, "true");
+				strbuf_reset(&key);
+			}
+		}
+	}
+
+	strbuf_release(&key);
+	strbuf_release(&value);
+}
+
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
 	int is_bundle = 0, is_local;
@@ -755,20 +804,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	}
 
 	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
-	if (option_mirror || !option_bare) {
-		/* Configure the remote */
-		strbuf_addf(&key, "remote.%s.fetch", option_origin);
-		git_config_set_multivar(key.buf, value.buf, "^$", 0);
-		strbuf_reset(&key);
-
-		if (option_mirror) {
-			strbuf_addf(&key, "remote.%s.mirror", option_origin);
-			git_config_set(key.buf, "true");
-			strbuf_reset(&key);
-		}
-	}
-
 	strbuf_addf(&key, "remote.%s.url", option_origin);
 	git_config_set(key.buf, repo);
 	strbuf_reset(&key);
@@ -853,6 +888,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 					      "refs/heads/master");
 	}
 
+	write_refspec_config(src_ref_prefix, our_head_points_at,
+			remote_head_points_at, &branch_top);
+
 	if (is_local)
 		clone_local(path, git_dir);
 	else if (refs && complete_refs_before_fetch)
diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
new file mode 100755
index 0000000..8d32a97
--- /dev/null
+++ b/t/t5709-clone-refspec.sh
@@ -0,0 +1,145 @@
+#!/bin/sh
+
+test_description='test refspec written by clone-command'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	# Make two branches, "master" and "side"
+	echo one >file &&
+	git add file &&
+	git commit -m one &&
+	echo two >file &&
+	git commit -a -m two &&
+	git tag two &&
+	echo three >file &&
+	git commit -a -m three &&
+	git checkout -b side &&
+	echo four >file &&
+	git commit -a -m four &&
+	git checkout master &&
+
+	# default clone
+	git clone . dir_all &&
+
+	# default --single that follows HEAD=master
+	git clone --single-branch . dir_master &&
+
+	# default --single that follows HEAD=side
+	git checkout side &&
+	git clone --single-branch . dir_side &&
+
+	# explicit --single that follows side
+	git checkout master &&
+	git clone --single-branch --branch side . dir_side2 &&
+
+	# default --single with --mirror
+	git clone --single-branch --mirror . dir_mirror &&
+
+	# default --single with --branch and --mirror
+	git clone --single-branch --mirror --branch side . dir_mirror_side &&
+
+	# --single that does not know what branch to follow
+	git checkout two^ &&
+	git clone --single-branch . dir_detached &&
+
+	# explicit --single with tag
+	git clone --single-branch --branch two . dir_tag &&
+
+	# advance both "master" and "side" branches
+	git checkout side &&
+	echo five >file &&
+	git commit -a -m five &&
+	git checkout master &&
+	echo six >file &&
+	git commit -a -m six
+'
+
+test_expect_success 'by default all branches will be kept updated' '
+	(
+		cd dir_all && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# follow both master and side
+	git for-each-ref refs/heads >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at master' '
+	(
+		cd dir_master && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow master
+	git for-each-ref refs/heads/master >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at side' '
+	(
+		cd dir_side && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow side
+	git for-each-ref refs/heads/side >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch side' '
+	(
+		cd dir_side2 && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow side
+	git for-each-ref refs/heads/side >expect &&
+	test_cmp expect actual
+'
+
+
+test_expect_success '--single-branch with explicit --branch tag' '
+	(
+		cd dir_tag && git fetch &&
+		git for-each-ref refs/tags >../actual
+	) &&
+	git for-each-ref refs/tags >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with --mirror' '
+	(
+		cd dir_mirror && git fetch &&
+		git for-each-ref refs > ../actual
+	) &&
+	git for-each-ref refs >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch and --mirror' '
+	(
+		cd dir_mirror_side && git fetch &&
+		git for-each-ref refs > ../actual
+	) &&
+	git for-each-ref refs >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with detached' '
+	(
+		cd dir_detached && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	)
+	# nothing
+	>expect &&
+	test_cmp expect actual
+'
+
+test_done
-- 
1.7.12.396.g7954078

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCHv6] clone --single: limit the fetch refspec to fetched branch
  2012-09-18 19:14                           ` [PATCHv6] " Ralf Thielow
@ 2012-09-18 19:42                             ` Junio C Hamano
  2012-09-18 19:45                             ` Junio C Hamano
  2012-09-19  7:36                             ` [PATCHv6] " Nguyen Thai Ngoc Duy
  2 siblings, 0 replies; 39+ messages in thread
From: Junio C Hamano @ 2012-09-18 19:42 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> After running "git clone --single", the resulting repository has the
> usual default "+refs/heads/*:refs/remotes/origin/*" wildcard fetch
> refspec installed, which means that a subsequent "git fetch" will
> end up grabbing all the other branches.
>
> Update the fetch refspec to cover only the singly cloned ref instead
> to correct this.
>
> That means:
> If "--single" is used without "--branch" or "--mirror", the
> fetch refspec covers the branch on which remote's HEAD points to.
> If "--single" is used with "--branch", it'll cover only the branch
> specified in the "--branch" option.
> If "--single" is combined with "--mirror", then it'll cover all
> refs of the cloned repository.
> If "--single" is used with "--branch" that specifies a tag, then
> it'll cover only the ref for this tag.
>
> Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
> ---
>
> changes in v6
> - remove initial created tests (they tested in a too deep level)
> - add tests for "--mirror" option
> - add tests for the case of cloning a tag
> - update commit message
>
> I've tried to update "Documentation/git-clone.txt", but I don't
> know in which way this patch changes already described behaviour.
> The resulting refspec seems only be covered in the last part of
> the "--single-branch" section by describing "--no-single-branch",
> but this hasn't changed. Or did I miss something?

I do not think we are changing anything.  The whole "--single-branch"
was an half-baked afterthought hack that nobody anticipated the user
to later issue "git fetch" in the resulting repository, and everybody
involved in the series (the maintainer included) were just happy to
see the resulting code only transferred objects needed for the branch
without wasting bandwidth for objects needed for other branches, and
stopped thinking beyond that X-<.

If anything, we need to _add_ the description of what happens when
further fetches are done.  The second and the third paragraph in
the DESCRIPTION section talks only about the normal case, so at
least at the end of the second paragraph we should say "But if you
use --single-branch, all of this is different".  And what happens
when you do use --single-branch should be described in the part that
describes that option, e.g.

 Documentation/git-clone.txt | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git c/Documentation/git-clone.txt w/Documentation/git-clone.txt
index c1ddd4c..f59bc49 100644
--- c/Documentation/git-clone.txt
+++ w/Documentation/git-clone.txt
@@ -29,7 +29,8 @@ currently active branch.
 After the clone, a plain `git fetch` without arguments will update
 all the remote-tracking branches, and a `git pull` without
 arguments will in addition merge the remote master branch into the
-current master branch, if any.
+current master branch, if any (this is untrue when "--single-branch"
+is given; see below).
 
 This default configuration is achieved by creating references to
 the remote branch heads under `refs/remotes/origin` and
@@ -152,9 +153,11 @@ objects from the source repository into a pack in the cloned repository.
 -b <name>::
 	Instead of pointing the newly created HEAD to the branch pointed
 	to by the cloned repository's HEAD, point to `<name>` branch
-	instead. `--branch` can also take tags and treat them like
-	detached HEAD. In a non-bare repository, this is the branch
+	instead. In a non-bare repository, this is the branch
 	that will be checked out.
++
+`--branch` can also take tags and detaches the HEAD
+at that commit in the resulting repository. 
 
 --upload-pack <upload-pack>::
 -u <upload-pack>::
@@ -193,6 +196,12 @@ objects from the source repository into a pack in the cloned repository.
 	clone with the `--depth` option, this is the default, unless
 	`--no-single-branch` is given to fetch the histories near the
 	tips of all branches.
++
+Further fetches into the resulting repository will only update the
+remote tracking branch for the branch this option was used for the
+initial cloning.  If the HEAD at the remote did not point at any
+branch when `--single-branch` clone was made, no remote tracking
+branch is created.
 
 --recursive::
 --recurse-submodules::

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCHv6] clone --single: limit the fetch refspec to fetched branch
  2012-09-18 19:14                           ` [PATCHv6] " Ralf Thielow
  2012-09-18 19:42                             ` Junio C Hamano
@ 2012-09-18 19:45                             ` Junio C Hamano
  2012-09-19 16:45                               ` [PATCHv7] " Ralf Thielow
  2012-09-19  7:36                             ` [PATCHv6] " Nguyen Thai Ngoc Duy
  2 siblings, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-18 19:45 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> + ...
> +	# explicit --single with tag
> +	git clone --single-branch --branch two . dir_tag &&
> +
> +	# advance both "master" and "side" branches
> +	git checkout side &&
> +	echo five >file &&
> +	git commit -a -m five &&
> +	git checkout master &&
> +	echo six >file &&
> +	git commit -a -m six

Don't we also want to cover your "delivery" tag scenario by updating
the tag "two" before letting the clones fetch in the following test?

> + ...
> +test_expect_success '--single-branch with explicit --branch tag' '
> +	(
> +		cd dir_tag && git fetch &&
> +		git for-each-ref refs/tags >../actual
> +	) &&
> +	git for-each-ref refs/tags >expect &&
> +	test_cmp expect actual
> +'

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv6] clone --single: limit the fetch refspec to fetched branch
  2012-09-18 19:14                           ` [PATCHv6] " Ralf Thielow
  2012-09-18 19:42                             ` Junio C Hamano
  2012-09-18 19:45                             ` Junio C Hamano
@ 2012-09-19  7:36                             ` Nguyen Thai Ngoc Duy
  2012-09-19  8:24                               ` Ralf Thielow
  2 siblings, 1 reply; 39+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-09-19  7:36 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: gitster, git

On Wed, Sep 19, 2012 at 2:14 AM, Ralf Thielow <ralf.thielow@gmail.com> wrote:
> +test_expect_success '--single-branch with explicit --branch tag' '
> +       (
> +               cd dir_tag && git fetch &&
> +               git for-each-ref refs/tags >../actual
> +       ) &&
> +       git for-each-ref refs/tags >expect &&
> +       test_cmp expect actual
> +'

We should have added the tag right after cloning, not until the first
git-fetch. Not that I object how you do it in this patch. Just a note
to myself that if I'm going to do that, I'll need to update this test
to update the change tag before fetching and verify the tag is updated
after git-fetch.
-- 
Duy

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCHv6] clone --single: limit the fetch refspec to fetched branch
  2012-09-19  7:36                             ` [PATCHv6] " Nguyen Thai Ngoc Duy
@ 2012-09-19  8:24                               ` Ralf Thielow
  0 siblings, 0 replies; 39+ messages in thread
From: Ralf Thielow @ 2012-09-19  8:24 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: gitster, git

On Wed, Sep 19, 2012 at 9:36 AM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> On Wed, Sep 19, 2012 at 2:14 AM, Ralf Thielow <ralf.thielow@gmail.com> wrote:
>> +test_expect_success '--single-branch with explicit --branch tag' '
>> +       (
>> +               cd dir_tag && git fetch &&
>> +               git for-each-ref refs/tags >../actual
>> +       ) &&
>> +       git for-each-ref refs/tags >expect &&
>> +       test_cmp expect actual
>> +'
>
> We should have added the tag right after cloning, not until the first
> git-fetch. Not that I object how you do it in this patch. Just a note
> to myself that if I'm going to do that, I'll need to update this test
> to update the change tag before fetching and verify the tag is updated
> after git-fetch.
> --
> Duy

Right. I'll create two tests to replace this one. The first test
verifys that the tag
has been added after cloning. And in the second test, the tag gets updated in
the cloned repository and we verify that the next fetch updates the tag, which
catches my "delivery" tag example.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCHv7] clone --single: limit the fetch refspec to fetched branch
  2012-09-18 19:45                             ` Junio C Hamano
@ 2012-09-19 16:45                               ` Ralf Thielow
  2012-09-19 23:26                                 ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-19 16:45 UTC (permalink / raw)
  To: gitster; +Cc: pclouds, git, Ralf Thielow

After running "git clone --single", the resulting repository has the
usual default "+refs/heads/*:refs/remotes/origin/*" wildcard fetch
refspec installed, which means that a subsequent "git fetch" will
end up grabbing all the other branches.

Update the fetch refspec to cover only the singly cloned ref instead
to correct this.

That means:
If "--single" is used without "--branch" or "--mirror", the
fetch refspec covers the branch on which remote's HEAD points to.
If "--single" is used with "--branch", it'll cover only the branch
specified in the "--branch" option.
If "--single" is combined with "--mirror", then it'll cover all
refs of the cloned repository.
If "--single" is used with "--branch" that specifies a tag, then
it'll cover only the ref for this tag.

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---

Changes in v7:
- remove a test which has shown that after the next "git fetch"
  the tags will be the same (was actually a bit senseless)
- add a test to show that the initial clone with "--single" fetches tags
- add a test to show when using "--single" with "--branch"
  which points to a tag, then the next "git fetch" will update
  this tag if it was updated in the cloned repository
- update documentation of "git clone" (Thanks to Junio)

 Documentation/git-clone.txt |  15 +++--
 builtin/clone.c             |  66 +++++++++++++++----
 t/t5709-clone-refspec.sh    | 155 ++++++++++++++++++++++++++++++++++++++++++++
 3 Dateien geändert, 218 Zeilen hinzugefügt(+), 18 Zeilen entfernt(-)
 create mode 100755 t/t5709-clone-refspec.sh

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index c1ddd4c..6d98ef3 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -29,7 +29,8 @@ currently active branch.
 After the clone, a plain `git fetch` without arguments will update
 all the remote-tracking branches, and a `git pull` without
 arguments will in addition merge the remote master branch into the
-current master branch, if any.
+current master branch, if any (this is untrue when "--single-branch"
+is given; see below).
 
 This default configuration is achieved by creating references to
 the remote branch heads under `refs/remotes/origin` and
@@ -152,9 +153,10 @@ objects from the source repository into a pack in the cloned repository.
 -b <name>::
 	Instead of pointing the newly created HEAD to the branch pointed
 	to by the cloned repository's HEAD, point to `<name>` branch
-	instead. `--branch` can also take tags and treat them like
-	detached HEAD. In a non-bare repository, this is the branch
-	that will be checked out.
+	instead. In a non-bare repository, this is the branch that will
+	be checked out.
+	`--branch` can also take tags and detaches the HEAD at that commit
+	in the resulting repository.
 
 --upload-pack <upload-pack>::
 -u <upload-pack>::
@@ -193,6 +195,11 @@ objects from the source repository into a pack in the cloned repository.
 	clone with the `--depth` option, this is the default, unless
 	`--no-single-branch` is given to fetch the histories near the
 	tips of all branches.
+	Further fetches into the resulting repository will only update the
+	remote tracking branch for the branch this option was used for the
+	initial cloning.  If the HEAD at the remote did not point at any
+	branch when `--single-branch` clone was made, no remote tracking
+	branch is created.
 
 --recursive::
 --recurse-submodules::
diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..431635c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -610,6 +610,55 @@ static void write_config(struct string_list *config)
 	}
 }
 
+static void write_refspec_config(const char* src_ref_prefix,
+		const struct ref* our_head_points_at,
+		const struct ref* remote_head_points_at, struct strbuf* branch_top)
+{
+	struct strbuf key = STRBUF_INIT;
+	struct strbuf value = STRBUF_INIT;
+
+	if (option_mirror || !option_bare) {
+		if (option_single_branch && !option_mirror) {
+			if (option_branch) {
+				if (strstr(our_head_points_at->name, "refs/tags/"))
+					strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
+						our_head_points_at->name);
+				else
+					strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+						branch_top->buf, option_branch);
+			} else if (remote_head_points_at) {
+				strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
+						branch_top->buf,
+						skip_prefix(remote_head_points_at->name, "refs/heads/"));
+			}
+			/*
+			 * otherwise, the next "git fetch" will
+			 * simply fetch from HEAD without updating
+			 * any remote tracking branch, which is what
+			 * we want.
+			 */
+		} else {
+			strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
+		}
+		/* Configure the remote */
+		if (value.len) {
+			strbuf_reset(&key);
+			strbuf_addf(&key, "remote.%s.fetch", option_origin);
+			git_config_set_multivar(key.buf, value.buf, "^$", 0);
+			strbuf_reset(&key);
+
+			if (option_mirror) {
+				strbuf_addf(&key, "remote.%s.mirror", option_origin);
+				git_config_set(key.buf, "true");
+				strbuf_reset(&key);
+			}
+		}
+	}
+
+	strbuf_release(&key);
+	strbuf_release(&value);
+}
+
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
 	int is_bundle = 0, is_local;
@@ -755,20 +804,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	}
 
 	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
-	if (option_mirror || !option_bare) {
-		/* Configure the remote */
-		strbuf_addf(&key, "remote.%s.fetch", option_origin);
-		git_config_set_multivar(key.buf, value.buf, "^$", 0);
-		strbuf_reset(&key);
-
-		if (option_mirror) {
-			strbuf_addf(&key, "remote.%s.mirror", option_origin);
-			git_config_set(key.buf, "true");
-			strbuf_reset(&key);
-		}
-	}
-
 	strbuf_addf(&key, "remote.%s.url", option_origin);
 	git_config_set(key.buf, repo);
 	strbuf_reset(&key);
@@ -853,6 +888,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 					      "refs/heads/master");
 	}
 
+	write_refspec_config(src_ref_prefix, our_head_points_at,
+			remote_head_points_at, &branch_top);
+
 	if (is_local)
 		clone_local(path, git_dir);
 	else if (refs && complete_refs_before_fetch)
diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
new file mode 100755
index 0000000..69a0779
--- /dev/null
+++ b/t/t5709-clone-refspec.sh
@@ -0,0 +1,155 @@
+#!/bin/sh
+
+test_description='test refspec written by clone-command'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	# Make two branches, "master" and "side"
+	echo one >file &&
+	git add file &&
+	git commit -m one &&
+	echo two >file &&
+	git commit -a -m two &&
+	git tag two &&
+	echo three >file &&
+	git commit -a -m three &&
+	git checkout -b side &&
+	echo four >file &&
+	git commit -a -m four &&
+	git checkout master &&
+
+	# default clone
+	git clone . dir_all &&
+
+	# default --single that follows HEAD=master
+	git clone --single-branch . dir_master &&
+
+	# default --single that follows HEAD=side
+	git checkout side &&
+	git clone --single-branch . dir_side &&
+
+	# explicit --single that follows side
+	git checkout master &&
+	git clone --single-branch --branch side . dir_side2 &&
+
+	# default --single with --mirror
+	git clone --single-branch --mirror . dir_mirror &&
+
+	# default --single with --branch and --mirror
+	git clone --single-branch --mirror --branch side . dir_mirror_side &&
+
+	# --single that does not know what branch to follow
+	git checkout two^ &&
+	git clone --single-branch . dir_detached &&
+
+	# explicit --single with tag
+	git clone --single-branch --branch two . dir_tag &&
+
+	# advance both "master" and "side" branches
+	git checkout side &&
+	echo five >file &&
+	git commit -a -m five &&
+	git checkout master &&
+	echo six >file &&
+	git commit -a -m six
+'
+
+test_expect_success 'by default all branches will be kept updated' '
+	(
+		cd dir_all && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# follow both master and side
+	git for-each-ref refs/heads >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at master' '
+	(
+		cd dir_master && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow master
+	git for-each-ref refs/heads/master >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at side' '
+	(
+		cd dir_side && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow side
+	git for-each-ref refs/heads/side >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch side' '
+	(
+		cd dir_side2 && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow side
+	git for-each-ref refs/heads/side >expect &&
+	test_cmp expect actual
+'
+
+
+test_expect_success '--single-branch fetches tags' '
+	(
+		cd dir_all &&
+		git for-each-ref refs/tags >../actual
+	) &&
+	git for-each-ref refs/tags >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch with tag fetches updated tag' '
+	git tag -d two && git tag two &&
+	(
+		cd dir_tag && git fetch &&
+		git for-each-ref refs/tags >../actual
+	) &&
+	git for-each-ref refs/tags >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with --mirror' '
+	(
+		cd dir_mirror && git fetch &&
+		git for-each-ref refs > ../actual
+	) &&
+	git for-each-ref refs >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch and --mirror' '
+	(
+		cd dir_mirror_side && git fetch &&
+		git for-each-ref refs > ../actual
+	) &&
+	git for-each-ref refs >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with detached' '
+	(
+		cd dir_detached && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	)
+	# nothing
+	>expect &&
+	test_cmp expect actual
+'
+
+test_done
-- 
1.7.12.396.g7954078

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCHv7] clone --single: limit the fetch refspec to fetched branch
  2012-09-19 16:45                               ` [PATCHv7] " Ralf Thielow
@ 2012-09-19 23:26                                 ` Junio C Hamano
  2012-09-20 18:04                                   ` [PATCHv8] " Ralf Thielow
  0 siblings, 1 reply; 39+ messages in thread
From: Junio C Hamano @ 2012-09-19 23:26 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Ralf Thielow <ralf.thielow@gmail.com> writes:

> diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
> new file mode 100755
> index 0000000..69a0779
> --- /dev/null
> +++ b/t/t5709-clone-refspec.sh
> @@ -0,0 +1,155 @@
> +#!/bin/sh
> +
> +test_description='test refspec written by clone-command'
> +. ./test-lib.sh
> +
> +test_expect_success 'setup' '
> +	# Make two branches, "master" and "side"
> + ...
> +	# explicit --single with tag
> +	git clone --single-branch --branch two . dir_tag &&
> +
> +	# advance both "master" and "side" branches
> +	git checkout side &&
> +	echo five >file &&
> +	git commit -a -m five &&
> +	git checkout master &&
> +	echo six >file &&
> +	git commit -a -m six
> +'
> +
> + ...
> +test_expect_success '--single-branch with explicit --branch with tag fetches updated tag' '
> +	git tag -d two && git tag two &&

Curious.  Was it insufficient to update this tag at the end of the
"setup" process like everybody else where

	# advance both "master" and "side" branches

happens?

Not that it is wrong to do this, but it looked somewhat
inconsistent.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCHv8] clone --single: limit the fetch refspec to fetched branch
  2012-09-19 23:26                                 ` Junio C Hamano
@ 2012-09-20 18:04                                   ` Ralf Thielow
  2012-09-20 21:17                                     ` Junio C Hamano
  0 siblings, 1 reply; 39+ messages in thread
From: Ralf Thielow @ 2012-09-20 18:04 UTC (permalink / raw)
  To: gitster; +Cc: pclouds, git, Ralf Thielow

After running "git clone --single", the resulting repository has the
usual default "+refs/heads/*:refs/remotes/origin/*" wildcard fetch
refspec installed, which means that a subsequent "git fetch" will
end up grabbing all the other branches.

Update the fetch refspec to cover only the singly cloned ref instead
to correct this.

That means:
If "--single" is used without "--branch" or "--mirror", the
fetch refspec covers the branch on which remote's HEAD points to.
If "--single" is used with "--branch", it'll cover only the branch
specified in the "--branch" option.
If "--single" is combined with "--mirror", then it'll cover all
refs of the cloned repository.
If "--single" is used with "--branch" that specifies a tag, then
it'll cover only the ref for this tag.

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---

changes in v8:
- remove unnecessary strbuf_reset
- remove test from v7 which has shown that tags get fetched when cloning
- add test to show that tags will not being updated when using simple "git clone"
- change position of the tag in the setup, not directly in the test

 Documentation/git-clone.txt |  15 +++--
 builtin/clone.c             |  65 ++++++++++++++----
 t/t5709-clone-refspec.sh    | 156 ++++++++++++++++++++++++++++++++++++++++++++
 3 Dateien geändert, 218 Zeilen hinzugefügt(+), 18 Zeilen entfernt(-)
 create mode 100755 t/t5709-clone-refspec.sh

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index c1ddd4c..6d98ef3 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -29,7 +29,8 @@ currently active branch.
 After the clone, a plain `git fetch` without arguments will update
 all the remote-tracking branches, and a `git pull` without
 arguments will in addition merge the remote master branch into the
-current master branch, if any.
+current master branch, if any (this is untrue when "--single-branch"
+is given; see below).
 
 This default configuration is achieved by creating references to
 the remote branch heads under `refs/remotes/origin` and
@@ -152,9 +153,10 @@ objects from the source repository into a pack in the cloned repository.
 -b <name>::
 	Instead of pointing the newly created HEAD to the branch pointed
 	to by the cloned repository's HEAD, point to `<name>` branch
-	instead. `--branch` can also take tags and treat them like
-	detached HEAD. In a non-bare repository, this is the branch
-	that will be checked out.
+	instead. In a non-bare repository, this is the branch that will
+	be checked out.
+	`--branch` can also take tags and detaches the HEAD at that commit
+	in the resulting repository.
 
 --upload-pack <upload-pack>::
 -u <upload-pack>::
@@ -193,6 +195,11 @@ objects from the source repository into a pack in the cloned repository.
 	clone with the `--depth` option, this is the default, unless
 	`--no-single-branch` is given to fetch the histories near the
 	tips of all branches.
+	Further fetches into the resulting repository will only update the
+	remote tracking branch for the branch this option was used for the
+	initial cloning.  If the HEAD at the remote did not point at any
+	branch when `--single-branch` clone was made, no remote tracking
+	branch is created.
 
 --recursive::
 --recurse-submodules::
diff --git a/builtin/clone.c b/builtin/clone.c
index 5e8f3ba..047239c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -610,6 +610,54 @@ static void write_config(struct string_list *config)
 	}
 }
 
+static void write_refspec_config(const char* src_ref_prefix,
+		const struct ref* our_head_points_at,
+		const struct ref* remote_head_points_at, struct strbuf* branch_top)
+{
+	struct strbuf key = STRBUF_INIT;
+	struct strbuf value = STRBUF_INIT;
+
+	if (option_mirror || !option_bare) {
+		if (option_single_branch && !option_mirror) {
+			if (option_branch) {
+				if (strstr(our_head_points_at->name, "refs/tags/"))
+					strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
+						our_head_points_at->name);
+				else
+					strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+						branch_top->buf, option_branch);
+			} else if (remote_head_points_at) {
+				strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
+						branch_top->buf,
+						skip_prefix(remote_head_points_at->name, "refs/heads/"));
+			}
+			/*
+			 * otherwise, the next "git fetch" will
+			 * simply fetch from HEAD without updating
+			 * any remote tracking branch, which is what
+			 * we want.
+			 */
+		} else {
+			strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
+		}
+		/* Configure the remote */
+		if (value.len) {
+			strbuf_addf(&key, "remote.%s.fetch", option_origin);
+			git_config_set_multivar(key.buf, value.buf, "^$", 0);
+			strbuf_reset(&key);
+
+			if (option_mirror) {
+				strbuf_addf(&key, "remote.%s.mirror", option_origin);
+				git_config_set(key.buf, "true");
+				strbuf_reset(&key);
+			}
+		}
+	}
+
+	strbuf_release(&key);
+	strbuf_release(&value);
+}
+
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
 	int is_bundle = 0, is_local;
@@ -755,20 +803,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	}
 
 	strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
-	if (option_mirror || !option_bare) {
-		/* Configure the remote */
-		strbuf_addf(&key, "remote.%s.fetch", option_origin);
-		git_config_set_multivar(key.buf, value.buf, "^$", 0);
-		strbuf_reset(&key);
-
-		if (option_mirror) {
-			strbuf_addf(&key, "remote.%s.mirror", option_origin);
-			git_config_set(key.buf, "true");
-			strbuf_reset(&key);
-		}
-	}
-
 	strbuf_addf(&key, "remote.%s.url", option_origin);
 	git_config_set(key.buf, repo);
 	strbuf_reset(&key);
@@ -853,6 +887,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 					      "refs/heads/master");
 	}
 
+	write_refspec_config(src_ref_prefix, our_head_points_at,
+			remote_head_points_at, &branch_top);
+
 	if (is_local)
 		clone_local(path, git_dir);
 	else if (refs && complete_refs_before_fetch)
diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh
new file mode 100755
index 0000000..6f1ea98
--- /dev/null
+++ b/t/t5709-clone-refspec.sh
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+test_description='test refspec written by clone-command'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	# Make two branches, "master" and "side"
+	echo one >file &&
+	git add file &&
+	git commit -m one &&
+	echo two >file &&
+	git commit -a -m two &&
+	git tag two &&
+	echo three >file &&
+	git commit -a -m three &&
+	git checkout -b side &&
+	echo four >file &&
+	git commit -a -m four &&
+	git checkout master &&
+
+	# default clone
+	git clone . dir_all &&
+
+	# default --single that follows HEAD=master
+	git clone --single-branch . dir_master &&
+
+	# default --single that follows HEAD=side
+	git checkout side &&
+	git clone --single-branch . dir_side &&
+
+	# explicit --single that follows side
+	git checkout master &&
+	git clone --single-branch --branch side . dir_side2 &&
+
+	# default --single with --mirror
+	git clone --single-branch --mirror . dir_mirror &&
+
+	# default --single with --branch and --mirror
+	git clone --single-branch --mirror --branch side . dir_mirror_side &&
+
+	# --single that does not know what branch to follow
+	git checkout two^ &&
+	git clone --single-branch . dir_detached &&
+
+	# explicit --single with tag
+	git clone --single-branch --branch two . dir_tag &&
+
+	# advance both "master" and "side" branches
+	git checkout side &&
+	echo five >file &&
+	git commit -a -m five &&
+	git checkout master &&
+	echo six >file &&
+	git commit -a -m six &&
+
+	# update tag
+	git tag -d two && git tag two
+'
+
+test_expect_success 'by default all branches will be kept updated' '
+	(
+		cd dir_all && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# follow both master and side
+	git for-each-ref refs/heads >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'by default no tags will be kept updated' '
+	(
+		cd dir_all && git fetch &&
+		git for-each-ref refs/tags >../actual
+	) &&
+	git for-each-ref refs/tags >expect &&
+	test_must_fail test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at master' '
+	(
+		cd dir_master && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow master
+	git for-each-ref refs/heads/master >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at side' '
+	(
+		cd dir_side && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow side
+	git for-each-ref refs/heads/side >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch side' '
+	(
+		cd dir_side2 && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	) &&
+	# only follow side
+	git for-each-ref refs/heads/side >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch with tag fetches updated tag' '
+	(
+		cd dir_tag && git fetch &&
+		git for-each-ref refs/tags >../actual
+	) &&
+	git for-each-ref refs/tags >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with --mirror' '
+	(
+		cd dir_mirror && git fetch &&
+		git for-each-ref refs > ../actual
+	) &&
+	git for-each-ref refs >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with explicit --branch and --mirror' '
+	(
+		cd dir_mirror_side && git fetch &&
+		git for-each-ref refs > ../actual
+	) &&
+	git for-each-ref refs >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--single-branch with detached' '
+	(
+		cd dir_detached && git fetch &&
+		git for-each-ref refs/remotes/origin |
+		sed -e "/HEAD$/d" \
+		    -e "s|/remotes/origin/|/heads/|" >../actual
+	)
+	# nothing
+	>expect &&
+	test_cmp expect actual
+'
+
+test_done
-- 
1.7.12.396.g7954078

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCHv8] clone --single: limit the fetch refspec to fetched branch
  2012-09-20 18:04                                   ` [PATCHv8] " Ralf Thielow
@ 2012-09-20 21:17                                     ` Junio C Hamano
  0 siblings, 0 replies; 39+ messages in thread
From: Junio C Hamano @ 2012-09-20 21:17 UTC (permalink / raw)
  To: Ralf Thielow; +Cc: pclouds, git

Thanks.

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2012-09-20 21:17 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-13 18:38 is this behaviour expected for "git clone --single-branch"? Ralf Thielow
2012-09-13 18:45 ` Junio C Hamano
2012-09-13 18:48   ` Ralf Thielow
2012-09-14  5:09     ` [PATCH] clone: fix refspec on "--single-branch" option Ralf Thielow
2012-09-14  5:35       ` Junio C Hamano
2012-09-14  6:48         ` Junio C Hamano
2012-09-14 13:10           ` Nguyen Thai Ngoc Duy
2012-09-14 14:25             ` Ralf Thielow
2012-09-14 16:02             ` Junio C Hamano
2012-09-14 18:11           ` [PATCHv2] " Ralf Thielow
2012-09-14 19:22             ` Junio C Hamano
2012-09-14 21:13               ` [PATCHv3] " Ralf Thielow
2012-09-14 22:45                 ` Junio C Hamano
2012-09-16  8:13                   ` [PATCHv4] clone --single: limit the fetch refspec to fetched branch Ralf Thielow
2012-09-17  4:48                     ` Junio C Hamano
2012-09-17 12:06                     ` Nguyen Thai Ngoc Duy
2012-09-17 12:11                       ` Nguyen Thai Ngoc Duy
2012-09-17 19:21                         ` [PATCHv5] " Ralf Thielow
2012-09-17 20:18                           ` Junio C Hamano
2012-09-17 21:04                             ` Ralf Thielow
2012-09-17 21:39                               ` Junio C Hamano
2012-09-18 14:08                                 ` Ralf Thielow
2012-09-18 16:57                                   ` Junio C Hamano
2012-09-18 19:14                           ` [PATCHv6] " Ralf Thielow
2012-09-18 19:42                             ` Junio C Hamano
2012-09-18 19:45                             ` Junio C Hamano
2012-09-19 16:45                               ` [PATCHv7] " Ralf Thielow
2012-09-19 23:26                                 ` Junio C Hamano
2012-09-20 18:04                                   ` [PATCHv8] " Ralf Thielow
2012-09-20 21:17                                     ` Junio C Hamano
2012-09-19  7:36                             ` [PATCHv6] " Nguyen Thai Ngoc Duy
2012-09-19  8:24                               ` Ralf Thielow
2012-09-17 20:09                         ` [PATCHv4] " Junio C Hamano
2012-09-18  1:04                           ` Nguyen Thai Ngoc Duy
2012-09-18  3:56                             ` Junio C Hamano
2012-09-17 13:25                       ` Ralf Thielow
2012-09-17 20:08                       ` Junio C Hamano
2012-09-18  1:02                         ` Nguyen Thai Ngoc Duy
2012-09-14 18:42           ` [PATCH] clone: fix refspec on "--single-branch" option Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).