threads / patch / 20723

patchAdd option -b/--branch to clone for select a new HEAD

Subject: [PATCH] Add option -b/--branch to clone for select a new HEAD

## tl;dr

6 messages between Aug 24, 2009 and Aug 25, 2009. Diffs are folded; open one to read it.

replies: 5people: 3as markdown or json

Kirill A. Korinskiy· Aug 24, 2009, 20:42 UTC · lore
Sometimes (especially on production systems) we need to use only one
remote branch for building software. It really annoying to clone
origin and then swith branch by hand everytime. So this patch provide
functionality to clone remote branch with one command without using
checkout after clone.
---
 Documentation/git-clone.txt |    4 ++++
 builtin-clone.c             |   26 +++++++++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)
Show changes to 2 files +27 −3

Documentation/git-clone.txt, builtin-clone.c

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 2c63a0f..50446d2 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -127,6 +127,10 @@ objects from the source repository into a pack in the cloned repository.
 	Instead of using the remote name 'origin' to keep track
 	of the upstream repository, use <name>.
 
+--branch <name>::
+-b <name>::
+	Instead of using the remote HEAD as master, use <name> branch.
+
 --upload-pack <upload-pack>::
 -u <upload-pack>::
 	When given, and the repository to clone from is accessed
diff --git a/builtin-clone.c b/builtin-clone.c
index 32dea74..4420c68 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -41,6 +41,7 @@ static int option_quiet, option_no_checkout, option_bare, option_mirror;
 static int option_local, option_no_hardlinks, option_shared;
 static char *option_template, *option_reference, *option_depth;
 static char *option_origin = NULL;
+static char *option_branch = NULL;
 static char *option_upload_pack = "git-upload-pack";
 static int option_verbose;
 
@@ -65,6 +66,8 @@ static struct option builtin_clone_options[] = {
 		   "reference repository"),
 	OPT_STRING('o', "origin", &option_origin, "branch",
 		   "use <branch> instead of 'origin' to track upstream"),
+	OPT_STRING('b', "branch", &option_branch, "branch",
+		   "use <branch> from 'origin' as HEAD"),
 	OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
 		   "path to git-upload-pack on the remote"),
 	OPT_STRING(0, "depth", &option_depth, "depth",
@@ -347,8 +350,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	const char *repo_name, *repo, *work_tree, *git_dir;
 	char *path, *dir;
 	int dest_exists;
-	const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
-	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
+	const struct ref *refs, *head_points_at, *remote_head = NULL, *mapped_refs;
+	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT, branch_head = STRBUF_INIT;
 	struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
 	struct transport *transport = NULL;
 	char *src_ref_prefix = "refs/heads/";
@@ -372,6 +375,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 		if (option_origin)
 			die("--bare and --origin %s options are incompatible.",
 			    option_origin);
+		if (option_branch)
+			die("--bare and --branch %s options are incompatible.",
+			    option_branch);
 		option_no_checkout = 1;
 	}
 
@@ -518,7 +524,21 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
 		mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
 
