aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/pack-objects.c31
-rwxr-xr-xt/t5305-include-tag.sh52
2 files changed, 82 insertions, 1 deletions
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index f854ca425..ea5367e45 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2104,6 +2104,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;
@@ -2111,7 +2140,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;
}
diff --git a/t/t5305-include-tag.sh b/t/t5305-include-tag.sh
index e3c6c620c..a5eca210b 100755
--- a/t/t5305-include-tag.sh
+++ b/t/t5305-include-tag.sh
@@ -63,4 +63,56 @@ test_expect_success 'check unpacked result (have commit, have tag)' '
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