Merge branch 'kh/format-patch-range-diff-notes' into jch

The 'format-patch' command has been updated with options to
configure notes specifically for range-diff output, allowing them to
differ from the notes displayed on the patches themselves.

* kh/format-patch-range-diff-notes:
  format-patch: learn --[no-]range-diff-notes
  format-patch: simplify get_notes_arg parameters
jch
Junio C Hamano 2026-10-12 09:25:56 -07:00
commit 156e0b9b3f
3 changed files with 141 additions and 6 deletions

View File

@ -378,6 +378,17 @@ case is to show comparison with an older iteration of the same
topic and the tool should find more correspondence between the two
sets of patches.

`--range-diff-notes=<ref>`::
`--no-range-diff-notes`::
Used with `--range-diff`, tweak what notes to display in the
range diff.
+
The default behavior is to display the same notes in the range diff as
on the patches; see `--notes`. Use `--range-diff-notes=<ref>` to use
_<ref>_ for the range diff instead. This option can be given multiple
times to show notes from multiple refs. Use `--no-range-diff-notes` to
disable notes in the range diff.

`--notes[=<ref>]`::
`--no-notes`::
Append the notes (see linkgit:git-notes[1]) for the commit

View File

@ -1327,22 +1327,53 @@ do_pp:
strbuf_release(&subject_sb);
}

struct rdiff_notes {
/*
* True if we want to override the notes behavior
* of 'format-patch'
*/
bool override;
struct string_list notes;
};

static int rdiff_notes_cb(const struct option *option,
const char *arg,
int unset)
{
struct option opt = *option;
struct rdiff_notes *rdiff_notes = option->value;

rdiff_notes->override = 1;
opt.value = &rdiff_notes->notes;
return parse_opt_string_list(&opt, arg, unset);
}

static int get_notes_refs(struct string_list_item *item, void *arg)
{
strvec_pushf(arg, "--notes=%s", item->string);
return 0;
}

static void get_notes_args(struct strvec *arg, struct rev_info *rev)
static void get_notes_args(struct rdiff_notes *rdiff_notes,
struct rev_info *rev)
{
if (!rev->show_notes) {
strvec_push(arg, "--no-notes");
if (rdiff_notes->override) {
if (rdiff_notes->notes.nr)
for_each_string_list(&rdiff_notes->notes,
get_notes_refs,
&rev->rdiff_log_arg);
else
strvec_push(&rev->rdiff_log_arg, "--no-notes");
} else if (!rev->show_notes) {
strvec_push(&rev->rdiff_log_arg, "--no-notes");
} else if (rev->notes_opt.use_default_notes > 0 ||
(rev->notes_opt.use_default_notes == -1 &&
!rev->notes_opt.extra_notes_refs.nr)) {
strvec_push(arg, "--notes");
strvec_push(&rev->rdiff_log_arg, "--notes");
} else {
for_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);
for_each_string_list(&rev->notes_opt.extra_notes_refs,
get_notes_refs,
&rev->rdiff_log_arg);
}
}

