From 03a8eddfd1bd7cdce0b2361753691f53c00e5ba6 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 17 Mar 2013 04:23:46 -0400 Subject: pack-refs: write peeled entry for non-tags 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 Signed-off-by: Junio C Hamano --- t/t3211-peel-ref.sh | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100755 t/t3211-peel-ref.sh (limited to 't') diff --git a/t/t3211-peel-ref.sh b/t/t3211-peel-ref.sh new file mode 100755 index 000000000..85f09be9f --- /dev/null +++ b/t/t3211-peel-ref.sh @@ -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 -- cgit v1.2.1 From c29c46fa2e21e608ce2e603649af5bf38e7969c2 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Mon, 18 Mar 2013 07:37:32 -0400 Subject: pack-refs: add fully-peeled trait Older versions of pack-refs did not write peel lines for refs outside of refs/tags. This meant that on reading the pack-refs file, we might set the REF_KNOWS_PEELED flag for such a ref, even though we do not know anything about its peeled value. The previous commit updated the writer to always peel, no matter what the ref is. That means that packed-refs files written by newer versions of git are fine to be read by both old and new versions of git. However, we still have the problem of reading packed-refs files written by older versions of git, or by other implementations which have not yet learned the same trick. The simplest fix would be to always unset the REF_KNOWS_PEELED flag for refs outside of refs/tags that do not have a peel line (if it has a peel line, we know it is valid, but we cannot assume a missing peel line means anything). But that loses an important optimization, as upload-pack should not need to load the object pointed to by refs/heads/foo to determine that it is not a tag. Instead, we add a "fully-peeled" trait to the packed-refs file. If it is set, we know that we can trust a missing peel line to mean that a ref cannot be peeled. Otherwise, we fall back to assuming nothing. [commit message and tests by Jeff King ] Signed-off-by: Michael Haggerty Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t3211-peel-ref.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 't') diff --git a/t/t3211-peel-ref.sh b/t/t3211-peel-ref.sh index 85f09be9f..d4d7792ea 100755 --- a/t/t3211-peel-ref.sh +++ b/t/t3211-peel-ref.sh @@ -39,4 +39,26 @@ test_expect_success 'refs are peeled outside of refs/tags (packed)' ' test_cmp expect actual ' +test_expect_success 'create old-style pack-refs without fully-peeled' ' + # Git no longer writes without fully-peeled, so we just write our own + # from scratch; we could also munge the existing file to remove the + # fully-peeled bits, but that seems even more prone to failure, + # especially if the format ever changes again. At least this way we + # know we are emulating exactly what an older git would have written. + { + echo "# pack-refs with: peeled " && + print_ref "refs/heads/master" && + print_ref "refs/outside/foo" && + print_ref "refs/tags/base" && + print_ref "refs/tags/foo" && + echo "^$(git rev-parse "refs/tags/foo^{}")" + } >tmp && + mv tmp .git/packed-refs +' + +test_expect_success 'refs are peeled outside of refs/tags (old packed)' ' + git show-ref -d >actual && + test_cmp expect actual +' + test_done -- cgit v1.2.1