Code

clone: allow --branch to take a tag
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Mon, 16 Jan 2012 09:46:15 +0000 (16:46 +0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 17 Jan 2012 00:26:26 +0000 (16:26 -0800)
Because a tag ref cannot be put to HEAD, HEAD will become detached.
This is consistent with "git checkout <tag>".

This is mostly useful in shallow clone, where it allows you to clone a
tag in addtion to branches.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-clone.txt
builtin/clone.c
t/t5500-fetch-pack.sh
t/t5601-clone.sh

index 0931a3e39237da0abbf03c43a2f35092ea48efd5..6e22522c4f7e97dbab42b3cbb5b538cdea3b4d74 100644 (file)
@@ -147,8 +147,9 @@ 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. In a non-bare repository, this is the branch that will
-       be checked out.
+       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.
 
 --upload-pack <upload-pack>::
 -u <upload-pack>::
index 3cfedb3a93be673e46bf753c40d1012fca1faf5c..651b4cc20bd932876e35dd16f6ac2a7ecfc9b501 100644 (file)
@@ -420,6 +420,15 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch
        strbuf_addstr(&head, branch);
        ref = find_ref_by_name(refs, head.buf);
        strbuf_release(&head);
+
+       if (ref)
+               return ref;
+
+       strbuf_addstr(&head, "refs/tags/");
+       strbuf_addstr(&head, branch);
+       ref = find_ref_by_name(refs, head.buf);
+       strbuf_release(&head);
+
        return ref;
 }
 
@@ -441,8 +450,12 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
                if (!remote_head && option_branch)
                        warning(_("Could not find remote branch %s to clone."),
                                option_branch);
-               else
+               else {
                        get_fetch_map(remote_head, refspec, &tail, 0);
+
+                       /* if --branch=tag, pull the requested tag explicitly */
+                       get_fetch_map(remote_head, tag_refspec, &tail, 0);
+               }
        } else
                get_fetch_map(refs, refspec, &tail, 0);
 
@@ -515,6 +528,11 @@ static void update_head(const struct ref *our, const struct ref *remote,
                        update_ref(msg, "HEAD", our->old_sha1, NULL, 0, DIE_ON_ERR);
                        install_branch_config(0, head, option_origin, our->name);
                }
+       } else if (our) {
+               struct commit *c = lookup_commit_reference(our->old_sha1);
+               /* --branch specifies a non-branch (i.e. tags), detach HEAD */
+               update_ref(msg, "HEAD", c->object.sha1,
+                          NULL, REF_NODEREF, DIE_ON_ERR);
        } else if (remote) {
                /*
                 * We know remote HEAD points to a non-branch, or
index 5237066140bc41632ed38541acdf3c30a7a0534d..ce51692bb2b9ae221d11458a01ab8ef669f24659 100755 (executable)
@@ -311,4 +311,19 @@ EOF
        test_cmp count6.expected count6.actual
 '
 
+test_expect_success 'shallow cloning single tag' '
+       git clone --depth 1 --branch=TAGB1 "file://$(pwd)/." shallow7 &&
+       cat >taglist.expected <<\EOF &&
+TAGB1
+TAGB2
+EOF
+       GIT_DIR=shallow7/.git git tag -l >taglist.actual &&
+       test_cmp taglist.expected taglist.actual &&
+
+       echo "in-pack: 7" > count7.expected &&
+       GIT_DIR=shallow7/.git git count-objects -v |
+               grep "^in-pack" > count7.actual &&
+       test_cmp count7.expected count7.actual
+'
+
 test_done
index e0b8db6c536a488389fb573f4e5cb15d552b7e98..67869b4813dd354f4376ead1470ecb0e58929302 100755 (executable)
@@ -271,4 +271,13 @@ test_expect_success 'clone from original with relative alternate' '
        grep /src/\\.git/objects target-10/objects/info/alternates
 '
 
+test_expect_success 'clone checking out a tag' '
+       git clone --branch=some-tag src dst.tag &&
+       GIT_DIR=src/.git git rev-parse some-tag >expected &&
+       test_cmp expected dst.tag/.git/HEAD &&
+       GIT_DIR=dst.tag/.git git config remote.origin.fetch >fetch.actual &&
+       echo "+refs/heads/*:refs/remotes/origin/*" >fetch.expected &&
+       test_cmp fetch.expected fetch.actual
+'
+
 test_done