summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 68ea474)
raw | patch | inline | side by side (parent: 68ea474)
author | Jeff King <peff@peff.net> | |
Wed, 26 Aug 2009 19:05:08 +0000 (15:05 -0400) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Thu, 27 Aug 2009 02:36:20 +0000 (19:36 -0700) |
We currently point the HEAD of a newly cloned repo to the
same ref as the parent repo's HEAD. While a user can then
"git checkout -b foo origin/foo" whichever branch they
choose, it is more convenient and more efficient to tell
clone which branch you want in the first place.
Based on a patch by Kirill A. Korinskiy.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
same ref as the parent repo's HEAD. While a user can then
"git checkout -b foo origin/foo" whichever branch they
choose, it is more convenient and more efficient to tell
clone which branch you want in the first place.
Based on a patch by Kirill A. Korinskiy.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-clone.txt | patch | blob | history | |
builtin-clone.c | patch | blob | history | |
t/t5706-clone-branch.sh | [new file with mode: 0755] | patch | blob |
index 2c63a0fbaee0e246538607c8e2f983eb6eafa8e5..1cd1ecc746a884816db7945d6a41946a5c698123 100644 (file)
Instead of using the remote name 'origin' to keep track
of the upstream repository, use <name>.
+--branch <name>::
+-b <name>::
+ Instead of pointing the newly created HEAD to the branch pointed
+ to by the cloned repositoroy's HEAD, point to <name> branch
+ instead. In a non-bare repository, this is the branch that will
+ be checked out.
+
--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 32dea74d78381ca1dffdac7f88e45a89a9825104..9d79301b8e373baa0cadccf8dc4ee3f4ed39e8b6 100644 (file)
--- a/builtin-clone.c
+++ b/builtin-clone.c
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;
"reference repository"),
OPT_STRING('o', "origin", &option_origin, "branch",
"use <branch> instead of 'origin' to track upstream"),
+ OPT_STRING('b', "branch", &option_branch, "branch",
+ "checkout <branch> instead of the remote's 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",
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, *remote_head, *mapped_refs;
+ const struct ref *remote_head_points_at;
+ const struct ref *our_head_points_at;
struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
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);
+ remote_head_points_at =
+ guess_remote_head(remote_head, mapped_refs, 0);
+
+ if (option_branch) {
+ struct strbuf head = STRBUF_INIT;
+ strbuf_addstr(&head, src_ref_prefix);
+ strbuf_addstr(&head, option_branch);
+ our_head_points_at =
+ find_ref_by_name(mapped_refs, head.buf);
+ strbuf_release(&head);
+
+ if (!our_head_points_at) {
+ warning("Remote branch %s not found in "
+ "upstream %s, using HEAD instead",
+ option_branch, option_origin);
+ our_head_points_at = remote_head_points_at;
+ }
+ }
+ else
+ our_head_points_at = remote_head_points_at;
}
else {
warning("You appear to have cloned an empty repository.");
- head_points_at = NULL;
+ our_head_points_at = NULL;
+ remote_head_points_at = NULL;
remote_head = NULL;
option_no_checkout = 1;
if (!option_bare)
"refs/heads/master");
}
- if (head_points_at) {
- /* Local default branch link */
- create_symref("HEAD", head_points_at->name, NULL);
+ if (remote_head_points_at && !option_bare) {
+ struct strbuf head_ref = STRBUF_INIT;
+ strbuf_addstr(&head_ref, branch_top.buf);
+ strbuf_addstr(&head_ref, "HEAD");
+ create_symref(head_ref.buf,
+ remote_head_points_at->peer_ref->name,
+ reflog_msg.buf);
+ }
+ if (our_head_points_at) {
+ /* Local default branch link */
+ create_symref("HEAD", our_head_points_at->name, NULL);
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 */
+ const char *head = skip_prefix(our_head_points_at->name,
+ "refs/heads/");
update_ref(reflog_msg.buf, "HEAD",
- head_points_at->old_sha1,
+ our_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,
- reflog_msg.buf);
-
install_branch_config(0, head, option_origin,
- head_points_at->name);
+ our_head_points_at->name);
}
} else if (remote_head) {
/* Source had detached HEAD pointing somewhere. */
- if (!option_bare)
+ if (!option_bare) {
update_ref(reflog_msg.buf, "HEAD",
remote_head->old_sha1,
NULL, REF_NODEREF, DIE_ON_ERR);
+ our_head_points_at = remote_head;
+ }
} else {
/* Nothing to checkout out */
if (!option_no_checkout)
opts.src_index = &the_index;
opts.dst_index = &the_index;
- tree = parse_tree_indirect(remote_head->old_sha1);
+ tree = parse_tree_indirect(our_head_points_at->old_sha1);
parse_tree(tree);
init_tree_desc(&t, tree->buffer, tree->size);
unpack_trees(1, &t, &opts);
diff --git a/t/t5706-clone-branch.sh b/t/t5706-clone-branch.sh
--- /dev/null
+++ b/t/t5706-clone-branch.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+test_description='clone --branch option'
+. ./test-lib.sh
+
+check_HEAD() {
+ echo refs/heads/"$1" >expect &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual
+}
+
+check_file() {
+ echo "$1" >expect &&
+ test_cmp expect file
+}
+
+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 >file && git add file && git commit -m two &&
+ git checkout master)
+'
+
+test_expect_success 'vanilla clone chooses HEAD' '
+ git clone parent clone &&
+ (cd clone &&
+ check_HEAD master &&
+ check_file one
+ )
+'
+
+test_expect_success 'clone -b chooses specified branch' '
+ git clone -b two parent clone-two &&
+ (cd clone-two &&
+ check_HEAD two &&
+ check_file two
+ )
+'
+
+test_expect_success 'clone -b sets up tracking' '
+ (cd clone-two &&
+ echo origin >expect &&
+ git config branch.two.remote >actual &&
+ echo refs/heads/two >>expect &&
+ git config branch.two.merge >>actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'clone -b does not munge remotes/origin/HEAD' '
+ (cd clone-two &&
+ echo refs/remotes/origin/master >expect &&
+ git symbolic-ref refs/remotes/origin/HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'clone -b with bogus branch chooses HEAD' '
+ git clone -b bogus parent clone-bogus &&
+ (cd clone-bogus &&
+ check_HEAD master &&
+ check_file one
+ )
+'
+
+test_done