Skip to content

Commit

Permalink
pack-refs: write peeled entry for non-tags
Browse files Browse the repository at this point in the history
When we pack an annotated tag ref, we write not only the
sha1 of the tag object along with the ref, but also the sha1
obtained by peeling the tag. This lets readers of the
pack-refs file know the peeled value without having to
actually load the object, speeding up upload-pack's ref
advertisement.

The writer marks a packed-refs file with peeled refs using
the "peeled" trait at the top of the file. When the reader
sees this trait, it knows that each ref is either followed
by its peeled value, or it is not an annotated tag.

However, there is a mismatch between the assumptions of the
reader and writer. The writer will only peel refs under
refs/tags, but the reader does not know this; it will assume
a ref without a peeled value must not be a tag object. Thus
an annotated tag object placed outside of the refs/tags
hierarchy will not have its peeled value printed by
upload-pack.

The simplest way to fix this is to start writing peel values
for all refs. This matches what the reader expects for both
new and old versions of git.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jeff King authored and Junio C Hamano committed Mar 17, 2013
1 parent f7892d1 commit 03a8edd
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 8 deletions.
16 changes: 8 additions & 8 deletions pack-refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
int flags, void *cb_data)
{
struct pack_refs_cb_data *cb = cb_data;
struct object *o;
int is_tag_ref;

/* Do not pack the symbolic refs */
Expand All @@ -39,14 +40,13 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
return 0;

fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
if (is_tag_ref) {
struct object *o = parse_object_or_die(sha1, path);
if (o->type == OBJ_TAG) {
o = deref_tag(o, path, 0);
if (o)
fprintf(cb->refs_file, "^%s\n",
sha1_to_hex(o->sha1));
}

o = parse_object_or_die(sha1, path);
if (o->type == OBJ_TAG) {
o = deref_tag(o, path, 0);
if (o)
fprintf(cb->refs_file, "^%s\n",
sha1_to_hex(o->sha1));
}

if ((cb->flags & PACK_REFS_PRUNE) && !do_not_prune(flags)) {
Expand Down
42 changes: 42 additions & 0 deletions t/t3211-peel-ref.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/sh

test_description='tests for the peel_ref optimization of packed-refs'
. ./test-lib.sh

test_expect_success 'create annotated tag in refs/tags' '
test_commit base &&
git tag -m annotated foo
'

test_expect_success 'create annotated tag outside of refs/tags' '
git update-ref refs/outside/foo refs/tags/foo
'

# This matches show-ref's output
print_ref() {
echo "$(git rev-parse "$1") $1"
}

test_expect_success 'set up expected show-ref output' '
{
print_ref "refs/heads/master" &&
print_ref "refs/outside/foo" &&
print_ref "refs/outside/foo^{}" &&
print_ref "refs/tags/base" &&
print_ref "refs/tags/foo" &&
print_ref "refs/tags/foo^{}"
} >expect
'

test_expect_success 'refs are peeled outside of refs/tags (loose)' '
git show-ref -d >actual &&
test_cmp expect actual
'

test_expect_success 'refs are peeled outside of refs/tags (packed)' '
git pack-refs --all &&
git show-ref -d >actual &&
test_cmp expect actual
'

test_done

0 comments on commit 03a8edd

Please sign in to comment.