-		remote_head = find_ref_by_name(refs, "HEAD");
+		if (option_branch) {
+			strbuf_addf(&branch_head, "%s%s", src_ref_prefix, option_branch);
+
+			remote_head = find_ref_by_name(refs, branch_head.buf);
+		}
+
+		if (!remote_head) {
+			if (option_branch)
+				warning("Remote branch %s not found in upstream %s"
+					", using HEAD instead",
+					option_branch, option_origin);
+
+			remote_head = find_ref_by_name(refs, "HEAD");
+		}
+
 		head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
 	}
 	else {
-- 
1.6.2
Jeff King· Aug 25, 2009, 01:57 UTC · re: Kirill A. Korinskiy · lore

Re: [PATCH] Add option -b/--branch to clone for select a new HEAD

On Tue, Aug 25, 2009 at 12:42:48AM +0400, Kirill A. Korinskiy wrote:
Show 5 quoted lines
> Sometimes (especially on production systems) we need to use only one
> remote branch for building software. It really annoying to clone
> origin and then swith branch by hand everytime. So this patch provide
> functionality to clone remote branch with one command without using
> checkout after clone.

If you are doing this a lot, it is probably a sign that you should repoint the "HEAD" of the parent repository.

That being said, you may want one branch half the time, and another branch the other half. So I think this is a good feature.

A few comments:
> ---
>  Documentation/git-clone.txt |    4 ++++
>  builtin-clone.c             |   26 +++++++++++++++++++++++---
>  2 files changed, 27 insertions(+), 3 deletions(-)
Tests?
> -	const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
> -	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
> +	const struct ref *refs, *head_points_at, *remote_head = NULL, *mapped_refs;
> +	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT, branch_head = STRBUF_INIT;

Style nit: I don't know if we have a style guideline for declaring variables, but I find these "many variables on a line" declarations annoying for reviewing, since it is hard to see what actually changed (and yes, you only added a declaration on one, so I am partially complaining about the person who came before you :) ).

> +		if (option_branch)
> +			die("--bare and --branch %s options are incompatible.",
> +			    option_branch);

Hmm. Would it perhaps make sense to have "--bare --branch foo" point the HEAD of the newly created bare repo, but not impact the (nonexistent) working tree?

-Peff
Junio C Hamano· Aug 25, 2009, 02:13 UTC · re: Jeff King · lore

Re: [PATCH] Add option -b/--branch to clone for select a new HEAD

Jeff King <peff@peff.net> writes:
Show 15 quoted lines
> On Tue, Aug 25, 2009 at 12:42:48AM +0400, Kirill A. Korinskiy wrote:
>
>> Sometimes (especially on production systems) we need to use only one
>> remote branch for building software. It really annoying to clone
>> origin and then swith branch by hand everytime. So this patch provide
>> functionality to clone remote branch with one command without using
>> checkout after clone.
>
> If you are doing this a lot, it is probably a sign that you should
> repoint the "HEAD" of the parent repository.
>
> That being said, you may want one branch half the time, and another
> branch the other half. So I think this is a good feature.
>
> A few comments:

Very good review snipped, as I agree with everything you said (except that you did not point out the lack of sign-off).

Kirill A. Korinskiy· Aug 25, 2009, 17:20 UTC · re: Junio C Hamano · lore

Sometimes (especially on production systems) we need to use only one remote branch for building software. It really annoying to clone origin and then swith branch by hand everytime. So this patch provide functionality to clone remote branch with one command without using checkout after clone.

Signed-off-by: Kirill A. Korinskiy <catap@catap.ru>
---
 Documentation/git-clone.txt |    4 ++++
 builtin-clone.c             |   23 ++++++++++++++++++++---
 t/t5706-clone-brnach.sh     |   31 +++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 3 deletions(-)
 create mode 100755 t/t5706-clone-brnach.sh
Show changes to 3 files +55 −3

Documentation/git-clone.txt, builtin-clone.c, t/t5706-clone-brnach.sh

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 2c63a0f..50446d2 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -127,6 +127,10 @@ objects from the source repository into a pack in the cloned repository.
 	Instead of using the remote name 'origin' to keep track
 	of the upstream repository, use <name>.
 
+--branch <name>::
+-b <name>::
+	Instead of using the remote HEAD as master, use <name> branch.
+
 --upload-pack <upload-pack>::
 -u <upload-pack>::
 	When given, and the repository to clone from is accessed
diff --git a/builtin-clone.c b/builtin-clone.c
index 32dea74..9cea056 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -41,6 +41,7 @@ static int option_quiet, option_no_checkout, option_bare, option_mirror;
 static int option_local, option_no_hardlinks, option_shared;
 static char *option_template, *option_reference, *option_depth;
 static char *option_origin = NULL;
+static char *option_branch = NULL;
 static char *option_upload_pack = "git-upload-pack";
 static int option_verbose;
 
@@ -65,6 +66,8 @@ static struct option builtin_clone_options[] = {
 		   "reference repository"),
 	OPT_STRING('o', "origin", &option_origin, "branch",
 		   "use <branch> instead of 'origin' to track upstream"),
+	OPT_STRING('b', "branch", &option_branch, "branch",
+		   "use <branch> from 'origin' as HEAD"),
 	OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
 		   "path to git-upload-pack on the remote"),
 	OPT_STRING(0, "depth", &option_depth, "depth",
@@ -347,8 +350,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	const char *repo_name, *repo, *work_tree, *git_dir;
 	char *path, *dir;
 	int dest_exists;
-	const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
-	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
+	const struct ref *refs, *head_points_at, *remote_head = NULL, *mapped_refs;
+	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT, branch_head = STRBUF_INIT;
 	struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
 	struct transport *transport = NULL;
 	char *src_ref_prefix = "refs/heads/";
@@ -518,7 +521,21 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
 		mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
 
-		remote_head = find_ref_by_name(refs, "HEAD");
+		if (option_branch) {
+			strbuf_addf(&branch_head, "%s%s", src_ref_prefix, option_branch);
+
+			remote_head = find_ref_by_name(refs, branch_head.buf);
+		}
+
+		if (!remote_head) {
+			if (option_branch)
+				warning("Remote branch %s not found in upstream %s"
+					", using HEAD instead",
+					option_branch, option_origin);
+
+			remote_head = find_ref_by_name(refs, "HEAD");
+		}
+
 		head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
 	}
 	else {
diff --git a/t/t5706-clone-brnach.sh b/t/t5706-clone-brnach.sh
new file mode 100755
index 0000000..1f2704b
--- /dev/null
+++ b/t/t5706-clone-brnach.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='branch clone options'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+
+	mkdir parent &&
+	(cd parent && git init &&
+	 echo one >file && git add file &&
+	 git commit -m one && git checkout -b two &&
+	 echo two >f && git add f && git commit -m two &&
+	 git checkout master)
+
+'
+
+test_expect_success 'clone' '
+
+	git clone parent clone &&
+	(cd clone && git rev-parse --verify refs/remotes/origin/master)
+
+'
+
+test_expect_success 'clone -b' '
+
+	git clone -b two parent clone-b &&
+	(cd clone && git rev-parse --verify refs/remotes/origin/two)
+
+'
+
+test_done
-- 
1.6.2
Jeff King· Aug 25, 2009, 19:00 UTC · re: Kirill A. Korinskiy · lore

Re: [PATCH] Add option -b/--branch to clone for select a new HEAD

Thanks for revising, it is looking a bit better. A few comments still, though:

On Tue, Aug 25, 2009 at 09:20:06PM +0400, Kirill A. Korinskiy wrote:
Show 5 quoted lines
> Sometimes (especially on production systems) we need to use only one
> remote branch for building software. It really annoying to clone
> origin and then swith branch by hand everytime. So this patch provide
> functionality to clone remote branch with one command without using
> checkout after clone.
Typos:
  s/It/It's/
  s/swith/switch/
  s/provide/provides/
  s/clone remote/clone a remote/
>  t/t5706-clone-brnach.sh     |   31 +++++++++++++++++++++++++++++++
Typo: s/brnach/branch/ :)
Show 13 quoted lines
> +test_expect_success 'clone' '
> +
> +	git clone parent clone &&
> +	(cd clone && git rev-parse --verify refs/remotes/origin/master)
> +
> +'
> +
> +test_expect_success 'clone -b' '
> +
> +	git clone -b two parent clone-b &&
> +	(cd clone && git rev-parse --verify refs/remotes/origin/two)
> +
> +'

