summaryrefslogtreecommitdiff
path: root/revision.c
diff options
context:
space:
mode:
authorThomas Rast <trast@inf.ethz.ch>2013-08-03 10:36:15 (GMT)
committerJunio C Hamano <gitster@pobox.com>2013-08-05 15:27:00 (GMT)
commit838f9a15667cfefa9e645c26627ce81ce7599915 (patch)
tree77c06d6fb1c158f6d8f8b61920e65ab7b25579a2 /revision.c
parent53d00b39ce00073ab6b450488acc3f532a223e8f (diff)
downloadgit-838f9a15667cfefa9e645c26627ce81ce7599915.zip
git-838f9a15667cfefa9e645c26627ce81ce7599915.tar.gz
git-838f9a15667cfefa9e645c26627ce81ce7599915.tar.bz2
log: use true parents for diff when walking reflogs
The reflog walking logic (git log -g) replaces the true parent list with the preceding commit in the reflog. This results in bogus commit diffs when combined with options such as -p; the diff is against the reflog predecessor, not the parent of the commit. Save the true parents on the side, extending the functions from the previous commit. The diff logic picks them up and uses them to show the correct diffs. We do have to be somewhat careful about repeated calling of save_parents(), since the reflog may list a commit more than once. We now store (commit_list*)-1 to distinguish the "not saved yet" and "root commit" cases. This lets us preserve an empty parent list even if save_parents() is repeatedly called. Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Thomas Rast <trast@inf.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
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 e3ca936..ac20d1a 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)