{"thread":{"id":"66213","subject":"[PATCH 0/3] format-patch: learn --[no-]range-diff-notes","startedAt":"2026-08-24T20:36:03Z","lastAt":"2026-10-04T17:59:42Z","messageCount":41,"participants":["kristofferhaugsbakk@fastmail.com","Junio C Hamano","Kristoffer Haugsbakk","D. Ben Knoble"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"551153","messageId":"CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz","threadId":"66213","inReplyTo":null,"subject":"[PATCH 0/3] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-08-24T20:35:41Z","receivedAt":"2026-08-24T20:36:03Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\nTopic name: kh/format-patch-range-diff-notes\n\nTopic summary: Teach 'format-patch' options to tweak notes output in the\nrange diff independent of what notes are output in the patches.\n\nSee patch 3/3 for details.\n\nThis is motivated by wanting to turn off range diff notes, but the goal\nhere is to implement it in full generality.\n\n(How many of us `git format-patch --notes` users are there out there? More\nthan a dozen?)\n\nI have implemented this behavior for myself and used it for many\nmonths. But that was hacky and only suitable for one person’s use.\nSo this is a completely new implementation. In other words: this is\nnew code, *not* tested for months.\n\n§ CI\n\nhttps://github.com/LemmingAvalanche/git/actions/runs/32762207178\n\nI seem to have finally learned now that I ought to push to my public Git\ntree for CI, not my private one. The latter seems to consistently give me\n“insufficient funds” errors. But I don’t know.\n\n[1/3] format-patch: simplify get_notes_arg parameters\n[2/3] revision.h: rename struct member to reflect notes role\n[3/3] format-patch: learn --[no-]range-diff-notes\n\n Documentation/git-format-patch.adoc |  17 +++++\n builtin/log.c                       |  21 +++---\n log-tree.c                          |   2 +-\n revision.c                          |  13 ++++\n revision.h                          |   9 ++-\n t/t3206-range-diff.sh               | 105 ++++++++++++++++++++++++++++\n 6 files changed, 156 insertions(+), 11 deletions(-)\n\n\nbase-commit: 1a3e64c6c4a623626ff0687008732a8e007e2a1c\n-- \n2.55.0.13.g85d2d65e389\n\n"},{"id":"551154","messageId":"simplify_params.c58@msgid.xyz","threadId":"66213","inReplyTo":"CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz","subject":"[PATCH 1/3] format-patch: simplify get_notes_arg parameters","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-08-24T20:35:42Z","receivedAt":"2026-08-24T20:36:21Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\n85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n`rdiff_log_arg` to `struct rev_info`. I changed `get_notes_arg` by\nsimply replacing the first argument with an access on this struct\nmember. But the second argument was already `struct rev_info`. So I\nshould have just simplified to *only* passing that parameter. Let’s do\nthat now.\n\nNow is also a good time to format this `for_each...` line since it’s\ngotten quite long.\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (testing):\n    just compile tested\n\n builtin/log.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 350b35c5563..560af00e2fd 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1333,16 +1333,18 @@ static int get_notes_refs(struct string_list_item *item, void *arg)\n \treturn 0;\n }\n \n-static void get_notes_args(struct strvec *arg, struct rev_info *rev)\n+static void get_notes_args(struct rev_info *rev)\n {\n \tif (!rev->show_notes) {\n-\t\tstrvec_push(arg, \"--no-notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n \t\t    !rev->notes_opt.extra_notes_refs.nr)) {\n-\t\tstrvec_push(arg, \"--notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--notes\");\n \t} else {\n-\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);\n+\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs,\n+\t\t\t\t     get_notes_refs,\n+\t\t\t\t     &rev->rdiff_log_arg);\n \t}\n }\n \n@@ -2404,7 +2406,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&(rev.rdiff_log_arg), &rev);\n+\t\tget_notes_args(&rev);\n \t}\n \n \t/*\n-- \n2.55.0.13.g85d2d65e389\n\n"},{"id":"551155","messageId":"member_rdiff_notes_arg.c59@msgid.xyz","threadId":"66213","inReplyTo":"CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz","subject":"[PATCH 2/3] revision.h: rename struct member to reflect notes role","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-08-24T20:35:43Z","receivedAt":"2026-08-24T20:36:39Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\nThe `struct rev_info` member `rdiff_log_arg` is only used to pass\n`--[no-]notes` options to git-range-diff(1), which in turn passes it\non to git-log(1). The “log” in the name is fine since other code paths\ncould choose to use it to pass something else on to git-range-diff(1)\n(as long as it makes sense to git-log(1)). However, we will in the next\ncommit change `revision.c:handle_revision_opt` to push and clear this\n`strvec` based on notes options that the user passes. That means that\nonly one type of git-log(1) option will be suitable for it. So let’s\nrename it to `rdiff_notes_arg`.\n\nThis structure member got its “log” name in 85bd88a7 (revision: add\nrdiff_log_arg to rev_info, 2025-09-25), which was based on the renaming\nof the `range-diff.c` variable `other_arg` to `log_arg`.[1] Now, in\n`range-diff.c` this `log_arg` really is used for multiple different\ngit-log(1) options, namely `--[no-]notes` and `--remerge-diff`. But we\ncan keep this `rev_info` member notes-only.\n\n† 1: in 71fd6c69 (range-diff: rename other_arg to log_arg, 2025-09-25)\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (testing):\n    just compile tested\n\n builtin/log.c | 10 +++++-----\n log-tree.c    |  2 +-\n revision.h    |  4 ++--\n 3 files changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 560af00e2fd..28a93c45463 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1336,15 +1336,15 @@ static int get_notes_refs(struct string_list_item *item, void *arg)\n static void get_notes_args(struct rev_info *rev)\n {\n \tif (!rev->show_notes) {\n-\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n+\t\tstrvec_push(&rev->rdiff_notes_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n \t\t    !rev->notes_opt.extra_notes_refs.nr)) {\n-\t\tstrvec_push(&rev->rdiff_log_arg, \"--notes\");\n+\t\tstrvec_push(&rev->rdiff_notes_arg, \"--notes\");\n \t} else {\n \t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs,\n \t\t\t\t     get_notes_refs,\n-\t\t\t\t     &rev->rdiff_log_arg);\n+\t\t\t\t     &rev->rdiff_notes_arg);\n \t}\n }\n \n@@ -1475,7 +1475,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,\n \t\t\t.dual_color = 1,\n \t\t\t.max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT,\n \t\t\t.diffopt = &opts,\n-\t\t\t.log_arg = &rev->rdiff_log_arg\n+\t\t\t.log_arg = &rev->rdiff_notes_arg\n \t\t};\n \n \t\trepo_diff_setup(the_repository, &opts);\n@@ -2569,7 +2569,7 @@ int cmd_format_patch(int argc,\n \trev.diffopt.no_free = 0;\n \trelease_revisions(&rev);\n \tformat_config_release(&cfg);\n-\tstrvec_clear(&rev.rdiff_log_arg);\n+\tstrvec_clear(&rev.rdiff_notes_arg);\n \treturn 0;\n }\n \ndiff --git a/log-tree.c b/log-tree.c\nindex 83a3c4bf9b1..fd6ddf32af4 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -718,7 +718,7 @@ static void show_diff_of_diff(struct rev_info *opt)\n \t\t\t.dual_color = 1,\n \t\t\t.max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT,\n \t\t\t.diffopt = &opts,\n-\t\t\t.log_arg = &opt->rdiff_log_arg\n+\t\t\t.log_arg = &opt->rdiff_notes_arg\n \t\t};\n \n \t\tmemcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));\ndiff --git a/revision.h b/revision.h\nindex acf6d06b241..39cca04d9e5 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -351,7 +351,7 @@ struct rev_info {\n \t/* range-diff */\n \tconst char *rdiff1;\n \tconst char *rdiff2;\n-\tstruct strvec rdiff_log_arg;\n+\tstruct strvec rdiff_notes_arg;\n \tint creation_factor;\n \tconst char *rdiff_title;\n \n@@ -432,7 +432,7 @@ struct rev_info {\n \t.expand_tabs_in_log = -1, \\\n \t.commit_format = CMIT_FMT_DEFAULT, \\\n \t.expand_tabs_in_log_default = 8, \\\n-\t.rdiff_log_arg = STRVEC_INIT, \\\n+\t.rdiff_notes_arg = STRVEC_INIT, \\\n }\n \n /**\n-- \n2.55.0.13.g85d2d65e389\n\n"},{"id":"551156","messageId":"format-patch_learn_--range-diff-notes.c5a@msgid.xyz","threadId":"66213","inReplyTo":"CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz","subject":"[PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-08-24T20:35:44Z","receivedAt":"2026-08-24T20:36:58Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\ngit-format-patch(1) passes on the notes behavior that it is using for\nthe patches to git-range-diff(1). In turn you get the same Git notes\ndisplayed in the range diff as the ones you used to generate the\npatches. And that makes sense in most cases.\n\nHowever, I often make notes between series versions that mostly prepend\nto the original. They end up looking like this:\n\n    v3:\n    [desc.]\n    v2:\n    [descr.]\n    v1:\n    [descr.]\n\nThese notes are meant for the git-format-patch(1) output since they\ndocument the iterations. But including them also includes them in the\nrange diff. And they have nothing useful to say there.\n\nSo it would be useful to turn off range diff notes handling with\nsomething like `--no-range-diff-notes`. This could then be turned on\nagain with `--range-diff-notes`.\n\nAn off/on switch is enough for this behavior. However, a bare (no arg)\noption (together with the negation) is not consistent with `--[no-]notes\n[=<ref>]` and could cause confusion. And we are both conceptually and\nliterally constructing an argument list to pass on to git-range-diff(1),\nwhich does have the same option format as git-format-patch(1). Moreover,\nit is useful to be able to specify exactly what notes you want\ngit-format-patch(1) and git-range-diff(1) to use.[1] So let’s generalize\nit so that you can pass in whatever notes refs you want.\n\nBut now we are faced with a problem that `--notes` does not have; how do\nwe distinguish an empty `struct string_list` meaning these two things?:\n\n• No such options given\n• `--no-range-diff-notes`\n\nWell, we can’t. Therefore we need `rdiff_override_notes` to set whenever\nany of these options are given.\n\nHowever, we may also want to turn *off* this override. Just like how we\ncan countermand any notes ref we pass in:\n\n    --notes=custom --no-notes\n\nTo that end, let’s make `--range-diff-notes` when the list of options is\nempty special. Then it means: go back to using whatever git-format-\npatch(1) wants to use.\n\nNow, `--notes` is a bit special in that it has an optional\nargument. Implementing this with a parse-options callback is not\nuser-friendly; the following does *not* mean what it looks like:\n\n    --parse-option --another-option\n\nNamely, it is not a bare `--parse-option` followed by another\noption. Rather, it’s one option:\n\n    --parse-option=--another-option\n\nAnd we need the bare `--range-diff-notes` form in order to turn off\nnotes overriding. For that reason, let’s implement these new options in\n`revision.c:handle_revision_opt`, just like the `--notes` options are.\n\n† 1: For example, let say we have two notes ref that are used for a\n     patch series:\n\n     1. testing. What the user has done to test this iteration.\n     2. changelog. The same example from the introduction.\n\n     You could include both notes on the patches but only show `testing` in\n     the range diff.\n\n***\n\nNote that using `--creation-factor` without `--range-diff` will cause\nthe command to die. But this is not the case for `--[no-]range-diff-\nnotes`. Yes, we could introduce struct member `rdiff_notes_arg_used` or\nsomething in order to detect the same condition. Or turn `rdiff_notes_\noverride` into a tri-state `int`. But the extra code is not worth that\nin my opinion.\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (testing):\n    CI: https://github.com/LemmingAvalanche/git/actions/runs/32762207178\n\n Documentation/git-format-patch.adoc |  17 +++++\n builtin/log.c                       |   5 +-\n revision.c                          |  13 ++++\n revision.h                          |   5 ++\n t/t3206-range-diff.sh               | 105 ++++++++++++++++++++++++++++\n 5 files changed, 144 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\nindex 191f64b77d1..e0ba435dfcf 100644\n--- a/Documentation/git-format-patch.adoc\n+++ b/Documentation/git-format-patch.adoc\n@@ -378,6 +378,23 @@ case is to show comparison with an older iteration of the same\n topic and the tool should find more correspondence between the two\n sets of patches.\n \n+`--range-diff-notes[=<ref>]`::\n+`--no-range-diff-notes`::\n+\tUsed with `--range-diff`, tweak what notes to display in the\n+\trange diff. For example, you can use `--no-range-diff-notes` to\n+\tturn off all notes in the range diff. The default behavior is\n+\tto display the same notes in the range diff as on the patches\n+\t(see `--notes`).\n++\n+You may want to turn off this notes override after it has been\n+activated. Use this sequence to do that:\n++\n+----\n+--no-range-diff-notes --range-diff-notes\n+----\n++\n+Now the range diff is back to displaying the same notes as the patches.\n+\n `--notes[=<ref>]`::\n `--no-notes`::\n \tAppend the notes (see linkgit:git-notes[1]) for the commit\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 28a93c45463..de997bc9ab0 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1335,7 +1335,10 @@ static int get_notes_refs(struct string_list_item *item, void *arg)\n \n static void get_notes_args(struct rev_info *rev)\n {\n-\tif (!rev->show_notes) {\n+\tif (rev->rdiff_override_notes) {\n+\t\tif (!rev->rdiff_notes_arg.nr)\n+\t\t\tstrvec_push(&rev->rdiff_notes_arg, \"--no-notes\");\n+\t} else if (!rev->show_notes) {\n \t\tstrvec_push(&rev->rdiff_notes_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\ndiff --git a/revision.c b/revision.c\nindex 50dc8b19913..1e21f2861cc 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2625,6 +2625,19 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->notes_opt.use_default_notes = 1;\n \t} else if (!strcmp(arg, \"--no-standard-notes\")) {\n \t\trevs->notes_opt.use_default_notes = 0;\n+\t} else if (!strcmp(arg, \"--no-range-diff-notes\")) {\n+\t\tstrvec_clear(&revs->rdiff_notes_arg);\n+\t\trevs->rdiff_override_notes = 1;\n+\t} else if (!strcmp(arg, \"--range-diff-notes\")) {\n+\t\t/*\n+\t\t * Allow the user to use '--no-range-diff-notes\n+\t\t * --range-diff-notes' in order to go back to\n+\t\t * using the 'format-patch' notes behavior\n+\t\t */\n+\t\trevs->rdiff_override_notes = revs->rdiff_notes_arg.nr;\n+\t} else if (skip_prefix(arg, \"--range-diff-notes=\", &optarg)) {\n+\t\tstrvec_pushf(&revs->rdiff_notes_arg, \"--notes=%s\", optarg);\n+\t\trevs->rdiff_override_notes = 1;\n \t} else if (!strcmp(arg, \"--oneline\")) {\n \t\trevs->verbose_header = 1;\n \t\tget_commit_format(\"oneline\", revs);\ndiff --git a/revision.h b/revision.h\nindex 39cca04d9e5..e8dbf774b00 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -351,6 +351,11 @@ struct rev_info {\n \t/* range-diff */\n \tconst char *rdiff1;\n \tconst char *rdiff2;\n+\t/*\n+\t * whether to use 'rdiff_notes_arg' or inherited\n+\t * notes behavior\n+\t */\n+\tbool rdiff_override_notes;\n \tstruct strvec rdiff_notes_arg;\n \tint creation_factor;\n \tconst char *rdiff_title;\ndiff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\nindex ef92704de39..db238d0a5a1 100755\n--- a/t/t3206-range-diff.sh\n+++ b/t/t3206-range-diff.sh\n@@ -845,6 +845,111 @@ test_expect_success 'format-patch --range-diff with multiple notes' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'format-patch --range-diff --notes=custom --no-range-diff-notes' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=$prev --notes=custom \\\n+\t\t--no-range-diff-notes --cover-letter \\\n+\t\tmain..unmodified >actual &&\n+\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --range-diff-notes uses --notes behavior' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=$prev --notes=custom \\\n+\t\t--range-diff-notes --cover-letter \\\n+\t\tmain..unmodified >actual &&\n+\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes=rdiff' '\n+\ttest_when_finished \"git notes --ref=patch remove topic unmodified || :\" &&\n+\tgit notes --ref=patch add -m \"only for patch 1\" topic &&\n+\tgit notes --ref=patch add -m \"only for patch 2\" unmodified &&\n+\ttest_when_finished \"git notes --ref=rdiff remove topic unmodified || :\" &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 1\" topic &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 2\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=$prev --notes=patch \\\n+\t\t--range-diff-notes=rdiff --cover-letter \\\n+\t\tmain..unmodified >actual &&\n+\ttest_grep \"^Notes (patch):\" 0004-* &&\n+\ttest_grep ! \"^Notes (rdiff):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (rdiff) ##\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (patch) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-range-diff-notes --range-diff-notes uses --notes behavior' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=$prev --notes=custom \\\n+\t\t--no-range-diff-notes --range-diff-notes --cover-letter \\\n+\t\tmain..unmodified >actual &&\n+\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --range-diff-notes uses --notes behavior' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=$prev --notes=custom \\\n+\t\t--range-diff-notes --cover-letter \\\n+\t\tmain..unmodified >actual &&\n+\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-range-diff-notes does not use default notes' '\n+\ttest_when_finished \"git notes remove topic unmodified || :\" &&\n+\tgit notes add -m \"topic note1\" topic &&\n+\tgit notes add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=$prev \\\n+\t\t--no-range-diff-notes --cover-letter \\\n+\t\tmain..unmodified >actual &&\n+\ttest_grep ! \"^Notes:\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-range-diff-notes on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --notes=custom --range-diff=$prev \\\n+\t\t--no-range-diff-notes -1 --stdout >actual &&\n+\ttest_grep \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep ! \"## Notes (custom) ##\" actual\n+'\n+\n+test_expect_success 'format-patch --range-diff --range-diff-notes=custom on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --no-notes --range-diff=$prev \\\n+\t\t--range-diff-notes=custom -1 --stdout >actual &&\n+\ttest_grep ! \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep \"## Notes (custom) ##\" actual\n+'\n+\n test_expect_success '--left-only/--right-only' '\n \tgit switch --orphan left-right &&\n \ttest_commit first &&\n-- \n2.55.0.13.g85d2d65e389\n\n"},{"id":"551159","messageId":"xmqqjypfp2vl.fsf@gitster.g","threadId":"66213","inReplyTo":"format-patch_learn_--range-diff-notes.c5a@msgid.xyz","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-24T22:31:10Z","receivedAt":"2026-08-24T22:31:12Z","isPatch":true,"body":"kristofferhaugsbakk@fastmail.com writes:\n\n> diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\n> index 191f64b77d1..e0ba435dfcf 100644\n> --- a/Documentation/git-format-patch.adoc\n> +++ b/Documentation/git-format-patch.adoc\n> @@ -378,6 +378,23 @@ case is to show comparison with an older iteration of the same\n>  topic and the tool should find more correspondence between the two\n>  sets of patches.\n>  \n> +`--range-diff-notes[=<ref>]`::\n> +`--no-range-diff-notes`::\n> +\tUsed with `--range-diff`, tweak what notes to display in the\n> +\trange diff. For example, you can use `--no-range-diff-notes` to\n> +\tturn off all notes in the range diff. The default behavior is\n> +\tto display the same notes in the range diff as on the patches\n> +\t(see `--notes`).\n> ++\n> +You may want to turn off this notes override after it has been\n> +activated. Use this sequence to do that:\n> ++\n> +----\n> +--no-range-diff-notes --range-diff-notes\n> +----\n> ++\n> +Now the range diff is back to displaying the same notes as the patches.\n> +\n\nHmph, this is a bit too complex for me.  When I say\n\n    $ git format-patch --no-notes --range-diff-notes ...\n\nI would expect that individual patches would not get notes, but the\nrange-diff will include them in the comparison.  But if\n--range-diff-notes just falls back to default (i.e., inherit what\npatches use), would I see the notes used in the range-diff?\n\n"},{"id":"551216","messageId":"16315616-097a-4fe2-8665-010e424afd8b@app.fastmail.com","threadId":"66213","inReplyTo":"xmqqjypfp2vl.fsf@gitster.g","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-08-25T18:36:50Z","receivedAt":"2026-08-25T18:37:16Z","isPatch":true,"body":"On Tue, Aug 25, 2026, at 00:31, Junio C Hamano wrote:\n> [snip]\n>> +Now the range diff is back to displaying the same notes as the patches.\n>> +\n>\n> Hmph, this is a bit too complex for me.  When I say\n>\n>     $ git format-patch --no-notes --range-diff-notes ...\n>\n> I would expect that individual patches would not get notes, but the\n> range-diff will include them in the comparison.  But if\n> --range-diff-notes just falls back to default (i.e., inherit what\n> patches use), would I see the notes used in the range-diff?\n\nYou will not get patch notes and not get\nrange diff notes. That --range-diff-notes\ntold it to use the patch notes which you\njust turned off/emptied the list.\n\nCode-wise, the list of notes is cleared so you\nyou would have to change the --notes implementation\nif you want to keep a sort of shadow list\nof not-patch-notes-but-RD-notes.\nAnd another problem, or fact, is that format-patch\ndoes not show notes by default. So what should\n--RD-notes show? The default notes?\n\nThanks\n\nsent from mobile\n\n"},{"id":"551399","messageId":"xmqqbjan6q7l.fsf@gitster.g","threadId":"66213","inReplyTo":"16315616-097a-4fe2-8665-010e424afd8b@app.fastmail.com","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T00:31:10Z","receivedAt":"2026-08-28T00:31:12Z","isPatch":true,"body":"\"Kristoffer Haugsbakk\" <kristofferhaugsbakk@fastmail.com> writes:\n\n>> Hmph, this is a bit too complex for me.  When I say\n>>\n>>     $ git format-patch --no-notes --range-diff-notes ...\n>>\n>> I would expect that individual patches would not get notes, but the\n>> range-diff will include them in the comparison.  But if\n>> --range-diff-notes just falls back to default (i.e., inherit what\n>> patches use), would I see the notes used in the range-diff?\n>\n> You will not get patch notes and not get\n> range diff notes. That --range-diff-notes\n> told it to use the patch notes which you\n> just turned off/emptied the list.\n>\n> Code-wise, the list of notes is cleared so you\n> you would have to change the --notes implementation\n> if you want to keep a sort of shadow list\n> of not-patch-notes-but-RD-notes.\n\nIOW, the design of how these options interact does not support the\nusecase I gave?\n\n> And another problem, or fact, is that format-patch\n> does not show notes by default. So what should\n> --RD-notes show? The default notes?\n\nI do not know.  My preference actually is not to introuce a new\noption whose interaction with the existing --notes option cannot be\ndefined in simple terms.\n"},{"id":"551415","messageId":"9335a35f-e9c0-4e62-812c-e5855c201003@app.fastmail.com","threadId":"66213","inReplyTo":"xmqqbjan6q7l.fsf@gitster.g","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-08-28T13:48:13Z","receivedAt":"2026-08-28T13:48:38Z","isPatch":true,"body":"On Fri, Aug 28, 2026, at 02:31, Junio C Hamano wrote:\n> \"Kristoffer Haugsbakk\" <kristofferhaugsbakk@fastmail.com> writes:\n>\n>>> Hmph, this is a bit too complex for me.  When I say\n>>>\n>>>     $ git format-patch --no-notes --range-diff-notes ...\n>>>\n>>> I would expect that individual patches would not get notes, but the\n>>> range-diff will include them in the comparison.  But if\n>>> --range-diff-notes just falls back to default (i.e., inherit what\n>>> patches use), would I see the notes used in the range-diff?\n>>\n>> You will not get patch notes and not get\n>> range diff notes. That --range-diff-notes\n>> told it to use the patch notes which you\n>> just turned off/emptied the list.\n>>\n>> Code-wise, the list of notes is cleared so you\n>> you would have to change the --notes implementation\n>> if you want to keep a sort of shadow list\n>> of not-patch-notes-but-RD-notes.\n>\n> IOW, the design of how these options interact does not support the\n> usecase I gave?\n\nCorrect as far as I understand the use case.\n\n>\n>> And another problem, or fact, is that format-patch\n>> does not show notes by default. So what should\n>> --RD-notes show? The default notes?\n>\n> I do not know.  My preference actually is not to introuce a new\n> option whose interaction with the existing --notes option cannot be\n> defined in simple terms.\n\nLet's drop this topic then.\n\nsent from mobile\n\n"},{"id":"551427","messageId":"xmqqpkz24193.fsf@gitster.g","threadId":"66213","inReplyTo":"9335a35f-e9c0-4e62-812c-e5855c201003@app.fastmail.com","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T17:13:12Z","receivedAt":"2026-08-28T17:13:15Z","isPatch":true,"body":"\"Kristoffer Haugsbakk\" <kristofferhaugsbakk@fastmail.com> writes:\n\n>> I do not know.  My preference actually is not to introuce a new\n>> option whose interaction with the existing --notes option cannot be\n>> defined in simple terms.\n>\n> Let's drop this topic then.\n\nThat is fine by me.  I was hoping that you'd come up with a way to\nadd this new option with simpler-to-explain interactions.  E.g.,\nwhen only --notes exists on the command line, it is used as the\nmaterial compared by the range-diff and as the material inserted\ninto the final output, but when both options exist, they work\nindependently, i.e., --notes gets used only as the final output,\nwhile --range-diff-notes gets used only for comparison material,\nor something like that.\n"},{"id":"551751","messageId":"b3c66de3-0ced-446f-9bd6-73412a8c92b5@app.fastmail.com","threadId":"66213","inReplyTo":"xmqqpkz24193.fsf@gitster.g","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-09-02T13:19:52Z","receivedAt":"2026-09-02T13:20:16Z","isPatch":true,"body":"On Fri, Aug 28, 2026, at 19:13, Junio C Hamano wrote:\n> \"Kristoffer Haugsbakk\" <kristofferhaugsbakk@fastmail.com> writes:\n>\n>>> I do not know.  My preference actually is not to introuce a new\n>>> option whose interaction with the existing --notes option cannot be\n>>> defined in simple terms.\n>>\n>> Let's drop this topic then.\n>\n> That is fine by me.  I was hoping that you'd come up with a way to\n> add this new option with simpler-to-explain interactions.  E.g.,\n> when only --notes exists on the command line, it is used as the\n> material compared by the range-diff and as the material inserted\n> into the final output, but when both options exist, they work\n> independently, i.e., --notes gets used only as the final output,\n> while --range-diff-notes gets used only for comparison material,\n> or something like that.\n\nThis is how it works. The `--range-diff-notes` behavior that the doc\ndiscusses is just the special case when the list of notes for the range\ndiff is empty.\n\nThat this wasn’t clear is the fault of the doc here.\n"},{"id":"552058","messageId":"e3b7ef75-08e6-4529-ac75-56f800d2f4a4@app.fastmail.com","threadId":"66213","inReplyTo":"b3c66de3-0ced-446f-9bd6-73412a8c92b5@app.fastmail.com","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-09-06T07:22:27Z","receivedAt":"2026-09-06T07:22:52Z","isPatch":true,"body":"On Wed, Sep 2, 2026, at 15:19, Kristoffer Haugsbakk wrote:\n> On Fri, Aug 28, 2026, at 19:13, Junio C Hamano wrote:\n>> \"Kristoffer Haugsbakk\" <kristofferhaugsbakk@fastmail.com> writes:\n>>\n>>>> I do not know.  My preference actually is not to introuce a new\n>>>> option whose interaction with the existing --notes option cannot be\n>>>> defined in simple terms.\n>>>\n>>> Let's drop this topic then.\n>>\n>> That is fine by me.  I was hoping that you'd come up with a way to\n>> add this new option with simpler-to-explain interactions.  E.g.,\n>> when only --notes exists on the command line, it is used as the\n>> material compared by the range-diff and as the material inserted\n>> into the final output, but when both options exist, they work\n>> independently, i.e., --notes gets used only as the final output,\n>> while --range-diff-notes gets used only for comparison material,\n>> or something like that.\n>\n> This is how it works. The `--range-diff-notes` behavior that the doc\n> discusses is just the special case when the list of notes for the range\n> diff is empty.\n>\n> That this wasn’t clear is the fault of the doc here.\n\nSeeing as how the doc was unclear and did not spell out how you can\nbuild two separate list of notes, here’s a draft of a rewrite:\n\n    `--range-diff-notes[=<ref>]`::\n    `--no-range-diff-notes`::\n            Used with `--range-diff`, tweak what notes to display in the\n            range diff.\n    +\n    The default behavior is to display the same notes in the range diff as\n    on the patches; see `--notes`. But you can use these options to use a\n    different list of notes. For example, say you have given three notes\n    refs to `--notes`. At this point those same three notes will be\n    displayed in the range diff. But then you pass\n    `--range-diff-notes=<ref>`. Now the range diff will only display\n    _<ref>_. You can of course pass more refs to this option, just like\n    `--notes`. And you can also turn off all notes with\n    `--no-range-diff-notes`.\n    +\n    You may want to turn off this notes override behavior after it has been\n    activated. Use this sequence to do that:\n    +\n    ----\n    --no-range-diff-notes --range-diff-notes\n    ----\n    +\n    Now the range diff is back to displaying the same notes as the\n    patches. Going back to the three `--notes` example: now the range diff\n    will show all three notes again.\n"},{"id":"552072","messageId":"CALnO6CA-6m58sJCf=5_GwK3GE8=EfhzgsheWBqMQjc0r+N7+Xg@mail.gmail.com","threadId":"66213","inReplyTo":"e3b7ef75-08e6-4529-ac75-56f800d2f4a4@app.fastmail.com","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-06T13:37:55Z","receivedAt":"2026-09-06T13:38:07Z","isPatch":true,"body":"On Sun, Sep 6, 2026 at 3:23 AM Kristoffer Haugsbakk\n<kristofferhaugsbakk@fastmail.com> wrote:\n>\n> On Wed, Sep 2, 2026, at 15:19, Kristoffer Haugsbakk wrote:\n> > On Fri, Aug 28, 2026, at 19:13, Junio C Hamano wrote:\n[snip]\n> >> That is fine by me.  I was hoping that you'd come up with a way to\n> >> add this new option with simpler-to-explain interactions.  E.g.,\n> >> when only --notes exists on the command line, it is used as the\n> >> material compared by the range-diff and as the material inserted\n> >> into the final output, but when both options exist, they work\n> >> independently, i.e., --notes gets used only as the final output,\n> >> while --range-diff-notes gets used only for comparison material,\n> >> or something like that.\n> >\n> > This is how it works. The `--range-diff-notes` behavior that the doc\n> > discusses is just the special case when the list of notes for the range\n> > diff is empty.\n> >\n> > That this wasn’t clear is the fault of the doc here.\n>\n> Seeing as how the doc was unclear and did not spell out how you can\n> build two separate list of notes, here’s a draft of a rewrite:\n>\n>     `--range-diff-notes[=<ref>]`::\n>     `--no-range-diff-notes`::\n>             Used with `--range-diff`, tweak what notes to display in the\n>             range diff.\n>     +\n>     The default behavior is to display the same notes in the range diff as\n>     on the patches; see `--notes`. But you can use these options to use a\n>     different list of notes. For example, say you have given three notes\n>     refs to `--notes`. At this point those same three notes will be\n>     displayed in the range diff. But then you pass\n>     `--range-diff-notes=<ref>`. Now the range diff will only display\n>     _<ref>_. You can of course pass more refs to this option, just like\n>     `--notes`. And you can also turn off all notes with\n>     `--no-range-diff-notes`.\n>     +\n>     You may want to turn off this notes override behavior after it has been\n\n[nit: should we call this \"no notes\" override behavior? Otherwise I\nthink we are referring to --range-diff-notes=<ref> overriding\n--notes=…]\n\n>     activated. Use this sequence to do that:\n>     +\n>     ----\n>     --no-range-diff-notes --range-diff-notes\n>     ----\n>     +\n>     Now the range diff is back to displaying the same notes as the\n>     patches. Going back to the three `--notes` example: now the range diff\n>     will show all three notes again.\n\nA bit long, but easy to follow and understand the interactions, I\nthink. The examples are helpful.\n\n-- \nD. Ben Knoble\n"},{"id":"552076","messageId":"392dc2b3-59cf-4fd4-8c73-38a57c8d0423@app.fastmail.com","threadId":"66213","inReplyTo":"CALnO6CA-6m58sJCf=5_GwK3GE8=EfhzgsheWBqMQjc0r+N7+Xg@mail.gmail.com","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-09-06T16:44:39Z","receivedAt":"2026-09-06T16:45:03Z","isPatch":true,"body":"On Sun, Sep 6, 2026, at 15:37, D. Ben Knoble wrote:\n> On Sun, Sep 6, 2026 at 3:23 AM Kristoffer Haugsbakk\n>> >[snip]\n>> > That this wasn’t clear is the fault of the doc here.\n>>\n>> Seeing as how the doc was unclear and did not spell out how you can\n>> build two separate list of notes, here’s a draft of a rewrite:\n>>\n>>     `--range-diff-notes[=<ref>]`::\n>>     `--no-range-diff-notes`::\n>>             Used with `--range-diff`, tweak what notes to display in the\n>>             range diff.\n>>     +\n>>     The default behavior is to display the same notes in the range diff as\n>>     on the patches; see `--notes`. But you can use these options to use a\n>>     different list of notes. For example, say you have given three notes\n>>     refs to `--notes`. At this point those same three notes will be\n>>     displayed in the range diff. But then you pass\n>>     `--range-diff-notes=<ref>`. Now the range diff will only display\n>>     _<ref>_. You can of course pass more refs to this option, just like\n>>     `--notes`. And you can also turn off all notes with\n>>     `--no-range-diff-notes`.\n>>     +\n>>     You may want to turn off this notes override behavior after it has been\n>\n> [nit: should we call this \"no notes\" override behavior? Otherwise I\n> think we are referring to --range-diff-notes=<ref> overriding\n> --notes=…]\n\n(I will shorten `range-diff` to `RD` for semi-brevity)\n\nWhat I mean here by “notes override behavior” is turning off all\n`--[no-]RD-notes` options. It means turning off `--RD-notes` as well as\n`--no-RD-notes`. And without the override you are back to the default\nbehavior where `--notes` dictates the notes for the range diff.\n\nSo that the utility is a bit more clear than these unmotivated examples,\nhere’s an example alias (with forced linebreaks):\n\n    my-fp = format-patch --notes=review --notes=testing\n        --notes=attribution --notes=changelog\n        --range-diff-notes=changelog\n\nThe patches will have four notes while the range diff will have one.\n\nBut you may want to disregard that last `--RD-notes` and in turn get all\nof the notes in the range diff. But without repeating yourself. Then you\ncan do this:\n\n    my-fp --no-range-diff-notes --range-diff-notes\n\nThe option (the negation) is not sufficient since it would turn off all\nrange diff notes. But this special meaning of `--RD-notes` allows you to\ngo back to just regular `--notes` behavior. That `--RD-notes` has a\nspecial meaning when the list of range diff notes is empty does not lose\nanything since `--range-diff-notes` would just be a noöp otherwise.[1]\n\nBut I should point out in this doc that bare `--RD-notes` does not use\nthe default notes.\n\nOf course, there could be a dedicated option to turn these options off.\n\nOr to just not support it. ;)\n\n(my standard verbosity level might not be doing me any favors\non this point.)\n\n***\n\nThat might seem like a lot of “power” for something as niche as\noverriding-then-reverting patch contra range diff notes. But code\nwise I don’t think the price is high... :)\n\n† 1: I just tested the behavior of `--notes` (no arg) on\n     `format-patch`. Yes, it does respect the default notes ref just\n     like git-log(1) does. So an alternative would be to have\n     `--RD-notes` do the same.\n\n     But I do not think some convenient default notes ref is good for a\n     command which is supposed to generate patches for email\n     sendout. For `log` you can make convenient notes to yourself and\n     conveniently display them. But `format-patch` should demand more\n     intentionality. (I also wrote about this on a bugfix for\n     `format-patch` behavior some years ago.)[2]\n† 2: I suspect there is a bug-looking like behavior in that\n     `format-patch` seems to use `notes.displayRef` for the default\n     notes (not just /refs/notes/commits). It should just respect\n     `format.notes`, I think. But I can look at that later.\n\n>\n>>     activated. Use this sequence to do that:\n>>     +\n>>     ----\n>>     --no-range-diff-notes --range-diff-notes\n>>     ----\n>>     +\n>>     Now the range diff is back to displaying the same notes as the\n>>     patches. Going back to the three `--notes` example: now the range diff\n>>     will show all three notes again.\n>\n> A bit long, but easy to follow and understand the interactions, I\n> think. The examples are helpful.\n\nThanks. I noticed the lines kept creeping up, but it is more involved\nthan most options; an option for passing on to another command which\nalso overrides the behavior of another option.\n\nThanks for taking a look at this niche topic. Though I see that you are\none of the dozen of us[3] who use Git notes on his submissions. ;)\n\n🔗 3: https://lore.kernel.org/git/CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz/T/#m6a7cbbe0fc456e7e62125d903b706ae5a547315b\n"},{"id":"552080","messageId":"xmqqcxuq483g.fsf@gitster.g","threadId":"66213","inReplyTo":"e3b7ef75-08e6-4529-ac75-56f800d2f4a4@app.fastmail.com","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-06T17:12:35Z","receivedAt":"2026-09-06T17:12:38Z","isPatch":true,"body":"\"Kristoffer Haugsbakk\" <kristofferhaugsbakk@fastmail.com> writes:\n\n> Seeing as how the doc was unclear and did not spell out how you can\n> build two separate list of notes, here’s a draft of a rewrite:\n>\n>     `--range-diff-notes[=<ref>]`::\n>     `--no-range-diff-notes`::\n>             Used with `--range-diff`, tweak what notes to display in the\n>             range diff.\n>     +\n>     The default behavior is to display the same notes in the range diff as\n>     on the patches; see `--notes`. But you can use these options to use a\n>     different list of notes. For example, say you have given three notes\n>     refs to `--notes`. At this point those same three notes will be\n>     displayed in the range diff. But then you pass\n>     `--range-diff-notes=<ref>`. Now the range diff will only display\n>     _<ref>_. You can of course pass more refs to this option, just like\n>     `--notes`. And you can also turn off all notes with\n>     `--no-range-diff-notes`.\n\nUp to this point it is quite clear how the two interact.  Even\nthough it does not appear in the above paragraph, the rules\nessentially are \"Without --range-diff-notes, the refs that are\nspecified by --notes are used for both purposes\" and \"When you use\n--range-diff-notes, --notes and --range-diff-notes give independent\nsets of notes, the former is shown only in the output, the latter is\nused only for comparison\".\n\nBut the following paragraph, while it may be correctly describing\nwhat the code does, does not tell me why you would even want to do\nso.  \n\nFor example, if you have --notes=foo --notes=bar always given in an\nalias, i.e.\n\n    [alias] fmt = format-patch --notes=foo --notes=bar\n\nbut in one invocation you would want to use different set of notes\nonly for comparison, you would\n\n    git fmt --range-diff-notes=\n\nif you do not want any notes participate in the comparison, or\n\n    git fmt --range-diff-notes=bar\n\nyou want only 'bar' to be used in the comparison.\n\nIf you had --range-diff-notes=foo in a similar way in an alias,\n\n    [alias] fmtr = format-patch --range-diff-notes=foo --notes=bar\n\nyou may need a way to tell that 'foo' no longer participates in the\ncomparison with\n\n    git fmtr --no-range-diff-notes\n\nIf the rule is that once you say --no-range-diff-notes the internal\nstate is reset and the command behaves as if no --range-diff-notes\noption is ever given [*], then that would still leave --notes=bar so\nthe command would beave as if\n\n    git format-patch --notes=bar\n\nwere given, which means bar will now affect both, so if you want\n'bar' not to be used for comparison, you would need some way to\npretend as if you said\n\n    git format-patch --range-diff-notes= --notes=bar\n\nand ...\n\n>     +\n>     You may want to turn off this notes override behavior after it has been\n>     activated. Use this sequence to do that:\n>     +\n>     ----\n>     --no-range-diff-notes --range-diff-notes\n>     ----\n>     +\n>     Now the range diff is back to displaying the same notes as the\n>     patches. Going back to the three `--notes` example: now the range diff\n>     will show all three notes again.\n\n... may be a way to do so, perhaps?\n\nBUT I think that is a strange interpretation and notation.  Normal\npeople would rather assume, once you said --no-range-diff-notes, you\ndo not want any notes to be used for range-diff comparison.  IOW, I\nfind the earlier rule [*] that makes --no-range-diff-notes only tell\nthe command to pretend that no --range-diff-notes is ever given,\nwhich leads to the above conclusion, a source of confusion.\n\nIf the rule were \"if you say --no-range-diff-notes, you are saying\nthat you do not want any notes used for range-diff\" (and similarly\n\"if you say --no-notes you are saying that you do not want any notes\nused\"), would it make the workaround in the last part unnecessary?\nUnder such a world order, \n\n    git fmtr --no-range-diff-notes\n\nwould mean that --no-range-diff-notes tells that you do not want any\nnotes participate in the comparison, so any --notes in the alias\ndefinition of fmtr would be used only for the final display.  And\n\n    git fmtr --no-range-diff-notes --range-diff-notes\n\nwould tell the command that on top of the previous state, you are\nadding 0 notes to the set of notes used for comparisons, so it would\nbe a no op.  If it were\n\n    git fmtr --no-range-diff-notes --range-diff-notes=bar\n\nthen you'd let --notes in the fmtr alias definition to be used for\nfinal display, --range-diff-notes in the fmtr alias definition to be\ntotally ignored, and bar is used for comparison.\n\nWould that logically make sense and make it easier to understand?\n\nThanks.\n\n"},{"id":"552082","messageId":"CALnO6CDhFNozhFSM74fpGX68tGGw=eMeyJ-5K=4XVCC2Fi4AsA@mail.gmail.com","threadId":"66213","inReplyTo":"392dc2b3-59cf-4fd4-8c73-38a57c8d0423@app.fastmail.com","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-06T17:57:40Z","receivedAt":"2026-09-06T17:57:53Z","isPatch":true,"body":"On Sun, Sep 6, 2026 at 12:45 PM Kristoffer Haugsbakk\n<kristofferhaugsbakk@fastmail.com> wrote:\n>\n> On Sun, Sep 6, 2026, at 15:37, D. Ben Knoble wrote:\n> > On Sun, Sep 6, 2026 at 3:23 AM Kristoffer Haugsbakk\n> >> >[snip]\n> >> > That this wasn’t clear is the fault of the doc here.\n> >>\n> >> Seeing as how the doc was unclear and did not spell out how you can\n> >> build two separate list of notes, here’s a draft of a rewrite:\n> >>\n> >>     `--range-diff-notes[=<ref>]`::\n> >>     `--no-range-diff-notes`::\n> >>             Used with `--range-diff`, tweak what notes to display in the\n> >>             range diff.\n> >>     +\n> >>     The default behavior is to display the same notes in the range diff as\n> >>     on the patches; see `--notes`. But you can use these options to use a\n> >>     different list of notes. For example, say you have given three notes\n> >>     refs to `--notes`. At this point those same three notes will be\n> >>     displayed in the range diff. But then you pass\n> >>     `--range-diff-notes=<ref>`. Now the range diff will only display\n> >>     _<ref>_. You can of course pass more refs to this option, just like\n> >>     `--notes`. And you can also turn off all notes with\n> >>     `--no-range-diff-notes`.\n> >>     +\n> >>     You may want to turn off this notes override behavior after it has been\n> >\n> > [nit: should we call this \"no notes\" override behavior? Otherwise I\n> > think we are referring to --range-diff-notes=<ref> overriding\n> > --notes=…]\n>\n> (I will shorten `range-diff` to `RD` for semi-brevity)\n>\n> What I mean here by “notes override behavior” is turning off all\n> `--[no-]RD-notes` options. It means turning off `--RD-notes` as well as\n> `--no-RD-notes`. And without the override you are back to the default\n> behavior where `--notes` dictates the notes for the range diff.\n>\n> So that the utility is a bit more clear than these unmotivated examples,\n> here’s an example alias (with forced linebreaks):\n>\n>     my-fp = format-patch --notes=review --notes=testing\n>         --notes=attribution --notes=changelog\n>         --range-diff-notes=changelog\n>\n> The patches will have four notes while the range diff will have one.\n>\n> But you may want to disregard that last `--RD-notes` and in turn get all\n> of the notes in the range diff. But without repeating yourself. Then you\n> can do this:\n>\n>     my-fp --no-range-diff-notes --range-diff-notes\n>\n> The option (the negation) is not sufficient since it would turn off all\n> range diff notes. But this special meaning of `--RD-notes` allows you to\n> go back to just regular `--notes` behavior. That `--RD-notes` has a\n> special meaning when the list of range diff notes is empty does not lose\n> anything since `--range-diff-notes` would just be a noöp otherwise.[1]\n\nAha! I _did_ misunderstand, then :) I thought this example in the\nproposal was for the case where \"my-fp\" has \"--no-RD-notes\" and we\nwanted to re-add them with \"--RD-notes\".\n\nHeh, definitely a bit confusing, but spelled out it makes sense.\n\n> But I should point out in this doc that bare `--RD-notes` does not use\n> the default notes.\n>\n> Of course, there could be a dedicated option to turn these options off.\n\nI thought about that, as well, after re-absorbing the examples. I'm\nnot sure what to call it, though. \"disable-RD-notes\" is a mouthful and\ndoesn't seem to have precedence from my (spotty!) memory of various\nsubcommands.\n\n> Or to just not support it. ;)\n>\n> (my standard verbosity level might not be doing me any favors\n> on this point.)\n>\n> ***\n>\n> That might seem like a lot of “power” for something as niche as\n> overriding-then-reverting patch contra range diff notes. But code\n> wise I don’t think the price is high... :)\n\nReading from the sidelines, it seems we have often gotten ourselves in\ntrouble because the code was easy and too easily reflected in the user\ninterface. OTOH, I'm not sure what else to do here ;)\n\n> † 1: I just tested the behavior of `--notes` (no arg) on\n>      `format-patch`. Yes, it does respect the default notes ref just\n>      like git-log(1) does. So an alternative would be to have\n>      `--RD-notes` do the same.\n>\n>      But I do not think some convenient default notes ref is good for a\n>      command which is supposed to generate patches for email\n>      sendout. For `log` you can make convenient notes to yourself and\n>      conveniently display them. But `format-patch` should demand more\n>      intentionality. (I also wrote about this on a bugfix for\n>      `format-patch` behavior some years ago.)[2]\n> † 2: I suspect there is a bug-looking like behavior in that\n>      `format-patch` seems to use `notes.displayRef` for the default\n>      notes (not just /refs/notes/commits). It should just respect\n>      `format.notes`, I think. But I can look at that later.\n\nHuh, interesting. \"git help format-patch\" says format.notes turns on\n\"--notes\", so I would guess without looking further that it is a\nboolean.\n\nYet \"git help config\" says it can provide a ref.\n\nSo, yeah, I would expect format-patch should use format.notes over\nnotes.displayRef.\n\n> > A bit long, but easy to follow and understand the interactions, I\n> > think. The examples are helpful.\n>\n> Thanks. I noticed the lines kept creeping up, but it is more involved\n> than most options; an option for passing on to another command which\n> also overrides the behavior of another option.\n\nThe price of flexibility ;)\n\n> Thanks for taking a look at this niche topic. Though I see that you are\n> one of the dozen of us[3] who use Git notes on his submissions. ;)\n>\n> 🔗 3: https://lore.kernel.org/git/CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz/T/#m6a7cbbe0fc456e7e62125d903b706ae5a547315b\n\n<3\n\n-- \nD. Ben Knoble\n"},{"id":"552341","messageId":"8f0a076b-4822-44e2-a842-cc1e39ae1c1d@app.fastmail.com","threadId":"66213","inReplyTo":"xmqqcxuq483g.fsf@gitster.g","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-09-09T18:08:17Z","receivedAt":"2026-09-09T18:08:41Z","isPatch":true,"body":"On Sun, Sep 6, 2026, at 19:12, Junio C Hamano wrote:\n> \"Kristoffer Haugsbakk\" <kristofferhaugsbakk@fastmail.com> writes:\n>\n>> Seeing as how the doc was unclear and did not spell out how you can\n>> build two separate list of notes, here’s a draft of a rewrite:\n>>\n>>     `--range-diff-notes[=<ref>]`::\n>>     `--no-range-diff-notes`::\n>>             Used with `--range-diff`, tweak what notes to display in the\n>>             range diff.\n>>     +\n>>     The default behavior is to display the same notes in the range diff as\n>>     on the patches; see `--notes`. But you can use these options to use a\n>>     different list of notes. For example, say you have given three notes\n>>     refs to `--notes`. At this point those same three notes will be\n>>     displayed in the range diff. But then you pass\n>>     `--range-diff-notes=<ref>`. Now the range diff will only display\n>>     _<ref>_. You can of course pass more refs to this option, just like\n>>     `--notes`. And you can also turn off all notes with\n>>     `--no-range-diff-notes`.\n>\n> Up to this point it is quite clear how the two interact.  Even\n> though it does not appear in the above paragraph, the rules\n> essentially are \"Without --range-diff-notes, the refs that are\n> specified by --notes are used for both purposes\" and \"When you use\n> --range-diff-notes, --notes and --range-diff-notes give independent\n> sets of notes, the former is shown only in the output, the latter is\n> used only for comparison\".\n>\n> But the following paragraph, while it may be correctly describing\n> what the code does, does not tell me why you would even want to do\n> so.\n>\n> For example, if you have --notes=foo --notes=bar always given in an\n> alias, i.e.\n>\n>     [alias] fmt = format-patch --notes=foo --notes=bar\n>\n> but in one invocation you would want to use different set of notes\n> only for comparison, you would\n>\n>     git fmt --range-diff-notes=\n\nSide note: using `--range-diff-notes=` (empty arg) to signal no-notes\nwould be inconsistent with `--notes`. Those options just take that\nvalue. Then they inevitably output:\n\n    $ git log --notes=\n    warning: notes ref refs/notes/ is invalid\n    [output]\n\n>\n> if you do not want any notes participate in the comparison, or\n>\n>     git fmt --range-diff-notes=bar\n>\n> you want only 'bar' to be used in the comparison.\n>\n> If you had --range-diff-notes=foo in a similar way in an alias,\n>\n>     [alias] fmtr = format-patch --range-diff-notes=foo --notes=bar\n>\n> you may need a way to tell that 'foo' no longer participates in the\n> comparison with\n>\n>     git fmtr --no-range-diff-notes\n>\n> If the rule is that once you say --no-range-diff-notes the internal\n> state is reset and the command behaves as if no --range-diff-notes\n> option is ever given [*], then that would still leave --notes=bar so\n> the command would beave as if\n>\n>     git format-patch --notes=bar\n>\n> were given, which means bar will now affect both, so if you want\n> 'bar' not to be used for comparison, you would need some way to\n> pretend as if you said\n>\n>     git format-patch --range-diff-notes= --notes=bar\n>\n> and ...\n>\n>>     +\n>>     You may want to turn off this notes override behavior after it has been\n>>     activated. Use this sequence to do that:\n>>     +\n>>     ----\n>>     --no-range-diff-notes --range-diff-notes\n>>     ----\n>>     +\n>>     Now the range diff is back to displaying the same notes as the\n>>     patches. Going back to the three `--notes` example: now the range diff\n>>     will show all three notes again.\n>\n> ... may be a way to do so, perhaps?\n>\n> BUT I think that is a strange interpretation and notation.  Normal\n> people would rather assume, once you said --no-range-diff-notes, you\n> do not want any notes to be used for range-diff comparison.  IOW, I\n> find the earlier rule [*] that makes --no-range-diff-notes only tell\n> the command to pretend that no --range-diff-notes is ever given,\n> which leads to the above conclusion, a source of confusion.\n\nThanks for the detailed walkthrough.\n\nI don’t understand why you contrast these two approaches:\n\n(I’m using `RD` as a shorthand for `range-diff` again)\n\n1. `--no-RD-notes` means “revert to whatever `--notes` is up to”, as if\n   no `--[no-]RD-notes` of any kind were ever given\n2. `--no-RD-notes` means “no range diff/comparison notes at all”\n\nSince (2) was the only design I presented. Is the point that you can use\nthese two approaches to eventually find a way to implement the “revert\nto `--notes` behavior”? Well, if so I understand.\n\n>\n> If the rule were \"if you say --no-range-diff-notes, you are saying\n> that you do not want any notes used for range-diff\" (and similarly\n> \"if you say --no-notes you are saying that you do not want any notes\n> used\"), would it make the workaround in the last part unnecessary?\n\nYou seem to be saying that (1), which is not in my implementation, is\nused which in turn necessitates the workaround presented in the part of\nthe doc that you presented. But that’s not the case.\n\n> Under such a world order,\n>\n>     git fmtr --no-range-diff-notes\n>\n> would mean that --no-range-diff-notes tells that you do not want any\n> notes participate in the comparison, so any --notes in the alias\n> definition of fmtr would be used only for the final display.  And\n>\n>     git fmtr --no-range-diff-notes --range-diff-notes\n>\n> would tell the command that on top of the previous state, you are\n> adding 0 notes to the set of notes used for comparisons, so it would\n> be a no op.  If it were\n>\n>     git fmtr --no-range-diff-notes --range-diff-notes=bar\n>\n> then you'd let --notes in the fmtr alias definition to be used for\n> final display, --range-diff-notes in the fmtr alias definition to be\n> totally ignored, and bar is used for comparison.\n>\n> Would that logically make sense and make it easier to understand?\n\nHere we lose the power to revert to what `--notes` is using. (Which you\ndemonstrated the utility of with the alias.) But I think that is\nfine. It is a niche behavior of a niche option. Does not warrant the\nend-user to think this hard at all.\n\nSo here is my redesign:\n\n• There are only `--no-RD-notes` and `--RD-notes=<ref>`, i.e. the last\n  one has to have an argument. Since we have no use for arg-less\n  `--RD-notes` any more.\n• That means that we can use a regular pars-opts callback instead of\n  adding it to `revision.c:handle_revision_opt`.\n• The same rule about interaction with patch notes: no such RD notes\n  means that the patches notes determine what notes the range diff\n  gets. *With* any such options, however, they are determined only by\n  those options. That includes turning off all range diff notes with\n  `--no-RD-notes`.\n• No feature for the niche behavior of turning *back on* “use the patch\n  notes” behavior for the range diff notes\n\nThoughts? I’ll try to work on the reroll in the meantime.\n"},{"id":"552348","messageId":"xmqqpkymqm9z.fsf@gitster.g","threadId":"66213","inReplyTo":"8f0a076b-4822-44e2-a842-cc1e39ae1c1d@app.fastmail.com","subject":"Re: [PATCH 3/3] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-09T19:04:24Z","receivedAt":"2026-09-09T19:04:26Z","isPatch":true,"body":"\"Kristoffer Haugsbakk\" <kristofferhaugsbakk@fastmail.com> writes:\n\n> Side note: using `--range-diff-notes=` (empty arg) to signal no-notes\n> would be inconsistent with `--notes`. Those options just take that\n> value. Then they inevitably output:\n>\n>     $ git log --notes=\n>     warning: notes ref refs/notes/ is invalid\n>     [output]\n\nAh, I didn't know that one.  It sounds like a UI bug we can safely\nfix without worrying about being backward incompatible.\n\n> I don’t understand why you contrast these two approaches:\n>\n> (I’m using `RD` as a shorthand for `range-diff` again)\n>\n> 1. `--no-RD-notes` means “revert to whatever `--notes` is up to”, as if\n>    no `--[no-]RD-notes` of any kind were ever given\n> 2. `--no-RD-notes` means “no range diff/comparison notes at all”\n>\n> Since (2) was the only design I presented. Is the point that you can use\n> these two approaches to eventually find a way to implement the “revert\n> to `--notes` behavior”? Well, if so I understand.\n\nNo.  I thought #1 was what you were doing, which was how I thought\nwas the only way for the command line you suggested in an earlier\nmessage would make sense.\n\n    You may want to turn off this notes override behavior after it has been\n    activated. Use this sequence to do that:\n    +\n    ----\n    --no-range-diff-notes --range-diff-notes\n    ----\n    +\n    Now the range diff is back to displaying the same notes as the\n    patches. Going back to the three `--notes` example: now the range diff\n    will show all three notes again.\n\nUnder the interpretation #2, the first --no-RD-notes tells us that\nwe won't use notes for comparison, and then the next --RD-notes\ntells us that we use notes listed as parameter to it (which is \"no\nnotes\") for comparison, so the \"notes override behaviour\" is not\nturned off.  We use no notes for comparison, and use the ones that\nare given with --notes=<note> only for display.\n\nUnder the interpretation #1, the first --no-RD-notes would make the\ncommand behave as if no --RD-notes were even given, and --notes=<note>\nwould be used both for comparison and display.  Then --RD-notes that\nsays there is no particular notes you want for comparison would make\nthe <note> given earlier with --notes=<note> not to be used for\ncomparison.  After spelling it out like this, it seems that even #1\ndoes not turn off this notes override behaviour, either.  I admit\nthat I wasn't thinking about interpretation #1 too deeply as I\nwasn't interested in seeing it happen.\n\nSo it is good that we agree we want to use the interpretation #2.\nWhich means the \"You may want to turn off ...\" part of the\ndocumentation inaccurate (I think I've already suggested striking it\noff in an earlier message).\n\n"},{"id":"553365","messageId":"V2_CV_format-patch_learn_--range-diff-notes.cdb@m5gid.xyz","threadId":"66213","inReplyTo":"CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz","subject":"[PATCH v2 0/2] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-09-26T18:27:44Z","receivedAt":"2026-09-26T18:27:55Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\nTopic name (applied): kh/format-patch-range-diff-notes\n\nTopic summary: Teach 'format-patch' options to tweak notes output in the\nrange diff independent of what notes are output in the patches.\n\nHey, sorry if someone got duplicate emails right now! I tried to send out\nabout ten minutes ago but it didn’t hit the list. It turned out that there\nwas no `To` header.\n\nWell I don’t know if emails without `To` are sent to the `Cc` addresses.\n\n***\n\nSee patch 2/2 for details.\n\nThis is motivated by wanting to turn off range diff notes, but the goal\nhere is to implement it in full generality.\n\n(How many of us `git format-patch --notes` users are there out there? More\nthan a dozen? Maybe just D. Ben Knoble and me?)\n\nI have implemented this behavior for myself and used it for many\nmonths. But that was hacky and only suitable for one person’s use.\nSo this is a completely new implementation. In other words: this is\nnew code, *not* tested for months.\n\n§ Changes in v2\n\nThis version drops the whole functionality around being able to *go\nback* (and forth) to using `--notes` for the range diff.[1] The behavior\nwas too complex to explain and motivate compared to the utility (little).\n\n🔗 1: https://lore.kernel.org/git/8f0a076b-4822-44e2-a842-cc1e39ae1c1d@app.fastmail.com/#t\n\nThis also means that the implementation is quite different. Now it just\nuses a parse-options callback instead of adding if/else to\n`revision.c:handle_revision_opt`.\n\nSee patch 2/2 for details.\n\nVersion 1 patch 2/3 is dropped. It was a rename motivated by the changes to\n`struct rev_info` in version 1 patch 3/3, which is now gone. The v1 3/3\nchange needed the struct member to stay notes-only, but that is no longer\nrequired.\n\n[1/2] format-patch: simplify get_notes_arg parameters\n[2/2] format-patch: learn --[no-]range-diff-notes\n\n Documentation/git-format-patch.adoc | 15 +++++\n builtin/log.c                       | 62 ++++++++++++++++++--\n t/t3206-range-diff.sh               | 87 +++++++++++++++++++++++++++++\n 3 files changed, 158 insertions(+), 6 deletions(-)\n\nInterdiff against v1:\ndiff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\nindex e0ba435dfcf..5907f299a8d 100644\n--- a/Documentation/git-format-patch.adoc\n+++ b/Documentation/git-format-patch.adoc\n@@ -378,22 +378,20 @@ case is to show comparison with an older iteration of the same\n topic and the tool should find more correspondence between the two\n sets of patches.\n \n-`--range-diff-notes[=<ref>]`::\n+`--range-diff-notes=<ref>`::\n `--no-range-diff-notes`::\n \tUsed with `--range-diff`, tweak what notes to display in the\n-\trange diff. For example, you can use `--no-range-diff-notes` to\n-\tturn off all notes in the range diff. The default behavior is\n-\tto display the same notes in the range diff as on the patches\n-\t(see `--notes`).\n+\trange diff.\n +\n-You may want to turn off this notes override after it has been\n-activated. Use this sequence to do that:\n-+\n-----\n---no-range-diff-notes --range-diff-notes\n-----\n-+\n-Now the range diff is back to displaying the same notes as the patches.\n+The default behavior is to display the same notes in the range diff as\n+on the patches; see `--notes`. But you can use these options to use a\n+different list of notes. For example, say you have given three notes\n+refs to `--notes`. At this point those same three notes will be\n+displayed in the range diff. But then you pass\n+`--range-diff-notes=<ref>`. Now the range diff will only display\n+_<ref>_. You can of course pass more refs to this option, just like\n+`--notes`. And you can also turn off all range diff notes with\n+`--no-range-diff-notes`.\n \n `--notes[=<ref>]`::\n `--no-notes`::\ndiff --git a/builtin/log.c b/builtin/log.c\nindex de997bc9ab0..d70101f0755 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1327,27 +1327,65 @@ static void prepare_cover_text(struct pretty_print_context *pp,\n \tstrbuf_release(&subject_sb);\n }\n \n+struct rdiff_notes {\n+\t/*\n+\t * True if we want to override the notes behavior\n+\t * of 'format-patch'\n+\t */\n+\tbool override;\n+\tstruct string_list notes;\n+};\n+\n+static int rdiff_notes_cb(const struct option *option,\n+\t\t       const char *arg,\n+\t\t       int unset)\n+{\n+\tstruct rdiff_notes *rdiff_notes = option->value;\n+\n+\trdiff_notes->override = 1;\n+\n+\t/*\n+\t * The rest is the same as\n+\t * parse-options-cb.c:parse_opt_string_list\n+\t */\n+\tif (unset) {\n+\t\tstring_list_clear(&rdiff_notes->notes, 0);\n+\t\treturn 0;\n+\t}\n+\n+\tif (!arg)\n+\t\treturn -1;\n+\n+\tstring_list_append(&rdiff_notes->notes, arg);\n+\treturn 0;\n+}\n+\n static int get_notes_refs(struct string_list_item *item, void *arg)\n {\n \tstrvec_pushf(arg, \"--notes=%s\", item->string);\n \treturn 0;\n }\n \n-static void get_notes_args(struct rev_info *rev)\n+static void get_notes_args(struct rdiff_notes *rdiff_notes,\n+\t\t\t   struct rev_info *rev)\n {\n-\tif (rev->rdiff_override_notes) {\n-\t\tif (!rev->rdiff_notes_arg.nr)\n-\t\t\tstrvec_push(&rev->rdiff_notes_arg, \"--no-notes\");\n+\tif (rdiff_notes->override) {\n+\t\tif (rdiff_notes->notes.nr)\n+\t\t\tfor_each_string_list(&rdiff_notes->notes,\n+\t\t\t\t\t     get_notes_refs,\n+\t\t\t\t\t     &rev->rdiff_log_arg);\n+\t\telse\n+\t\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (!rev->show_notes) {\n-\t\tstrvec_push(&rev->rdiff_notes_arg, \"--no-notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n \t\t    !rev->notes_opt.extra_notes_refs.nr)) {\n-\t\tstrvec_push(&rev->rdiff_notes_arg, \"--notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--notes\");\n \t} else {\n \t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs,\n \t\t\t\t     get_notes_refs,\n-\t\t\t\t     &rev->rdiff_notes_arg);\n+\t\t\t\t     &rev->rdiff_log_arg);\n \t}\n }\n \n@@ -1478,7 +1516,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,\n \t\t\t.dual_color = 1,\n \t\t\t.max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT,\n \t\t\t.diffopt = &opts,\n-\t\t\t.log_arg = &rev->rdiff_notes_arg\n+\t\t\t.log_arg = &rev->rdiff_log_arg\n \t\t};\n \n \t\trepo_diff_setup(the_repository, &opts);\n@@ -1998,6 +2036,9 @@ int cmd_format_patch(int argc,\n \tstruct strbuf rdiff1 = STRBUF_INIT;\n \tstruct strbuf rdiff2 = STRBUF_INIT;\n \tstruct strbuf rdiff_title = STRBUF_INIT;\n+\tstruct rdiff_notes rdiff_notes = {\n+\t\t.notes = STRING_LIST_INIT_NODUP,\n+\t};\n \tconst char *rfc = NULL;\n \tint creation_factor = -1;\n \tconst char *signature = git_version_string;\n@@ -2094,6 +2135,9 @@ int cmd_format_patch(int argc,\n \t\t\t     parse_opt_object_name),\n \t\tOPT_STRING(0, \"range-diff\", &rdiff_prev, N_(\"refspec\"),\n \t\t\t   N_(\"show changes against <refspec> in cover letter or single patch\")),\n+\t\tOPT_CALLBACK_F(0, \"range-diff-notes\", &rdiff_notes, N_(\"note\"),\n+\t\t\t       N_(\"override notes behavior for the range diff\"),\n+\t\t\t       0, rdiff_notes_cb),\n \t\tOPT_INTEGER(0, \"creation-factor\", &creation_factor,\n \t\t\t    N_(\"percentage by which creation is weighted\")),\n \t\tOPT_BOOL(0, \"force-in-body-from\", &force_in_body_from,\n@@ -2409,7 +2453,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&rev);\n+\t\tget_notes_args(&rdiff_notes, &rev);\n \t}\n \n \t/*\n@@ -2572,7 +2616,8 @@ int cmd_format_patch(int argc,\n \trev.diffopt.no_free = 0;\n \trelease_revisions(&rev);\n \tformat_config_release(&cfg);\n-\tstrvec_clear(&rev.rdiff_notes_arg);\n+\tstrvec_clear(&rev.rdiff_log_arg);\n+\tstring_list_clear(&rdiff_notes.notes, 0);\n \treturn 0;\n }\n \ndiff --git a/log-tree.c b/log-tree.c\nindex fd6ddf32af4..83a3c4bf9b1 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -718,7 +718,7 @@ static void show_diff_of_diff(struct rev_info *opt)\n \t\t\t.dual_color = 1,\n \t\t\t.max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT,\n \t\t\t.diffopt = &opts,\n-\t\t\t.log_arg = &opt->rdiff_notes_arg\n+\t\t\t.log_arg = &opt->rdiff_log_arg\n \t\t};\n \n \t\tmemcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));\ndiff --git a/revision.c b/revision.c\nindex 1e21f2861cc..50dc8b19913 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2625,19 +2625,6 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->notes_opt.use_default_notes = 1;\n \t} else if (!strcmp(arg, \"--no-standard-notes\")) {\n \t\trevs->notes_opt.use_default_notes = 0;\n-\t} else if (!strcmp(arg, \"--no-range-diff-notes\")) {\n-\t\tstrvec_clear(&revs->rdiff_notes_arg);\n-\t\trevs->rdiff_override_notes = 1;\n-\t} else if (!strcmp(arg, \"--range-diff-notes\")) {\n-\t\t/*\n-\t\t * Allow the user to use '--no-range-diff-notes\n-\t\t * --range-diff-notes' in order to go back to\n-\t\t * using the 'format-patch' notes behavior\n-\t\t */\n-\t\trevs->rdiff_override_notes = revs->rdiff_notes_arg.nr;\n-\t} else if (skip_prefix(arg, \"--range-diff-notes=\", &optarg)) {\n-\t\tstrvec_pushf(&revs->rdiff_notes_arg, \"--notes=%s\", optarg);\n-\t\trevs->rdiff_override_notes = 1;\n \t} else if (!strcmp(arg, \"--oneline\")) {\n \t\trevs->verbose_header = 1;\n \t\tget_commit_format(\"oneline\", revs);\ndiff --git a/revision.h b/revision.h\nindex e8dbf774b00..acf6d06b241 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -351,12 +351,7 @@ struct rev_info {\n \t/* range-diff */\n \tconst char *rdiff1;\n \tconst char *rdiff2;\n-\t/*\n-\t * whether to use 'rdiff_notes_arg' or inherited\n-\t * notes behavior\n-\t */\n-\tbool rdiff_override_notes;\n-\tstruct strvec rdiff_notes_arg;\n+\tstruct strvec rdiff_log_arg;\n \tint creation_factor;\n \tconst char *rdiff_title;\n \n@@ -437,7 +432,7 @@ struct rev_info {\n \t.expand_tabs_in_log = -1, \\\n \t.commit_format = CMIT_FMT_DEFAULT, \\\n \t.expand_tabs_in_log_default = 8, \\\n-\t.rdiff_notes_arg = STRVEC_INIT, \\\n+\t.rdiff_log_arg = STRVEC_INIT, \\\n }\n \n /**\ndiff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\nindex db238d0a5a1..640c5dec52e 100755\n--- a/t/t3206-range-diff.sh\n+++ b/t/t3206-range-diff.sh\n@@ -845,28 +845,49 @@ test_expect_success 'format-patch --range-diff with multiple notes' '\n \ttest_cmp expect actual\n '\n \n+# Unlike '--notes', '--range-diff-notes' requires a value\n+test_expect_success 'format-patch --range-diff-notes requires a value' '\n+\tcat >expect <<-EOF &&\n+\terror: option \\`range-diff-notes${SQ} requires a value\n+\tEOF\n+\ttest_must_fail git format-patch --range-diff=main..topic \\\n+\t\t--cover-letter --range-diff-notes 2>actual &&\n+\ttest_cmp expect actual\n+'\n+\n+# The '--range-diff-notes' has no effect but is allowed\n+test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\ttest_file_not_empty 0000-cover-letter* &&\n+\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes \" 0000-cover-letter*\n+'\n+\n test_expect_success 'format-patch --range-diff --notes=custom --no-range-diff-notes' '\n \ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n \tgit notes --ref=custom add -m \"topic note1\" topic &&\n \tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n \ttest_when_finished \"rm -f 000?-*\" &&\n-\tgit format-patch --range-diff=$prev --notes=custom \\\n+\tgit format-patch --range-diff=main..topic --notes=custom \\\n \t\t--no-range-diff-notes --cover-letter \\\n-\t\tmain..unmodified >actual &&\n+\t\tmain..unmodified &&\n \ttest_grep \"^Notes (custom):\" 0004-* &&\n \ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n \ttest_grep ! \"## Notes (custom) ##\" 0000-cover-letter*\n '\n \n-test_expect_success 'format-patch --range-diff --range-diff-notes uses --notes behavior' '\n+test_expect_success 'format-patch --range-diff --no-notes --range-diff-notes=custom' '\n \ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n \tgit notes --ref=custom add -m \"topic note1\" topic &&\n \tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n \ttest_when_finished \"rm -f 000?-*\" &&\n-\tgit format-patch --range-diff=$prev --notes=custom \\\n-\t\t--range-diff-notes --cover-letter \\\n-\t\tmain..unmodified >actual &&\n-\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\tgit format-patch --range-diff=main..topic --no-notes \\\n+\t\t--range-diff-notes=custom --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep ! \"^Notes (custom):\" 0004-* &&\n \ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n \ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n '\n@@ -879,9 +900,9 @@ test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes=\n \tgit notes --ref=rdiff add -m \"only for range diff 1\" topic &&\n \tgit notes --ref=rdiff add -m \"only for range diff 2\" unmodified &&\n \ttest_when_finished \"rm -f 000?-*\" &&\n-\tgit format-patch --range-diff=$prev --notes=patch \\\n+\tgit format-patch --range-diff=main..topic --notes=patch \\\n \t\t--range-diff-notes=rdiff --cover-letter \\\n-\t\tmain..unmodified >actual &&\n+\t\tmain..unmodified &&\n \ttest_grep \"^Notes (patch):\" 0004-* &&\n \ttest_grep ! \"^Notes (rdiff):\" 0004-* &&\n \ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n@@ -889,50 +910,11 @@ test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes=\n \ttest_grep ! \"## Notes (patch) ##\" 0000-cover-letter*\n '\n \n-test_expect_success 'format-patch --range-diff --no-range-diff-notes --range-diff-notes uses --notes behavior' '\n-\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n-\tgit notes --ref=custom add -m \"topic note1\" topic &&\n-\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n-\ttest_when_finished \"rm -f 000?-*\" &&\n-\tgit format-patch --range-diff=$prev --notes=custom \\\n-\t\t--no-range-diff-notes --range-diff-notes --cover-letter \\\n-\t\tmain..unmodified >actual &&\n-\ttest_grep \"^Notes (custom):\" 0004-* &&\n-\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n-\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n-'\n-\n-test_expect_success 'format-patch --range-diff --range-diff-notes uses --notes behavior' '\n-\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n-\tgit notes --ref=custom add -m \"topic note1\" topic &&\n-\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n-\ttest_when_finished \"rm -f 000?-*\" &&\n-\tgit format-patch --range-diff=$prev --notes=custom \\\n-\t\t--range-diff-notes --cover-letter \\\n-\t\tmain..unmodified >actual &&\n-\ttest_grep \"^Notes (custom):\" 0004-* &&\n-\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n-\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n-'\n-\n-test_expect_success 'format-patch --range-diff --no-range-diff-notes does not use default notes' '\n-\ttest_when_finished \"git notes remove topic unmodified || :\" &&\n-\tgit notes add -m \"topic note1\" topic &&\n-\tgit notes add -m \"unmodified note1\" unmodified &&\n-\ttest_when_finished \"rm -f 000?-*\" &&\n-\tgit format-patch --range-diff=$prev \\\n-\t\t--no-range-diff-notes --cover-letter \\\n-\t\tmain..unmodified >actual &&\n-\ttest_grep ! \"^Notes:\" 0004-* &&\n-\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n-\ttest_grep ! \"## Notes ##\" 0000-cover-letter*\n-'\n-\n test_expect_success 'format-patch --range-diff --no-range-diff-notes on single patch' '\n \ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n \tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n \tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n-\tgit format-patch --notes=custom --range-diff=$prev \\\n+\tgit format-patch --notes=custom --range-diff=main..topic \\\n \t\t--no-range-diff-notes -1 --stdout >actual &&\n \ttest_grep \"Notes (custom):\" actual &&\n \ttest_grep \"^Range-diff:\" actual &&\n@@ -943,7 +925,7 @@ test_expect_success 'format-patch --range-diff --range-diff-notes=custom on sing\n \ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n \tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n \tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n-\tgit format-patch --no-notes --range-diff=$prev \\\n+\tgit format-patch --range-diff=main..topic \\\n \t\t--range-diff-notes=custom -1 --stdout >actual &&\n \ttest_grep ! \"Notes (custom):\" actual &&\n \ttest_grep \"^Range-diff:\" actual &&\nRange-diff against v1:\n1:  977f9c2e97a = 1:  977f9c2e97a format-patch: simplify get_notes_arg parameters\n2:  2a555d40ced < -:  ----------- revision.h: rename struct member to reflect notes role\n3:  058f5fdc8da ! 2:  bf66e94e376 format-patch: learn --[no-]range-diff-notes\n    @@ Commit message\n         • No such options given\n         • `--no-range-diff-notes`\n     \n    -    Well, we can’t. Therefore we need `rdiff_override_notes` to set whenever\n    +    Well, we can’t. Therefore we need `rdiff_notes.override` to set whenever\n         any of these options are given.\n     \n    -    However, we may also want to turn *off* this override. Just like how we\n    -    can countermand any notes ref we pass in:\n    -\n    -        --notes=custom --no-notes\n    -\n    -    To that end, let’s make `--range-diff-notes` when the list of options is\n    -    empty special. Then it means: go back to using whatever git-format-\n    -    patch(1) wants to use.\n    -\n    -    Now, `--notes` is a bit special in that it has an optional\n    -    argument. Implementing this with a parse-options callback is not\n    -    user-friendly; the following does *not* mean what it looks like:\n    -\n    -        --parse-option --another-option\n    -\n    -    Namely, it is not a bare `--parse-option` followed by another\n    -    option. Rather, it’s one option:\n    -\n    -        --parse-option=--another-option\n    -\n    -    And we need the bare `--range-diff-notes` form in order to turn off\n    -    notes overriding. For that reason, let’s implement these new options in\n    -    `revision.c:handle_revision_opt`, just like the `--notes` options are.\n    -\n         † 1: For example, let say we have two notes ref that are used for a\n              patch series:\n     \n    @@ Commit message\n     \n         Note that using `--creation-factor` without `--range-diff` will cause\n         the command to die. But this is not the case for `--[no-]range-diff-\n    -    notes`. Yes, we could introduce struct member `rdiff_notes_arg_used` or\n    -    something in order to detect the same condition. Or turn `rdiff_notes_\n    -    override` into a tri-state `int`. But the extra code is not worth that\n    -    in my opinion.\n    +    notes`; we would have to check `rdiff_notes.override`, which is a sticky\n    +    value (cannot be turned off). The reason is that it is potentially\n    +    inconvenient to error out since it would not let you turn off\n    +    `--range-diff` in, say, some alias that uses `--no-range-diff-\n    +    notes`. Granted, it is difficult for me to come up with a concrete use\n    +    case since `--range-diff` requires a value, specifically a value which\n    +    is probably not that reusable (revision range), and yet you have\n    +    something like an alias set up with it. But why spend code closing\n    +    that door? There is no usability upside to erroring out.\n    +\n    +    ***\n    +\n    +    Add two tests here for the single-patch case, i.e. the case where the\n    +    range diff is on the patch and not in the cover letter. These are meant\n    +    as regression tests based on my encounter with single-patch range diff\n    +    notes handling bug.[2]\n    +\n    +    † 2: 155986b4 (format-patch: handle range-diff on notes correctly for\n    +         single patches, 2025-09-25)\n     \n         Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n     \n     \n      ## Notes (testing) ##\n    -    CI: https://github.com/LemmingAvalanche/git/actions/runs/32762207178\n    +    CI: https://github.com/LemmingAvalanche/git/actions/runs/36231842902\n    +\n    +    This run is on a previous iteration where v1 patch/commit 2/3 was still\n    +    there. But that is just a rename. So I compiled and tested\n    +    `t/t3206-range-diff.sh` and took that as proof that the full CI/build run\n    +    is still valid.\n     \n      ## Documentation/git-format-patch.adoc ##\n     @@ Documentation/git-format-patch.adoc: case is to show comparison with an older iteration of the same\n      topic and the tool should find more correspondence between the two\n      sets of patches.\n      \n    -+`--range-diff-notes[=<ref>]`::\n    ++`--range-diff-notes=<ref>`::\n     +`--no-range-diff-notes`::\n     +\tUsed with `--range-diff`, tweak what notes to display in the\n    -+\trange diff. For example, you can use `--no-range-diff-notes` to\n    -+\tturn off all notes in the range diff. The default behavior is\n    -+\tto display the same notes in the range diff as on the patches\n    -+\t(see `--notes`).\n    -++\n    -+You may want to turn off this notes override after it has been\n    -+activated. Use this sequence to do that:\n    ++\trange diff.\n     ++\n    -+----\n    -+--no-range-diff-notes --range-diff-notes\n    -+----\n    -++\n    -+Now the range diff is back to displaying the same notes as the patches.\n    ++The default behavior is to display the same notes in the range diff as\n    ++on the patches; see `--notes`. But you can use these options to use a\n    ++different list of notes. For example, say you have given three notes\n    ++refs to `--notes`. At this point those same three notes will be\n    ++displayed in the range diff. But then you pass\n    ++`--range-diff-notes=<ref>`. Now the range diff will only display\n    ++_<ref>_. You can of course pass more refs to this option, just like\n    ++`--notes`. And you can also turn off all range diff notes with\n    ++`--no-range-diff-notes`.\n     +\n      `--notes[=<ref>]`::\n      `--no-notes`::\n      \tAppend the notes (see linkgit:git-notes[1]) for the commit\n     \n      ## builtin/log.c ##\n    -@@ builtin/log.c: static int get_notes_refs(struct string_list_item *item, void *arg)\n    +@@ builtin/log.c: static void prepare_cover_text(struct pretty_print_context *pp,\n    + \tstrbuf_release(&subject_sb);\n    + }\n    + \n    ++struct rdiff_notes {\n    ++\t/*\n    ++\t * True if we want to override the notes behavior\n    ++\t * of 'format-patch'\n    ++\t */\n    ++\tbool override;\n    ++\tstruct string_list notes;\n    ++};\n    ++\n    ++static int rdiff_notes_cb(const struct option *option,\n    ++\t\t       const char *arg,\n    ++\t\t       int unset)\n    ++{\n    ++\tstruct rdiff_notes *rdiff_notes = option->value;\n    ++\n    ++\trdiff_notes->override = 1;\n    ++\n    ++\t/*\n    ++\t * The rest is the same as\n    ++\t * parse-options-cb.c:parse_opt_string_list\n    ++\t */\n    ++\tif (unset) {\n    ++\t\tstring_list_clear(&rdiff_notes->notes, 0);\n    ++\t\treturn 0;\n    ++\t}\n    ++\n    ++\tif (!arg)\n    ++\t\treturn -1;\n    ++\n    ++\tstring_list_append(&rdiff_notes->notes, arg);\n    ++\treturn 0;\n    ++}\n    ++\n    + static int get_notes_refs(struct string_list_item *item, void *arg)\n    + {\n    + \tstrvec_pushf(arg, \"--notes=%s\", item->string);\n    + \treturn 0;\n    + }\n      \n    - static void get_notes_args(struct rev_info *rev)\n    +-static void get_notes_args(struct rev_info *rev)\n    ++static void get_notes_args(struct rdiff_notes *rdiff_notes,\n    ++\t\t\t   struct rev_info *rev)\n      {\n     -\tif (!rev->show_notes) {\n    -+\tif (rev->rdiff_override_notes) {\n    -+\t\tif (!rev->rdiff_notes_arg.nr)\n    -+\t\t\tstrvec_push(&rev->rdiff_notes_arg, \"--no-notes\");\n    ++\tif (rdiff_notes->override) {\n    ++\t\tif (rdiff_notes->notes.nr)\n    ++\t\t\tfor_each_string_list(&rdiff_notes->notes,\n    ++\t\t\t\t\t     get_notes_refs,\n    ++\t\t\t\t\t     &rev->rdiff_log_arg);\n    ++\t\telse\n    ++\t\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n     +\t} else if (!rev->show_notes) {\n    - \t\tstrvec_push(&rev->rdiff_notes_arg, \"--no-notes\");\n    + \t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n      \t} else if (rev->notes_opt.use_default_notes > 0 ||\n      \t\t   (rev->notes_opt.use_default_notes == -1 &&\n    -\n    - ## revision.c ##\n    -@@ revision.c: static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n    - \t\trevs->notes_opt.use_default_notes = 1;\n    - \t} else if (!strcmp(arg, \"--no-standard-notes\")) {\n    - \t\trevs->notes_opt.use_default_notes = 0;\n    -+\t} else if (!strcmp(arg, \"--no-range-diff-notes\")) {\n    -+\t\tstrvec_clear(&revs->rdiff_notes_arg);\n    -+\t\trevs->rdiff_override_notes = 1;\n    -+\t} else if (!strcmp(arg, \"--range-diff-notes\")) {\n    -+\t\t/*\n    -+\t\t * Allow the user to use '--no-range-diff-notes\n    -+\t\t * --range-diff-notes' in order to go back to\n    -+\t\t * using the 'format-patch' notes behavior\n    -+\t\t */\n    -+\t\trevs->rdiff_override_notes = revs->rdiff_notes_arg.nr;\n    -+\t} else if (skip_prefix(arg, \"--range-diff-notes=\", &optarg)) {\n    -+\t\tstrvec_pushf(&revs->rdiff_notes_arg, \"--notes=%s\", optarg);\n    -+\t\trevs->rdiff_override_notes = 1;\n    - \t} else if (!strcmp(arg, \"--oneline\")) {\n    - \t\trevs->verbose_header = 1;\n    - \t\tget_commit_format(\"oneline\", revs);\n    -\n    - ## revision.h ##\n    -@@ revision.h: struct rev_info {\n    - \t/* range-diff */\n    - \tconst char *rdiff1;\n    - \tconst char *rdiff2;\n    -+\t/*\n    -+\t * whether to use 'rdiff_notes_arg' or inherited\n    -+\t * notes behavior\n    -+\t */\n    -+\tbool rdiff_override_notes;\n    - \tstruct strvec rdiff_notes_arg;\n    - \tint creation_factor;\n    - \tconst char *rdiff_title;\n    +@@ builtin/log.c: int cmd_format_patch(int argc,\n    + \tstruct strbuf rdiff1 = STRBUF_INIT;\n    + \tstruct strbuf rdiff2 = STRBUF_INIT;\n    + \tstruct strbuf rdiff_title = STRBUF_INIT;\n    ++\tstruct rdiff_notes rdiff_notes = {\n    ++\t\t.notes = STRING_LIST_INIT_NODUP,\n    ++\t};\n    + \tconst char *rfc = NULL;\n    + \tint creation_factor = -1;\n    + \tconst char *signature = git_version_string;\n    +@@ builtin/log.c: int cmd_format_patch(int argc,\n    + \t\t\t     parse_opt_object_name),\n    + \t\tOPT_STRING(0, \"range-diff\", &rdiff_prev, N_(\"refspec\"),\n    + \t\t\t   N_(\"show changes against <refspec> in cover letter or single patch\")),\n    ++\t\tOPT_CALLBACK_F(0, \"range-diff-notes\", &rdiff_notes, N_(\"note\"),\n    ++\t\t\t       N_(\"override notes behavior for the range diff\"),\n    ++\t\t\t       0, rdiff_notes_cb),\n    + \t\tOPT_INTEGER(0, \"creation-factor\", &creation_factor,\n    + \t\t\t    N_(\"percentage by which creation is weighted\")),\n    + \t\tOPT_BOOL(0, \"force-in-body-from\", &force_in_body_from,\n    +@@ builtin/log.c: int cmd_format_patch(int argc,\n    + \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n    + \t\t\t\t\t     _(\"Range-diff:\"),\n    + \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n    +-\t\tget_notes_args(&rev);\n    ++\t\tget_notes_args(&rdiff_notes, &rev);\n    + \t}\n    + \n    + \t/*\n    +@@ builtin/log.c: int cmd_format_patch(int argc,\n    + \trelease_revisions(&rev);\n    + \tformat_config_release(&cfg);\n    + \tstrvec_clear(&rev.rdiff_log_arg);\n    ++\tstring_list_clear(&rdiff_notes.notes, 0);\n    + \treturn 0;\n    + }\n    + \n     \n      ## t/t3206-range-diff.sh ##\n     @@ t/t3206-range-diff.sh: test_expect_success 'format-patch --range-diff with multiple notes' '\n      \ttest_cmp expect actual\n      '\n      \n    ++# Unlike '--notes', '--range-diff-notes' requires a value\n    ++test_expect_success 'format-patch --range-diff-notes requires a value' '\n    ++\tcat >expect <<-EOF &&\n    ++\terror: option \\`range-diff-notes${SQ} requires a value\n    ++\tEOF\n    ++\ttest_must_fail git format-patch --range-diff=main..topic \\\n    ++\t\t--cover-letter --range-diff-notes 2>actual &&\n    ++\ttest_cmp expect actual\n    ++'\n    ++\n    ++# The '--range-diff-notes' has no effect but is allowed\n    ++test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n    ++\ttest_when_finished \"rm -f 000?-*\" &&\n    ++\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n    ++\t\tmain..unmodified &&\n    ++\ttest_when_finished \"rm -f 000?-*\" &&\n    ++\ttest_file_not_empty 0000-cover-letter* &&\n    ++\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n    ++\ttest_grep ! \"## Notes \" 0000-cover-letter*\n    ++'\n    ++\n     +test_expect_success 'format-patch --range-diff --notes=custom --no-range-diff-notes' '\n     +\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n     +\tgit notes --ref=custom add -m \"topic note1\" topic &&\n     +\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n     +\ttest_when_finished \"rm -f 000?-*\" &&\n    -+\tgit format-patch --range-diff=$prev --notes=custom \\\n    ++\tgit format-patch --range-diff=main..topic --notes=custom \\\n     +\t\t--no-range-diff-notes --cover-letter \\\n    -+\t\tmain..unmodified >actual &&\n    ++\t\tmain..unmodified &&\n     +\ttest_grep \"^Notes (custom):\" 0004-* &&\n     +\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n     +\ttest_grep ! \"## Notes (custom) ##\" 0000-cover-letter*\n     +'\n     +\n    -+test_expect_success 'format-patch --range-diff --range-diff-notes uses --notes behavior' '\n    ++test_expect_success 'format-patch --range-diff --no-notes --range-diff-notes=custom' '\n     +\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n     +\tgit notes --ref=custom add -m \"topic note1\" topic &&\n     +\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n     +\ttest_when_finished \"rm -f 000?-*\" &&\n    -+\tgit format-patch --range-diff=$prev --notes=custom \\\n    -+\t\t--range-diff-notes --cover-letter \\\n    -+\t\tmain..unmodified >actual &&\n    -+\ttest_grep \"^Notes (custom):\" 0004-* &&\n    ++\tgit format-patch --range-diff=main..topic --no-notes \\\n    ++\t\t--range-diff-notes=custom --cover-letter \\\n    ++\t\tmain..unmodified &&\n    ++\ttest_grep ! \"^Notes (custom):\" 0004-* &&\n     +\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n     +\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n     +'\n    @@ t/t3206-range-diff.sh: test_expect_success 'format-patch --range-diff with multi\n     +\tgit notes --ref=rdiff add -m \"only for range diff 1\" topic &&\n     +\tgit notes --ref=rdiff add -m \"only for range diff 2\" unmodified &&\n     +\ttest_when_finished \"rm -f 000?-*\" &&\n    -+\tgit format-patch --range-diff=$prev --notes=patch \\\n    ++\tgit format-patch --range-diff=main..topic --notes=patch \\\n     +\t\t--range-diff-notes=rdiff --cover-letter \\\n    -+\t\tmain..unmodified >actual &&\n    ++\t\tmain..unmodified &&\n     +\ttest_grep \"^Notes (patch):\" 0004-* &&\n     +\ttest_grep ! \"^Notes (rdiff):\" 0004-* &&\n     +\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n    @@ t/t3206-range-diff.sh: test_expect_success 'format-patch --range-diff with multi\n     +\ttest_grep ! \"## Notes (patch) ##\" 0000-cover-letter*\n     +'\n     +\n    -+test_expect_success 'format-patch --range-diff --no-range-diff-notes --range-diff-notes uses --notes behavior' '\n    -+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n    -+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n    -+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n    -+\ttest_when_finished \"rm -f 000?-*\" &&\n    -+\tgit format-patch --range-diff=$prev --notes=custom \\\n    -+\t\t--no-range-diff-notes --range-diff-notes --cover-letter \\\n    -+\t\tmain..unmodified >actual &&\n    -+\ttest_grep \"^Notes (custom):\" 0004-* &&\n    -+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n    -+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n    -+'\n    -+\n    -+test_expect_success 'format-patch --range-diff --range-diff-notes uses --notes behavior' '\n    -+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n    -+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n    -+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n    -+\ttest_when_finished \"rm -f 000?-*\" &&\n    -+\tgit format-patch --range-diff=$prev --notes=custom \\\n    -+\t\t--range-diff-notes --cover-letter \\\n    -+\t\tmain..unmodified >actual &&\n    -+\ttest_grep \"^Notes (custom):\" 0004-* &&\n    -+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n    -+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n    -+'\n    -+\n    -+test_expect_success 'format-patch --range-diff --no-range-diff-notes does not use default notes' '\n    -+\ttest_when_finished \"git notes remove topic unmodified || :\" &&\n    -+\tgit notes add -m \"topic note1\" topic &&\n    -+\tgit notes add -m \"unmodified note1\" unmodified &&\n    -+\ttest_when_finished \"rm -f 000?-*\" &&\n    -+\tgit format-patch --range-diff=$prev \\\n    -+\t\t--no-range-diff-notes --cover-letter \\\n    -+\t\tmain..unmodified >actual &&\n    -+\ttest_grep ! \"^Notes:\" 0004-* &&\n    -+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n    -+\ttest_grep ! \"## Notes ##\" 0000-cover-letter*\n    -+'\n    -+\n     +test_expect_success 'format-patch --range-diff --no-range-diff-notes on single patch' '\n     +\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n     +\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n     +\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n    -+\tgit format-patch --notes=custom --range-diff=$prev \\\n    ++\tgit format-patch --notes=custom --range-diff=main..topic \\\n     +\t\t--no-range-diff-notes -1 --stdout >actual &&\n     +\ttest_grep \"Notes (custom):\" actual &&\n     +\ttest_grep \"^Range-diff:\" actual &&\n    @@ t/t3206-range-diff.sh: test_expect_success 'format-patch --range-diff with multi\n     +\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n     +\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n     +\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n    -+\tgit format-patch --no-notes --range-diff=$prev \\\n    ++\tgit format-patch --range-diff=main..topic \\\n     +\t\t--range-diff-notes=custom -1 --stdout >actual &&\n     +\ttest_grep ! \"Notes (custom):\" actual &&\n     +\ttest_grep \"^Range-diff:\" actual &&\n\nbase-commit: 1a3e64c6c4a623626ff0687008732a8e007e2a1c\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"553366","messageId":"V2_simplify_params.cdc@msgid.xyz","threadId":"66213","inReplyTo":"V2_CV_format-patch_learn_--range-diff-notes.cdb@m5gid.xyz","subject":"[PATCH v2 1/2] format-patch: simplify get_notes_arg parameters","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-09-26T18:27:45Z","receivedAt":"2026-09-26T18:28:12Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\n85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n`rdiff_log_arg` to `struct rev_info`. I changed `get_notes_arg` by\nsimply replacing the first argument with an access on this struct\nmember. But the second argument was already `struct rev_info`. So I\nshould have just simplified to *only* passing that parameter. Let’s do\nthat now.\n\nNow is also a good time to format this `for_each...` line since it’s\ngotten quite long.\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (testing):\n    just compile tested\n\n builtin/log.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 350b35c5563..560af00e2fd 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1333,16 +1333,18 @@ static int get_notes_refs(struct string_list_item *item, void *arg)\n \treturn 0;\n }\n \n-static void get_notes_args(struct strvec *arg, struct rev_info *rev)\n+static void get_notes_args(struct rev_info *rev)\n {\n \tif (!rev->show_notes) {\n-\t\tstrvec_push(arg, \"--no-notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n \t\t    !rev->notes_opt.extra_notes_refs.nr)) {\n-\t\tstrvec_push(arg, \"--notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--notes\");\n \t} else {\n-\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);\n+\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs,\n+\t\t\t\t     get_notes_refs,\n+\t\t\t\t     &rev->rdiff_log_arg);\n \t}\n }\n \n@@ -2404,7 +2406,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&(rev.rdiff_log_arg), &rev);\n+\t\tget_notes_args(&rev);\n \t}\n \n \t/*\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"553367","messageId":"V2_format-patch_learn_--range-diff-notes.cdd@msgid.xyz","threadId":"66213","inReplyTo":"V2_CV_format-patch_learn_--range-diff-notes.cdb@m5gid.xyz","subject":"[PATCH v2 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-09-26T18:27:46Z","receivedAt":"2026-09-26T18:28:30Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\ngit-format-patch(1) passes on the notes behavior that it is using for\nthe patches to git-range-diff(1). In turn you get the same Git notes\ndisplayed in the range diff as the ones you used to generate the\npatches. And that makes sense in most cases.\n\nHowever, I often make notes between series versions that mostly prepend\nto the original. They end up looking like this:\n\n    v3:\n    [desc.]\n    v2:\n    [descr.]\n    v1:\n    [descr.]\n\nThese notes are meant for the git-format-patch(1) output since they\ndocument the iterations. But including them also includes them in the\nrange diff. And they have nothing useful to say there.\n\nSo it would be useful to turn off range diff notes handling with\nsomething like `--no-range-diff-notes`. This could then be turned on\nagain with `--range-diff-notes`.\n\nAn off/on switch is enough for this behavior. However, a bare (no arg)\noption (together with the negation) is not consistent with `--[no-]notes\n[=<ref>]` and could cause confusion. And we are both conceptually and\nliterally constructing an argument list to pass on to git-range-diff(1),\nwhich does have the same option format as git-format-patch(1). Moreover,\nit is useful to be able to specify exactly what notes you want\ngit-format-patch(1) and git-range-diff(1) to use.[1] So let’s generalize\nit so that you can pass in whatever notes refs you want.\n\nBut now we are faced with a problem that `--notes` does not have; how do\nwe distinguish an empty `struct string_list` meaning these two things?:\n\n• No such options given\n• `--no-range-diff-notes`\n\nWell, we can’t. Therefore we need `rdiff_notes.override` to set whenever\nany of these options are given.\n\n† 1: For example, let say we have two notes ref that are used for a\n     patch series:\n\n     1. testing. What the user has done to test this iteration.\n     2. changelog. The same example from the introduction.\n\n     You could include both notes on the patches but only show `testing` in\n     the range diff.\n\n***\n\nNote that using `--creation-factor` without `--range-diff` will cause\nthe command to die. But this is not the case for `--[no-]range-diff-\nnotes`; we would have to check `rdiff_notes.override`, which is a sticky\nvalue (cannot be turned off). The reason is that it is potentially\ninconvenient to error out since it would not let you turn off\n`--range-diff` in, say, some alias that uses `--no-range-diff-\nnotes`. Granted, it is difficult for me to come up with a concrete use\ncase since `--range-diff` requires a value, specifically a value which\nis probably not that reusable (revision range), and yet you have\nsomething like an alias set up with it. But why spend code closing\nthat door? There is no usability upside to erroring out.\n\n***\n\nAdd two tests here for the single-patch case, i.e. the case where the\nrange diff is on the patch and not in the cover letter. These are meant\nas regression tests based on my encounter with single-patch range diff\nnotes handling bug.[2]\n\n† 2: 155986b4 (format-patch: handle range-diff on notes correctly for\n     single patches, 2025-09-25)\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (series):\n    v2:\n    This version drops the whole functionality around being able to *go\n    back* (and forth) to using `--notes` for the range diff.[1] The\n    behavior was too complex to explain and motivate compared to the\n    utility (little).\n    \n    🔗 1: https://lore.kernel.org/git/8f0a076b-4822-44e2-a842-cc1e39ae1c1d@app.fastmail.com/#t\n    \n    Also:\n    \n    • Use a parse-options callback for the option instead of\n      `revision.c:handle_revision_opt`\n    • Msg: Rewrite the (former last) paragraph about why we are not\n      erroring when `--range-diff-notes` is given without\n      `--range-diff`. Partly because the facts have changed; now we\n      cannot turn off the `override` bit/flag. But it’s just many words\n      to say that: why spend code disallowing something that you might\n      as well allow?\n    • Add a couple more tests, so simple that they also have an\n      accompanying comment each explaining why they exist\n    • Msg: Add a paragraph explaining why there are two tests specifically\n      for the single-patch case. It’s not just to cover every permutation.\n    • Remove useless `>actual` in tests that don’t test `actual` (they\n      test the patch files instead)\n    • Fix (kind of) the tests that use `$prev` as in:\n    \n          git format-patch --range-diff=$prev\n    \n      This is a very questionable and indirect use from this part of the\n      suite:\n    \n          for prev in topic main..topic\n          do\n              [body]\n          done\n    \n      I.e. it is just `main..topic`. This is monkey-see-monkey-do code\n      from my previous visit of this file. Which then turns out in turn\n      is a monkey-_ from *another* author. I think the existing `$prev`\n      should get a cleanup (separately).\n\nNotes (testing):\n    CI: https://github.com/LemmingAvalanche/git/actions/runs/36231842902\n    \n    This run is on a previous iteration where v1 patch/commit 2/3 was still\n    there. But that is just a rename. So I compiled and tested\n    `t/t3206-range-diff.sh` and took that as proof that the full CI/build run\n    is still valid.\n\n Documentation/git-format-patch.adoc | 15 +++++\n builtin/log.c                       | 54 +++++++++++++++++-\n t/t3206-range-diff.sh               | 87 +++++++++++++++++++++++++++++\n 3 files changed, 153 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\nindex 191f64b77d1..5907f299a8d 100644\n--- a/Documentation/git-format-patch.adoc\n+++ b/Documentation/git-format-patch.adoc\n@@ -378,6 +378,21 @@ case is to show comparison with an older iteration of the same\n topic and the tool should find more correspondence between the two\n sets of patches.\n \n+`--range-diff-notes=<ref>`::\n+`--no-range-diff-notes`::\n+\tUsed with `--range-diff`, tweak what notes to display in the\n+\trange diff.\n++\n+The default behavior is to display the same notes in the range diff as\n+on the patches; see `--notes`. But you can use these options to use a\n+different list of notes. For example, say you have given three notes\n+refs to `--notes`. At this point those same three notes will be\n+displayed in the range diff. But then you pass\n+`--range-diff-notes=<ref>`. Now the range diff will only display\n+_<ref>_. You can of course pass more refs to this option, just like\n+`--notes`. And you can also turn off all range diff notes with\n+`--no-range-diff-notes`.\n+\n `--notes[=<ref>]`::\n `--no-notes`::\n \tAppend the notes (see linkgit:git-notes[1]) for the commit\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 560af00e2fd..d70101f0755 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1327,15 +1327,56 @@ static void prepare_cover_text(struct pretty_print_context *pp,\n \tstrbuf_release(&subject_sb);\n }\n \n+struct rdiff_notes {\n+\t/*\n+\t * True if we want to override the notes behavior\n+\t * of 'format-patch'\n+\t */\n+\tbool override;\n+\tstruct string_list notes;\n+};\n+\n+static int rdiff_notes_cb(const struct option *option,\n+\t\t       const char *arg,\n+\t\t       int unset)\n+{\n+\tstruct rdiff_notes *rdiff_notes = option->value;\n+\n+\trdiff_notes->override = 1;\n+\n+\t/*\n+\t * The rest is the same as\n+\t * parse-options-cb.c:parse_opt_string_list\n+\t */\n+\tif (unset) {\n+\t\tstring_list_clear(&rdiff_notes->notes, 0);\n+\t\treturn 0;\n+\t}\n+\n+\tif (!arg)\n+\t\treturn -1;\n+\n+\tstring_list_append(&rdiff_notes->notes, arg);\n+\treturn 0;\n+}\n+\n static int get_notes_refs(struct string_list_item *item, void *arg)\n {\n \tstrvec_pushf(arg, \"--notes=%s\", item->string);\n \treturn 0;\n }\n \n-static void get_notes_args(struct rev_info *rev)\n+static void get_notes_args(struct rdiff_notes *rdiff_notes,\n+\t\t\t   struct rev_info *rev)\n {\n-\tif (!rev->show_notes) {\n+\tif (rdiff_notes->override) {\n+\t\tif (rdiff_notes->notes.nr)\n+\t\t\tfor_each_string_list(&rdiff_notes->notes,\n+\t\t\t\t\t     get_notes_refs,\n+\t\t\t\t\t     &rev->rdiff_log_arg);\n+\t\telse\n+\t\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n+\t} else if (!rev->show_notes) {\n \t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n@@ -1995,6 +2036,9 @@ int cmd_format_patch(int argc,\n \tstruct strbuf rdiff1 = STRBUF_INIT;\n \tstruct strbuf rdiff2 = STRBUF_INIT;\n \tstruct strbuf rdiff_title = STRBUF_INIT;\n+\tstruct rdiff_notes rdiff_notes = {\n+\t\t.notes = STRING_LIST_INIT_NODUP,\n+\t};\n \tconst char *rfc = NULL;\n \tint creation_factor = -1;\n \tconst char *signature = git_version_string;\n@@ -2091,6 +2135,9 @@ int cmd_format_patch(int argc,\n \t\t\t     parse_opt_object_name),\n \t\tOPT_STRING(0, \"range-diff\", &rdiff_prev, N_(\"refspec\"),\n \t\t\t   N_(\"show changes against <refspec> in cover letter or single patch\")),\n+\t\tOPT_CALLBACK_F(0, \"range-diff-notes\", &rdiff_notes, N_(\"note\"),\n+\t\t\t       N_(\"override notes behavior for the range diff\"),\n+\t\t\t       0, rdiff_notes_cb),\n \t\tOPT_INTEGER(0, \"creation-factor\", &creation_factor,\n \t\t\t    N_(\"percentage by which creation is weighted\")),\n \t\tOPT_BOOL(0, \"force-in-body-from\", &force_in_body_from,\n@@ -2406,7 +2453,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&rev);\n+\t\tget_notes_args(&rdiff_notes, &rev);\n \t}\n \n \t/*\n@@ -2570,6 +2617,7 @@ int cmd_format_patch(int argc,\n \trelease_revisions(&rev);\n \tformat_config_release(&cfg);\n \tstrvec_clear(&rev.rdiff_log_arg);\n+\tstring_list_clear(&rdiff_notes.notes, 0);\n \treturn 0;\n }\n \ndiff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\nindex ef92704de39..640c5dec52e 100755\n--- a/t/t3206-range-diff.sh\n+++ b/t/t3206-range-diff.sh\n@@ -845,6 +845,93 @@ test_expect_success 'format-patch --range-diff with multiple notes' '\n \ttest_cmp expect actual\n '\n \n+# Unlike '--notes', '--range-diff-notes' requires a value\n+test_expect_success 'format-patch --range-diff-notes requires a value' '\n+\tcat >expect <<-EOF &&\n+\terror: option \\`range-diff-notes${SQ} requires a value\n+\tEOF\n+\ttest_must_fail git format-patch --range-diff=main..topic \\\n+\t\t--cover-letter --range-diff-notes 2>actual &&\n+\ttest_cmp expect actual\n+'\n+\n+# The '--range-diff-notes' has no effect but is allowed\n+test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\ttest_file_not_empty 0000-cover-letter* &&\n+\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes \" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=custom --no-range-diff-notes' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --notes=custom \\\n+\t\t--no-range-diff-notes --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-notes --range-diff-notes=custom' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --no-notes \\\n+\t\t--range-diff-notes=custom --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep ! \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes=rdiff' '\n+\ttest_when_finished \"git notes --ref=patch remove topic unmodified || :\" &&\n+\tgit notes --ref=patch add -m \"only for patch 1\" topic &&\n+\tgit notes --ref=patch add -m \"only for patch 2\" unmodified &&\n+\ttest_when_finished \"git notes --ref=rdiff remove topic unmodified || :\" &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 1\" topic &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 2\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --notes=patch \\\n+\t\t--range-diff-notes=rdiff --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep \"^Notes (patch):\" 0004-* &&\n+\ttest_grep ! \"^Notes (rdiff):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (rdiff) ##\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (patch) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-range-diff-notes on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --notes=custom --range-diff=main..topic \\\n+\t\t--no-range-diff-notes -1 --stdout >actual &&\n+\ttest_grep \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep ! \"## Notes (custom) ##\" actual\n+'\n+\n+test_expect_success 'format-patch --range-diff --range-diff-notes=custom on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --range-diff=main..topic \\\n+\t\t--range-diff-notes=custom -1 --stdout >actual &&\n+\ttest_grep ! \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep \"## Notes (custom) ##\" actual\n+'\n+\n test_expect_success '--left-only/--right-only' '\n \tgit switch --orphan left-right &&\n \ttest_commit first &&\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"553381","messageId":"xmqq33uusvst.fsf@gitster.g","threadId":"66213","inReplyTo":"V2_format-patch_learn_--range-diff-notes.cdd@msgid.xyz","subject":"Re: [PATCH v2 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-27T12:50:10Z","receivedAt":"2026-09-27T12:50:13Z","isPatch":true,"body":"kristofferhaugsbakk@fastmail.com writes:\n\n> diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\n> index ef92704de39..640c5dec52e 100755\n> --- a/t/t3206-range-diff.sh\n> +++ b/t/t3206-range-diff.sh\n> ...\n> +# The '--range-diff-notes' has no effect but is allowed\n> +test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n> +\ttest_when_finished \"rm -f 000?-*\" &&\n> +\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n> +\t\tmain..unmodified &&\n> +\ttest_when_finished \"rm -f 000?-*\" &&\n> +\ttest_file_not_empty 0000-cover-letter* &&\n> +\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n> +\ttest_grep ! \"## Notes \" 0000-cover-letter*\n> +'\n\nThe second test_when_finished is redundant, I suspect.\n\nOther than this minor nit, I didn't see anything questionable in\nthis step.\n\nThanks.\n"},{"id":"553390","messageId":"57741bea-f264-45ab-b5fc-52466fdcb03e@app.fastmail.com","threadId":"66213","inReplyTo":"xmqq33uusvst.fsf@gitster.g","subject":"Re: [PATCH v2 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2026-09-27T19:42:17Z","receivedAt":"2026-09-27T19:42:42Z","isPatch":true,"body":"\nOn Sun, Sep 27, 2026, at 14:50, Junio C Hamano wrote:\n> kristofferhaugsbakk@fastmail.com writes:\n>\n>> diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\n>> index ef92704de39..640c5dec52e 100755\n>> --- a/t/t3206-range-diff.sh\n>> +++ b/t/t3206-range-diff.sh\n>> ...\n>> +# The '--range-diff-notes' has no effect but is allowed\n>> +test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n>> +\ttest_when_finished \"rm -f 000?-*\" &&\n>> +\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n>> +\t\tmain..unmodified &&\n>> +\ttest_when_finished \"rm -f 000?-*\" &&\n>> +\ttest_file_not_empty 0000-cover-letter* &&\n>> +\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n>> +\ttest_grep ! \"## Notes \" 0000-cover-letter*\n>> +'\n>\n> The second test_when_finished is redundant, I suspect.\n\nOh yeah. If there is no Range-diff then\nthere won't be a notes section. I'll fix that\nin the next version.\n \n>\n> Other than this minor nit, I didn't see anything questionable in\n> this step.\n>\n> Thanks.\n"},{"id":"553490","messageId":"xmqq33uto0bl.fsf@gitster.g","threadId":"66213","inReplyTo":"57741bea-f264-45ab-b5fc-52466fdcb03e@app.fastmail.com","subject":"Re: [PATCH v2 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-28T15:35:58Z","receivedAt":"2026-09-28T15:36:01Z","isPatch":true,"body":"\"Kristoffer Haugsbakk\" <code@khaugsbakk.name> writes:\n\n> On Sun, Sep 27, 2026, at 14:50, Junio C Hamano wrote:\n>> kristofferhaugsbakk@fastmail.com writes:\n>>\n>>> diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\n>>> index ef92704de39..640c5dec52e 100755\n>>> --- a/t/t3206-range-diff.sh\n>>> +++ b/t/t3206-range-diff.sh\n>>> ...\n>>> +# The '--range-diff-notes' has no effect but is allowed\n>>> +test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n>>> +\ttest_when_finished \"rm -f 000?-*\" &&\n>>> +\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n>>> +\t\tmain..unmodified &&\n>>> +\ttest_when_finished \"rm -f 000?-*\" &&\n>>> +\ttest_file_not_empty 0000-cover-letter* &&\n>>> +\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n>>> +\ttest_grep ! \"## Notes \" 0000-cover-letter*\n>>> +'\n>>\n>> The second test_when_finished is redundant, I suspect.\n>\n> Oh yeah. If there is no Range-diff then\n> there won't be a notes section. I'll fix that\n> in the next version.\n\nI do not understand that comment.  I was merely saying that you are\nregistering the same clean-up-when-we-are-done handler twice.\nHaving the earlier invocation of \"test_when_finished rm -f 000?-*\"\nshoud be sufficient.  It does not make a difference whether we have\nnotes in the range-diff or not.\n"},{"id":"553500","messageId":"69ff90da-875c-44c5-bf00-f53fa61a0482@app.fastmail.com","threadId":"66213","inReplyTo":"xmqq33uto0bl.fsf@gitster.g","subject":"Re: [PATCH v2 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-09-28T15:53:56Z","receivedAt":"2026-09-28T15:54:20Z","isPatch":true,"body":"On Mon, Sep 28, 2026, at 17:35, Junio C Hamano wrote:\n> \"Kristoffer Haugsbakk\" <code@khaugsbakk.name> writes:\n>\n>> On Sun, Sep 27, 2026, at 14:50, Junio C Hamano wrote:\n>>> kristofferhaugsbakk@fastmail.com writes:\n>>>\n>>>> diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\n>>>> index ef92704de39..640c5dec52e 100755\n>>>> --- a/t/t3206-range-diff.sh\n>>>> +++ b/t/t3206-range-diff.sh\n>>>> ...\n>>>> +# The '--range-diff-notes' has no effect but is allowed\n>>>> +test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n>>>> +\ttest_when_finished \"rm -f 000?-*\" &&\n>>>> +\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n>>>> +\t\tmain..unmodified &&\n>>>> +\ttest_when_finished \"rm -f 000?-*\" &&\n>>>> +\ttest_file_not_empty 0000-cover-letter* &&\n>>>> +\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n>>>> +\ttest_grep ! \"## Notes \" 0000-cover-letter*\n>>>> +'\n>>>\n>>> The second test_when_finished is redundant, I suspect.\n>>\n>> Oh yeah. If there is no Range-diff then\n>> there won't be a notes section. I'll fix that\n>> in the next version.\n>\n> I do not understand that comment.  I was merely saying that you are\n> registering the same clean-up-when-we-are-done handler twice.\n> Having the earlier invocation of \"test_when_finished rm -f 000?-*\"\n> shoud be sufficient.  It does not make a difference whether we have\n> notes in the range-diff or not.\n\nYeah. For some reason in my head I jumped\nto assuming that second test_grep was in question. x)\n\nYeah that cleanup is redundant. It happens to be\nplaced where I have the Notes cleanup in the\nother tests.\n"},{"id":"553949","messageId":"V3_CV_format-patch_learn_--range-diff-notes.d39@m5gid.xyz","threadId":"66213","inReplyTo":"CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz","subject":"[PATCH v3 0/2] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-02T10:56:37Z","receivedAt":"2026-10-02T10:57:11Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\nTopic name (applied): kh/format-patch-range-diff-notes\n\nTopic summary: Teach 'format-patch' options to tweak notes output in the\nrange diff independent of what notes are output in the patches.\n\nSee patch 2/2 for details.\n\nThis is motivated by wanting to turn off range diff notes, but the goal\nhere is to implement it in full generality.\n\n(How many of us `git format-patch --notes` users are there out there? More\nthan a dozen? Maybe just D. Ben Knoble and me?)\n\nI have implemented this behavior for myself and used it for many\nmonths. But that was hacky and only suitable for one person’s use.\nSo this is a completely new implementation. In other words: this is\nnew code, *not* tested for months.\n\n§ Changes in v3\n\nFrom patch 2/2:\n\nRemove repeated and redundant `test_when_finished` on\npatch files:\n\nhttps://lore.kernel.org/git/CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz/T/#m06803e233a2e385e694432d45ecf402f7a67e482\n\n§ Link to v2\n\nhttps://lore.kernel.org/git/V2_CV_format-patch_learn_--range-diff-notes.cdb@m5gid.xyz/\n\n[1/2] format-patch: simplify get_notes_arg parameters\n[2/2] format-patch: learn --[no-]range-diff-notes\n\n Documentation/git-format-patch.adoc | 15 +++++\n builtin/log.c                       | 62 +++++++++++++++++++--\n t/t3206-range-diff.sh               | 86 +++++++++++++++++++++++++++++\n 3 files changed, 157 insertions(+), 6 deletions(-)\n\nInterdiff against v2:\ndiff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\nindex 640c5dec52e..679a707c873 100755\n--- a/t/t3206-range-diff.sh\n+++ b/t/t3206-range-diff.sh\n@@ -860,7 +860,6 @@ test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff\n \ttest_when_finished \"rm -f 000?-*\" &&\n \tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n \t\tmain..unmodified &&\n-\ttest_when_finished \"rm -f 000?-*\" &&\n \ttest_file_not_empty 0000-cover-letter* &&\n \ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n \ttest_grep ! \"## Notes \" 0000-cover-letter*\nRange-diff against v2:\n1:  977f9c2e97a = 1:  977f9c2e97a format-patch: simplify get_notes_arg parameters\n2:  bf66e94e376 ! 2:  748759ca021 format-patch: learn --[no-]range-diff-notes\n    @@ Commit message\n     \n     \n      ## Notes (testing) ##\n    -    CI: https://github.com/LemmingAvalanche/git/actions/runs/36231842902\n    -\n    -    This run is on a previous iteration where v1 patch/commit 2/3 was still\n    -    there. But that is just a rename. So I compiled and tested\n    -    `t/t3206-range-diff.sh` and took that as proof that the full CI/build run\n    -    is still valid.\n    +    For v3: only compiled and ran `t3206-range-diff`.\n     \n      ## Documentation/git-format-patch.adoc ##\n     @@ Documentation/git-format-patch.adoc: case is to show comparison with an older iteration of the same\n    @@ t/t3206-range-diff.sh: test_expect_success 'format-patch --range-diff with multi\n     +\ttest_when_finished \"rm -f 000?-*\" &&\n     +\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n     +\t\tmain..unmodified &&\n    -+\ttest_when_finished \"rm -f 000?-*\" &&\n     +\ttest_file_not_empty 0000-cover-letter* &&\n     +\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n     +\ttest_grep ! \"## Notes \" 0000-cover-letter*\n\nbase-commit: 1a3e64c6c4a623626ff0687008732a8e007e2a1c\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"553950","messageId":"V3_simplify_params.d3a@m5gid.xyz","threadId":"66213","inReplyTo":"V3_CV_format-patch_learn_--range-diff-notes.d39@m5gid.xyz","subject":"[PATCH v3 1/2] format-patch: simplify get_notes_arg parameters","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-02T10:56:38Z","receivedAt":"2026-10-02T10:57:29Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\n85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n`rdiff_log_arg` to `struct rev_info`. I changed `get_notes_arg` by\nsimply replacing the first argument with an access on this struct\nmember. But the second argument was already `struct rev_info`. So I\nshould have just simplified to *only* passing that parameter. Let’s do\nthat now.\n\nNow is also a good time to format this `for_each...` line since it’s\ngotten quite long.\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (testing):\n    just compile tested\n\n builtin/log.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 350b35c5563..560af00e2fd 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1333,16 +1333,18 @@ static int get_notes_refs(struct string_list_item *item, void *arg)\n \treturn 0;\n }\n \n-static void get_notes_args(struct strvec *arg, struct rev_info *rev)\n+static void get_notes_args(struct rev_info *rev)\n {\n \tif (!rev->show_notes) {\n-\t\tstrvec_push(arg, \"--no-notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n \t\t    !rev->notes_opt.extra_notes_refs.nr)) {\n-\t\tstrvec_push(arg, \"--notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--notes\");\n \t} else {\n-\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);\n+\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs,\n+\t\t\t\t     get_notes_refs,\n+\t\t\t\t     &rev->rdiff_log_arg);\n \t}\n }\n \n@@ -2404,7 +2406,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&(rev.rdiff_log_arg), &rev);\n+\t\tget_notes_args(&rev);\n \t}\n \n \t/*\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"553951","messageId":"V3_format-patch_learn_--range-diff-notes.d3b@m5gid.xyz","threadId":"66213","inReplyTo":"V3_CV_format-patch_learn_--range-diff-notes.d39@m5gid.xyz","subject":"[PATCH v3 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-02T10:56:39Z","receivedAt":"2026-10-02T10:57:48Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\ngit-format-patch(1) passes on the notes behavior that it is using for\nthe patches to git-range-diff(1). In turn you get the same Git notes\ndisplayed in the range diff as the ones you used to generate the\npatches. And that makes sense in most cases.\n\nHowever, I often make notes between series versions that mostly prepend\nto the original. They end up looking like this:\n\n    v3:\n    [desc.]\n    v2:\n    [descr.]\n    v1:\n    [descr.]\n\nThese notes are meant for the git-format-patch(1) output since they\ndocument the iterations. But including them also includes them in the\nrange diff. And they have nothing useful to say there.\n\nSo it would be useful to turn off range diff notes handling with\nsomething like `--no-range-diff-notes`. This could then be turned on\nagain with `--range-diff-notes`.\n\nAn off/on switch is enough for this behavior. However, a bare (no arg)\noption (together with the negation) is not consistent with `--[no-]notes\n[=<ref>]` and could cause confusion. And we are both conceptually and\nliterally constructing an argument list to pass on to git-range-diff(1),\nwhich does have the same option format as git-format-patch(1). Moreover,\nit is useful to be able to specify exactly what notes you want\ngit-format-patch(1) and git-range-diff(1) to use.[1] So let’s generalize\nit so that you can pass in whatever notes refs you want.\n\nBut now we are faced with a problem that `--notes` does not have; how do\nwe distinguish an empty `struct string_list` meaning these two things?:\n\n• No such options given\n• `--no-range-diff-notes`\n\nWell, we can’t. Therefore we need `rdiff_notes.override` to set whenever\nany of these options are given.\n\n† 1: For example, let say we have two notes ref that are used for a\n     patch series:\n\n     1. testing. What the user has done to test this iteration.\n     2. changelog. The same example from the introduction.\n\n     You could include both notes on the patches but only show `testing` in\n     the range diff.\n\n***\n\nNote that using `--creation-factor` without `--range-diff` will cause\nthe command to die. But this is not the case for `--[no-]range-diff-\nnotes`; we would have to check `rdiff_notes.override`, which is a sticky\nvalue (cannot be turned off). The reason is that it is potentially\ninconvenient to error out since it would not let you turn off\n`--range-diff` in, say, some alias that uses `--no-range-diff-\nnotes`. Granted, it is difficult for me to come up with a concrete use\ncase since `--range-diff` requires a value, specifically a value which\nis probably not that reusable (revision range), and yet you have\nsomething like an alias set up with it. But why spend code closing\nthat door? There is no usability upside to erroring out.\n\n***\n\nAdd two tests here for the single-patch case, i.e. the case where the\nrange diff is on the patch and not in the cover letter. These are meant\nas regression tests based on my encounter with single-patch range diff\nnotes handling bug.[2]\n\n† 2: 155986b4 (format-patch: handle range-diff on notes correctly for\n     single patches, 2025-09-25)\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (series):\n    v3:\n    • Remove repeated and redundant `test_when_finished` on\n      patch files[1]\n    \n      🔗 1: https://lore.kernel.org/git/CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz/T/#m06803e233a2e385e694432d45ecf402f7a67e482\n    \n    ---\n    \n    v2:\n    This version drops the whole functionality around being able to *go\n    back* (and forth) to using `--notes` for the range diff.[1] The\n    behavior was too complex to explain and motivate compared to the\n    utility (little).\n    \n    🔗 1: https://lore.kernel.org/git/8f0a076b-4822-44e2-a842-cc1e39ae1c1d@app.fastmail.com/#t\n    \n    Also:\n    \n    • Use a parse-options callback for the option instead of\n      `revision.c:handle_revision_opt`\n    • Msg: Rewrite the (former last) paragraph about why we are not\n      erroring when `--range-diff-notes` is given without\n      `--range-diff`. Partly because the facts have changed; now we\n      cannot turn off the `override` bit/flag. But it’s just many words\n      to say that: why spend code disallowing something that you might\n      as well allow?\n    • Add a couple more tests, so simple that they also have an\n      accompanying comment each explaining why they exist\n    • Msg: Add a paragraph explaining why there are two tests specifically\n      for the single-patch case. It’s not just to cover every permutation.\n    • Remove useless `>actual` in tests that don’t test `actual` (they\n      test the patch files instead)\n    • Fix (kind of) the tests that use `$prev` as in:\n    \n          git format-patch --range-diff=$prev\n    \n      This is a very questionable and indirect use from this part of the\n      suite:\n    \n          for prev in topic main..topic\n          do\n              [body]\n          done\n    \n      I.e. it is just `main..topic`. This is monkey-see-monkey-do code\n      from my previous visit of this file. Which then turns out in turn\n      is a monkey-_ from *another* author. I think the existing `$prev`\n      should get a cleanup (separately).\n\nNotes (testing):\n    For v3: only compiled and ran `t3206-range-diff`.\n\n Documentation/git-format-patch.adoc | 15 +++++\n builtin/log.c                       | 54 +++++++++++++++++-\n t/t3206-range-diff.sh               | 86 +++++++++++++++++++++++++++++\n 3 files changed, 152 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\nindex 191f64b77d1..5907f299a8d 100644\n--- a/Documentation/git-format-patch.adoc\n+++ b/Documentation/git-format-patch.adoc\n@@ -378,6 +378,21 @@ case is to show comparison with an older iteration of the same\n topic and the tool should find more correspondence between the two\n sets of patches.\n \n+`--range-diff-notes=<ref>`::\n+`--no-range-diff-notes`::\n+\tUsed with `--range-diff`, tweak what notes to display in the\n+\trange diff.\n++\n+The default behavior is to display the same notes in the range diff as\n+on the patches; see `--notes`. But you can use these options to use a\n+different list of notes. For example, say you have given three notes\n+refs to `--notes`. At this point those same three notes will be\n+displayed in the range diff. But then you pass\n+`--range-diff-notes=<ref>`. Now the range diff will only display\n+_<ref>_. You can of course pass more refs to this option, just like\n+`--notes`. And you can also turn off all range diff notes with\n+`--no-range-diff-notes`.\n+\n `--notes[=<ref>]`::\n `--no-notes`::\n \tAppend the notes (see linkgit:git-notes[1]) for the commit\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 560af00e2fd..d70101f0755 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1327,15 +1327,56 @@ static void prepare_cover_text(struct pretty_print_context *pp,\n \tstrbuf_release(&subject_sb);\n }\n \n+struct rdiff_notes {\n+\t/*\n+\t * True if we want to override the notes behavior\n+\t * of 'format-patch'\n+\t */\n+\tbool override;\n+\tstruct string_list notes;\n+};\n+\n+static int rdiff_notes_cb(const struct option *option,\n+\t\t       const char *arg,\n+\t\t       int unset)\n+{\n+\tstruct rdiff_notes *rdiff_notes = option->value;\n+\n+\trdiff_notes->override = 1;\n+\n+\t/*\n+\t * The rest is the same as\n+\t * parse-options-cb.c:parse_opt_string_list\n+\t */\n+\tif (unset) {\n+\t\tstring_list_clear(&rdiff_notes->notes, 0);\n+\t\treturn 0;\n+\t}\n+\n+\tif (!arg)\n+\t\treturn -1;\n+\n+\tstring_list_append(&rdiff_notes->notes, arg);\n+\treturn 0;\n+}\n+\n static int get_notes_refs(struct string_list_item *item, void *arg)\n {\n \tstrvec_pushf(arg, \"--notes=%s\", item->string);\n \treturn 0;\n }\n \n-static void get_notes_args(struct rev_info *rev)\n+static void get_notes_args(struct rdiff_notes *rdiff_notes,\n+\t\t\t   struct rev_info *rev)\n {\n-\tif (!rev->show_notes) {\n+\tif (rdiff_notes->override) {\n+\t\tif (rdiff_notes->notes.nr)\n+\t\t\tfor_each_string_list(&rdiff_notes->notes,\n+\t\t\t\t\t     get_notes_refs,\n+\t\t\t\t\t     &rev->rdiff_log_arg);\n+\t\telse\n+\t\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n+\t} else if (!rev->show_notes) {\n \t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n@@ -1995,6 +2036,9 @@ int cmd_format_patch(int argc,\n \tstruct strbuf rdiff1 = STRBUF_INIT;\n \tstruct strbuf rdiff2 = STRBUF_INIT;\n \tstruct strbuf rdiff_title = STRBUF_INIT;\n+\tstruct rdiff_notes rdiff_notes = {\n+\t\t.notes = STRING_LIST_INIT_NODUP,\n+\t};\n \tconst char *rfc = NULL;\n \tint creation_factor = -1;\n \tconst char *signature = git_version_string;\n@@ -2091,6 +2135,9 @@ int cmd_format_patch(int argc,\n \t\t\t     parse_opt_object_name),\n \t\tOPT_STRING(0, \"range-diff\", &rdiff_prev, N_(\"refspec\"),\n \t\t\t   N_(\"show changes against <refspec> in cover letter or single patch\")),\n+\t\tOPT_CALLBACK_F(0, \"range-diff-notes\", &rdiff_notes, N_(\"note\"),\n+\t\t\t       N_(\"override notes behavior for the range diff\"),\n+\t\t\t       0, rdiff_notes_cb),\n \t\tOPT_INTEGER(0, \"creation-factor\", &creation_factor,\n \t\t\t    N_(\"percentage by which creation is weighted\")),\n \t\tOPT_BOOL(0, \"force-in-body-from\", &force_in_body_from,\n@@ -2406,7 +2453,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&rev);\n+\t\tget_notes_args(&rdiff_notes, &rev);\n \t}\n \n \t/*\n@@ -2570,6 +2617,7 @@ int cmd_format_patch(int argc,\n \trelease_revisions(&rev);\n \tformat_config_release(&cfg);\n \tstrvec_clear(&rev.rdiff_log_arg);\n+\tstring_list_clear(&rdiff_notes.notes, 0);\n \treturn 0;\n }\n \ndiff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\nindex ef92704de39..679a707c873 100755\n--- a/t/t3206-range-diff.sh\n+++ b/t/t3206-range-diff.sh\n@@ -845,6 +845,92 @@ test_expect_success 'format-patch --range-diff with multiple notes' '\n \ttest_cmp expect actual\n '\n \n+# Unlike '--notes', '--range-diff-notes' requires a value\n+test_expect_success 'format-patch --range-diff-notes requires a value' '\n+\tcat >expect <<-EOF &&\n+\terror: option \\`range-diff-notes${SQ} requires a value\n+\tEOF\n+\ttest_must_fail git format-patch --range-diff=main..topic \\\n+\t\t--cover-letter --range-diff-notes 2>actual &&\n+\ttest_cmp expect actual\n+'\n+\n+# The '--range-diff-notes' has no effect but is allowed\n+test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_file_not_empty 0000-cover-letter* &&\n+\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes \" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=custom --no-range-diff-notes' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --notes=custom \\\n+\t\t--no-range-diff-notes --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-notes --range-diff-notes=custom' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --no-notes \\\n+\t\t--range-diff-notes=custom --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep ! \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes=rdiff' '\n+\ttest_when_finished \"git notes --ref=patch remove topic unmodified || :\" &&\n+\tgit notes --ref=patch add -m \"only for patch 1\" topic &&\n+\tgit notes --ref=patch add -m \"only for patch 2\" unmodified &&\n+\ttest_when_finished \"git notes --ref=rdiff remove topic unmodified || :\" &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 1\" topic &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 2\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --notes=patch \\\n+\t\t--range-diff-notes=rdiff --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep \"^Notes (patch):\" 0004-* &&\n+\ttest_grep ! \"^Notes (rdiff):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (rdiff) ##\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (patch) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-range-diff-notes on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --notes=custom --range-diff=main..topic \\\n+\t\t--no-range-diff-notes -1 --stdout >actual &&\n+\ttest_grep \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep ! \"## Notes (custom) ##\" actual\n+'\n+\n+test_expect_success 'format-patch --range-diff --range-diff-notes=custom on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --range-diff=main..topic \\\n+\t\t--range-diff-notes=custom -1 --stdout >actual &&\n+\ttest_grep ! \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep \"## Notes (custom) ##\" actual\n+'\n+\n test_expect_success '--left-only/--right-only' '\n \tgit switch --orphan left-right &&\n \ttest_commit first &&\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"553982","messageId":"xmqqtsn4xd17.fsf@gitster.g","threadId":"66213","inReplyTo":"V3_simplify_params.d3a@m5gid.xyz","subject":"Re: [PATCH v3 1/2] format-patch: simplify get_notes_arg parameters","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-02T16:50:12Z","receivedAt":"2026-10-02T16:50:14Z","isPatch":true,"body":"kristofferhaugsbakk@fastmail.com writes:\n\n> From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n>\n> 85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n> `rdiff_log_arg` to `struct rev_info`. I changed `get_notes_arg` by\n> simply replacing the first argument with an access on this struct\n> member. But the second argument was already `struct rev_info`. So I\n> should have just simplified to *only* passing that parameter. Let’s do\n> that now.\n\nThe readers do not necessarily want to read the \"author's journey\"\nnarrative in log messages.  Let's be more detached and objective,\nlike\n\n  85bd88a7e8 (revision: add rdiff_log_arg to rev_info, 2025-09-25)\n  updated get_notes_args() to push into rev->rdiff_log_arg instead\n  of an explicit strvec, but left the rev argument as the second\n  parameter and strvec *arg as the first. Simplify the signature of\n  get_notes_args() to take only struct rev_info *rev, dropping the\n  redundant strvec *arg parameter.\n\nperhaps?\n\n> Now is also a good time to format this `for_each...` line since it’s\n> gotten quite long.\n>\n> Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n> ---\n>\n> Notes (testing):\n>     just compile tested\n\nThe code change looks good.  As long as this stays as a static helper\nfunction, this is not a loss of flexibility but a simplification of\nthe calling convention.\n\n>  builtin/log.c | 12 +++++++-----\n>  1 file changed, 7 insertions(+), 5 deletions(-)\n>\n> diff --git a/builtin/log.c b/builtin/log.c\n> index 350b35c5563..560af00e2fd 100644\n> --- a/builtin/log.c\n> +++ b/builtin/log.c\n> @@ -1333,16 +1333,18 @@ static int get_notes_refs(struct string_list_item *item, void *arg)\n>  \treturn 0;\n>  }\n>  \n> -static void get_notes_args(struct strvec *arg, struct rev_info *rev)\n> +static void get_notes_args(struct rev_info *rev)\n>  {\n>  \tif (!rev->show_notes) {\n> -\t\tstrvec_push(arg, \"--no-notes\");\n> +\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n>  \t} else if (rev->notes_opt.use_default_notes > 0 ||\n>  \t\t   (rev->notes_opt.use_default_notes == -1 &&\n>  \t\t    !rev->notes_opt.extra_notes_refs.nr)) {\n> -\t\tstrvec_push(arg, \"--notes\");\n> +\t\tstrvec_push(&rev->rdiff_log_arg, \"--notes\");\n>  \t} else {\n> -\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);\n> +\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs,\n> +\t\t\t\t     get_notes_refs,\n> +\t\t\t\t     &rev->rdiff_log_arg);\n>  \t}\n>  }\n>  \n> @@ -2404,7 +2406,7 @@ int cmd_format_patch(int argc,\n>  \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n>  \t\t\t\t\t     _(\"Range-diff:\"),\n>  \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n> -\t\tget_notes_args(&(rev.rdiff_log_arg), &rev);\n> +\t\tget_notes_args(&rev);\n>  \t}\n>  \n>  \t/*\n"},{"id":"553988","messageId":"xmqqy0cgvwpi.fsf@gitster.g","threadId":"66213","inReplyTo":"V3_format-patch_learn_--range-diff-notes.d3b@m5gid.xyz","subject":"Re: [PATCH v3 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-02T17:28:09Z","receivedAt":"2026-10-02T17:28:11Z","isPatch":true,"body":"kristofferhaugsbakk@fastmail.com writes:\n\n> From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n>\n> git-format-patch(1) passes on the notes behavior that it is using for\n> the patches to git-range-diff(1). In turn you get the same Git notes\n> displayed in the range diff as the ones you used to generate the\n> patches. And that makes sense in most cases.\n>\n> However, I often make notes between series versions that mostly prepend\n> ...\n> something like an alias set up with it. But why spend code closing\n> that door? There is no usability upside to erroring out.\n\nThis is somewhat shared with the next step, but the commit message\nincludes a lengthy narrative of the author's thought process (\"An\noff/on switch is enough for this behavior...\", \"But now we are faced\nwith a problem...\", \"Well, we can't. Therefore we need...\").\n\nCan we strip out the conversational journey?  The log message should\nbe a concise, permanent technical reference explaining the problem\n(range diff notes inherit patch notes, which may contain irrelevant\niteration changelogs) and the solution (the new options and the\n.override flag).\n\n> diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\n> index 191f64b77d1..5907f299a8d 100644\n> --- a/Documentation/git-format-patch.adoc\n> +++ b/Documentation/git-format-patch.adoc\n> @@ -378,6 +378,21 @@ case is to show comparison with an older iteration of the same\n>  topic and the tool should find more correspondence between the two\n>  sets of patches.\n>  \n> +`--range-diff-notes=<ref>`::\n> +`--no-range-diff-notes`::\n> +\tUsed with `--range-diff`, tweak what notes to display in the\n> +\trange diff.\n> ++\n> +The default behavior is to display the same notes in the range diff as\n> +on the patches; see `--notes`. But you can use these options to use a\n> +different list of notes. For example, say you have given three notes\n> +refs to `--notes`. At this point those same three notes will be\n> +displayed in the range diff. But then you pass\n> +`--range-diff-notes=<ref>`. Now the range diff will only display\n> +_<ref>_. You can of course pass more refs to this option, just like\n> +`--notes`. And you can also turn off all range diff notes with\n> +`--no-range-diff-notes`.\n\nVery chatty and colloquial.  A technical reference manual should be\nconcise and direct.  Here is my attempt to condense it down to make\nit more readable:\n\n  By default, '--range-diff' displays the same notes as the patches\n  (see '--notes').  Use '--range-diff-notes=<ref>' to specify a\n  different notes ref for the range diff. This option can be given\n  multiple times to show notes from multiple refs.  Use\n  '--no-range-diff-notes' to disable notes in the range diff.\n\n> diff --git a/builtin/log.c b/builtin/log.c\n> index 560af00e2fd..d70101f0755 100644\n> --- a/builtin/log.c\n> +++ b/builtin/log.c\n> @@ -1327,15 +1327,56 @@ static void prepare_cover_text(struct pretty_print_context *pp,\n>  \tstrbuf_release(&subject_sb);\n>  }\n>  \n> +struct rdiff_notes {\n> +\t/*\n> +\t * True if we want to override the notes behavior\n> +\t * of 'format-patch'\n> +\t */\n> +\tbool override;\n> +\tstruct string_list notes;\n> +};\n> +\n> +static int rdiff_notes_cb(const struct option *option,\n> +\t\t       const char *arg,\n> +\t\t       int unset)\n> +{\n> +\tstruct rdiff_notes *rdiff_notes = option->value;\n> +\n> +\trdiff_notes->override = 1;\n> +\n> +\t/*\n> +\t * The rest is the same as\n> +\t * parse-options-cb.c:parse_opt_string_list\n> +\t */\n\nHmph, I wonder if it is more future-proof to wrap the string-list\ncallback like so ...\n\n        static int rdiff_notes_cb(const struct option *option,\n                               const char *arg,\n                               int unset)\n        {\n                struct option opt = *option;\n                struct rdiff_notes *rdiff_notes = opt.value;\n\n                rdiff_notes->override = 1;\n                opt.value = &rdiff_notes->notes;\n                return parse_opt_string_list(&opt, arg, unset);\n        }\n\n... than copying and letting the code drift apart.\n"},{"id":"553998","messageId":"d2360e73-6602-4418-af2e-265054ba8e2b@app.fastmail.com","threadId":"66213","inReplyTo":"xmqqtsn4xd17.fsf@gitster.g","subject":"Re: [PATCH v3 1/2] format-patch: simplify get_notes_arg parameters","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-02T18:51:38Z","receivedAt":"2026-10-02T18:52:03Z","isPatch":true,"body":"On Fri, Oct 2, 2026, at 18:50, Junio C Hamano wrote:\n> kristofferhaugsbakk@fastmail.com writes:\n>\n>> From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n>>\n>> 85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n>> `rdiff_log_arg` to `struct rev_info`. I changed `get_notes_arg` by\n>> simply replacing the first argument with an access on this struct\n>> member. But the second argument was already `struct rev_info`. So I\n>> should have just simplified to *only* passing that parameter. Let’s do\n>> that now.\n>\n> The readers do not necessarily want to read the \"author's journey\"\n> narrative in log messages.  Let's be more detached and objective,\n> like\n>\n>   85bd88a7e8 (revision: add rdiff_log_arg to rev_info, 2025-09-25)\n>   updated get_notes_args() to push into rev->rdiff_log_arg instead\n>   of an explicit strvec, but left the rev argument as the second\n>   parameter and strvec *arg as the first. Simplify the signature of\n>   get_notes_args() to take only struct rev_info *rev, dropping the\n>   redundant strvec *arg parameter.\n\nI don’t get what objective improvement there is by replacing “I did”\nwith “it happened”. This is not a gratuitous incidental biography but\njust says what your alternative says, only with a personal pronoun, less\ntechnical diction, and one word longer.\n\nBut I think we can shorten it with a little show-don’t-tell:\n\n    85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n    `rdiff_log_arg` to `struct rev_info`. `get_notes_arg` was changed to\n    take a second parameter, namely that member:\n\n        get_notes_args(&(rev.rdiff_log_arg), &rev);\n\n    But this is obviously unnecessary; we can just use `&rev`.\n\n    Now is also a good time to format this `for_each...` line since it’s\n    gotten quite long.\n\nThat’s 16 words less than my first version.\n\n>\n> perhaps?\n>\n>> Now is also a good time to format this `for_each...` line since it’s\n>> gotten quite long.\n>>\n>> Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n>> ---\n>>\n>> Notes (testing):\n>>     just compile tested\n>\n> The code change looks good.  As long as this stays as a static helper\n> function, this is not a loss of flexibility but a simplification of\n> the calling convention.\n>\n\nThanks for reviewing.\n"},{"id":"554000","messageId":"aea0780b-a390-4c40-80f4-6060da908dc0@app.fastmail.com","threadId":"66213","inReplyTo":"xmqqy0cgvwpi.fsf@gitster.g","subject":"Re: [PATCH v3 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-02T18:56:05Z","receivedAt":"2026-10-02T18:56:29Z","isPatch":true,"body":"On Fri, Oct 2, 2026, at 19:28, Junio C Hamano wrote:\n> kristofferhaugsbakk@fastmail.com writes:\n>\n>> From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n>>\n>> git-format-patch(1) passes on the notes behavior that it is using for\n>> the patches to git-range-diff(1). In turn you get the same Git notes\n>> displayed in the range diff as the ones you used to generate the\n>> patches. And that makes sense in most cases.\n>>\n>> However, I often make notes between series versions that mostly prepend\n>> ...\n>> something like an alias set up with it. But why spend code closing\n>> that door? There is no usability upside to erroring out.\n>\n> This is somewhat shared with the next step, but the commit message\n> includes a lengthy narrative of the author's thought process (\"An\n> off/on switch is enough for this behavior...\", \"But now we are faced\n> with a problem...\", \"Well, we can't. Therefore we need...\").\n>\n> Can we strip out the conversational journey?  The log message should\n> be a concise, permanent technical reference explaining the problem\n> (range diff notes inherit patch notes, which may contain irrelevant\n> iteration changelogs) and the solution (the new options and the\n> .override flag).\n\nSure.\n\n>\n>> diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\n>> index 191f64b77d1..5907f299a8d 100644\n>> --- a/Documentation/git-format-patch.adoc\n>> +++ b/Documentation/git-format-patch.adoc\n>> @@ -378,6 +378,21 @@ case is to show comparison with an older iteration of the same\n>>  topic and the tool should find more correspondence between the two\n>>  sets of patches.\n>>\n>> +`--range-diff-notes=<ref>`::\n>> +`--no-range-diff-notes`::\n>> +\tUsed with `--range-diff`, tweak what notes to display in the\n>> +\trange diff.\n>> ++\n>> +The default behavior is to display the same notes in the range diff as\n>> +on the patches; see `--notes`. But you can use these options to use a\n>> +different list of notes. For example, say you have given three notes\n>> +refs to `--notes`. At this point those same three notes will be\n>> +displayed in the range diff. But then you pass\n>> +`--range-diff-notes=<ref>`. Now the range diff will only display\n>> +_<ref>_. You can of course pass more refs to this option, just like\n>> +`--notes`. And you can also turn off all range diff notes with\n>> +`--no-range-diff-notes`.\n>\n> Very chatty and colloquial.  A technical reference manual should be\n> concise and direct.  Here is my attempt to condense it down to make\n> it more readable:\n>\n>   By default, '--range-diff' displays the same notes as the patches\n>   (see '--notes').  Use '--range-diff-notes=<ref>' to specify a\n>   different notes ref for the range diff. This option can be given\n>   multiple times to show notes from multiple refs.  Use\n>   '--no-range-diff-notes' to disable notes in the range diff.\n\nFine. The only thing I was concerned about was someone jumping to the\nconclusion that the `--range-diff-notes=<ref>` would be additive to the\n`--notes` options. But this says “different notes ref” which clearly\nmeans that the intent is to discard the `--notes` for the range diff.\n\nI think that version of yours is better.\n\n>[snip]\n>> +static int rdiff_notes_cb(const struct option *option,\n>> +\t\t       const char *arg,\n>> +\t\t       int unset)\n>> +{\n>> +\tstruct rdiff_notes *rdiff_notes = option->value;\n>> +\n>> +\trdiff_notes->override = 1;\n>> +\n>> +\t/*\n>> +\t * The rest is the same as\n>> +\t * parse-options-cb.c:parse_opt_string_list\n>> +\t */\n>\n> Hmph, I wonder if it is more future-proof to wrap the string-list\n> callback like so ...\n>\n>         static int rdiff_notes_cb(const struct option *option,\n>                                const char *arg,\n>                                int unset)\n>         {\n>                 struct option opt = *option;\n>                 struct rdiff_notes *rdiff_notes = opt.value;\n>\n>                 rdiff_notes->override = 1;\n>                 opt.value = &rdiff_notes->notes;\n>                 return parse_opt_string_list(&opt, arg, unset);\n>         }\n>\n> ... than copying and letting the code drift apart.\n\nObviously better.\n"},{"id":"554003","messageId":"30249b7b-b6f7-4065-9a83-db93d69ad0f1@app.fastmail.com","threadId":"66213","inReplyTo":"xmqqtsn4xd17.fsf@gitster.g","subject":"Re: [PATCH v3 1/2] format-patch: simplify get_notes_arg parameters","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-02T19:07:05Z","receivedAt":"2026-10-02T19:07:30Z","isPatch":true,"body":"On Fri, Oct 2, 2026, at 19:28, Junio C Hamano wrote:\n> kristofferhaugsbakk@fastmail.com writes:\n>\n>> From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n>>\n>> git-format-patch(1) passes on the notes behavior that it is using for\n>> the patches to git-range-diff(1). In turn you get the same Git notes\n>> displayed in the range diff as the ones you used to generate the\n>> patches. And that makes sense in most cases.\n>>\n>> However, I often make notes between series versions that mostly prepend\n>> ...\n>> something like an alias set up with it. But why spend code closing\n>> that door? There is no usability upside to erroring out.\n>\n> This is somewhat shared with the next step, but the commit message\n> includes a lengthy narrative of the author's thought process (\"An\n> off/on switch is enough for this behavior...\", \"But now we are faced\n> with a problem...\", \"Well, we can't. Therefore we need...\").\n>\n> Can we strip out the conversational journey?  The log message should\n> be a concise, permanent technical reference explaining the problem\n> (range diff notes inherit patch notes, which may contain irrelevant\n> iteration changelogs) and the solution (the new options and the\n> .override flag).\n\nSure.\n\n>\n>> diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\n>> index 191f64b77d1..5907f299a8d 100644\n>> --- a/Documentation/git-format-patch.adoc\n>> +++ b/Documentation/git-format-patch.adoc\n>> @@ -378,6 +378,21 @@ case is to show comparison with an older iteration of the same\n>>  topic and the tool should find more correspondence between the two\n>>  sets of patches.\n>>\n>> +`--range-diff-notes=<ref>`::\n>> +`--no-range-diff-notes`::\n>> +\tUsed with `--range-diff`, tweak what notes to display in the\n>> +\trange diff.\n>> ++\n>> +The default behavior is to display the same notes in the range diff as\n>> +on the patches; see `--notes`. But you can use these options to use a\n>> +different list of notes. For example, say you have given three notes\n>> +refs to `--notes`. At this point those same three notes will be\n>> +displayed in the range diff. But then you pass\n>> +`--range-diff-notes=<ref>`. Now the range diff will only display\n>> +_<ref>_. You can of course pass more refs to this option, just like\n>> +`--notes`. And you can also turn off all range diff notes with\n>> +`--no-range-diff-notes`.\n>\n> Very chatty and colloquial.  A technical reference manual should be\n> concise and direct.  Here is my attempt to condense it down to make\n> it more readable:\n>\n>   By default, '--range-diff' displays the same notes as the patches\n>   (see '--notes').  Use '--range-diff-notes=<ref>' to specify a\n>   different notes ref for the range diff. This option can be given\n>   multiple times to show notes from multiple refs.  Use\n>   '--no-range-diff-notes' to disable notes in the range diff.\n\nFine. The only thing I was concerned about was someone jumping to the\nconclusion that the `--range-diff-notes=<ref>` would be additive to the\n`--notes` options. But this says “different notes ref” which clearly\nmeans that the intent is to discard the `--notes` for the range diff.\n\nI think that version of yours is better.\n\n>[snip]\n>> +static int rdiff_notes_cb(const struct option *option,\n>> +\t\t       const char *arg,\n>> +\t\t       int unset)\n>> +{\n>> +\tstruct rdiff_notes *rdiff_notes = option->value;\n>> +\n>> +\trdiff_notes->override = 1;\n>> +\n>> +\t/*\n>> +\t * The rest is the same as\n>> +\t * parse-options-cb.c:parse_opt_string_list\n>> +\t */\n>\n> Hmph, I wonder if it is more future-proof to wrap the string-list\n> callback like so ...\n>\n>         static int rdiff_notes_cb(const struct option *option,\n>                                const char *arg,\n>                                int unset)\n>         {\n>                 struct option opt = *option;\n>                 struct rdiff_notes *rdiff_notes = opt.value;\n>\n>                 rdiff_notes->override = 1;\n>                 opt.value = &rdiff_notes->notes;\n>                 return parse_opt_string_list(&opt, arg, unset);\n>         }\n>\n> ... than copying and letting the code drift apart.\n\nObviously better.\n"},{"id":"554004","messageId":"bf0a9780-4f7f-4eb6-94c8-96a33d129a35@app.fastmail.com","threadId":"66213","inReplyTo":"30249b7b-b6f7-4065-9a83-db93d69ad0f1@app.fastmail.com","subject":"Re: [PATCH v3 1/2] format-patch: simplify get_notes_arg parameters","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-02T19:13:15Z","receivedAt":"2026-10-02T19:13:40Z","isPatch":true,"body":"On Fri, Oct 2, 2026, at 21:07, Kristoffer Haugsbakk wrote:\n> On Fri, Oct 2, 2026, at 19:28, Junio C Hamano wrote:\n>> kristofferhaugsbakk@fastmail.com writes:\n>>\n>>> From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n>>>\n>>> git-format-patch(1) passes on the notes behavior that it is using for\n>>> the patches to git-range-diff(1). In turn you get the same Git notes\n>>> displayed in the range diff as the ones you used to generate the\n>>> patches. And that makes sense in most cases.\n>>>\n>>> However, I often make notes between series versions that mostly prepend\n>>> ...\n>>> something like an alias set up with it. But why spend code closing\n>>> that door? There is no usability upside to erroring out.\n>>\n>> This is somewhat shared with the next step, but the commit message\n>> includes a lengthy narrative of the author's thought process (\"An\n>> off/on switch is enough for this behavior...\", \"But now we are faced\n>> with a problem...\", \"Well, we can't. Therefore we need...\").\n>>\n>> Can we strip out the conversational journey?  The log message should\n>> be a concise, permanent technical reference explaining the problem\n>> (range diff notes inherit patch notes, which may contain irrelevant\n>> iteration changelogs) and the solution (the new options and the\n>> .override flag).\n>\n> Sure.\n>[snip]\n\nSorry about this duplicate that message that replied to the wrong\nemail as well.\n"},{"id":"554105","messageId":"V4_CV_format-patch_learn_--range-diff-notes.d5c@m5gid.xyz","threadId":"66213","inReplyTo":"CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz","subject":"[PATCH v4 0/2] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-04T10:17:52Z","receivedAt":"2026-10-04T10:18:29Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\nTopic name (applied): kh/format-patch-range-diff-notes\n\nTopic summary: Teach 'format-patch' options to tweak notes output in the\nrange diff independent of what notes are output in the patches.\n\nSee patch 2/2 for details.\n\nThis is motivated by wanting to turn off range diff notes, but the goal\nhere is to implement it in full generality.\n\n(How many of us `git format-patch --notes` users are there out there? More\nthan a dozen? Maybe just D. Ben Knoble and me?)\n\nI have implemented this behavior for myself and used it for many\nmonths. But that was hacky and only suitable for one person’s use.\nSo this is a completely new implementation. In other words: this is\nnew code, *not* tested for months.\n\n§ Changes in v4\n\nMostly trim expository fat. Also one code refactor. See the patch *notes*\nfor details.\n\n§ Link to v3\n\nhttps://lore.kernel.org/git/V3_CV_format-patch_learn_--range-diff-notes.d39@m5gid.xyz/\n\n[1/2] format-patch: simplify get_notes_arg parameters\n[2/2] format-patch: learn --[no-]range-diff-notes\n\n Documentation/git-format-patch.adoc | 11 ++++\n builtin/log.c                       | 50 +++++++++++++++--\n t/t3206-range-diff.sh               | 86 +++++++++++++++++++++++++++++\n 3 files changed, 141 insertions(+), 6 deletions(-)\n\nInterdiff against v3:\ndiff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\nindex 5907f299a8d..2399ba24454 100644\n--- a/Documentation/git-format-patch.adoc\n+++ b/Documentation/git-format-patch.adoc\n@@ -384,14 +384,10 @@ sets of patches.\n \trange diff.\n +\n The default behavior is to display the same notes in the range diff as\n-on the patches; see `--notes`. But you can use these options to use a\n-different list of notes. For example, say you have given three notes\n-refs to `--notes`. At this point those same three notes will be\n-displayed in the range diff. But then you pass\n-`--range-diff-notes=<ref>`. Now the range diff will only display\n-_<ref>_. You can of course pass more refs to this option, just like\n-`--notes`. And you can also turn off all range diff notes with\n-`--no-range-diff-notes`.\n+on the patches; see `--notes`. Use `--range-diff-notes=<ref>` to use\n+_<ref>_ for the range diff instead. This option can be given multiple\n+times to show notes from multiple refs. Use `--no-range-diff-notes` to\n+disable notes in the range diff.\n \n `--notes[=<ref>]`::\n `--no-notes`::\ndiff --git a/builtin/log.c b/builtin/log.c\nindex d70101f0755..445400ba782 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1337,27 +1337,15 @@ struct rdiff_notes {\n };\n \n static int rdiff_notes_cb(const struct option *option,\n-\t\t       const char *arg,\n-\t\t       int unset)\n+\t\t\t  const char *arg,\n+\t\t\t  int unset)\n {\n+\tstruct option opt = *option;\n \tstruct rdiff_notes *rdiff_notes = option->value;\n \n \trdiff_notes->override = 1;\n-\n-\t/*\n-\t * The rest is the same as\n-\t * parse-options-cb.c:parse_opt_string_list\n-\t */\n-\tif (unset) {\n-\t\tstring_list_clear(&rdiff_notes->notes, 0);\n-\t\treturn 0;\n-\t}\n-\n-\tif (!arg)\n-\t\treturn -1;\n-\n-\tstring_list_append(&rdiff_notes->notes, arg);\n-\treturn 0;\n+\topt.value = &rdiff_notes->notes;\n+\treturn parse_opt_string_list(&opt, arg, unset);\n }\n \n static int get_notes_refs(struct string_list_item *item, void *arg)\nRange-diff against v3:\n1:  977f9c2e97a ! 1:  bb60f300d3f format-patch: simplify get_notes_arg parameters\n    @@ Commit message\n         format-patch: simplify get_notes_arg parameters\n     \n         85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n    -    `rdiff_log_arg` to `struct rev_info`. I changed `get_notes_arg` by\n    -    simply replacing the first argument with an access on this struct\n    -    member. But the second argument was already `struct rev_info`. So I\n    -    should have just simplified to *only* passing that parameter. Let’s do\n    -    that now.\n    +    `rdiff_log_arg` to `struct rev_info`. `get_notes_arg` was changed to\n    +    take a second parameter, namely that member:\n    +\n    +        get_notes_args(&(rev.rdiff_log_arg), &rev);\n    +\n    +    But this is obviously unnecessary; we can just use `&rev`.\n     \n         Now is also a good time to format this `for_each...` line since it’s\n         gotten quite long.\n    @@ Commit message\n     \n     \n      ## Notes (testing) ##\n    +    v1:\n         just compile tested\n     \n      ## builtin/log.c ##\n2:  748759ca021 ! 2:  4cbd312fec6 format-patch: learn --[no-]range-diff-notes\n    @@ Commit message\n         document the iterations. But including them also includes them in the\n         range diff. And they have nothing useful to say there.\n     \n    -    So it would be useful to turn off range diff notes handling with\n    -    something like `--no-range-diff-notes`. This could then be turned on\n    -    again with `--range-diff-notes`.\n    +    Let’s teach git-format-patch(1) `--[no-]range-diff-notes` so that we\n    +    can pass in different notes refs to the range diff, or just turn them\n    +    off entirely.\n     \n    -    An off/on switch is enough for this behavior. However, a bare (no arg)\n    -    option (together with the negation) is not consistent with `--[no-]notes\n    -    [=<ref>]` and could cause confusion. And we are both conceptually and\n    -    literally constructing an argument list to pass on to git-range-diff(1),\n    -    which does have the same option format as git-format-patch(1). Moreover,\n    -    it is useful to be able to specify exactly what notes you want\n    -    git-format-patch(1) and git-range-diff(1) to use.[1] So let’s generalize\n    -    it so that you can pass in whatever notes refs you want.\n    +    In addition to storing the list of notes, we also need a boolean\n    +    `override` to distinguish these two cases:\n     \n    -    But now we are faced with a problem that `--notes` does not have; how do\n    -    we distinguish an empty `struct string_list` meaning these two things?:\n    -\n    -    • No such options given\n    -    • `--no-range-diff-notes`\n    -\n    -    Well, we can’t. Therefore we need `rdiff_notes.override` to set whenever\n    -    any of these options are given.\n    -\n    -    † 1: For example, let say we have two notes ref that are used for a\n    -         patch series:\n    -\n    -         1. testing. What the user has done to test this iteration.\n    -         2. changelog. The same example from the introduction.\n    -\n    -         You could include both notes on the patches but only show `testing` in\n    -         the range diff.\n    +    1. No such options were given and empty list (use `--notes`)\n    +    2. Options were given and empty list (`--no-...` given; don’t use notes)\n     \n         ***\n     \n    @@ Commit message\n         Add two tests here for the single-patch case, i.e. the case where the\n         range diff is on the patch and not in the cover letter. These are meant\n         as regression tests based on my encounter with single-patch range diff\n    -    notes handling bug.[2]\n    +    notes handling bug.[1]\n     \n    -    † 2: 155986b4 (format-patch: handle range-diff on notes correctly for\n    +    † 1: 155986b4 (format-patch: handle range-diff on notes correctly for\n              single patches, 2025-09-25)\n     \n    +    Helped-by: Junio C Hamano <gitster@pobox.com>\n         Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n     \n     \n      ## Notes (testing) ##\n    -    For v3: only compiled and ran `t3206-range-diff`.\n    +    v4:\n    +    • Compiled and ran `t3206-range-diff`.\n    +    • Ran `make html` and looked at git-format-patch(1).\n     \n      ## Documentation/git-format-patch.adoc ##\n     @@ Documentation/git-format-patch.adoc: case is to show comparison with an older iteration of the same\n    @@ Documentation/git-format-patch.adoc: case is to show comparison with an older it\n     +\trange diff.\n     ++\n     +The default behavior is to display the same notes in the range diff as\n    -+on the patches; see `--notes`. But you can use these options to use a\n    -+different list of notes. For example, say you have given three notes\n    -+refs to `--notes`. At this point those same three notes will be\n    -+displayed in the range diff. But then you pass\n    -+`--range-diff-notes=<ref>`. Now the range diff will only display\n    -+_<ref>_. You can of course pass more refs to this option, just like\n    -+`--notes`. And you can also turn off all range diff notes with\n    -+`--no-range-diff-notes`.\n    ++on the patches; see `--notes`. Use `--range-diff-notes=<ref>` to use\n    ++_<ref>_ for the range diff instead. This option can be given multiple\n    ++times to show notes from multiple refs. Use `--no-range-diff-notes` to\n    ++disable notes in the range diff.\n     +\n      `--notes[=<ref>]`::\n      `--no-notes`::\n    @@ builtin/log.c: static void prepare_cover_text(struct pretty_print_context *pp,\n     +};\n     +\n     +static int rdiff_notes_cb(const struct option *option,\n    -+\t\t       const char *arg,\n    -+\t\t       int unset)\n    ++\t\t\t  const char *arg,\n    ++\t\t\t  int unset)\n     +{\n    ++\tstruct option opt = *option;\n     +\tstruct rdiff_notes *rdiff_notes = option->value;\n     +\n     +\trdiff_notes->override = 1;\n    -+\n    -+\t/*\n    -+\t * The rest is the same as\n    -+\t * parse-options-cb.c:parse_opt_string_list\n    -+\t */\n    -+\tif (unset) {\n    -+\t\tstring_list_clear(&rdiff_notes->notes, 0);\n    -+\t\treturn 0;\n    -+\t}\n    -+\n    -+\tif (!arg)\n    -+\t\treturn -1;\n    -+\n    -+\tstring_list_append(&rdiff_notes->notes, arg);\n    -+\treturn 0;\n    ++\topt.value = &rdiff_notes->notes;\n    ++\treturn parse_opt_string_list(&opt, arg, unset);\n     +}\n     +\n      static int get_notes_refs(struct string_list_item *item, void *arg)\n\nbase-commit: 1a3e64c6c4a623626ff0687008732a8e007e2a1c\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"554106","messageId":"V4_simplify_params.d5d@m5gid.xyz","threadId":"66213","inReplyTo":"V4_CV_format-patch_learn_--range-diff-notes.d5c@m5gid.xyz","subject":"[PATCH v4 1/2] format-patch: simplify get_notes_arg parameters","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-04T10:17:53Z","receivedAt":"2026-10-04T10:18:47Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\n85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n`rdiff_log_arg` to `struct rev_info`. `get_notes_arg` was changed to\ntake a second parameter, namely that member:\n\n    get_notes_args(&(rev.rdiff_log_arg), &rev);\n\nBut this is obviously unnecessary; we can just use `&rev`.\n\nNow is also a good time to format this `for_each...` line since it’s\ngotten quite long.\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (series):\n    v4:\n    • Shorter commit message. No I.[1]\n      🔗 1: https://lore.kernel.org/git/CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz/T/#mfbb107570d497be5bfe54fe209014b607f5d5830\n\nNotes (testing):\n    v1:\n    just compile tested\n\n builtin/log.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 350b35c5563..560af00e2fd 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1333,16 +1333,18 @@ static int get_notes_refs(struct string_list_item *item, void *arg)\n \treturn 0;\n }\n \n-static void get_notes_args(struct strvec *arg, struct rev_info *rev)\n+static void get_notes_args(struct rev_info *rev)\n {\n \tif (!rev->show_notes) {\n-\t\tstrvec_push(arg, \"--no-notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n \t\t    !rev->notes_opt.extra_notes_refs.nr)) {\n-\t\tstrvec_push(arg, \"--notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--notes\");\n \t} else {\n-\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);\n+\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs,\n+\t\t\t\t     get_notes_refs,\n+\t\t\t\t     &rev->rdiff_log_arg);\n \t}\n }\n \n@@ -2404,7 +2406,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&(rev.rdiff_log_arg), &rev);\n+\t\tget_notes_args(&rev);\n \t}\n \n \t/*\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"554107","messageId":"V4_format-patch_learn_--range-diff-notes.d5e@m5gid.xyz","threadId":"66213","inReplyTo":"V4_CV_format-patch_learn_--range-diff-notes.d5c@m5gid.xyz","subject":"[PATCH v4 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-04T10:17:54Z","receivedAt":"2026-10-04T10:19:04Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\ngit-format-patch(1) passes on the notes behavior that it is using for\nthe patches to git-range-diff(1). In turn you get the same Git notes\ndisplayed in the range diff as the ones you used to generate the\npatches. And that makes sense in most cases.\n\nHowever, I often make notes between series versions that mostly prepend\nto the original. They end up looking like this:\n\n    v3:\n    [desc.]\n    v2:\n    [descr.]\n    v1:\n    [descr.]\n\nThese notes are meant for the git-format-patch(1) output since they\ndocument the iterations. But including them also includes them in the\nrange diff. And they have nothing useful to say there.\n\nLet’s teach git-format-patch(1) `--[no-]range-diff-notes` so that we\ncan pass in different notes refs to the range diff, or just turn them\noff entirely.\n\nIn addition to storing the list of notes, we also need a boolean\n`override` to distinguish these two cases:\n\n1. No such options were given and empty list (use `--notes`)\n2. Options were given and empty list (`--no-...` given; don’t use notes)\n\n***\n\nNote that using `--creation-factor` without `--range-diff` will cause\nthe command to die. But this is not the case for `--[no-]range-diff-\nnotes`; we would have to check `rdiff_notes.override`, which is a sticky\nvalue (cannot be turned off). The reason is that it is potentially\ninconvenient to error out since it would not let you turn off\n`--range-diff` in, say, some alias that uses `--no-range-diff-\nnotes`. Granted, it is difficult for me to come up with a concrete use\ncase since `--range-diff` requires a value, specifically a value which\nis probably not that reusable (revision range), and yet you have\nsomething like an alias set up with it. But why spend code closing\nthat door? There is no usability upside to erroring out.\n\n***\n\nAdd two tests here for the single-patch case, i.e. the case where the\nrange diff is on the patch and not in the cover letter. These are meant\nas regression tests based on my encounter with single-patch range diff\nnotes handling bug.[1]\n\n† 1: 155986b4 (format-patch: handle range-diff on notes correctly for\n     single patches, 2025-09-25)\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (series):\n    v4:\n    • Msg: Trim all the expository fat, which only loses the footnote\n      about “what if you had a changelog and testing notes” (in terms\n      of “real substance”) as a trade for getting to the point quite\n      quickly (relatively speaking)[1]\n      🔗 1: https://lore.kernel.org/git/30249b7b-b6f7-4065-9a83-db93d69ad0f1@app.fastmail.com/#t\n    • An obvious refactor: call `parse_opt_string_list` instead of\n      manually inlining it along with a comment saying “we inlined\n      it”[1]\n    • Trim the fat from the doc. Straightforward explanation: use this to get\n      `<ref>` instead. Use multiple times for more refs. `--no-...` to\n      turn off. Lifted from the proposal by Junio with some\n      modifications (use `<ref>` to more tersely discuss “a different\n      notes ref”)[1]\n    • Msg: credit help\n    • `clang-format` on `rdiff_notes_cb`\n    \n    🔗 1: https://lore.kernel.org/git/xmqqy0cgvwpi.fsf@gitster.g/\n    \n    ---\n    \n    v3:\n    • Remove repeated and redundant `test_when_finished` on\n      patch files[1]\n    \n      🔗 1: https://lore.kernel.org/git/CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz/T/#m06803e233a2e385e694432d45ecf402f7a67e482\n    ---\n    v2:\n    This version drops the whole functionality around being able to *go\n    back* (and forth) to using `--notes` for the range diff.[1] The\n    behavior was too complex to explain and motivate compared to the\n    utility (little).\n    \n    🔗 1: https://lore.kernel.org/git/8f0a076b-4822-44e2-a842-cc1e39ae1c1d@app.fastmail.com/#t\n    \n    Also:\n    \n    • Use a parse-options callback for the option instead of\n      `revision.c:handle_revision_opt`\n    • Msg: Rewrite the (former last) paragraph about why we are not\n      erroring when `--range-diff-notes` is given without\n      `--range-diff`. Partly because the facts have changed; now we\n      cannot turn off the `override` bit/flag. But it’s just many words\n      to say that: why spend code disallowing something that you might\n      as well allow?\n    • Add a couple more tests, so simple that they also have an\n      accompanying comment each explaining why they exist\n    • Msg: Add a paragraph explaining why there are two tests specifically\n      for the single-patch case. It’s not just to cover every permutation.\n    • Remove useless `>actual` in tests that don’t test `actual` (they\n      test the patch files instead)\n    • Fix (kind of) the tests that use `$prev` as in:\n    \n          git format-patch --range-diff=$prev\n    \n      This is a very questionable and indirect use from this part of the\n      suite:\n    \n          for prev in topic main..topic\n          do\n              [body]\n          done\n    \n      I.e. it is just `main..topic`. This is monkey-see-monkey-do code\n      from my previous visit of this file. Which then turns out in turn\n      is a monkey-_ from *another* author. I think the existing `$prev`\n      should get a cleanup (separately).\n\nNotes (testing):\n    v4:\n    • Compiled and ran `t3206-range-diff`.\n    • Ran `make html` and looked at git-format-patch(1).\n\n Documentation/git-format-patch.adoc | 11 ++++\n builtin/log.c                       | 42 +++++++++++++-\n t/t3206-range-diff.sh               | 86 +++++++++++++++++++++++++++++\n 3 files changed, 136 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\nindex 191f64b77d1..2399ba24454 100644\n--- a/Documentation/git-format-patch.adoc\n+++ b/Documentation/git-format-patch.adoc\n@@ -378,6 +378,17 @@ case is to show comparison with an older iteration of the same\n topic and the tool should find more correspondence between the two\n sets of patches.\n \n+`--range-diff-notes=<ref>`::\n+`--no-range-diff-notes`::\n+\tUsed with `--range-diff`, tweak what notes to display in the\n+\trange diff.\n++\n+The default behavior is to display the same notes in the range diff as\n+on the patches; see `--notes`. Use `--range-diff-notes=<ref>` to use\n+_<ref>_ for the range diff instead. This option can be given multiple\n+times to show notes from multiple refs. Use `--no-range-diff-notes` to\n+disable notes in the range diff.\n+\n `--notes[=<ref>]`::\n `--no-notes`::\n \tAppend the notes (see linkgit:git-notes[1]) for the commit\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 560af00e2fd..445400ba782 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1327,15 +1327,44 @@ static void prepare_cover_text(struct pretty_print_context *pp,\n \tstrbuf_release(&subject_sb);\n }\n \n+struct rdiff_notes {\n+\t/*\n+\t * True if we want to override the notes behavior\n+\t * of 'format-patch'\n+\t */\n+\tbool override;\n+\tstruct string_list notes;\n+};\n+\n+static int rdiff_notes_cb(const struct option *option,\n+\t\t\t  const char *arg,\n+\t\t\t  int unset)\n+{\n+\tstruct option opt = *option;\n+\tstruct rdiff_notes *rdiff_notes = option->value;\n+\n+\trdiff_notes->override = 1;\n+\topt.value = &rdiff_notes->notes;\n+\treturn parse_opt_string_list(&opt, arg, unset);\n+}\n+\n static int get_notes_refs(struct string_list_item *item, void *arg)\n {\n \tstrvec_pushf(arg, \"--notes=%s\", item->string);\n \treturn 0;\n }\n \n-static void get_notes_args(struct rev_info *rev)\n+static void get_notes_args(struct rdiff_notes *rdiff_notes,\n+\t\t\t   struct rev_info *rev)\n {\n-\tif (!rev->show_notes) {\n+\tif (rdiff_notes->override) {\n+\t\tif (rdiff_notes->notes.nr)\n+\t\t\tfor_each_string_list(&rdiff_notes->notes,\n+\t\t\t\t\t     get_notes_refs,\n+\t\t\t\t\t     &rev->rdiff_log_arg);\n+\t\telse\n+\t\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n+\t} else if (!rev->show_notes) {\n \t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n@@ -1995,6 +2024,9 @@ int cmd_format_patch(int argc,\n \tstruct strbuf rdiff1 = STRBUF_INIT;\n \tstruct strbuf rdiff2 = STRBUF_INIT;\n \tstruct strbuf rdiff_title = STRBUF_INIT;\n+\tstruct rdiff_notes rdiff_notes = {\n+\t\t.notes = STRING_LIST_INIT_NODUP,\n+\t};\n \tconst char *rfc = NULL;\n \tint creation_factor = -1;\n \tconst char *signature = git_version_string;\n@@ -2091,6 +2123,9 @@ int cmd_format_patch(int argc,\n \t\t\t     parse_opt_object_name),\n \t\tOPT_STRING(0, \"range-diff\", &rdiff_prev, N_(\"refspec\"),\n \t\t\t   N_(\"show changes against <refspec> in cover letter or single patch\")),\n+\t\tOPT_CALLBACK_F(0, \"range-diff-notes\", &rdiff_notes, N_(\"note\"),\n+\t\t\t       N_(\"override notes behavior for the range diff\"),\n+\t\t\t       0, rdiff_notes_cb),\n \t\tOPT_INTEGER(0, \"creation-factor\", &creation_factor,\n \t\t\t    N_(\"percentage by which creation is weighted\")),\n \t\tOPT_BOOL(0, \"force-in-body-from\", &force_in_body_from,\n@@ -2406,7 +2441,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&rev);\n+\t\tget_notes_args(&rdiff_notes, &rev);\n \t}\n \n \t/*\n@@ -2570,6 +2605,7 @@ int cmd_format_patch(int argc,\n \trelease_revisions(&rev);\n \tformat_config_release(&cfg);\n \tstrvec_clear(&rev.rdiff_log_arg);\n+\tstring_list_clear(&rdiff_notes.notes, 0);\n \treturn 0;\n }\n \ndiff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\nindex ef92704de39..679a707c873 100755\n--- a/t/t3206-range-diff.sh\n+++ b/t/t3206-range-diff.sh\n@@ -845,6 +845,92 @@ test_expect_success 'format-patch --range-diff with multiple notes' '\n \ttest_cmp expect actual\n '\n \n+# Unlike '--notes', '--range-diff-notes' requires a value\n+test_expect_success 'format-patch --range-diff-notes requires a value' '\n+\tcat >expect <<-EOF &&\n+\terror: option \\`range-diff-notes${SQ} requires a value\n+\tEOF\n+\ttest_must_fail git format-patch --range-diff=main..topic \\\n+\t\t--cover-letter --range-diff-notes 2>actual &&\n+\ttest_cmp expect actual\n+'\n+\n+# The '--range-diff-notes' has no effect but is allowed\n+test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_file_not_empty 0000-cover-letter* &&\n+\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes \" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=custom --no-range-diff-notes' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --notes=custom \\\n+\t\t--no-range-diff-notes --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-notes --range-diff-notes=custom' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --no-notes \\\n+\t\t--range-diff-notes=custom --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep ! \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes=rdiff' '\n+\ttest_when_finished \"git notes --ref=patch remove topic unmodified || :\" &&\n+\tgit notes --ref=patch add -m \"only for patch 1\" topic &&\n+\tgit notes --ref=patch add -m \"only for patch 2\" unmodified &&\n+\ttest_when_finished \"git notes --ref=rdiff remove topic unmodified || :\" &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 1\" topic &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 2\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --notes=patch \\\n+\t\t--range-diff-notes=rdiff --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep \"^Notes (patch):\" 0004-* &&\n+\ttest_grep ! \"^Notes (rdiff):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (rdiff) ##\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (patch) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-range-diff-notes on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --notes=custom --range-diff=main..topic \\\n+\t\t--no-range-diff-notes -1 --stdout >actual &&\n+\ttest_grep \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep ! \"## Notes (custom) ##\" actual\n+'\n+\n+test_expect_success 'format-patch --range-diff --range-diff-notes=custom on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --range-diff=main..topic \\\n+\t\t--range-diff-notes=custom -1 --stdout >actual &&\n+\ttest_grep ! \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep \"## Notes (custom) ##\" actual\n+'\n+\n test_expect_success '--left-only/--right-only' '\n \tgit switch --orphan left-right &&\n \ttest_commit first &&\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"554118","messageId":"xmqqqzi5touh.fsf@gitster.g","threadId":"66213","inReplyTo":"V4_format-patch_learn_--range-diff-notes.d5e@m5gid.xyz","subject":"Re: [PATCH v4 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-04T16:25:26Z","receivedAt":"2026-10-04T16:25:29Z","isPatch":true,"body":"kristofferhaugsbakk@fastmail.com writes:\n\n> From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n>\n> git-format-patch(1) passes on the notes behavior that it is using for\n> the patches to git-range-diff(1). In turn you get the same Git notes\n> displayed in the range diff as the ones you used to generate the\n> patches. And that makes sense in most cases.\n>\n> However, I often make notes between series versions that mostly prepend\n> to the original. They end up looking like this:\n>\n>     v3:\n>     [desc.]\n>     v2:\n>     [descr.]\n>     v1:\n>     [descr.]\n>\n> These notes are meant for the git-format-patch(1) output since they\n> document the iterations. But including them also includes them in the\n> range diff. And they have nothing useful to say there.\n>\n> Let’s teach git-format-patch(1) `--[no-]range-diff-notes` so that we\n> can pass in different notes refs to the range diff, or just turn them\n> off entirely.\n>\n> In addition to storing the list of notes, we also need a boolean\n> `override` to distinguish these two cases:\n>\n> 1. No such options were given and empty list (use `--notes`)\n> 2. Options were given and empty list (`--no-...` given; don’t use notes)\n\nNicely described.\n\n> ***\n> Note that using `--creation-factor` without `--range-diff` will cause\n> the command to die. But this is not the case for `--[no-]range-diff-\n> notes`; we would have to check `rdiff_notes.override`, which is a sticky\n> value (cannot be turned off). The reason is that it is potentially\n> inconvenient to error out since it would not let you turn off\n> `--range-diff` in, say, some alias that uses `--no-range-diff-\n> notes`. Granted, it is difficult for me to come up with a concrete use\n> case since `--range-diff` requires a value, specifically a value which\n> is probably not that reusable (revision range), and yet you have\n> something like an alias set up with it. But why spend code closing\n> that door? There is no usability upside to erroring out.\n\nIn short, do you mean something like this?\n\n  Unlike `--creation-factor`, `--[no-]range-diff-notes` does not\n  error out when used without `--range-diff`.  This flexibility\n  accommodates workflows where users might configure default options\n  in aliases or wrapper scripts, allowing `--range-diff` to be\n  toggled independently.\n\nI suspect that erroring out when only creation-factor is given,\nperhaps via an alias, was a design mistake.  A user who wants to use\na setting customized for their workflow must resort to an alias\nbecause there is no configuration variable to control its default.\nIn that light, the same argument for --[no-]range-diff-notes applies\nhere.  On the other hand, perhaps if we had a configuration variable\nto control which notes are compared in range-diff and shown in the\noutput, we would not have to worry about these things.  I do not\nknow.\n\nOther than that (no, not the \"shall we also add a configuration?\",\nwhich I consider is outside the topic, but the overly verbose log\nmessage that gives wandering thought process that does not help the\nreaders with crisp reasoning that leads to the decision which they\nmay or may not agree with), it looks good.\n"},{"id":"554120","messageId":"8df975c9-0f90-4ec5-8003-7f4757067fe2@app.fastmail.com","threadId":"66213","inReplyTo":"xmqqqzi5touh.fsf@gitster.g","subject":"Re: [PATCH v4 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-04T17:30:50Z","receivedAt":"2026-10-04T17:31:15Z","isPatch":true,"body":"On Sun, Oct 4, 2026, at 18:25, Junio C Hamano wrote:\n> kristofferhaugsbakk@fastmail.com writes:\n>>[snip]\n>> ***\n>> Note that using `--creation-factor` without `--range-diff` will cause\n>> the command to die. But this is not the case for `--[no-]range-diff-\n>> notes`; we would have to check `rdiff_notes.override`, which is a sticky\n>> value (cannot be turned off). The reason is that it is potentially\n>> inconvenient to error out since it would not let you turn off\n>> `--range-diff` in, say, some alias that uses `--no-range-diff-\n>> notes`. Granted, it is difficult for me to come up with a concrete use\n>> case since `--range-diff` requires a value, specifically a value which\n>> is probably not that reusable (revision range), and yet you have\n>> something like an alias set up with it. But why spend code closing\n>> that door? There is no usability upside to erroring out.\n>\n> In short, do you mean something like this?\n>\n>   Unlike `--creation-factor`, `--[no-]range-diff-notes` does not\n>   error out when used without `--range-diff`.  This flexibility\n>   accommodates workflows where users might configure default options\n>   in aliases or wrapper scripts, allowing `--range-diff` to be\n>   toggled independently.\n\nThat’s a better way to describe it. I think I will use it pretty much\nverbatim.\n\nNow in hindsight, with your version on display in front of me, I don’t\nknow why I couldn’t make that paragraph more straighforward. Sometimes I\ngo on a narrative journey because I think it is clearer (but never\nshorter), but here I didn’t want to do that at all. I just wanted to lay\nout the motivation. Stumped.\n\n>\n> I suspect that erroring out when only creation-factor is given,\n> perhaps via an alias, was a design mistake.  A user who wants to use\n> a setting customized for their workflow must resort to an alias\n> because there is no configuration variable to control its default.\n> In that light, the same argument for --[no-]range-diff-notes applies\n> here.  On the other hand, perhaps if we had a configuration variable\n> to control which notes are compared in range-diff and shown in the\n> output, we would not have to worry about these things.  I do not\n> know.\n\nYeah it can prevent some workflows while not really helping prevent any\nerrors, I think.\n\nI think I can make this next version right now. I have tried to give\nmore time to each version (like the last one, intentionally waiting more\nthan a day) in order to give other people time to react to them. However\nat this point most of the changes in this series are so stable that I\ndon’t think there are any points to interject to for some hypotethetical\nperson that already had two days or so to speak up.\n\n>[snip]\n"},{"id":"554122","messageId":"V5_CV_format-patch_learn_--range-diff-notes.d6b@m5gid.xyz","threadId":"66213","inReplyTo":"CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz","subject":"[PATCH v5 0/2] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-04T17:58:33Z","receivedAt":"2026-10-04T17:59:06Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\nTopic name (applied): kh/format-patch-range-diff-notes\n\nTopic summary: Teach 'format-patch' options to tweak notes output in the\nrange diff independent of what notes are output in the patches.\n\nSee patch 2/2 for details.\n\nThis is motivated by wanting to turn off range diff notes, but the goal\nhere is to implement it in full generality.\n\n(How many of us `git format-patch --notes` users are there out there? More\nthan a dozen? Maybe just D. Ben Knoble and me?)\n\nI have implemented this behavior for myself and used it for many\nmonths. But that was hacky and only suitable for one person’s use.\nSo this is a completely new implementation. In other words: this is\nnew code, *not* tested for months.\n\n§ Changes in v5\n\nPatch 2/2:\n\n• Msg: Shorten paragraph about “why not error out like\n  --creation-factor...” while keeping the exact same\n  information.[1]\n  🔗 1: https://lore.kernel.org/git/xmqqqzi5touh.fsf@gitster.g/\n• Msg: ... Also drop the thematic breaks (***). I think the\n  paragraphs flow well enough now to the point that they are not\n  needed.\n\n§ Link to v4\n\nhttps://lore.kernel.org/git/V4_CV_format-patch_learn_--range-diff-notes.d5c@m5gid.xyz/\n\n[1/2] format-patch: simplify get_notes_arg parameters\n[2/2] format-patch: learn --[no-]range-diff-notes\n\n Documentation/git-format-patch.adoc | 11 ++++\n builtin/log.c                       | 50 +++++++++++++++--\n t/t3206-range-diff.sh               | 86 +++++++++++++++++++++++++++++\n 3 files changed, 141 insertions(+), 6 deletions(-)\n\nInterdiff against v4:\nRange-diff against v4:\n1:  bb60f300d3f = 1:  bb60f300d3f format-patch: simplify get_notes_arg parameters\n2:  4cbd312fec6 ! 2:  676361b383e format-patch: learn --[no-]range-diff-notes\n    @@ Commit message\n         1. No such options were given and empty list (use `--notes`)\n         2. Options were given and empty list (`--no-...` given; don’t use notes)\n     \n    -    ***\n    -\n    -    Note that using `--creation-factor` without `--range-diff` will cause\n    -    the command to die. But this is not the case for `--[no-]range-diff-\n    -    notes`; we would have to check `rdiff_notes.override`, which is a sticky\n    -    value (cannot be turned off). The reason is that it is potentially\n    -    inconvenient to error out since it would not let you turn off\n    -    `--range-diff` in, say, some alias that uses `--no-range-diff-\n    -    notes`. Granted, it is difficult for me to come up with a concrete use\n    -    case since `--range-diff` requires a value, specifically a value which\n    -    is probably not that reusable (revision range), and yet you have\n    -    something like an alias set up with it. But why spend code closing\n    -    that door? There is no usability upside to erroring out.\n    -\n    -    ***\n    +    Unlike `--creation-factor`, `--[no-]range-diff-notes` does not error out\n    +    when used without `--range-diff`. This flexibility accommodates\n    +    workflows where users might configure default options in aliases or\n    +    wrapper scripts, allowing `--range-diff` to be toggled independently.\n     \n         Add two tests here for the single-patch case, i.e. the case where the\n         range diff is on the patch and not in the cover letter. These are meant\n\nbase-commit: 1a3e64c6c4a623626ff0687008732a8e007e2a1c\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"554123","messageId":"V5_simplify_params.d6c@m5gid.xyz","threadId":"66213","inReplyTo":"V5_CV_format-patch_learn_--range-diff-notes.d6b@m5gid.xyz","subject":"[PATCH v5 1/2] format-patch: simplify get_notes_arg parameters","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-04T17:58:34Z","receivedAt":"2026-10-04T17:59:24Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\n85bd88a7 (revision: add rdiff_log_arg to rev_info, 2025-09-25) added\n`rdiff_log_arg` to `struct rev_info`. `get_notes_arg` was changed to\ntake a second parameter, namely that member:\n\n    get_notes_args(&(rev.rdiff_log_arg), &rev);\n\nBut this is obviously unnecessary; we can just use `&rev`.\n\nNow is also a good time to format this `for_each...` line since it’s\ngotten quite long.\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (series):\n    v4:\n    • Shorter commit message. No I.[1]\n      🔗 1: https://lore.kernel.org/git/CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz/T/#mfbb107570d497be5bfe54fe209014b607f5d5830\n\nNotes (testing):\n    v1:\n    just compile tested\n\n builtin/log.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 350b35c5563..560af00e2fd 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1333,16 +1333,18 @@ static int get_notes_refs(struct string_list_item *item, void *arg)\n \treturn 0;\n }\n \n-static void get_notes_args(struct strvec *arg, struct rev_info *rev)\n+static void get_notes_args(struct rev_info *rev)\n {\n \tif (!rev->show_notes) {\n-\t\tstrvec_push(arg, \"--no-notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n \t\t    !rev->notes_opt.extra_notes_refs.nr)) {\n-\t\tstrvec_push(arg, \"--notes\");\n+\t\tstrvec_push(&rev->rdiff_log_arg, \"--notes\");\n \t} else {\n-\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);\n+\t\tfor_each_string_list(&rev->notes_opt.extra_notes_refs,\n+\t\t\t\t     get_notes_refs,\n+\t\t\t\t     &rev->rdiff_log_arg);\n \t}\n }\n \n@@ -2404,7 +2406,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&(rev.rdiff_log_arg), &rev);\n+\t\tget_notes_args(&rev);\n \t}\n \n \t/*\n-- \n2.55.0.793.gc667de3f2c5\n\n"},{"id":"554124","messageId":"V5_format-patch_learn_--range-diff-notes.d6d@m5gid.xyz","threadId":"66213","inReplyTo":"V5_CV_format-patch_learn_--range-diff-notes.d6b@m5gid.xyz","subject":"[PATCH v5 2/2] format-patch: learn --[no-]range-diff-notes","fromName":"","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-10-04T17:58:35Z","receivedAt":"2026-10-04T17:59:42Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\ngit-format-patch(1) passes on the notes behavior that it is using for\nthe patches to git-range-diff(1). In turn you get the same Git notes\ndisplayed in the range diff as the ones you used to generate the\npatches. And that makes sense in most cases.\n\nHowever, I often make notes between series versions that mostly prepend\nto the original. They end up looking like this:\n\n    v3:\n    [desc.]\n    v2:\n    [descr.]\n    v1:\n    [descr.]\n\nThese notes are meant for the git-format-patch(1) output since they\ndocument the iterations. But including them also includes them in the\nrange diff. And they have nothing useful to say there.\n\nLet’s teach git-format-patch(1) `--[no-]range-diff-notes` so that we\ncan pass in different notes refs to the range diff, or just turn them\noff entirely.\n\nIn addition to storing the list of notes, we also need a boolean\n`override` to distinguish these two cases:\n\n1. No such options were given and empty list (use `--notes`)\n2. Options were given and empty list (`--no-...` given; don’t use notes)\n\nUnlike `--creation-factor`, `--[no-]range-diff-notes` does not error out\nwhen used without `--range-diff`. This flexibility accommodates\nworkflows where users might configure default options in aliases or\nwrapper scripts, allowing `--range-diff` to be toggled independently.\n\nAdd two tests here for the single-patch case, i.e. the case where the\nrange diff is on the patch and not in the cover letter. These are meant\nas regression tests based on my encounter with single-patch range diff\nnotes handling bug.[1]\n\n† 1: 155986b4 (format-patch: handle range-diff on notes correctly for\n     single patches, 2025-09-25)\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\n---\n\nNotes (series):\n    v5:\n    • Msg: Shorten paragraph about “why not error out like\n      --creation-factor...” while keeping the exact same\n      information.[1] Now the commit message fits on one screen for\n      me! (1080p)\n      🔗 1: https://lore.kernel.org/git/xmqqqzi5touh.fsf@gitster.g/\n    • Msg: ... Also drop the thematic breaks (***). I think the\n      paragraphs flow well enough now to the point that they are not\n      needed.\n    \n    ---\n    \n    v4:\n    • Msg: Trim all the expository fat, which only loses the footnote\n      about “what if you had a changelog and testing notes” (in terms\n      of “real substance”) as a trade for getting to the point quite\n      quickly (relatively speaking)[1]\n      🔗 1: https://lore.kernel.org/git/30249b7b-b6f7-4065-9a83-db93d69ad0f1@app.fastmail.com/#t\n    • An obvious refactor: call `parse_opt_string_list` instead of\n      manually inlining it along with a comment saying “we inlined\n      it”[1]\n    • Trim the fat from the doc. Straightforward explanation: use this to get\n      `<ref>` instead. Use multiple times for more refs. `--no-...` to\n      turn off. Lifted from the proposal by Junio with some\n      modifications (use `<ref>` to more tersely discuss “a different\n      notes ref”)[1]\n    • Msg: credit help\n    • `clang-format` on `rdiff_notes_cb`\n    \n    🔗 1: https://lore.kernel.org/git/xmqqy0cgvwpi.fsf@gitster.g/\n    ---\n    v3:\n    • Remove repeated and redundant `test_when_finished` on\n      patch files[1]\n    \n      🔗 1: https://lore.kernel.org/git/CV_format-patch_learn_--range-diff-notes.c57@msgid.xyz/T/#m06803e233a2e385e694432d45ecf402f7a67e482\n    ---\n    v2:\n    This version drops the whole functionality around being able to *go\n    back* (and forth) to using `--notes` for the range diff.[1] The\n    behavior was too complex to explain and motivate compared to the\n    utility (little).\n    \n    🔗 1: https://lore.kernel.org/git/8f0a076b-4822-44e2-a842-cc1e39ae1c1d@app.fastmail.com/#t\n    \n    Also:\n    \n    • Use a parse-options callback for the option instead of\n      `revision.c:handle_revision_opt`\n    • Msg: Rewrite the (former last) paragraph about why we are not\n      erroring when `--range-diff-notes` is given without\n      `--range-diff`. Partly because the facts have changed; now we\n      cannot turn off the `override` bit/flag. But it’s just many words\n      to say that: why spend code disallowing something that you might\n      as well allow?\n    • Add a couple more tests, so simple that they also have an\n      accompanying comment each explaining why they exist\n    • Msg: Add a paragraph explaining why there are two tests specifically\n      for the single-patch case. It’s not just to cover every permutation.\n    • Remove useless `>actual` in tests that don’t test `actual` (they\n      test the patch files instead)\n    • Fix (kind of) the tests that use `$prev` as in:\n    \n          git format-patch --range-diff=$prev\n    \n      This is a very questionable and indirect use from this part of the\n      suite:\n    \n          for prev in topic main..topic\n          do\n              [body]\n          done\n    \n      I.e. it is just `main..topic`. This is monkey-see-monkey-do code\n      from my previous visit of this file. Which then turns out in turn\n      is a monkey-_ from *another* author. I think the existing `$prev`\n      should get a cleanup (separately).\n\nNotes (testing):\n    v4:\n    • Compiled and ran `t3206-range-diff`.\n    • Ran `make html` and looked at git-format-patch(1).\n\n Documentation/git-format-patch.adoc | 11 ++++\n builtin/log.c                       | 42 +++++++++++++-\n t/t3206-range-diff.sh               | 86 +++++++++++++++++++++++++++++\n 3 files changed, 136 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc\nindex 191f64b77d1..2399ba24454 100644\n--- a/Documentation/git-format-patch.adoc\n+++ b/Documentation/git-format-patch.adoc\n@@ -378,6 +378,17 @@ case is to show comparison with an older iteration of the same\n topic and the tool should find more correspondence between the two\n sets of patches.\n \n+`--range-diff-notes=<ref>`::\n+`--no-range-diff-notes`::\n+\tUsed with `--range-diff`, tweak what notes to display in the\n+\trange diff.\n++\n+The default behavior is to display the same notes in the range diff as\n+on the patches; see `--notes`. Use `--range-diff-notes=<ref>` to use\n+_<ref>_ for the range diff instead. This option can be given multiple\n+times to show notes from multiple refs. Use `--no-range-diff-notes` to\n+disable notes in the range diff.\n+\n `--notes[=<ref>]`::\n `--no-notes`::\n \tAppend the notes (see linkgit:git-notes[1]) for the commit\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 560af00e2fd..445400ba782 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1327,15 +1327,44 @@ static void prepare_cover_text(struct pretty_print_context *pp,\n \tstrbuf_release(&subject_sb);\n }\n \n+struct rdiff_notes {\n+\t/*\n+\t * True if we want to override the notes behavior\n+\t * of 'format-patch'\n+\t */\n+\tbool override;\n+\tstruct string_list notes;\n+};\n+\n+static int rdiff_notes_cb(const struct option *option,\n+\t\t\t  const char *arg,\n+\t\t\t  int unset)\n+{\n+\tstruct option opt = *option;\n+\tstruct rdiff_notes *rdiff_notes = option->value;\n+\n+\trdiff_notes->override = 1;\n+\topt.value = &rdiff_notes->notes;\n+\treturn parse_opt_string_list(&opt, arg, unset);\n+}\n+\n static int get_notes_refs(struct string_list_item *item, void *arg)\n {\n \tstrvec_pushf(arg, \"--notes=%s\", item->string);\n \treturn 0;\n }\n \n-static void get_notes_args(struct rev_info *rev)\n+static void get_notes_args(struct rdiff_notes *rdiff_notes,\n+\t\t\t   struct rev_info *rev)\n {\n-\tif (!rev->show_notes) {\n+\tif (rdiff_notes->override) {\n+\t\tif (rdiff_notes->notes.nr)\n+\t\t\tfor_each_string_list(&rdiff_notes->notes,\n+\t\t\t\t\t     get_notes_refs,\n+\t\t\t\t\t     &rev->rdiff_log_arg);\n+\t\telse\n+\t\t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n+\t} else if (!rev->show_notes) {\n \t\tstrvec_push(&rev->rdiff_log_arg, \"--no-notes\");\n \t} else if (rev->notes_opt.use_default_notes > 0 ||\n \t\t   (rev->notes_opt.use_default_notes == -1 &&\n@@ -1995,6 +2024,9 @@ int cmd_format_patch(int argc,\n \tstruct strbuf rdiff1 = STRBUF_INIT;\n \tstruct strbuf rdiff2 = STRBUF_INIT;\n \tstruct strbuf rdiff_title = STRBUF_INIT;\n+\tstruct rdiff_notes rdiff_notes = {\n+\t\t.notes = STRING_LIST_INIT_NODUP,\n+\t};\n \tconst char *rfc = NULL;\n \tint creation_factor = -1;\n \tconst char *signature = git_version_string;\n@@ -2091,6 +2123,9 @@ int cmd_format_patch(int argc,\n \t\t\t     parse_opt_object_name),\n \t\tOPT_STRING(0, \"range-diff\", &rdiff_prev, N_(\"refspec\"),\n \t\t\t   N_(\"show changes against <refspec> in cover letter or single patch\")),\n+\t\tOPT_CALLBACK_F(0, \"range-diff-notes\", &rdiff_notes, N_(\"note\"),\n+\t\t\t       N_(\"override notes behavior for the range diff\"),\n+\t\t\t       0, rdiff_notes_cb),\n \t\tOPT_INTEGER(0, \"creation-factor\", &creation_factor,\n \t\t\t    N_(\"percentage by which creation is weighted\")),\n \t\tOPT_BOOL(0, \"force-in-body-from\", &force_in_body_from,\n@@ -2406,7 +2441,7 @@ int cmd_format_patch(int argc,\n \t\trev.rdiff_title = diff_title(&rdiff_title, reroll_count,\n \t\t\t\t\t     _(\"Range-diff:\"),\n \t\t\t\t\t     _(\"Range-diff against v%d:\"));\n-\t\tget_notes_args(&rev);\n+\t\tget_notes_args(&rdiff_notes, &rev);\n \t}\n \n \t/*\n@@ -2570,6 +2605,7 @@ int cmd_format_patch(int argc,\n \trelease_revisions(&rev);\n \tformat_config_release(&cfg);\n \tstrvec_clear(&rev.rdiff_log_arg);\n+\tstring_list_clear(&rdiff_notes.notes, 0);\n \treturn 0;\n }\n \ndiff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh\nindex ef92704de39..679a707c873 100755\n--- a/t/t3206-range-diff.sh\n+++ b/t/t3206-range-diff.sh\n@@ -845,6 +845,92 @@ test_expect_success 'format-patch --range-diff with multiple notes' '\n \ttest_cmp expect actual\n '\n \n+# Unlike '--notes', '--range-diff-notes' requires a value\n+test_expect_success 'format-patch --range-diff-notes requires a value' '\n+\tcat >expect <<-EOF &&\n+\terror: option \\`range-diff-notes${SQ} requires a value\n+\tEOF\n+\ttest_must_fail git format-patch --range-diff=main..topic \\\n+\t\t--cover-letter --range-diff-notes 2>actual &&\n+\ttest_cmp expect actual\n+'\n+\n+# The '--range-diff-notes' has no effect but is allowed\n+test_expect_success 'format-patch --range-diff-notes=not-a-note (no --range-diff)' '\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff-notes=not-a-note --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_file_not_empty 0000-cover-letter* &&\n+\ttest_grep ! \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes \" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=custom --no-range-diff-notes' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --notes=custom \\\n+\t\t--no-range-diff-notes --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-notes --range-diff-notes=custom' '\n+\ttest_when_finished \"git notes --ref=custom remove topic unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note1\" topic &&\n+\tgit notes --ref=custom add -m \"unmodified note1\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --no-notes \\\n+\t\t--range-diff-notes=custom --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep ! \"^Notes (custom):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (custom) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --notes=patch --range-diff-notes=rdiff' '\n+\ttest_when_finished \"git notes --ref=patch remove topic unmodified || :\" &&\n+\tgit notes --ref=patch add -m \"only for patch 1\" topic &&\n+\tgit notes --ref=patch add -m \"only for patch 2\" unmodified &&\n+\ttest_when_finished \"git notes --ref=rdiff remove topic unmodified || :\" &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 1\" topic &&\n+\tgit notes --ref=rdiff add -m \"only for range diff 2\" unmodified &&\n+\ttest_when_finished \"rm -f 000?-*\" &&\n+\tgit format-patch --range-diff=main..topic --notes=patch \\\n+\t\t--range-diff-notes=rdiff --cover-letter \\\n+\t\tmain..unmodified &&\n+\ttest_grep \"^Notes (patch):\" 0004-* &&\n+\ttest_grep ! \"^Notes (rdiff):\" 0004-* &&\n+\ttest_grep \"^Range-diff:\" 0000-cover-letter* &&\n+\ttest_grep \"## Notes (rdiff) ##\" 0000-cover-letter* &&\n+\ttest_grep ! \"## Notes (patch) ##\" 0000-cover-letter*\n+'\n+\n+test_expect_success 'format-patch --range-diff --no-range-diff-notes on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --notes=custom --range-diff=main..topic \\\n+\t\t--no-range-diff-notes -1 --stdout >actual &&\n+\ttest_grep \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep ! \"## Notes (custom) ##\" actual\n+'\n+\n+test_expect_success 'format-patch --range-diff --range-diff-notes=custom on single patch' '\n+\ttest_when_finished \"git notes --ref=custom remove HEAD unmodified || :\" &&\n+\tgit notes --ref=custom add -m \"topic note (custom)\" HEAD &&\n+\tgit notes --ref=custom add -m \"unmodified note (custom)\" unmodified &&\n+\tgit format-patch --range-diff=main..topic \\\n+\t\t--range-diff-notes=custom -1 --stdout >actual &&\n+\ttest_grep ! \"Notes (custom):\" actual &&\n+\ttest_grep \"^Range-diff:\" actual &&\n+\ttest_grep \"## Notes (custom) ##\" actual\n+'\n+\n test_expect_success '--left-only/--right-only' '\n \tgit switch --orphan left-right &&\n \ttest_commit first &&\n-- \n2.55.0.793.gc667de3f2c5\n\n"}]}