Is this really testing the right thing? Shouldn't you always have refs/remotes/origin/*, no matter what "-b" says? The difference should be that HEAD in the first test will point to 'master', and to 'two' in the second test.

-Peff
Kirill A. Korinskiy· Aug 25, 2009, 12:30 UTC · re: Jeff King · lore
Sometimes (especially on production systems) we need to use only one
remote branch for building software. It really annoying to clone
origin and then swith branch by hand everytime. So this patch provide
functionality to clone remote branch with one command without using
checkout after clone.
---
 Documentation/git-clone.txt |    4 ++++
 builtin-clone.c             |   23 ++++++++++++++++++++---
 t/t5706-clone-brnach.sh     |   31 +++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 3 deletions(-)
 create mode 100755 t/t5706-clone-brnach.sh
Show changes to 3 files +55 −3

Documentation/git-clone.txt, builtin-clone.c, t/t5706-clone-brnach.sh

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 2c63a0f..50446d2 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -127,6 +127,10 @@ objects from the source repository into a pack in the cloned repository.
 	Instead of using the remote name 'origin' to keep track
 	of the upstream repository, use <name>.
 
+--branch <name>::
+-b <name>::
+	Instead of using the remote HEAD as master, use <name> branch.
+
 --upload-pack <upload-pack>::
 -u <upload-pack>::
 	When given, and the repository to clone from is accessed
