got log: do a first-parent commit traversal instead of N-parent Running 'got log' on a repository with merge commits shows that this code isn't ready to handle merge commits yet. It printed many commits multiple times and used up a lot of memory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
diff --git a/got/got.c b/got/got.c
index 46570b4..c9ea7a8 100644
--- a/got/got.c
+++ b/got/got.c
@@ -364,8 +364,12 @@ print_commits(struct got_object *root_obj, struct got_object_id *root_id,
while (!TAILQ_EMPTY(&commits)) {
struct got_parent_id *pid;
+ struct got_object *obj;
+ struct got_commit_object *pcommit;
+ struct commit_queue_entry *pentry;
entry = TAILQ_FIRST(&commits);
+
err = print_commit(entry->commit, entry->id, repo, show_patch);
if (err)
break;
@@ -373,39 +377,38 @@ print_commits(struct got_object *root_obj, struct got_object_id *root_id,
if (limit && --limit == 0)
break;
- SIMPLEQ_FOREACH(pid, &entry->commit->parent_ids, entry) {
- struct got_object *obj;
- struct got_commit_object *pcommit;
- struct commit_queue_entry *pentry;
-
- err = got_object_open(&obj, repo, pid->id);
- if (err)
- break;
- if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
- err = got_error(GOT_ERR_OBJ_TYPE);
- break;
- }
-
- err = got_object_commit_open(&pcommit, repo, obj);
- got_object_close(obj);
- if (err)
- break;
-
- pentry = calloc(1, sizeof(*pentry));
- if (pentry == NULL) {
- err = got_error_from_errno();
- got_object_commit_close(pcommit);
- break;
- }
- pentry->id = got_object_id_dup(pid->id);
- if (pentry->id == NULL) {
- err = got_error_from_errno();
- got_object_commit_close(pcommit);
- break;
- }
- pentry->commit = pcommit;
- TAILQ_INSERT_TAIL(&commits, pentry, entry);
+ if (entry->commit->nparents == 0)
+ break;
+
+ /* Follow the first parent (TODO: handle merge commits). */
+ pid = SIMPLEQ_FIRST(&entry->commit->parent_ids);
+ err = got_object_open(&obj, repo, pid->id);
+ if (err)
+ break;
+ if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
+ err = got_error(GOT_ERR_OBJ_TYPE);
+ break;
+ }
+
+ err = got_object_commit_open(&pcommit, repo, obj);
+ got_object_close(obj);
+ if (err)
+ break;
+
+ pentry = calloc(1, sizeof(*pentry));
+ if (pentry == NULL) {
+ err = got_error_from_errno();
+ got_object_commit_close(pcommit);
+ break;
+ }
+ pentry->id = got_object_id_dup(pid->id);
+ if (pentry->id == NULL) {
+ err = got_error_from_errno();
+ got_object_commit_close(pcommit);
+ break;
}
+ pentry->commit = pcommit;
+ TAILQ_INSERT_TAIL(&commits, pentry, entry);
TAILQ_REMOVE(&commits, entry, entry);
got_object_commit_close(entry->commit);