free(entry);
if (revs->reflog_info) {
+ save_parents(revs, commit);
fake_reflog_parent(revs->reflog_info, commit);
commit->object.flags &= ~(ADDED | SEEN | SHOWN);
}
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;
}
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)
test_cmp expect actual
'
+# This guards against the alternative of showing the diffs vs. the
+# reflog ancestor. The reflog used is designed to list the commits
+# more than once, so as to exercise the corresponding logic.
+test_expect_success 'git log -g -p shows diffs vs. parents' '
+ test_commit two &&
+ git branch flipflop &&
+ git update-ref refs/heads/flipflop -m flip1 HEAD^ &&
+ git update-ref refs/heads/flipflop -m flop1 HEAD &&
+ git update-ref refs/heads/flipflop -m flip2 HEAD^ &&
+ git log -g -p flipflop >reflog &&
+ grep -v ^Reflog reflog >actual &&
+ git log -1 -p HEAD^ >log.one &&
+ git log -1 -p HEAD >log.two &&
+ (
+ cat log.one; echo
+ cat log.two; echo
+ cat log.one; echo
+ cat log.two
+ ) >expect &&
+ test_cmp expect actual
+'
+
test_done