Skip to content

Commit cc5fa2f

Browse files
newrengitster
authored andcommitted
Make rev-list --objects work together with pathspecs
When traversing commits, the selection of commits would heed the list of pathspecs passed, but subsequent walking of the trees of those commits would not. This resulted in 'rev-list --objects HEAD -- <paths>' displaying objects at unwanted paths. Have process_tree() call tree_entry_interesting() to determine which paths are interesting and should be walked. Naturally, this change can provide a large speedup when paths are specified together with --objects, since many tree entries are now correctly ignored. Interestingly, though, this change also gives me a small (~1%) but repeatable speedup even when no paths are specified with --objects. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f577b92 commit cc5fa2f

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

list-objects.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,15 @@ static void process_tree(struct rev_info *revs,
6161
struct tree *tree,
6262
show_object_fn show,
6363
struct name_path *path,
64+
struct strbuf *base,
6465
const char *name)
6566
{
6667
struct object *obj = &tree->object;
6768
struct tree_desc desc;
6869
struct name_entry entry;
6970
struct name_path me;
71+
int all_interesting = (revs->diffopt.pathspec.nr == 0);
72+
int baselen = base->len;
7073

7174
if (!revs->tree_objects)
7275
return;
@@ -82,13 +85,32 @@ static void process_tree(struct rev_info *revs,
8285
me.elem = name;
8386
me.elem_len = strlen(name);
8487

88+
if (!all_interesting) {
89+
strbuf_addstr(base, name);
90+
if (base->len)
91+
strbuf_addch(base, '/');
92+
}
93+
8594
init_tree_desc(&desc, tree->buffer, tree->size);
8695

8796
while (tree_entry(&desc, &entry)) {
97+
if (!all_interesting) {
98+
int showit = tree_entry_interesting(&entry,
99+
base, 0,
100+
&revs->diffopt.pathspec);
101+
102+
if (showit < 0)
103+
break;
104+
else if (!showit)
105+
continue;
106+
else if (showit == 2)
107+
all_interesting = 1;
108+
}
109+
88110
if (S_ISDIR(entry.mode))
89111
process_tree(revs,
90112
lookup_tree(entry.sha1),
91-
show, &me, entry.path);
113+
show, &me, base, entry.path);
92114
else if (S_ISGITLINK(entry.mode))
93115
process_gitlink(revs, entry.sha1,
94116
show, &me, entry.path);
@@ -97,6 +119,7 @@ static void process_tree(struct rev_info *revs,
97119
lookup_blob(entry.sha1),
98120
show, &me, entry.path);
99121
}
122+
strbuf_setlen(base, baselen);
100123
free(tree->buffer);
101124
tree->buffer = NULL;
102125
}
@@ -146,7 +169,9 @@ void traverse_commit_list(struct rev_info *revs,
146169
{
147170
int i;
148171
struct commit *commit;
172+
struct strbuf base;
149173

174+
strbuf_init(&base, PATH_MAX);
150175
while ((commit = get_revision(revs)) != NULL) {
151176
add_pending_tree(revs, commit->tree);
152177
show_commit(commit, data);
@@ -164,7 +189,7 @@ void traverse_commit_list(struct rev_info *revs,
164189
}
165190
if (obj->type == OBJ_TREE) {
166191
process_tree(revs, (struct tree *)obj, show_object,
167-
NULL, name);
192+
NULL, &base, name);
168193
continue;
169194
}
170195
if (obj->type == OBJ_BLOB) {
@@ -181,4 +206,5 @@ void traverse_commit_list(struct rev_info *revs,
181206
revs->pending.alloc = 0;
182207
revs->pending.objects = NULL;
183208
}
209+
strbuf_release(&base);
184210
}

0 commit comments

Comments
 (0)