git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v3 0/2] git-clone: Add new option --branch to override initial branch
@ 2009-03-27 17:45 Tor Arne Vestbø
  2009-03-27 17:45 ` [PATCH v3 1/2] Move find_ref_by_name_abbrev to refs.c so it can be used globally Tor Arne Vestbø
  2009-03-27 17:45 ` [PATCH v3 2/2] git-clone: Add new option --branch to override initial branch Tor Arne Vestbø
  0 siblings, 2 replies; 3+ messages in thread
From: Tor Arne Vestbø @ 2009-03-27 17:45 UTC (permalink / raw
  To: gitster; +Cc: git, Johannes.Schindelin

This mini-series is a continuation of the efforts to add add a new
option to git clone to allow overriding the initial branch.

The previous patch (v2) and discussion can be found here:

  http://thread.gmane.org/gmane.comp.version-control.git/111967/focus=111983

With Junios' comments to v2 of my patch here:

  http://thread.gmane.org/gmane.comp.version-control.git/111967/focus=111983

I believe I've covered all the issues in the review, but if there's
still issues please let me know and I'll rework the patch.

Best,

Tor Arne


Tor Arne Vestbø (2):
  Move find_ref_by_name_abbrev to refs.c so it can be used globally
  git-clone: Add new option --branch to override initial branch

 Documentation/git-clone.txt |    5 +++
 builtin-clone.c             |   71 +++++++++++++++++++++++++-----------------
 cache.h                     |    1 +
 refs.c                      |   10 ++++++
 remote.c                    |   10 ------
 t/t5702-clone-options.sh    |   70 ++++++++++++++++++++++++++++++++++++++++--
 6 files changed, 125 insertions(+), 42 deletions(-)

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

* [PATCH v3 1/2] Move find_ref_by_name_abbrev to refs.c so it can be used globally
  2009-03-27 17:45 [PATCH v3 0/2] git-clone: Add new option --branch to override initial branch Tor Arne Vestbø
@ 2009-03-27 17:45 ` Tor Arne Vestbø
  2009-03-27 17:45 ` [PATCH v3 2/2] git-clone: Add new option --branch to override initial branch Tor Arne Vestbø
  1 sibling, 0 replies; 3+ messages in thread
From: Tor Arne Vestbø @ 2009-03-27 17:45 UTC (permalink / raw
  To: gitster; +Cc: git, Johannes.Schindelin

Signed-off-by: Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
---
 cache.h  |    1 +
 refs.c   |   10 ++++++++++
 remote.c |   10 ----------
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/cache.h b/cache.h
index f48e80b..23699a8 100644
--- a/cache.h
+++ b/cache.h
@@ -815,6 +815,7 @@ struct ref {
 #define REF_TAGS	(1u << 2)
 
 extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
+extern struct ref *find_ref_by_name_abbrev(const struct ref *list, const char *name);
 
 #define CONNECT_VERBOSE       (1u << 0)
 extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
diff --git a/refs.c b/refs.c
index 26b0014..161e053 100644
--- a/refs.c
+++ b/refs.c
@@ -1644,3 +1644,13 @@ struct ref *find_ref_by_name(const struct ref *list, const char *name)
 			return (struct ref *)list;
 	return NULL;
 }
+
+struct ref *find_ref_by_name_abbrev(const struct ref *list, const char *name)
+{
+	for ( ; list; list = list->next) {
+		if (refname_match(name, list->name, ref_fetch_rules))
+			return (struct ref *)list;
+	}
+	return NULL;
+}
+
diff --git a/remote.c b/remote.c
index e5d6b10..e903b39 100644
--- a/remote.c
+++ b/remote.c
@@ -1220,16 +1220,6 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
 	return ret;
 }
 
-static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const char *name)
-{
-	const struct ref *ref;
-	for (ref = refs; ref; ref = ref->next) {
-		if (refname_match(name, ref->name, ref_fetch_rules))
-			return ref;
-	}
-	return NULL;
-}
-
 struct ref *get_remote_ref(const struct ref *remote_refs, const char *name)
 {
 	const struct ref *ref = find_ref_by_name_abbrev(remote_refs, name);
-- 
1.6.2.GIT

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

* [PATCH v3 2/2] git-clone: Add new option --branch to override initial branch
  2009-03-27 17:45 [PATCH v3 0/2] git-clone: Add new option --branch to override initial branch Tor Arne Vestbø
  2009-03-27 17:45 ` [PATCH v3 1/2] Move find_ref_by_name_abbrev to refs.c so it can be used globally Tor Arne Vestbø
@ 2009-03-27 17:45 ` Tor Arne Vestbø
  1 sibling, 0 replies; 3+ messages in thread
From: Tor Arne Vestbø @ 2009-03-27 17:45 UTC (permalink / raw
  To: gitster; +Cc: git, Johannes.Schindelin

The option '--branch' (short -b) allows the user to override the initial
branch created and checked out by git-clone (normally this is the active
branch of the remote repository).

If the selected branch is not found the operation aborts.

The rationale for this option is to allow new users to Git, who might
not be familiar with the concepts of tracking branches versus normal
branches (or even branches at all), to easily clone a repository and
start working on a branch other than the remote's active branch.

Signed-off-by: Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
---

The above situation can be found in projects which keep a master branch
for active development, as well as one or more maintenance branches for
released versions of the project. If a user would like to fix a bug for
a released version, he could use the proposed new option and simply do:

  $ git clone git://git.foo.com/project.git --branch 1.6

The manual steps to achieve the same thing would be something like:

  $ git clone -n git://git.foo.com/project.git        # (1)
  $ cd project                                        # (2)
  $ git checkout -t origin/1.6                        # (3)
  $ git branch -D master                              # (4)

A new user to Git might find this list of commands a bit daunting. It
is also somewhat fragile, as running 'git status' after step (2) will
create an index and hence prevent a checkout due to merge conflicts.

(The reason for deleting the master branch in step (4) is to prevent
errors when the user tries to push his changes to the (rebased) 1.6
branch without also rebasing his master branch against origin/master)


 Documentation/git-clone.txt |    5 +++
 builtin-clone.c             |   71 +++++++++++++++++++++++++-----------------
 t/t5702-clone-options.sh    |   70 ++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 114 insertions(+), 32 deletions(-)

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 95f08b9..e7feb4d 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -119,6 +119,11 @@ then the cloned repository will become corrupt.
 	Instead of using the remote name 'origin' to keep track
 	of the upstream repository, use <name> instead.
 
+--branch <name>::
+-b <name>::
+	Instead of using the remote repository's active branch as the
+	initial branch, use <name> instead.
+
 --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 0031b5f..0d03c87 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;
 static char *option_upload_pack = "git-upload-pack";
 static int option_verbose;
 
@@ -69,6 +70,8 @@ static struct option builtin_clone_options[] = {
 		   "path to git-upload-pack on the remote"),
 	OPT_STRING(0, "depth", &option_depth, "depth",
 		    "create a shallow clone of that depth"),
+	OPT_STRING('b', "branch", &option_branch, "branch",
+		    "initial remote branch to check out"),
 
 	OPT_END()
 };
@@ -323,7 +326,9 @@ 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;
+	const struct ref *refs, *mapped_refs;
+	const struct ref *remote_head = NULL, *remote_head_points_at = NULL;
+	const struct ref *initial_branch = NULL;
 	struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
 	struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
 	struct transport *transport = NULL;
@@ -495,46 +500,35 @@ 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");
-		head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
-	}
-	else {
+		remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
+
+		if (option_branch) {
+			initial_branch = find_ref_by_name_abbrev(refs, option_branch);
+			if (!initial_branch)
+				die("remote has no branch named '%s'.", option_branch);
+		} else {
+			initial_branch = remote_head_points_at;
+		}
+	} else {
 		warning("You appear to have cloned an empty repository.");
-		head_points_at = NULL;
-		remote_head = NULL;
 		option_no_checkout = 1;
 		if (!option_bare)
 			install_branch_config(0, "master", option_origin,
 					      "refs/heads/master");
 	}
 
