Skip to content

Commit 2073949

Browse files
peffgitster
authored andcommitted
traverse_commit_list: support pending blobs/trees with paths
When we call traverse_commit_list, we may have trees and blobs in the pending array. As we process these, we pass the "name" field from the pending entry as the path of the object within the tree (which then becomes the root path if we recurse into subtrees). When we set up the traversal in prepare_revision_walk, though, the "name" field of any pending trees and blobs is likely to be the ref at which we found the object. We would not want to make this part of the path (e.g., doing so would make "git rev-list --objects v2.6.11-tree" in linux.git show paths like "v2.6.11-tree/Makefile", which is nonsensical). Therefore prepare_revision_walk sets the name field of each pending tree and blobs to the empty string. However, this leaves no room for a caller who does know the correct path of a pending object to propagate that information to the revision walker. We can fix this by making two related changes: 1. Use the "path" field as the path instead of the "name" field in traverse_commit_list. If the path is not set, default to "" (which is what we always ended up with in the current code, because of prepare_revision_walk). 2. In prepare_revision_walk, make a complete copy of the entry. This makes the path field available to the walker (if there is one), solving our problem. Leaving the name field intact is now OK, as we do not use it as a path due to point (1) above (and we can use it to make more meaningful error messages if we want). We also make the original "mode" field available to the walker, though it does not actually use it. Note that we still re-add the pending objects and free the old ones (so we may strdup the path and name only to free the old ones). This could be made more efficient by simply copying the object_array entries that we are keeping. However, that would require more restructuring of the code, and is not done here. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9e0c3c4 commit 2073949

File tree

2 files changed

+32
-9
lines changed

2 files changed

+32
-9
lines changed

list-objects.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,21 +208,24 @@ void traverse_commit_list(struct rev_info *revs,
208208
struct object_array_entry *pending = revs->pending.objects + i;
209209
struct object *obj = pending->item;
210210
const char *name = pending->name;
211+
const char *path = pending->path;
211212
if (obj->flags & (UNINTERESTING | SEEN))
212213
continue;
213214
if (obj->type == OBJ_TAG) {
214215
obj->flags |= SEEN;
215216
show_object(obj, NULL, name, data);
216217
continue;
217218
}
219+
if (!path)
220+
path = "";
218221
if (obj->type == OBJ_TREE) {
219222
process_tree(revs, (struct tree *)obj, show_object,
220-
NULL, &base, name, data);
223+
NULL, &base, path, data);
221224
continue;
222225
}
223226
if (obj->type == OBJ_BLOB) {
224227
process_blob(revs, (struct blob *)obj, show_object,
225-
NULL, name, data);
228+
NULL, path, data);
226229
continue;
227230
}
228231
die("unknown pending object %s (%s)",

revision.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,10 @@ void mark_parents_uninteresting(struct commit *commit)
198198
}
199199
}
200200

201-
static void add_pending_object_with_mode(struct rev_info *revs,
201+
static void add_pending_object_with_path(struct rev_info *revs,
202202
struct object *obj,
203-
const char *name, unsigned mode)
203+
const char *name, unsigned mode,
204+
const char *path)
204205
{
205206
if (!obj)
206207
return;
@@ -220,7 +221,14 @@ static void add_pending_object_with_mode(struct rev_info *revs,
220221
if (st)
221222
return;
222223
}
223-
add_object_array_with_mode(obj, name, &revs->pending, mode);
224+
add_object_array_with_path(obj, name, &revs->pending, mode, path);
225+
}
226+
227+
static void add_pending_object_with_mode(struct rev_info *revs,
228+
struct object *obj,
229+
const char *name, unsigned mode)
230+
{
231+
add_pending_object_with_path(revs, obj, name, mode, NULL);
224232
}
225233

226234
void add_pending_object(struct rev_info *revs,
@@ -265,8 +273,12 @@ void add_pending_sha1(struct rev_info *revs, const char *name,
265273
}
266274

267275
static struct commit *handle_commit(struct rev_info *revs,
268-
struct object *object, const char *name)
276+
struct object_array_entry *entry)
269277
{
278+
struct object *object = entry->item;
279+
const char *name = entry->name;
280+
const char *path = entry->path;
281+
unsigned int mode = entry->mode;
270282
unsigned long flags = object->flags;
271283

272284
/*
@@ -285,6 +297,14 @@ static struct commit *handle_commit(struct rev_info *revs,
285297
die("bad object %s", sha1_to_hex(tag->tagged->sha1));
286298
}
287299
object->flags |= flags;
300+
/*
301+
* We'll handle the tagged object by looping or dropping
302+
* through to the non-tag handlers below. Do not
303+
* propagate data from the tag's pending entry.
304+
*/
305+
name = "";
306+
path = NULL;
307+
mode = 0;
288308
}
289309

290310
/*
@@ -316,7 +336,7 @@ static struct commit *handle_commit(struct rev_info *revs,
316336
mark_tree_contents_uninteresting(tree);
317337
return NULL;
318338
}
319-
add_pending_object(revs, object, "");
339+
add_pending_object_with_path(revs, object, name, mode, path);
320340
return NULL;
321341
}
322342

@@ -328,7 +348,7 @@ static struct commit *handle_commit(struct rev_info *revs,
328348
return NULL;
329349
if (flags & UNINTERESTING)
330350
return NULL;
331-
add_pending_object(revs, object, "");
351+
add_pending_object_with_path(revs, object, name, mode, path);
332352
return NULL;
333353
}
334354
die("%s is unknown object", name);
@@ -2666,7 +2686,7 @@ int prepare_revision_walk(struct rev_info *revs)
26662686
revs->pending.objects = NULL;
26672687
for (i = 0; i < old_pending.nr; i++) {
26682688
struct object_array_entry *e = old_pending.objects + i;
2669-
struct commit *commit = handle_commit(revs, e->item, e->name);
2689+
struct commit *commit = handle_commit(revs, e);
26702690
if (commit) {
26712691
if (!(commit->object.flags & SEEN)) {
26722692
commit->object.flags |= SEEN;

0 commit comments

Comments
 (0)