summaryrefslogtreecommitdiff
path: root/revision.c
diff options
context:
space:
mode:
Diffstat (limited to 'revision.c')
-rw-r--r--revision.c28
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)