Message ID | pull.1825.v3.git.1733999352289.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | Accepted |
Commit | f94bfa151623d7e675db9465ae7ff0b33e4825f3 |
Headers | show |
Series | [v3] log: --remerge-diff needs to keep around commit parents | expand |
"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com> writes: > This problem is most obvious when traversing the commits in reverse: In > that instance, if a parent of a merge commit has been shown as part of > the `git log` command, by the time the merge commit's diff needs to be > computed, that parent commit's list of parent commits will have been set > to `NULL` and as a result no merge base will be found (even if one > should be found). > > Traversing commits in reverse is far from the only circumstance in which > this problem occurs, though. There are many avenues to traversing at > least one commit in the revision walk that will later be part of a merge > base computation, for example when not even walking any revisions in > `git show <merge1> <merge2>` where `<merge1>` is part of the commit > graph between the parents of `<merge2>`. > > Another way to force a scenario where a commit is traversed before it > has to be traversed again as part of a merge base computation is to > start with two revisions (where the first one is reachable from the > second but not in a first-parent ancestry) and show the commit log with > `--topo-order` and `--first-parent`. > > Let's fix this by special-casing the `remerge_diff` mode, similar to > what we did with reflogs in f35650dff6a4 (log: do not free parents when > walking reflog, 2017-07-07). Nicely described. > This fixes a bug that is pretty much as old as the remerge-diff > machinery itself. I noticed it while writing my reply to Hannes Sixt's > concerns about my range-diff --diff-merges=<mode> patch > diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh > index 07323ebafe0..a68c6bfa036 100755 > --- a/t/t4069-remerge-diff.sh > +++ b/t/t4069-remerge-diff.sh > @@ -317,4 +317,11 @@ test_expect_success 'remerge-diff turns off history simplification' ' > test_cmp expect actual > ' > > +test_expect_success 'remerge-diff with --reverse' ' > + git log -1 --remerge-diff --oneline ab_resolution^ >expect && > + git log -1 --remerge-diff --oneline ab_resolution >>expect && > + git log -2 --remerge-diff --oneline ab_resolution --reverse >actual && > + test_cmp expect actual > +' > + Will queue. Let me mark it for 'next'. Thanks.
diff --git a/builtin/log.c b/builtin/log.c index c0a8bb95e98..2f88a3e607d 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -522,10 +522,14 @@ static int cmd_log_walk_no_free(struct rev_info *rev) * but we didn't actually show the commit. */ rev->max_count++; - if (!rev->reflog_info) { + if (!rev->reflog_info && !rev->remerge_diff) { /* * We may show a given commit multiple times when - * walking the reflogs. + * walking the reflogs. Therefore we still need it. + * + * Likewise, we potentially still need the parents + * of * already shown commits to determine merge + * bases when showing remerge diffs. */ free_commit_buffer(the_repository->parsed_objects, commit); diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh index 07323ebafe0..a68c6bfa036 100755 --- a/t/t4069-remerge-diff.sh +++ b/t/t4069-remerge-diff.sh @@ -317,4 +317,11 @@ test_expect_success 'remerge-diff turns off history simplification' ' test_cmp expect actual ' +test_expect_success 'remerge-diff with --reverse' ' + git log -1 --remerge-diff --oneline ab_resolution^ >expect && + git log -1 --remerge-diff --oneline ab_resolution >>expect && + git log -2 --remerge-diff --oneline ab_resolution --reverse >actual && + test_cmp expect actual +' + test_done