Merge branch 'jk/pack-tag-of-tag'

"git pack-objects --include-tag" was taught that when we know that
we are sending an object C, we want a tag B that directly points at
C but also a tag A that points at the tag B.  We used to miss the
intermediate tag B in some cases.

* jk/pack-tag-of-tag:
  pack-objects: walk tag chains for --include-tag
  t5305: simplify packname handling
  t5305: use "git -C"
  t5305: drop "dry-run" of unpack-objects
  t5305: move cleanup into test block
This commit is contained in:
Junio C Hamano 2016-09-15 14:11:14 -07:00
commit 9883ec2c73
2 changed files with 95 additions and 30 deletions

View File

@ -2123,6 +2123,35 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p) #define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
#endif #endif
static void add_tag_chain(const struct object_id *oid)
{
struct tag *tag;
/*
* We catch duplicates already in add_object_entry(), but we'd
* prefer to do this extra check to avoid having to parse the
* tag at all if we already know that it's being packed (e.g., if
* it was included via bitmaps, we would not have parsed it
* previously).
*/
if (packlist_find(&to_pack, oid->hash, NULL))
return;
tag = lookup_tag(oid->hash);
while (1) {
if (!tag || parse_tag(tag) || !tag->tagged)
die("unable to pack objects reachable from tag %s",
oid_to_hex(oid));
add_object_entry(tag->object.oid.hash, OBJ_TAG, NULL, 0);
if (tag->tagged->type != OBJ_TAG)
return;
tag = (struct tag *)tag->tagged;
}
}
static int add_ref_tag(const char *path, const struct object_id *oid, int flag, void *cb_data) static int add_ref_tag(const char *path, const struct object_id *oid, int flag, void *cb_data)
{ {
struct object_id peeled; struct object_id peeled;
@ -2130,7 +2159,7 @@ static int add_ref_tag(const char *path, const struct object_id *oid, int flag,
if (starts_with(path, "refs/tags/") && /* is a tag? */ if (starts_with(path, "refs/tags/") && /* is a tag? */
!peel_ref(path, peeled.hash) && /* peelable? */ !peel_ref(path, peeled.hash) && /* peelable? */
packlist_find(&to_pack, peeled.hash, NULL)) /* object packed? */ packlist_find(&to_pack, peeled.hash, NULL)) /* object packed? */
add_object_entry(oid->hash, OBJ_TAG, NULL, 0); add_tag_chain(oid);
return 0; return 0;
} }

View File

@ -25,58 +25,94 @@ test_expect_success setup '
} >obj-list } >obj-list
' '
rm -rf clone.git
test_expect_success 'pack without --include-tag' ' test_expect_success 'pack without --include-tag' '
packname_1=$(git pack-objects \ packname=$(git pack-objects \
--window=0 \ --window=0 \
test-1 <obj-list) test-no-include <obj-list)
' '
test_expect_success 'unpack objects' ' test_expect_success 'unpack objects' '
( rm -rf clone.git &&
GIT_DIR=clone.git && git init clone.git &&
export GIT_DIR && git -C clone.git unpack-objects <test-no-include-${packname}.pack
git init &&
git unpack-objects -n <test-1-${packname_1}.pack &&
git unpack-objects <test-1-${packname_1}.pack
)
' '
test_expect_success 'check unpacked result (have commit, no tag)' ' test_expect_success 'check unpacked result (have commit, no tag)' '
git rev-list --objects $commit >list.expect && git rev-list --objects $commit >list.expect &&
( test_must_fail git -C clone.git cat-file -e $tag &&
test_must_fail env GIT_DIR=clone.git git cat-file -e $tag && git -C clone.git rev-list --objects $commit >list.actual &&
git rev-list --objects $commit
) >list.actual &&
test_cmp list.expect list.actual test_cmp list.expect list.actual
' '
rm -rf clone.git
test_expect_success 'pack with --include-tag' ' test_expect_success 'pack with --include-tag' '
packname_1=$(git pack-objects \ packname=$(git pack-objects \
--window=0 \ --window=0 \
--include-tag \ --include-tag \
test-2 <obj-list) test-include <obj-list)
' '
test_expect_success 'unpack objects' ' test_expect_success 'unpack objects' '
( rm -rf clone.git &&
GIT_DIR=clone.git && git init clone.git &&
export GIT_DIR && git -C clone.git unpack-objects <test-include-${packname}.pack
git init &&
git unpack-objects -n <test-2-${packname_1}.pack &&
git unpack-objects <test-2-${packname_1}.pack
)
' '
test_expect_success 'check unpacked result (have commit, have tag)' ' test_expect_success 'check unpacked result (have commit, have tag)' '
git rev-list --objects mytag >list.expect && git rev-list --objects mytag >list.expect &&
( git -C clone.git rev-list --objects $tag >list.actual &&
GIT_DIR=clone.git &&
export GIT_DIR &&
git rev-list --objects $tag
) >list.actual &&
test_cmp list.expect list.actual test_cmp list.expect list.actual
' '
# A tag of a tag, where the "inner" tag is not otherwise
# reachable, and a full peel points to a commit reachable from HEAD.
test_expect_success 'create hidden inner tag' '
test_commit commit &&
git tag -m inner inner HEAD &&
git tag -m outer outer inner &&
git tag -d inner
'
test_expect_success 'pack explicit outer tag' '
packname=$(
{
echo HEAD &&
echo outer
} |
git pack-objects --revs test-hidden-explicit
)
'
test_expect_success 'unpack objects' '
rm -rf clone.git &&
git init clone.git &&
git -C clone.git unpack-objects <test-hidden-explicit-${packname}.pack
'
test_expect_success 'check unpacked result (have all objects)' '
git -C clone.git rev-list --objects $(git rev-parse outer HEAD)
'
test_expect_success 'pack implied outer tag' '
packname=$(
echo HEAD |
git pack-objects --revs --include-tag test-hidden-implied
)
'
test_expect_success 'unpack objects' '
rm -rf clone.git &&
git init clone.git &&
git -C clone.git unpack-objects <test-hidden-implied-${packname}.pack
'
test_expect_success 'check unpacked result (have all objects)' '
git -C clone.git rev-list --objects $(git rev-parse outer HEAD)
'
test_expect_success 'single-branch clone can transfer tag' '
rm -rf clone.git &&
git clone --no-local --single-branch -b master . clone.git &&
git -C clone.git fsck
'
test_done test_done