rebase --stat: fix when rebasing to an unrelated history

When rebasing to a commit history that has no common commits with the current branch, there is no merge base. In diffstat mode, this means that we cannot compare to the merge base, but we have to compare to the empty tree instead. Also, if running in verbose diffstat mode, we should not output Changes from <merge-base> to <onto> as that does not make sense without any merge base. Note: neither scripted nor built-in versoin of `git rebase` were prepared for this situation well. We use this opportunity not only to fix the bug(s), but also to make both versions' output consistent in this instance. And add a regression test to keep this working in all eternity. Reported-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Nov 29, 2018 at 05:01 UTC 8797f0f008722537f56ed0bf16ebec45682b7497
3 files changed +30 -8
builtin/rebase.c
+12 -6
@@ -1481,10 +1481,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1481 if (options.flags & REBASE_DIFFSTAT) {
1482 struct diff_options opts;
1483
1484 - if (options.flags & REBASE_VERBOSE)
1485 - printf(_("Changes from %s to %s:\n"),
1486 - oid_to_hex(&merge_base),
1487 - oid_to_hex(&options.onto->object.oid));
1484 + if (options.flags & REBASE_VERBOSE) {
1485 + if (is_null_oid(&merge_base))
1486 + printf(_("Changes to %s:\n"),
1487 + oid_to_hex(&options.onto->object.oid));
1488 + else
1489 + printf(_("Changes from %s to %s:\n"),
1490 + oid_to_hex(&merge_base),
1491 + oid_to_hex(&options.onto->object.oid));
1492 + }
1493
1494 /* We want color (if set), but no pager */
1495 diff_setup(&opts);
@@ -1494,8 +1499,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1499 DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
1500 opts.detect_rename = DIFF_DETECT_RENAME;
1501 diff_setup_done(&opts);
1497 - diff_tree_oid(&merge_base, &options.onto->object.oid,
1498 - "", &opts);
1502 + diff_tree_oid(is_null_oid(&merge_base) ?
1503 + the_hash_algo->empty_tree : &merge_base,
1504 + &options.onto->object.oid, "", &opts);
1505 diffcore_std(&opts);
1506 diff_flush(&opts);
1507 }
git-legacy-rebase.sh
+8 -2
@@ -718,10 +718,16 @@ if test -n "$diffstat"
718 then
719 if test -n "$verbose"
720 then
721 - echo "$(eval_gettext "Changes from \$mb to \$onto:")"
721 + if test -z "$mb"
722 + then
723 + echo "$(eval_gettext "Changes to \$onto:")"
724 + else
725 + echo "$(eval_gettext "Changes from \$mb to \$onto:")"
726 + fi
727 fi
728 + mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
729 # We want color (if set), but no pager
724 - GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
730 + GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
731 fi
732
733 test -n "$interactive_rebase" && run_specific_rebase
t/t3406-rebase-message.sh
+10
@@ -91,4 +91,14 @@ test_expect_success 'error out early upon -C<n> or --whitespace=<bad>' '
91 test_i18ngrep "Invalid whitespace option" err
92 '
93
94 +test_expect_success 'rebase -i onto unrelated history' '
95 + git init unrelated &&
96 + test_commit -C unrelated 1 &&
97 + git -C unrelated remote add -f origin "$PWD" &&
98 + git -C unrelated branch --set-upstream-to=origin/master &&
99 + git -C unrelated -c core.editor=true rebase -i -v --stat >actual &&
100 + test_i18ngrep "Changes to " actual &&
101 + test_i18ngrep "5 files changed" actual
102 +'
103 +
104 test_done