diff --git a/builtin-clone.c b/builtin-clone.c
index 32dea74..9cea056 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -41,6 +41,7 @@ static int option_quiet, option_no_checkout, option_bare, option_mirror;
 static int option_local, option_no_hardlinks, option_shared;
 static char *option_template, *option_reference, *option_depth;
 static char *option_origin = NULL;
+static char *option_branch = NULL;
 static char *option_upload_pack = "git-upload-pack";
 static int option_verbose;
 
@@ -65,6 +66,8 @@ static struct option builtin_clone_options[] = {
 		   "reference repository"),
 	OPT_STRING('o', "origin", &option_origin, "branch",
 		   "use <branch> instead of 'origin' to track upstream"),
+	OPT_STRING('b', "branch", &option_branch, "branch",
+		   "use <branch> from 'origin' as HEAD"),
 	OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
 		   "path to git-upload-pack on the remote"),
 	OPT_STRING(0, "depth", &option_depth, "depth",
@@ -347,8 +350,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	const char *repo_name, *repo, *work_tree, *git_dir;
 	char *path, *dir;
 	int dest_exists;
-	const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
-	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
+	const struct ref *refs, *head_points_at, *remote_head = NULL, *mapped_refs;
+	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT, branch_head = STRBUF_INIT;
 	struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
 	struct transport *transport = NULL;
 	char *src_ref_prefix = "refs/heads/";
@@ -518,7 +521,21 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
 		mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
 
-		remote_head = find_ref_by_name(refs, "HEAD");
+		if (option_branch) {
+			strbuf_addf(&branch_head, "%s%s", src_ref_prefix, option_branch);
+
+			remote_head = find_ref_by_name(refs, branch_head.buf);
+		}
+
+		if (!remote_head) {
+			if (option_branch)
+				warning("Remote branch %s not found in upstream %s"
+					", using HEAD instead",
+					option_branch, option_origin);
+
+			remote_head = find_ref_by_name(refs, "HEAD");
+		}
+
 		head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
 	}
 	else {
diff --git a/t/t5706-clone-brnach.sh b/t/t5706-clone-brnach.sh
new file mode 100755
index 0000000..1f2704b
--- /dev/null
+++ b/t/t5706-clone-brnach.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='branch clone options'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+
+	mkdir parent &&
+	(cd parent && git init &&
+	 echo one >file && git add file &&
+	 git commit -m one && git checkout -b two &&
+	 echo two >f && git add f && git commit -m two &&
+	 git checkout master)
+
+'
+
+test_expect_success 'clone' '
+
+	git clone parent clone &&
+	(cd clone && git rev-parse --verify refs/remotes/origin/master)
+
+'
+
+test_expect_success 'clone -b' '
+
+	git clone -b two parent clone-b &&
+	(cd clone && git rev-parse --verify refs/remotes/origin/two)
+
+'
+
+test_done
-- 
1.6.2

← back to recent threads