Skip to content

Commit

Permalink
clone: allow --branch to take a tag
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
pclouds authored and gitster committed Jan 17, 2012
1 parent 920b691 commit 5a7d5b6
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 3 deletions.
5 changes: 3 additions & 2 deletions Documentation/git-clone.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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>::
Expand Down
20 changes: 19 additions & 1 deletion builtin/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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);

Expand Down Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions t/t5500-fetch-pack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions t/t5601-clone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 5a7d5b6

Please sign in to comment.