Merge branch 'jk/pack-tag-of-tag'
authorJunio C Hamano <gitster@pobox.com>
Thu, 15 Sep 2016 21:11:14 +0000 (14:11 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 15 Sep 2016 21:11:14 +0000 (14:11 -0700)
"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

builtin/pack-objects.c
t/t5305-include-tag.sh
index 4a63398960c42d91821c4278a4cfbd11c1f1a7a4..0954375be9ea5fe2b416d4142b6987ff2b5ec94f 100644 (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)
 #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)
 {
        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? */
            !peel_ref(path, peeled.hash)    && /* peelable? */
            packlist_find(&to_pack, peeled.hash, NULL))      /* object packed? */
-               add_object_entry(oid->hash, OBJ_TAG, NULL, 0);
+               add_tag_chain(oid);
        return 0;
 }
 
index f314ad50791142b42c5f2807b5f086bbe9e1caad..a5eca210b8963c4881fd8be858d13b88401b9888 100755 (executable)
@@ -25,58 +25,94 @@ test_expect_success setup '
        } >obj-list
 '
 
-rm -rf clone.git
 test_expect_success 'pack without --include-tag' '
-       packname_1=$(git pack-objects \
+       packname=$(git pack-objects \
                --window=0 \
-               test-1 <obj-list)
+               test-no-include <obj-list)
 '
 
 test_expect_success 'unpack objects' '
-       (
-               GIT_DIR=clone.git &&
-               export GIT_DIR &&
-               git init &&
-               git unpack-objects -n <test-1-${packname_1}.pack &&
-               git unpack-objects <test-1-${packname_1}.pack
-       )
+       rm -rf clone.git &&
+       git init clone.git &&
+       git -C clone.git unpack-objects <test-no-include-${packname}.pack
 '
 
 test_expect_success 'check unpacked result (have commit, no tag)' '
        git rev-list --objects $commit >list.expect &&
-       (
-               test_must_fail env GIT_DIR=clone.git git cat-file -e $tag &&
-               git rev-list --objects $commit
-       ) >list.actual &&
+       test_must_fail git -C clone.git cat-file -e $tag &&
+       git -C clone.git rev-list --objects $commit >list.actual &&
        test_cmp list.expect list.actual
 '
 
-rm -rf clone.git
 test_expect_success 'pack with --include-tag' '
-       packname_1=$(git pack-objects \
+       packname=$(git pack-objects \
                --window=0 \
                --include-tag \
-               test-2 <obj-list)
+               test-include <obj-list)
 '
 
 test_expect_success 'unpack objects' '
-       (
-               GIT_DIR=clone.git &&
-               export GIT_DIR &&
-               git init &&
-               git unpack-objects -n <test-2-${packname_1}.pack &&
-               git unpack-objects <test-2-${packname_1}.pack
-       )
+       rm -rf clone.git &&
+       git init clone.git &&
+       git -C clone.git unpack-objects <test-include-${packname}.pack
 '
 
 test_expect_success 'check unpacked result (have commit, have tag)' '
        git rev-list --objects mytag >list.expect &&
-       (
-               GIT_DIR=clone.git &&
-               export GIT_DIR &&
-               git rev-list --objects $tag
-       ) >list.actual &&
+       git -C clone.git rev-list --objects $tag >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