diff options
Diffstat (limited to 'revision.c')
-rw-r--r-- | revision.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/revision.c b/revision.c index e3ca9361b4..ac20d1aaed 100644 --- a/revision.c +++ b/revision.c @@ -2848,6 +2848,7 @@ static struct commit *get_revision_1(struct rev_info *revs) free(entry); if (revs->reflog_info) { + save_parents(revs, commit); fake_reflog_parent(revs->reflog_info, commit); commit->object.flags &= ~(ADDED | SEEN | SHOWN); } @@ -3083,6 +3084,8 @@ void put_revision_mark(const struct rev_info *revs, const struct commit *commit) define_commit_slab(saved_parents, struct commit_list *); +#define EMPTY_PARENT_LIST ((struct commit_list *)-1) + void save_parents(struct rev_info *revs, struct commit *commit) { struct commit_list **pp; @@ -3093,16 +3096,35 @@ void save_parents(struct rev_info *revs, struct commit *commit) } pp = saved_parents_at(revs->saved_parents_slab, commit); - assert(*pp == NULL); - *pp = copy_commit_list(commit->parents); + + /* + * When walking with reflogs, we may visit the same commit + * several times: once for each appearance in the reflog. + * + * In this case, save_parents() will be called multiple times. + * We want to keep only the first set of parents. We need to + * store a sentinel value for an empty (i.e., NULL) parent + * list to distinguish it from a not-yet-saved list, however. + */ + if (*pp) + return; + if (commit->parents) + *pp = copy_commit_list(commit->parents); + else + *pp = EMPTY_PARENT_LIST; } struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit) { + struct commit_list *parents; + if (!revs->saved_parents_slab) return commit->parents; - return *saved_parents_at(revs->saved_parents_slab, commit); + parents = *saved_parents_at(revs->saved_parents_slab, commit); + if (parents == EMPTY_PARENT_LIST) + return NULL; + return parents; } void free_saved_parents(struct rev_info *revs) |