Skip to content

Commit fe02e1c

Browse files
derrickstoleedscho
authored andcommitted
path-walk: allow visiting tags
In anticipation of using the path-walk API to analyze tags or include them in a pack-file, add the ability to walk the tags that were included in the revision walk. Signed-off-by: Derrick Stolee <stolee@gmail.com>
1 parent 54f5c77 commit fe02e1c

File tree

5 files changed

+146
-8
lines changed

5 files changed

+146
-8
lines changed

Diff for: Documentation/technical/api-path-walk.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ If you want the path-walk API to emit `UNINTERESTING` objects based on the
4848
commit walk's boundary, be sure to set `revs.boundary` so the boundary
4949
commits are emitted.
5050

51-
`commits`, `blobs`, `trees`::
51+
`commits`, `blobs`, `trees`, `tags`::
5252
By default, these members are enabled and signal that the path-walk
5353
API should call the `path_fn` on objects of these types. Specialized
5454
applications could disable some options to make it simpler to walk

Diff for: path-walk.c

+74
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "revision.h"
1414
#include "string-list.h"
1515
#include "strmap.h"
16+
#include "tag.h"
1617
#include "trace2.h"
1718
#include "tree.h"
1819
#include "tree-walk.h"
@@ -204,13 +205,86 @@ int walk_objects_by_path(struct path_walk_info *info)
204205
CALLOC_ARRAY(commit_list, 1);
205206
commit_list->type = OBJ_COMMIT;
206207

208+
if (info->tags)
209+
info->revs->tag_objects = 1;
210+
207211
/* Insert a single list for the root tree into the paths. */
208212
CALLOC_ARRAY(root_tree_list, 1);
209213
root_tree_list->type = OBJ_TREE;
210214
strmap_put(&ctx.paths_to_lists, root_path, root_tree_list);
215+
216+
/*
217+
* Set these values before preparing the walk to catch
218+
* lightweight tags pointing to non-commits.
219+
*/
220+
info->revs->blob_objects = info->blobs;
221+
info->revs->tree_objects = info->trees;
222+
211223
if (prepare_revision_walk(info->revs))
212224
die(_("failed to setup revision walk"));
213225

226+
info->revs->blob_objects = info->revs->tree_objects = 0;
227+
228+
if (info->tags) {
229+
struct oid_array tagged_blob_list = OID_ARRAY_INIT;
230+
struct oid_array tags = OID_ARRAY_INIT;
231+
232+
trace2_region_enter("path-walk", "tag-walk", info->revs->repo);
233+
234+
/*
235+
* Walk any pending objects at this point, but they should only
236+
* be tags.
237+
*/
238+
for (size_t i = 0; i < info->revs->pending.nr; i++) {
239+
struct object_array_entry *pending = info->revs->pending.objects + i;
240+
struct object *obj = pending->item;
241+
242+
if (obj->type == OBJ_COMMIT)
243+
continue;
244+
245+
while (obj->type == OBJ_TAG) {
246+
struct tag *tag = lookup_tag(info->revs->repo,
247+
&obj->oid);
248+
if (oid_array_lookup(&tags, &obj->oid) < 0)
249+
oid_array_append(&tags, &obj->oid);
250+
obj = tag->tagged;
251+
}
252+
253+
switch (obj->type) {
254+
case OBJ_TREE:
255+
if (info->trees &&
256+
oid_array_lookup(&root_tree_list->oids, &obj->oid) < 0)
257+
oid_array_append(&root_tree_list->oids, &obj->oid);
258+
break;
259+
260+
case OBJ_BLOB:
261+
if (info->blobs &&
262+
oid_array_lookup(&tagged_blob_list, &obj->oid) < 0)
263+
oid_array_append(&tagged_blob_list, &obj->oid);
264+
break;
265+
266+
case OBJ_COMMIT:
267+
/* Make sure it is in the object walk */
268+
add_pending_object(info->revs, obj, "");
269+
break;
270+
271+
default:
272+
BUG("should not see any other type here");
273+
}
274+
}
275+
276+
info->path_fn("", &tags, OBJ_TAG, info->path_fn_data);
277+
278+
if (tagged_blob_list.nr && info->blobs)
279+
info->path_fn("/tagged-blobs", &tagged_blob_list, OBJ_BLOB,
280+
info->path_fn_data);
281+
282+
trace2_data_intmax("path-walk", ctx.repo, "tags", tags.nr);
283+
trace2_region_leave("path-walk", "tag-walk", info->revs->repo);
284+
oid_array_clear(&tags);
285+
oid_array_clear(&tagged_blob_list);
286+
}
287+
214288
while ((c = get_revision(info->revs))) {
215289
struct object_id *oid;
216290
struct tree *t;

Diff for: path-walk.h

+2
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,14 @@ struct path_walk_info {
3737
int commits;
3838
int trees;
3939
int blobs;
40+
int tags;
4041
};
4142

4243
#define PATH_WALK_INFO_INIT { \
4344
.blobs = 1, \
4445
.trees = 1, \
4546
.commits = 1, \
47+
.tags = 1, \
4648
}
4749

