commit 7e66511645edba471993334510005bb30c00cefc from: Stefan Sperling date: Mon Apr 02 19:25:56 2018 UTC 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. commit - 675d71c4343c11708d0df6b8965cb4e6f3a42ea2 commit + 7e66511645edba471993334510005bb30c00cefc blob - 46570b469f891b3661e5361cc7bfe505ebc3afc4 blob + c9ea7a877089fb35835cb3d796c4f8efae413fbc --- got/got.c +++ got/got.c @@ -364,48 +364,51 @@ print_commits(struct got_object *root_obj, struct got_ 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; 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; - } + if (entry->commit->nparents == 0) + 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); + /* 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);