clone: allow --branch to take a tag
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>
Nguyễn Thái Ngọc Duy committed
Jan 16, 2012 at 16:46 UTC
5a7d5b683f869d3e3884a89775241afa515da9e7
4 files changed
+46
-3
Documentation/git-clone.txt
+3
-2
@@ -147,8 +147,9 @@ objects from the source repository into a pack in the cloned repository.
147
-b <name>::
148
Instead of pointing the newly created HEAD to the branch pointed
149
to by the cloned repository's HEAD, point to `<name>` branch
150
- instead. In a non-bare repository, this is the branch that will
151
- be checked out.
150
+ instead. `--branch` can also take tags and treat them like
151
+ detached HEAD. In a non-bare repository, this is the branch
152
+ that will be checked out.
153
154
--upload-pack <upload-pack>::
155
-u <upload-pack>::
builtin/clone.c
+19
-1
@@ -420,6 +420,15 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch
420
strbuf_addstr(&head, branch);
421
ref = find_ref_by_name(refs, head.buf);
422
strbuf_release(&head);
423
+
424
+ if (ref)
425
+ return ref;
426
+
427
+ strbuf_addstr(&head, "refs/tags/");
428
+ strbuf_addstr(&head, branch);
429
+ ref = find_ref_by_name(refs, head.buf);
430
+ strbuf_release(&head);
431
+
432
return ref;
433
}
434
@@ -441,8 +450,12 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
450
if (!remote_head && option_branch)
451
warning(_("Could not find remote branch %s to clone."),
452
option_branch);
444
- else
453
+ else {
454
get_fetch_map(remote_head, refspec, &tail, 0);
455
+
456
+ /* if --branch=tag, pull the requested tag explicitly */
457
+ get_fetch_map(remote_head, tag_refspec, &tail, 0);
458
+ }
459
} else
460
get_fetch_map(refs, refspec, &tail, 0);
461
@@ -515,6 +528,11 @@ static void update_head(const struct ref *our, const struct ref *remote,
528
update_ref(msg, "HEAD", our->old_sha1, NULL, 0, DIE_ON_ERR);
529
install_branch_config(0, head, option_origin, our->name);
530
}
531
+ } else if (our) {
532
+ struct commit *c = lookup_commit_reference(our->old_sha1);
533
+ /* --branch specifies a non-branch (i.e. tags), detach HEAD */
534
+ update_ref(msg, "HEAD", c->object.sha1,
535
+ NULL, REF_NODEREF, DIE_ON_ERR);
536
} else if (remote) {
537
/*
538
* We know remote HEAD points to a non-branch, or
t/t5500-fetch-pack.sh
+15
@@ -311,4 +311,19 @@ EOF
311
test_cmp count6.expected count6.actual
312
'
313
314
+test_expect_success 'shallow cloning single tag' '
315
+ git clone --depth 1 --branch=TAGB1 "file://$(pwd)/." shallow7 &&
316
+ cat >taglist.expected <<\EOF &&
317
+TAGB1
318
+TAGB2
319
+EOF
320
+ GIT_DIR=shallow7/.git git tag -l >taglist.actual &&
321
+ test_cmp taglist.expected taglist.actual &&
322
+
323
+ echo "in-pack: 7" > count7.expected &&
324
+ GIT_DIR=shallow7/.git git count-objects -v |
325
+ grep "^in-pack" > count7.actual &&
326
+ test_cmp count7.expected count7.actual
327
+'
328
+
329
test_done
t/t5601-clone.sh
+9
@@ -271,4 +271,13 @@ test_expect_success 'clone from original with relative alternate' '
271
grep /src/\\.git/objects target-10/objects/info/alternates
272
'
273
274
+test_expect_success 'clone checking out a tag' '
275
+ git clone --branch=some-tag src dst.tag &&
276
+ GIT_DIR=src/.git git rev-parse some-tag >expected &&
277
+ test_cmp expected dst.tag/.git/HEAD &&
278
+ GIT_DIR=dst.tag/.git git config remote.origin.fetch >fetch.actual &&
279
+ echo "+refs/heads/*:refs/remotes/origin/*" >fetch.expected &&
280
+ test_cmp fetch.expected fetch.actual
281
+'
282
+
283
test_done