4850
/**

Diff for: t/helper/test-path-walk.c

+11-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct path_walk_test_data {
2121
uintmax_t commit_nr;
2222
uintmax_t tree_nr;
2323
uintmax_t blob_nr;
24+
uintmax_t tag_nr;
2425
};
2526

2627
static int emit_block(const char *path, struct oid_array *oids,
@@ -45,6 +46,11 @@ static int emit_block(const char *path, struct oid_array *oids,
4546
tdata->blob_nr += oids->nr;
4647
break;
4748

49+
case OBJ_TAG:
50+
typestr = "TAG";
51+
tdata->tag_nr += oids->nr;
52+
break;
53+
4854
default:
4955
BUG("we do not understand this type");
5056
}
@@ -66,6 +72,8 @@ int cmd__path_walk(int argc, const char **argv)
6672
N_("toggle inclusion of blob objects")),
6773
OPT_BOOL(0, "commits", &info.commits,
6874
N_("toggle inclusion of commit objects")),
75+
OPT_BOOL(0, "tags", &info.tags,
76+
N_("toggle inclusion of tag objects")),
6977
OPT_BOOL(0, "trees", &info.trees,
7078
N_("toggle inclusion of tree objects")),
7179
OPT_END(),
@@ -91,8 +99,9 @@ int cmd__path_walk(int argc, const char **argv)
9199

92100
printf("commits:%" PRIuMAX "\n"
93101
"trees:%" PRIuMAX "\n"
94-
"blobs:%" PRIuMAX "\n",
95-
data.commit_nr, data.tree_nr, data.blob_nr);
102+
"blobs:%" PRIuMAX "\n"
103+
"tags:%" PRIuMAX "\n",
104+
data.commit_nr, data.tree_nr, data.blob_nr, data.tag_nr);
96105

97106
release_revisions(&revs);
98107
return res;

Diff for: t/t6601-path-walk.sh

+58-5
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,55 @@ test_description='direct path-walk API tests'
77
test_expect_success 'setup test repository' '
88
git checkout -b base &&
99
10+
# Make some objects that will only be reachable
11+
# via non-commit tags.
12+
mkdir child &&
13+
echo file >child/file &&
14+
git add child &&
15+
git commit -m "will abandon" &&
16+
git tag -a -m "tree" tree-tag HEAD^{tree} &&
17+
echo file2 >file2 &&
18+
git add file2 &&
19+
git commit --amend -m "will abandon" &&
20+
git tag tree-tag2 HEAD^{tree} &&
21+
22+
echo blob >file &&
23+
blob_oid=$(git hash-object -t blob -w --stdin <file) &&
24+
git tag -a -m "blob" blob-tag "$blob_oid" &&
25+
echo blob2 >file2 &&
26+
blob2_oid=$(git hash-object -t blob -w --stdin <file2) &&
27+
git tag blob-tag2 "$blob2_oid" &&
28+
29+
rm -fr child file file2 &&
30+
1031
mkdir left &&
1132
mkdir right &&
1233
echo a >a &&
1334
echo b >left/b &&
1435
echo c >right/c &&
1536
git add . &&
16-
git commit -m "first" &&
37+
git commit --amend -m "first" &&
38+
git tag -m "first" first HEAD &&
1739
1840
echo d >right/d &&
1941
git add right &&
2042
git commit -m "second" &&
43+
git tag -a -m "second (under)" second.1 HEAD &&
44+
git tag -a -m "second (top)" second.2 second.1 &&
2145
46+
# Set up file/dir collision in history.
47+
rm a &&
48+
mkdir a &&
49+
echo a >a/a &&
2250
echo bb >left/b &&
23-
git commit -a -m "third" &&
51+
git add a left &&
52+
git commit -m "third" &&
53+
git tag -a -m "third" third &&
2454
2555
git checkout -b topic HEAD~1 &&
2656
echo cc >right/c &&
27-
git commit -a -m "topic"
57+
git commit -a -m "topic" &&
58+
git tag -a -m "fourth" fourth
2859
'
2960

3061
test_expect_success 'all' '
@@ -40,19 +71,35 @@ test_expect_success 'all' '
4071
TREE::$(git rev-parse base^{tree})
4172
TREE::$(git rev-parse base~1^{tree})
4273
TREE::$(git rev-parse base~2^{tree})
74+
TREE::$(git rev-parse refs/tags/tree-tag^{})
75+
TREE::$(git rev-parse refs/tags/tree-tag2^{})
76+
TREE:a/:$(git rev-parse base:a)
4377
TREE:left/:$(git rev-parse base:left)
4478
TREE:left/:$(git rev-parse base~2:left)
4579
TREE:right/:$(git rev-parse topic:right)
4680
TREE:right/:$(git rev-parse base~1:right)
4781
TREE:right/:$(git rev-parse base~2:right)
48-
trees:9
82+
TREE:child/:$(git rev-parse refs/tags/tree-tag^{}:child)
83+
trees:13
4984
BLOB:a:$(git rev-parse base~2:a)
85+
BLOB:file2:$(git rev-parse refs/tags/tree-tag2^{}:file2)
5086
BLOB:left/b:$(git rev-parse base~2:left/b)
5187
BLOB:left/b:$(git rev-parse base:left/b)
5288
BLOB:right/c:$(git rev-parse base~2:right/c)
5389
BLOB:right/c:$(git rev-parse topic:right/c)
5490
BLOB:right/d:$(git rev-parse base~1:right/d)
55-
blobs:6
91+
BLOB:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
92+
BLOB:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
93+
BLOB:child/file:$(git rev-parse refs/tags/tree-tag^{}:child/file)
94+
blobs:10
95+
TAG::$(git rev-parse refs/tags/first)
96+
TAG::$(git rev-parse refs/tags/second.1)
97+
TAG::$(git rev-parse refs/tags/second.2)
98+
TAG::$(git rev-parse refs/tags/third)
99+
TAG::$(git rev-parse refs/tags/fourth)
100+
TAG::$(git rev-parse refs/tags/tree-tag)
101+
TAG::$(git rev-parse refs/tags/blob-tag)
102+
tags:7
56103
EOF
57104
58105
sort expect >expect.sorted &&
@@ -83,6 +130,7 @@ test_expect_success 'topic only' '
83130
BLOB:right/c:$(git rev-parse topic:right/c)
84131
BLOB:right/d:$(git rev-parse base~1:right/d)
85132
blobs:5
133+
tags:0
86134
EOF
87135
88136
sort expect >expect.sorted &&
@@ -106,6 +154,7 @@ test_expect_success 'topic, not base' '
106154
BLOB:right/c:$(git rev-parse topic:right/c)
107155
BLOB:right/d:$(git rev-parse topic:right/d)
108156
blobs:4
157+
tags:0
109158
EOF
110159
111160
sort expect >expect.sorted &&
@@ -126,6 +175,7 @@ test_expect_success 'topic, not base, only blobs' '
126175
BLOB:right/c:$(git rev-parse topic:right/c)
127176
BLOB:right/d:$(git rev-parse topic:right/d)
128177
blobs:4
178+
tags:0
129179
EOF
130180
131181
sort expect >expect.sorted &&
@@ -145,6 +195,7 @@ test_expect_success 'topic, not base, only commits' '
145195
commits:1
146196
trees:0
147197
blobs:0
198+
tags:0
148199
EOF
149200
150201
sort expect >expect.sorted &&
@@ -164,6 +215,7 @@ test_expect_success 'topic, not base, only trees' '
164215
TREE:right/:$(git rev-parse topic:right)
165216
trees:3
166217
blobs:0
218+
tags:0
167219
EOF
168220
169221
sort expect >expect.sorted &&
@@ -191,6 +243,7 @@ test_expect_success 'topic, not base, boundary' '
191243
BLOB:right/c:$(git rev-parse topic:right/c)
192244
BLOB:right/d:$(git rev-parse base~1:right/d)
193245
blobs:5
246+
tags:0
194247
EOF
195248
196249
sort expect >expect.sorted &&

0 commit comments

Comments
 (0)