]> git.ipfire.org Git - thirdparty/git.git/commitdiff
diff-tree: fix crash when used with --remerge-diff
authorXing Xin <xingxin.xx@bytedance.com>
Fri, 9 Aug 2024 07:24:52 +0000 (07:24 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 9 Aug 2024 15:07:44 +0000 (08:07 -0700)
When using "git-diff-tree" to get the tree diff for merge commits with
the diff format set to `remerge`, a bug is triggered as shown below:

  $ git diff-tree -r --remerge-diff 363337e6eb
  363337e6eb812d0c0d785ed4261544f35559ff8b
  BUG: log-tree.c:1006: did a remerge diff without remerge_objdir?!?

This bug is reported by `log-tree.c:do_remerge_diff`, where a bug check
added in commit 7b90ab467a (log: clean unneeded objects during log
--remerge-diff, 2022-02-02) detects the absence of `remerge_objdir` when
attempting to clean up temporary objects generated during the remerge
process.

After some further digging, I find that the remerge-related diff options
were introduced in db757e8b8d (show, log: provide a --remerge-diff
capability, 2022-02-02), which also affect the setup of `rev_info` for
"git-diff-tree", but were not accounted for in the original
implementation (inferred from the commit message).

Elijah Newren, the author of the remerge diff feature, notes that other
callers of `log-tree.c:log_tree_commit` (the only caller of
`log-tree.c:do_remerge_diff`) also exist, but:

  `builtin/am.c`: manually sets all flags; remerge_diff is not among them
  `sequencer.c`: manually sets all flags; remerge_diff is not among them

so `builtin/diff-tree.c` really is the only caller that was overlooked
when remerge-diff functionality was added.

This commit resolves the crash by adding `remerge_objdir` setup logic to
`builtin/diff-tree.c`, mirroring `builtin/log.c:cmd_log_walk_no_free`.
It also includes the necessary cleanup for `remerge_objdir`.

Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Xing Xin <xingxin.xx@bytedance.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/diff-tree.c
t/t4069-remerge-diff.sh

index a8e68ce8ef6275a99e2a4f62545d0e7d962dcf45..12012ea0939fd5a2b52f6885df904d5d2944e780 100644 (file)
@@ -9,6 +9,7 @@
 #include "read-cache-ll.h"
 #include "repository.h"
 #include "revision.h"
+#include "tmp-objdir.h"
 #include "tree.h"
 
 static struct rev_info log_tree_opt;
@@ -167,6 +168,13 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 
        opt->diffopt.rotate_to_strict = 1;
 
+       if (opt->remerge_diff) {
+               opt->remerge_objdir = tmp_objdir_create("remerge-diff");
+               if (!opt->remerge_objdir)
+                       die(_("unable to create temporary object directory"));
+               tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1);
+       }
+
        /*
         * NOTE!  We expect "a..b" to expand to "^a b" but it is
         * perfectly valid for revision range parser to yield "b ^a",
@@ -231,5 +239,10 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
                diff_free(&opt->diffopt);
        }
 
+       if (opt->remerge_diff) {
+               tmp_objdir_destroy(opt->remerge_objdir);
+               opt->remerge_objdir = NULL;
+       }
+
        return diff_result_code(&opt->diffopt);
 }
index 07323ebafe0d0cb49f08c4396116fa1f45687cd8..ca8f999caba54db646a81f99b7df519ee676197e 100755 (executable)
@@ -110,6 +110,41 @@ test_expect_success 'can filter out additional headers with pickaxe' '
        test_must_be_empty actual
 '
 
+test_expect_success 'remerge-diff also works for git-diff-tree' '
+       # With a clean merge
+       git diff-tree -r -p --remerge-diff --no-commit-id bc_resolution >actual &&
+       test_must_be_empty actual &&
+
+       # With both a resolved conflict and an unrelated change
+       cat <<-EOF >tmp &&
+       diff --git a/numbers b/numbers
+       remerge CONFLICT (content): Merge conflict in numbers
+       index a1fb731..6875544 100644
+       --- a/numbers
+       +++ b/numbers
+       @@ -1,13 +1,9 @@
+        1
+        2
+       -<<<<<<< b0ed5cb (change_a)
+       -three
+       -=======
+       -tres
+       ->>>>>>> 6cd3f82 (change_b)
+       +drei
+        4
+        5
+        6
+        7
+       -eight
+       +acht
+        9
+       EOF
+       sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+       git diff-tree -r -p --remerge-diff --no-commit-id ab_resolution >tmp &&
+       sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'setup non-content conflicts' '
        git switch --orphan base &&