[PATCH v2 0/2] format-patch: learn --[no-]range-diff-notes
- From
- kristofferhaugsbakk@fastmail.com <kristofferhaugsbakk@fastmail.com>
- Date
- Sep 26, 2026, 18:27 UTC
- Message-ID
- <V2_CV_format-patch_learn_--range-diff-notes.cdb@m5gid.xyz>
- In-Reply-To
- <CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz>
From: Kristoffer Haugsbakk <code@khaugsbakk.name>
Topic name (applied): kh/format-patch-range-diff-notes
Topic summary: Teach 'format-patch' options to tweak notes output in the range diff independent of what notes are output in the patches.
Hey, sorry if someone got duplicate emails right now! I tried to send out about ten minutes ago but it didn’t hit the list. It turned out that there was no `To` header.
Well I don’t know if emails without `To` are sent to the `Cc` addresses.
***
See patch 2/2 for details.
This is motivated by wanting to turn off range diff notes, but the goal here is to implement it in full generality.
(How many of us `git format-patch --notes` users are there out there? More than a dozen? Maybe just D. Ben Knoble and me?)
I have implemented this behavior for myself and used it for many months. But that was hacky and only suitable for one person’s use. So this is a completely new implementation. In other words: this is new code, *not* tested for months.
§ Changes in v2
This version drops the whole functionality around being able to *go back* (and forth) to using `--notes` for the range diff.[1] The behavior was too complex to explain and motivate compared to the utility (little).
🔗 1: https://lore.kernel.org/git/8f0a076b-4822-44e2-a842-cc1e39ae1c1d@app.fastmail.com/#t
This also means that the implementation is quite different. Now it just uses a parse-options callback instead of adding if/else to `revision.c:handle_revision_opt`.
See patch 2/2 for details.
Version 1 patch 2/3 is dropped. It was a rename motivated by the changes to `struct rev_info` in version 1 patch 3/3, which is now gone. The v1 3/3 change needed the struct member to stay notes-only, but that is no longer required.
[1/2] format-patch: simplify get_notes_arg parameters [2/2] format-patch: learn --[no-]range-diff-notes
Documentation/git-format-patch.adoc | 15 +++++ builtin/log.c | 62 ++++++++++++++++++-- t/t3206-range-diff.sh | 87 +++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 6 deletions(-)
Interdiff against v1:
diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc index e0ba435dfcf..5907f299a8d 100644 --- a/Documentation/git-format-patch.adoc +++ b/Documentation/git-format-patch.adoc @@ -378,22 +378,20 @@ 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>]`:: +`--range-diff-notes=<ref>`:: `--no-range-diff-notes`:: Used with `--range-diff`, tweak what notes to display in the - range diff. For example, you can use `--no-range-diff-notes` to - turn off all notes in the range diff. The default behavior is - to display the same notes in the range diff as on the patches - (see `--notes`). + range diff. + -You may want to turn off this notes override after it has been -activated. Use this sequence to do that: -+ ----- ---no-range-diff-notes --range-diff-notes ----- -+ -Now the range diff is back to displaying the same notes as the patches. +The default behavior is to display the same notes in the range diff as +on the patches; see `--notes`. But you can use these options to use a +different list of notes. For example, say you have given three notes +refs to `--notes`. At this point those same three notes will be +displayed in the range diff. But then you pass +`--range-diff-notes=<ref>`. Now the range diff will only display +_<ref>_. You can of course pass more refs to this option, just like +`--notes`. And you can also turn off all range diff notes with +`--no-range-diff-notes`. `--notes[=<ref>]`:: `--no-notes`:: diff --git a/builtin/log.c b/builtin/log.c index de997bc9ab0..d70101f0755 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1327,27 +1327,65 @@ static void prepare_cover_text(struct pretty_print_context *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 rdiff_notes *rdiff_notes = option->value; + + rdiff_notes->override = 1; + + /* + * The rest is the same as + * parse-options-cb.c:parse_opt_string_list + */ + if (unset) { + string_list_clear(&rdiff_notes->notes, 0); + return 0; + } + + if (!arg) + return -1; + + string_list_append(&rdiff_notes->notes, arg); + return 0; +} + 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 rev_info *rev) +static void get_notes_args(struct rdiff_notes *rdiff_notes, + struct rev_info *rev) { - if (rev->rdiff_override_notes) { - if (!rev->rdiff_notes_arg.nr) - strvec_push(&rev->rdiff_notes_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_notes_arg, "--no-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(&rev->rdiff_notes_arg, "--notes"); + strvec_push(&rev->rdiff_log_arg, "--notes"); } else { for_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, - &rev->rdiff_notes_arg); + &rev->rdiff_log_arg); } } @@ -1478,7 +1516,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, .dual_color = 1, .max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT, .diffopt = &opts, - .log_arg = &rev->rdiff_notes_arg + .log_arg = &rev->rdiff_log_arg }; repo_diff_setup(the_repository, &opts); @@ -1998,6 +2036,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; @@ -2094,6 +2135,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, @@ -2409,7 +2453,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); + get_notes_args(&rdiff_notes, &rev); } /* @@ -2572,7 +2616,8 @@ int cmd_format_patch(int argc, rev.diffopt.no_free = 0; release_revisions(&rev); format_config_release(&cfg); - strvec_clear(&rev.rdiff_notes_arg); + strvec_clear(&rev.rdiff_log_arg); + string_list_clear(&rdiff_notes.notes, 0); return 0; } diff --git a/log-tree.c b/log-tree.c index fd6ddf32af4..83a3c4bf9b1 100644 --- a/log-tree.c +++ b/log-tree.c @@ -718,7 +718,7 @@ static void show_diff_of_diff(struct rev_info *opt) .dual_color = 1, .max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT, .diffopt = &opts, - .log_arg = &opt->rdiff_notes_arg + .log_arg = &opt->rdiff_log_arg }; memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); diff --git a/revision.c b/revision.c index 1e21f2861cc..50dc8b19913 100644 --- a/revision.c +++ b/revision.c @@ -2625,19 +2625,6 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->notes_opt.use_default_notes = 1; } else if (!strcmp(arg, "--no-standard-notes")) { revs->notes_opt.use_default_notes = 0; - } else if (!strcmp(arg, "--no-range-diff-notes")) { - strvec_clear(&revs->rdiff_notes_arg); - revs->rdiff_override_notes = 1; - } else if (!strcmp(arg, "--range-diff-notes")) { - /* - * Allow the user to use '--no-range-diff-notes - * --range-diff-notes' in order to go back to - * using the 'format-patch' notes behavior - */ - revs->rdiff_override_notes = revs->rdiff_notes_arg.nr; - } else if (skip_prefix(arg, "--range-diff-notes=", &optarg)) { - strvec_pushf(&revs->rdiff_notes_arg, "--notes=%s", optarg); - revs->rdiff_override_notes = 1; } else if (!strcmp(arg, "--oneline")) { revs->verbose_header = 1; get_commit_format("oneline", revs); diff --git a/revision.h b/revision.h index e8dbf774b00..acf6d06b241 100644 --- a/revision.h +++ b/revision.h @@ -351,12 +351,7 @@ struct rev_info { /* range-diff */ const char *rdiff1; const char *rdiff2; - /* - * whether to use 'rdiff_notes_arg' or inherited - * notes behavior - */ - bool rdiff_override_notes; - struct strvec rdiff_notes_arg; + struct strvec rdiff_log_arg; int creation_factor; const char *rdiff_title; @@ -437,7 +432,7 @@ struct rev_info { .expand_tabs_in_log = -1, \ .commit_format = CMIT_FMT_DEFAULT, \ .expand_tabs_in_log_default = 8, \ - .rdiff_notes_arg = STRVEC_INIT, \ + .rdiff_log_arg = STRVEC_INIT, \ } /** diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index db238d0a5a1..640c5dec52e 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -845,28 +845,49 @@ 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_when_finished "rm -f 000?-*" && + 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=$prev --notes=custom \ + git format-patch --range-diff=main..topic --notes=custom \ --no-range-diff-notes --cover-letter \ - main..unmodified >actual && + 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 --range-diff-notes uses --notes behavior' ' +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=$prev --notes=custom \ - --range-diff-notes --cover-letter \ - main..unmodified >actual && - test_grep "^Notes (custom):" 0004-* && + 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* ' @@ -879,9 +900,9 @@ test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes= 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=$prev --notes=patch \ + git format-patch --range-diff=main..topic --notes=patch \ --range-diff-notes=rdiff --cover-letter \ - main..unmodified >actual && + main..unmodified && test_grep "^Notes (patch):" 0004-* && test_grep ! "^Notes (rdiff):" 0004-* && test_grep "^Range-diff:" 0000-cover-letter* && @@ -889,50 +910,11 @@ test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes= test_grep ! "## Notes (patch) ##" 0000-cover-letter* ' -test_expect_success 'format-patch --range-diff --no-range-diff-notes --range-diff-notes uses --notes behavior' ' - 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=$prev --notes=custom \ - --no-range-diff-notes --range-diff-notes --cover-letter \ - main..unmodified >actual && - 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 --range-diff-notes uses --notes behavior' ' - 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=$prev --notes=custom \ - --range-diff-notes --cover-letter \ - main..unmodified >actual && - 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-range-diff-notes does not use default notes' ' - test_when_finished "git notes remove topic unmodified || :" && - git notes add -m "topic note1" topic && - git notes add -m "unmodified note1" unmodified && - test_when_finished "rm -f 000?-*" && - git format-patch --range-diff=$prev \ - --no-range-diff-notes --cover-letter \ - main..unmodified >actual && - test_grep ! "^Notes:" 0004-* && - test_grep "^Range-diff:" 0000-cover-letter* && - test_grep ! "## Notes ##" 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=$prev \ + 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 && @@ -943,7 +925,7 @@ test_expect_success 'format-patch --range-diff --range-diff-notes=custom on sing 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 --no-notes --range-diff=$prev \ + git format-patch --range-diff=main..topic \ --range-diff-notes=custom -1 --stdout >actual && test_grep ! "Notes (custom):" actual && test_grep "^Range-diff:" actual && Range-diff against v1: 1: 977f9c2e97a = 1: 977f9c2e97a format-patch: simplify get_notes_arg parameters 2: 2a555d40ced < -: ----------- revision.h: rename struct member to reflect notes role 3: 058f5fdc8da ! 2: bf66e94e376 format-patch: learn --[no-]range-diff-notes @@ Commit message • No such options given • `--no-range-diff-notes` - Well, we can’t. Therefore we need `rdiff_override_notes` to set whenever + Well, we can’t. Therefore we need `rdiff_notes.override` to set whenever any of these options are given. - However, we may also want to turn *off* this override. Just like how we - can countermand any notes ref we pass in: - - --notes=custom --no-notes - - To that end, let’s make `--range-diff-notes` when the list of options is - empty special. Then it means: go back to using whatever git-format- - patch(1) wants to use. - - Now, `--notes` is a bit special in that it has an optional - argument. Implementing this with a parse-options callback is not - user-friendly; the following does *not* mean what it looks like: - - --parse-option --another-option - - Namely, it is not a bare `--parse-option` followed by another - option. Rather, it’s one option: - - --parse-option=--another-option - - And we need the bare `--range-diff-notes` form in order to turn off - notes overriding. For that reason, let’s implement these new options in - `revision.c:handle_revision_opt`, just like the `--notes` options are. - † 1: For example, let say we have two notes ref that are used for a patch series: @@ Commit message Note that using `--creation-factor` without `--range-diff` will cause the command to die. But this is not the case for `--[no-]range-diff- - notes`. Yes, we could introduce struct member `rdiff_notes_arg_used` or - something in order to detect the same condition. Or turn `rdiff_notes_ - override` into a tri-state `int`. But the extra code is not worth that - in my opinion. + notes`; we would have to check `rdiff_notes.override`, which is a sticky + value (cannot be turned off). The reason is that it is potentially + inconvenient to error out since it would not let you turn off + `--range-diff` in, say, some alias that uses `--no-range-diff- + notes`. Granted, it is difficult for me to come up with a concrete use + case since `--range-diff` requires a value, specifically a value which + is probably not that reusable (revision range), and yet you have + something like an alias set up with it. But why spend code closing + that door? There is no usability upside to erroring out. + + *** + + Add two tests here for the single-patch case, i.e. the case where the + range diff is on the patch and not in the cover letter. These are meant + as regression tests based on my encounter with single-patch range diff + notes handling bug.[2] + + † 2: 155986b4 (format-patch: handle range-diff on notes correctly for + single patches, 2025-09-25) Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> ## Notes (testing) ## - CI: https://github.com/LemmingAvalanche/git/actions/runs/32762207178 + CI: https://github.com/LemmingAvalanche/git/actions/runs/36231842902 + + This run is on a previous iteration where v1 patch/commit 2/3 was still + there. But that is just a rename. So I compiled and tested + `t/t3206-range-diff.sh` and took that as proof that the full CI/build run + is still valid. ## Documentation/git-format-patch.adoc ## @@ Documentation/git-format-patch.adoc: 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>]`:: ++`--range-diff-notes=<ref>`:: +`--no-range-diff-notes`:: + Used with `--range-diff`, tweak what notes to display in the -+ range diff. For example, you can use `--no-range-diff-notes` to -+ turn off all notes in the range diff. The default behavior is -+ to display the same notes in the range diff as on the patches -+ (see `--notes`). -++ -+You may want to turn off this notes override after it has been -+activated. Use this sequence to do that: ++ range diff. ++ -+---- -+--no-range-diff-notes --range-diff-notes -+---- -++ -+Now the range diff is back to displaying the same notes as the patches. ++The default behavior is to display the same notes in the range diff as ++on the patches; see `--notes`. But you can use these options to use a ++different list of notes. For example, say you have given three notes ++refs to `--notes`. At this point those same three notes will be ++displayed in the range diff. But then you pass ++`--range-diff-notes=<ref>`. Now the range diff will only display ++_<ref>_. You can of course pass more refs to this option, just like ++`--notes`. And you can also turn off all range diff notes with ++`--no-range-diff-notes`. + `--notes[=<ref>]`:: `--no-notes`:: Append the notes (see linkgit:git-notes[1]) for the commit ## builtin/log.c ## -@@ builtin/log.c: static int get_notes_refs(struct string_list_item *item, void *arg) +@@ builtin/log.c: static void prepare_cover_text(struct pretty_print_context *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 rdiff_notes *rdiff_notes = option->value; ++ ++ rdiff_notes->override = 1; ++ ++ /* ++ * The rest is the same as ++ * parse-options-cb.c:parse_opt_string_list ++ */ ++ if (unset) { ++ string_list_clear(&rdiff_notes->notes, 0); ++ return 0; ++ } ++ ++ if (!arg) ++ return -1; ++ ++ string_list_append(&rdiff_notes->notes, arg); ++ return 0; ++} ++ + 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 rev_info *rev) +-static void get_notes_args(struct rev_info *rev) ++static void get_notes_args(struct rdiff_notes *rdiff_notes, ++ struct rev_info *rev) { - if (!rev->show_notes) { -+ if (rev->rdiff_override_notes) { -+ if (!rev->rdiff_notes_arg.nr) -+ strvec_push(&rev->rdiff_notes_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_notes_arg, "--no-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 && - - ## revision.c ## -@@ revision.c: static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg - revs->notes_opt.use_default_notes = 1; - } else if (!strcmp(arg, "--no-standard-notes")) { - revs->notes_opt.use_default_notes = 0; -+ } else if (!strcmp(arg, "--no-range-diff-notes")) { -+ strvec_clear(&revs->rdiff_notes_arg); -+ revs->rdiff_override_notes = 1; -+ } else if (!strcmp(arg, "--range-diff-notes")) { -+ /* -+ * Allow the user to use '--no-range-diff-notes -+ * --range-diff-notes' in order to go back to -+ * using the 'format-patch' notes behavior -+ */ -+ revs->rdiff_override_notes = revs->rdiff_notes_arg.nr; -+ } else if (skip_prefix(arg, "--range-diff-notes=", &optarg)) { -+ strvec_pushf(&revs->rdiff_notes_arg, "--notes=%s", optarg); -+ revs->rdiff_override_notes = 1; - } else if (!strcmp(arg, "--oneline")) { - revs->verbose_header = 1; - get_commit_format("oneline", revs); - - ## revision.h ## -@@ revision.h: struct rev_info { - /* range-diff */ - const char *rdiff1; - const char *rdiff2; -+ /* -+ * whether to use 'rdiff_notes_arg' or inherited -+ * notes behavior -+ */ -+ bool rdiff_override_notes; - struct strvec rdiff_notes_arg; - int creation_factor; - const char *rdiff_title; +@@ builtin/log.c: 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; +@@ builtin/log.c: 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, +@@ builtin/log.c: 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); ++ get_notes_args(&rdiff_notes, &rev); + } + + /* +@@ builtin/log.c: int cmd_format_patch(int argc, + release_revisions(&rev); + format_config_release(&cfg); + strvec_clear(&rev.rdiff_log_arg); ++ string_list_clear(&rdiff_notes.notes, 0); + return 0; + } + ## t/t3206-range-diff.sh ## @@ t/t3206-range-diff.sh: 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_when_finished "rm -f 000?-*" && ++ 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=$prev --notes=custom \ ++ git format-patch --range-diff=main..topic --notes=custom \ + --no-range-diff-notes --cover-letter \ -+ main..unmodified >actual && ++ 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 --range-diff-notes uses --notes behavior' ' ++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=$prev --notes=custom \ -+ --range-diff-notes --cover-letter \ -+ main..unmodified >actual && -+ test_grep "^Notes (custom):" 0004-* && ++ 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* +' @@ t/t3206-range-diff.sh: test_expect_success 'format-patch --range-diff with multi + 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=$prev --notes=patch \ ++ git format-patch --range-diff=main..topic --notes=patch \ + --range-diff-notes=rdiff --cover-letter \ -+ main..unmodified >actual && ++ main..unmodified && + test_grep "^Notes (patch):" 0004-* && + test_grep ! "^Notes (rdiff):" 0004-* && + test_grep "^Range-diff:" 0000-cover-letter* && @@ t/t3206-range-diff.sh: test_expect_success 'format-patch --range-diff with multi + test_grep ! "## Notes (patch) ##" 0000-cover-letter* +' + -+test_expect_success 'format-patch --range-diff --no-range-diff-notes --range-diff-notes uses --notes behavior' ' -+ 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=$prev --notes=custom \ -+ --no-range-diff-notes --range-diff-notes --cover-letter \ -+ main..unmodified >actual && -+ 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 --range-diff-notes uses --notes behavior' ' -+ 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=$prev --notes=custom \ -+ --range-diff-notes --cover-letter \ -+ main..unmodified >actual && -+ 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-range-diff-notes does not use default notes' ' -+ test_when_finished "git notes remove topic unmodified || :" && -+ git notes add -m "topic note1" topic && -+ git notes add -m "unmodified note1" unmodified && -+ test_when_finished "rm -f 000?-*" && -+ git format-patch --range-diff=$prev \ -+ --no-range-diff-notes --cover-letter \ -+ main..unmodified >actual && -+ test_grep ! "^Notes:" 0004-* && -+ test_grep "^Range-diff:" 0000-cover-letter* && -+ test_grep ! "## Notes ##" 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=$prev \ ++ 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 && @@ t/t3206-range-diff.sh: test_expect_success 'format-patch --range-diff with multi + 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 --no-notes --range-diff=$prev \ ++ git format-patch --range-diff=main..topic \ + --range-diff-notes=custom -1 --stdout >actual && + test_grep ! "Notes (custom):" actual && + test_grep "^Range-diff:" actual && base-commit: 1a3e64c6c4a623626ff0687008732a8e007e2a1c
-- 2.55.0.793.gc667de3f2c5