-	if (head_points_at) {
-		/* Local default branch link */
-		create_symref("HEAD", head_points_at->name, NULL);
-
+	/* Set up remote HEAD */
+	if (remote_head_points_at) {
 		if (!option_bare) {
 			struct strbuf head_ref = STRBUF_INIT;
-			const char *head = head_points_at->name;
-
-			if (!prefixcmp(head, "refs/heads/"))
-				head += 11;
-
-			/* Set up the initial local branch */
-
-			/* Local branch initial value */
-			update_ref(reflog_msg.buf, "HEAD",
-				   head_points_at->old_sha1,
-				   NULL, 0, DIE_ON_ERR);
 
 			strbuf_addstr(&head_ref, branch_top.buf);
 			strbuf_addstr(&head_ref, "HEAD");
 
 			/* Remote branch link */
 			create_symref(head_ref.buf,
-				      head_points_at->peer_ref->name,
+				      remote_head_points_at->peer_ref->name,
 				      reflog_msg.buf);
-
-			install_branch_config(0, head, option_origin,
-					      head_points_at->name);
 		}
 	} else if (remote_head) {
 		/* Source had detached HEAD pointing somewhere. */
@@ -542,7 +536,26 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 			update_ref(reflog_msg.buf, "HEAD",
 				   remote_head->old_sha1,
 				   NULL, REF_NODEREF, DIE_ON_ERR);
-	} else {
+	}
+
+	/* Set up intitial branch and HEAD */
+	if (initial_branch) {
+		create_symref("HEAD", initial_branch->name, NULL);
+
+		if (!option_bare) {
+			const char *head = initial_branch->name;
+
+			if (!prefixcmp(head, "refs/heads/"))
+				head += 11;
+
+			update_ref(reflog_msg.buf, "HEAD",
+				   initial_branch->old_sha1,
+				   NULL, 0, DIE_ON_ERR);
+
+			install_branch_config(0, head, option_origin,
+					      initial_branch->name);
+		}
+	} else if (!remote_head) {
 		/* Nothing to checkout out */
 		if (!option_no_checkout)
 			warning("remote HEAD refers to nonexistent ref, "
@@ -554,6 +567,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 		transport_unlock_pack(transport);
 
 	if (!option_no_checkout) {
+		const struct ref *checkout_ref = initial_branch ? initial_branch : remote_head;
 		struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 		struct unpack_trees_options opts;
 		struct tree *tree;
@@ -572,8 +586,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 		opts.verbose_update = !option_quiet;
 		opts.src_index = &the_index;
 		opts.dst_index = &the_index;
-
-		tree = parse_tree_indirect(remote_head->old_sha1);
+		tree = parse_tree_indirect(checkout_ref->old_sha1);
 		parse_tree(tree);
 		init_tree_desc(&t, tree->buffer, tree->size);
 		unpack_trees(1, &t, &opts);
@@ -583,7 +596,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 			die("unable to write new index file");
 
 		err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
-				sha1_to_hex(remote_head->old_sha1), "1", NULL);
+				sha1_to_hex(checkout_ref->old_sha1), "1", NULL);
 	}
 
 	strbuf_release(&reflog_msg);
diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh
index 27825f5..08cd8bd 100755
--- a/t/t5702-clone-options.sh
+++ b/t/t5702-clone-options.sh
@@ -6,9 +6,14 @@ test_description='basic clone options'
 test_expect_success 'setup' '
 
 	mkdir parent &&
-	(cd parent && git init &&
-	 echo one >file && git add file &&
-	 git commit -m one)
+	(
+		cd parent && git init &&
+		echo one >file && git add file && git commit -m one &&
+		echo two >file && git add file && git commit -m two &&
+		git checkout -b topic &&
+		echo thee >topic-file && git add topic-file && git commit -m three &&
+		git checkout master
+	)
 
 '
 
@@ -32,4 +37,63 @@ test_expect_success 'redirected clone -v' '
 
 '
 
+test_expect_success 'clone --branch sets up the correct remote HEAD' '
+
+	git clone --branch=refs/heads/topic parent clone-topic-remote-head &&
+	(cd clone-topic-remote-head && grep master .git/refs/remotes/origin/HEAD)
+
+'
+
+test_expect_success 'clone --branch sets up the correct local branch' '
+
+	git clone --branch=refs/heads/topic parent clone-topic-name &&
+	(cd clone-topic-name && git rev-parse --verify refs/heads/topic)
+
+'
+
+test_expect_success 'clone --branch sets up the correct local HEAD' '
+
+	git clone --branch=refs/heads/topic parent clone-topic-head &&
+	(cd clone-topic-head && grep topic .git/HEAD)
+
+'
+
+test_expect_success 'clone --branch checks out the correct branch' '
+
+	git clone --branch=refs/heads/topic parent clone-topic-checkout &&
+	test -f clone-topic-checkout/topic-file
+
+'
+
+test_expect_success 'clone --branch works with -n' '
+
+	git clone -n --branch=refs/heads/topic parent clone-topic-checkout-n &&
+	! test -f clone-topic-checkout-n/topic-file
+
+'
+
+test_expect_success 'clone --branch works with detatched remote HEAD' '
+
+	(cd parent && git checkout master~1) &&
+	git clone --branch=refs/heads/topic parent clone-topic-checkout-detatched &&
+	test -f clone-topic-checkout-detatched/topic-file &&
+	(cd parent && git checkout master)
+
+'
+
+test_expect_success 'clone --branch works with invalid remote HEAD' '
+
+	(cd parent && echo "ref: refs/heads/nonexistent" > .git/HEAD) &&
+	git clone --branch=refs/heads/topic parent clone-topic-checkout-nonexistent &&
+	test -f clone-topic-checkout-nonexistent/topic-file  &&
+	(cd parent && git checkout master)
+'
+
+test_expect_success 'clone --branch works with abbreviated ref name' '
+
+	git clone --branch=topic parent clone-topic-abbreviated-name &&
+	(cd clone-topic-abbreviated-name && git rev-parse --verify refs/heads/topic)
+
+'
+
 test_done
-- 
1.6.2.GIT

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

end of thread, other threads:[~2009-03-27 17:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-27 17:45 [PATCH v3 0/2] git-clone: Add new option --branch to override initial branch Tor Arne Vestbø
2009-03-27 17:45 ` [PATCH v3 1/2] Move find_ref_by_name_abbrev to refs.c so it can be used globally Tor Arne Vestbø
2009-03-27 17:45 ` [PATCH v3 2/2] git-clone: Add new option --branch to override initial branch Tor Arne Vestbø

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).