@ -1993,6 +2024,9 @@ int cmd_format_patch(int argc,
struct strbuf rdiff1 = STRBUF_INIT;
struct strbuf rdiff2 = STRBUF_INIT;
struct strbuf rdiff_title = STRBUF_INIT;
struct rdiff_notes rdiff_notes = {
.notes = STRING_LIST_INIT_NODUP,
};
const char *rfc = NULL;
int creation_factor = -1;
const char *signature = git_version_string;
@ -2089,6 +2123,9 @@ int cmd_format_patch(int argc,
parse_opt_object_name),
OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"),
N_("show changes against <refspec> in cover letter or single patch")),
OPT_CALLBACK_F(0, "range-diff-notes", &rdiff_notes, N_("note"),
N_("override notes behavior for the range diff"),
0, rdiff_notes_cb),
OPT_INTEGER(0, "creation-factor", &creation_factor,
N_("percentage by which creation is weighted")),
OPT_BOOL(0, "force-in-body-from", &force_in_body_from,
@ -2404,7 +2441,7 @@ int cmd_format_patch(int argc,
rev.rdiff_title = diff_title(&rdiff_title, reroll_count,
_("Range-diff:"),
_("Range-diff against v%d:"));
get_notes_args(&(rev.rdiff_log_arg), &rev);
get_notes_args(&rdiff_notes, &rev);
}

/*
@ -2568,6 +2605,7 @@ done:
release_revisions(&rev);
format_config_release(&cfg);
strvec_clear(&rev.rdiff_log_arg);
string_list_clear(&rdiff_notes.notes, 0);
return 0;
}


View File

@ -845,6 +845,92 @@ test_expect_success 'format-patch --range-diff with multiple notes' '
test_cmp expect actual
'

# Unlike '--notes', '--range-diff-notes' requires a value
test_expect_success 'format-patch --range-diff-notes requires a value' '
cat >expect <<-EOF &&
error: option \`range-diff-notes${SQ} requires a value
EOF
test_must_fail git format-patch --range-diff=main..topic \
--cover-letter --range-diff-notes 2>actual &&
test_cmp expect actual
'

# The '--range-diff-notes' has no effect but is allowed
test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '
test_when_finished "rm -f 000?-*" &&
git format-patch --range-diff-notes=not-a-note --cover-letter \
main..unmodified &&
test_file_not_empty 0000-cover-letter* &&
test_grep ! "^Range-diff:" 0000-cover-letter* &&
test_grep ! "## Notes " 0000-cover-letter*
'

test_expect_success 'format-patch --range-diff --notes=custom --no-range-diff-notes' '
test_when_finished "git notes --ref=custom remove topic unmodified || :" &&
git notes --ref=custom add -m "topic note1" topic &&
git notes --ref=custom add -m "unmodified note1" unmodified &&
test_when_finished "rm -f 000?-*" &&
git format-patch --range-diff=main..topic --notes=custom \
--no-range-diff-notes --cover-letter \
main..unmodified &&
test_grep "^Notes (custom):" 0004-* &&
test_grep "^Range-diff:" 0000-cover-letter* &&
test_grep ! "## Notes (custom) ##" 0000-cover-letter*
'

test_expect_success 'format-patch --range-diff --no-notes --range-diff-notes=custom' '
test_when_finished "git notes --ref=custom remove topic unmodified || :" &&
git notes --ref=custom add -m "topic note1" topic &&
git notes --ref=custom add -m "unmodified note1" unmodified &&
test_when_finished "rm -f 000?-*" &&
git format-patch --range-diff=main..topic --no-notes \
--range-diff-notes=custom --cover-letter \
main..unmodified &&
test_grep ! "^Notes (custom):" 0004-* &&
test_grep "^Range-diff:" 0000-cover-letter* &&
test_grep "## Notes (custom) ##" 0000-cover-letter*
'

test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes=rdiff' '
test_when_finished "git notes --ref=patch remove topic unmodified || :" &&
git notes --ref=patch add -m "only for patch 1" topic &&
git notes --ref=patch add -m "only for patch 2" unmodified &&
test_when_finished "git notes --ref=rdiff remove topic unmodified || :" &&
git notes --ref=rdiff add -m "only for range diff 1" topic &&
git notes --ref=rdiff add -m "only for range diff 2" unmodified &&
test_when_finished "rm -f 000?-*" &&
git format-patch --range-diff=main..topic --notes=patch \
--range-diff-notes=rdiff --cover-letter \
main..unmodified &&
test_grep "^Notes (patch):" 0004-* &&
test_grep ! "^Notes (rdiff):" 0004-* &&
test_grep "^Range-diff:" 0000-cover-letter* &&
test_grep "## Notes (rdiff) ##" 0000-cover-letter* &&
test_grep ! "## Notes (patch) ##" 0000-cover-letter*
'

test_expect_success 'format-patch --range-diff --no-range-diff-notes on single patch' '
test_when_finished "git notes --ref=custom remove HEAD unmodified || :" &&
git notes --ref=custom add -m "topic note (custom)" HEAD &&
git notes --ref=custom add -m "unmodified note (custom)" unmodified &&
git format-patch --notes=custom --range-diff=main..topic \
--no-range-diff-notes -1 --stdout >actual &&
test_grep "Notes (custom):" actual &&
test_grep "^Range-diff:" actual &&
test_grep ! "## Notes (custom) ##" actual
'

test_expect_success 'format-patch --range-diff --range-diff-notes=custom on single patch' '
test_when_finished "git notes --ref=custom remove HEAD unmodified || :" &&
git notes --ref=custom add -m "topic note (custom)" HEAD &&
git notes --ref=custom add -m "unmodified note (custom)" unmodified &&
git format-patch --range-diff=main..topic \
--range-diff-notes=custom -1 --stdout >actual &&
test_grep ! "Notes (custom):" actual &&
test_grep "^Range-diff:" actual &&
test_grep "## Notes (custom) ##" actual
'

test_expect_success '--left-only/--right-only' '
git switch --orphan left-right &&
test_commit first &&