Skip to content

Commit f4315ee

Browse files
committed
Merge branch 'jk/pack-tag-of-tag' into maint
"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
2 parents 92d4266 + b773dde commit f4315ee

File tree

2 files changed

+95
-30
lines changed

2 files changed

+95
-30
lines changed

builtin/pack-objects.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2123,14 +2123,43 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
21232123
#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
21242124
#endif
21252125

2126+
static void add_tag_chain(const struct object_id *oid)
2127+
{
2128+
struct tag *tag;
2129+
2130+
/*
2131+
* We catch duplicates already in add_object_entry(), but we'd
2132+
* prefer to do this extra check to avoid having to parse the
2133+
* tag at all if we already know that it's being packed (e.g., if
2134+
* it was included via bitmaps, we would not have parsed it
2135+
* previously).
2136+
*/
2137+
if (packlist_find(&to_pack, oid->hash, NULL))
2138+
return;
2139+
2140+
tag = lookup_tag(oid->hash);
2141+
while (1) {
2142+
if (!tag || parse_tag(tag) || !tag->tagged)
2143+
die("unable to pack objects reachable from tag %s",
2144+
oid_to_hex(oid));
2145+
2146+
add_object_entry(tag->object.oid.hash, OBJ_TAG, NULL, 0);
2147+
2148+
if (tag->tagged->type != OBJ_TAG)
2149+
return;
2150+
2151+
tag = (struct tag *)tag->tagged;
2152+
}
2153+
}
2154+
21262155
static int add_ref_tag(const char *path, const struct object_id *oid, int flag, void *cb_data)
21272156
{
21282157
struct object_id peeled;
21292158

21302159
if (starts_with(path, "refs/tags/") && /* is a tag? */
21312160
!peel_ref(path, peeled.hash) && /* peelable? */
21322161
packlist_find(&to_pack, peeled.hash, NULL)) /* object packed? */
2133-
add_object_entry(oid->hash, OBJ_TAG, NULL, 0);
2162+
add_tag_chain(oid);
21342163
return 0;
21352164
}
21362165

t/t5305-include-tag.sh

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,58 +25,94 @@ test_expect_success setup '
2525
} >obj-list
2626
'
2727

28-
rm -rf clone.git
2928
test_expect_success 'pack without --include-tag' '
30-
packname_1=$(git pack-objects \
29+
packname=$(git pack-objects \
3130
--window=0 \
32-
test-1 <obj-list)
31+
test-no-include <obj-list)
3332
'
3433

3534
test_expect_success 'unpack objects' '
36-
(
37-
GIT_DIR=clone.git &&
38-
export GIT_DIR &&
39-
git init &&
40-
git unpack-objects -n <test-1-${packname_1}.pack &&
41-
git unpack-objects <test-1-${packname_1}.pack
42-
)
35+
rm -rf clone.git &&
36+
git init clone.git &&
37+
git -C clone.git unpack-objects <test-no-include-${packname}.pack
4338
'
4439

4540
test_expect_success 'check unpacked result (have commit, no tag)' '
4641
git rev-list --objects $commit >list.expect &&
47-
(
48-
test_must_fail env GIT_DIR=clone.git git cat-file -e $tag &&
49-
git rev-list --objects $commit
50-
) >list.actual &&
42+
test_must_fail git -C clone.git cat-file -e $tag &&
43+
git -C clone.git rev-list --objects $commit >list.actual &&
5144
test_cmp list.expect list.actual
5245
'
5346

54-
rm -rf clone.git
5547
test_expect_success 'pack with --include-tag' '
56-
packname_1=$(git pack-objects \
48+
packname=$(git pack-objects \
5749
--window=0 \
5850
--include-tag \
59-
test-2 <obj-list)
51+
test-include <obj-list)
6052
'
6153

6254
test_expect_success 'unpack objects' '
63-
(
64-
GIT_DIR=clone.git &&
65-
export GIT_DIR &&
66-
git init &&
67-
git unpack-objects -n <test-2-${packname_1}.pack &&
68-
git unpack-objects <test-2-${packname_1}.pack
69-
)
55+
rm -rf clone.git &&
56+
git init clone.git &&
57+
git -C clone.git unpack-objects <test-include-${packname}.pack
7058
'
7159

7260
test_expect_success 'check unpacked result (have commit, have tag)' '
7361
git rev-list --objects mytag >list.expect &&
74-
(
75-
GIT_DIR=clone.git &&
76-
export GIT_DIR &&
77-
git rev-list --objects $tag
78-
) >list.actual &&
62+
git -C clone.git rev-list --objects $tag >list.actual &&
7963
test_cmp list.expect list.actual
8064
'
8165

66+
# A tag of a tag, where the "inner" tag is not otherwise
67+
# reachable, and a full peel points to a commit reachable from HEAD.
68+
test_expect_success 'create hidden inner tag' '
69+
test_commit commit &&
70+
git tag -m inner inner HEAD &&
71+
git tag -m outer outer inner &&
72+
git tag -d inner
73+
'
74+
75+
test_expect_success 'pack explicit outer tag' '
76+
packname=$(
77+
{
78+
echo HEAD &&
79+
echo outer
80+
} |
81+
git pack-objects --revs test-hidden-explicit
82+
)
83+
'
84+
85+
test_expect_success 'unpack objects' '
86+
rm -rf clone.git &&
87+
git init clone.git &&
88+
git -C clone.git unpack-objects <test-hidden-explicit-${packname}.pack
89+
'
90+
91+
test_expect_success 'check unpacked result (have all objects)' '
92+
git -C clone.git rev-list --objects $(git rev-parse outer HEAD)
93+
'
94+
95+
test_expect_success 'pack implied outer tag' '
96+
packname=$(
97+
echo HEAD |
98+
git pack-objects --revs --include-tag test-hidden-implied
99+
)
100+
'
101+
102+
test_expect_success 'unpack objects' '
103+
rm -rf clone.git &&
104+
git init clone.git &&
105+
git -C clone.git unpack-objects <test-hidden-implied-${packname}.pack
106+
'
107+
108+
test_expect_success 'check unpacked result (have all objects)' '
109+
git -C clone.git rev-list --objects $(git rev-parse outer HEAD)
110+
'
111+
112+
test_expect_success 'single-branch clone can transfer tag' '
113+
rm -rf clone.git &&
114+
git clone --no-local --single-branch -b master . clone.git &&
115+
git -C clone.git fsck
116+
'
117+
82118
test_done

0 commit comments

Comments
 (0)