@matheusbsbs / matheus-bagliano / commits / cc5fa2fdaf
Fork 0

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 <newren@gmail.com> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Dec 17, 2010 at 20:26 UTC cc5fa2fdafa186d6e1e310828b22d0028e1fb51b
1 file changed +28 -2
list-objects.c
+28 -2
@@ -61,12 +61,15 @@ static void process_tree(struct rev_info *revs,
61 struct tree *tree,
62 show_object_fn show,
63 struct name_path *path,
64 + struct strbuf *base,
65 const char *name)
66 {
67 struct object *obj = &tree->object;
68 struct tree_desc desc;
69 struct name_entry entry;
70 struct name_path me;
71 + int all_interesting = (revs->diffopt.pathspec.nr == 0);
72 + int baselen = base->len;
73
74 if (!revs->tree_objects)
75 return;
@@ -82,13 +85,32 @@ static void process_tree(struct rev_info *revs,
85 me.elem = name;
86 me.elem_len = strlen(name);
87
88 + if (!all_interesting) {
89 + strbuf_addstr(base, name);
90 + if (base->len)
91 + strbuf_addch(base, '/');
92 + }
93 +
94 init_tree_desc(&desc, tree->buffer, tree->size);
95
96 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 +
110 if (S_ISDIR(entry.mode))
111 process_tree(revs,
112 lookup_tree(entry.sha1),
91 - show, &me, entry.path);
113 + show, &me, base, entry.path);
114 else if (S_ISGITLINK(entry.mode))
115 process_gitlink(revs, entry.sha1,
116 show, &me, entry.path);
@@ -97,6 +119,7 @@ static void process_tree(struct rev_info *revs,
119 lookup_blob(entry.sha1),
120 show, &me, entry.path);
121 }
122 + strbuf_setlen(base, baselen);
123 free(tree->buffer);
124 tree->buffer = NULL;
125 }
@@ -146,7 +169,9 @@ void traverse_commit_list(struct rev_info *revs,
169 {
170 int i;
171 struct commit *commit;
172 + struct strbuf base;
173
174 + strbuf_init(&base, PATH_MAX);
175 while ((commit = get_revision(revs)) != NULL) {
176 add_pending_tree(revs, commit->tree);
177 show_commit(commit, data);
@@ -164,7 +189,7 @@ void traverse_commit_list(struct rev_info *revs,
189 }
190 if (obj->type == OBJ_TREE) {
191 process_tree(revs, (struct tree *)obj, show_object,
167 - NULL, name);
192 + NULL, &base, name);
193 continue;
194 }
195 if (obj->type == OBJ_BLOB) {
@@ -181,4 +206,5 @@ void traverse_commit_list(struct rev_info *revs,
206 revs->pending.alloc = 0;
207 revs->pending.objects = NULL;
208 }
209 + strbuf_release(&base);
210 }