From: Vishal Verma <vishal.l.verma@intel.com>
To: "Kernel.org Tools" <tools@kernel.org>
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>,
Vishal Verma <vishal.l.verma@intel.com>
Subject: [PATCH b4] b4: Add option to b4-send to include git-notes
Date: Tue, 24 Feb 2026 18:01:49 -0700 [thread overview]
Message-ID: <20260224-add-git-notes-v1-1-9b7d3ab24b61@intel.com> (raw)
Add an option (and a config entry) for b4-send to include any git-notes
in the formatted patch after the '---' break.
Note that git-show with the notes option adds notes with a 'Notes:'
prefix, and with an indent. The convention for mailing lists is
typically to just include the notes after the break, without either of
the above. Do some regex munging to remove it.
Assisted by Claude Code.
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
I've only tested this using b4 send --dry-run until now. This patch
should be the first time actually sending anything with the
modifications. This paragraph should be coming from git-notes, not from
the b4-prep cover letter as it can for a single patch series - but I've
left the cover letter empty.
docs/config.rst | 22 ++++++++++++++++++++++
src/b4/__init__.py | 13 ++++++++++++-
src/b4/command.py | 4 ++++
src/b4/ez.py | 29 +++++++++++++++++++++--------
4 files changed, 59 insertions(+), 9 deletions(-)
diff --git a/docs/config.rst b/docs/config.rst
index a1145af..8c7b3eb 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -437,6 +437,28 @@ Contributor-oriented settings
Default: ``None``
+``b4.send-notes``
+ When set, includes git notes in the patches below the ``---`` line. This is
+ useful for adding per-patch changelog entries or other annotations that
+ should not be part of the permanent commit message. Notes are appended by
+ passing ``--notes`` to ``git show`` when generating patches. This can be
+ overridden on the command line with ``--notes`` or ``--no-notes`` flags to
+ ``b4 send``.
+
+ .. note::
+
+ Since git notes are keyed by commit hash, they are normally lost
+ when commits are rebased or amended (e.g. by ``b4 prep --edit-cover``).
+ To make git preserve notes across these operations, set the following
+ in your git configuration::
+
+ [notes]
+ rewriteRef = refs/notes/commits
+ rewrite.rebase = true
+ rewrite.amend = true
+
+ Default: ``no``
+
``b4.prep-perpatch-check-cmd`` (v0.14+)
The command to use when running ``--check``. The command is run once for each
patch to check. The patch file to check is piped through stdin. If this
diff --git a/src/b4/__init__.py b/src/b4/__init__.py
index 3d774f7..4309325 100644
--- a/src/b4/__init__.py
+++ b/src/b4/__init__.py
@@ -3670,7 +3670,8 @@ def git_range_to_patches(gitdir: Optional[str], start: str, end: str,
extrahdrs: Optional[List[Tuple[str, str]]] = None,
ignore_commits: Optional[Set[str]] = None,
limit_committer: Optional[str] = None,
- presubject: Optional[str] = None) -> List[Tuple[str, EmailMessage]]:
+ presubject: Optional[str] = None,
+ with_notes: bool = False) -> List[Tuple[str, EmailMessage]]:
gitargs = ['rev-list', '--no-merges', '--reverse']
if limit_committer:
gitargs += ['-F', f'--committer={limit_committer}']
@@ -3694,6 +3695,8 @@ def git_range_to_patches(gitdir: Optional[str], start: str, end: str,
'--encoding=utf-8',
'--find-renames',
]
+ if with_notes:
+ showargs.append('--notes')
if git_check_minimal_version("2.40"):
showargs.append("--default-prefix")
@@ -3758,6 +3761,14 @@ def git_range_to_patches(gitdir: Optional[str], start: str, end: str,
payload = msg.get_payload(decode=True)
if isinstance(payload, bytes):
payload = payload.decode()
+ if with_notes:
+ # git show --notes adds notes with a "Notes:" header and
+ # indentation. Strip that to match the mailing list
+ # convention of plain text after the "---" line.
+ payload = re.sub(
+ r'\nNotes:\n((?:[ \t]+.+\n)+)',
+ lambda m: '\n' + re.sub(r'^[ \t]+', '', m.group(1), flags=re.MULTILINE),
+ payload)
if inbodyhdrs:
payload = '\n'.join(inbodyhdrs) + '\n\n' + payload
if gitver and not payload.find('\n-- \n') > 0:
diff --git a/src/b4/command.py b/src/b4/command.py
index 1f8b8f1..37873c9 100644
--- a/src/b4/command.py
+++ b/src/b4/command.py
@@ -397,6 +397,10 @@ def setup_parser() -> argparse.ArgumentParser:
help='Resend a previously sent version of the series')
sp_send.add_argument('--no-sign', action='store_true', default=False,
help='Do not add the cryptographic attestation signature header')
+ sp_send.add_argument('--notes', dest='send_notes', action='store_true', default=None,
+ help='Include git notes in the patches below the --- line')
+ sp_send.add_argument('--no-notes', dest='send_notes', action='store_false',
+ help='Do not include git notes (overrides b4.send-notes config)')
sp_send.add_argument('--use-web-endpoint', dest='send_web', action='store_true', default=False,
help="Force going through the web endpoint")
ag_sendh = sp_send.add_argument_group('Web submission', 'Authenticate with the web submission endpoint')
diff --git a/src/b4/ez.py b/src/b4/ez.py
index 298e382..7e7bf5a 100644
--- a/src/b4/ez.py
+++ b/src/b4/ez.py
@@ -1567,7 +1567,7 @@ def rethread(patches: List[Tuple[str, EmailMessage]]) -> None:
def get_prep_branch_as_patches(movefrom: bool = True, thread: bool = True, addtracking: bool = True,
prefixes: Optional[List[str]] = None, usebranch: Optional[str] = None,
- expandprereqs: bool = True,
+ expandprereqs: bool = True, with_notes: bool = False,
) -> Tuple[List[Tuple[str, str]], List[Tuple[str, str]], str, List[Tuple[str, EmailMessage]]]:
cover, tracking = load_cover(strip_comments=True, usebranch=usebranch)
@@ -1604,7 +1604,8 @@ def get_prep_branch_as_patches(movefrom: bool = True, thread: bool = True, addtr
seriests=seriests,
mailfrom=mailfrom,
ignore_commits=ignore_commits,
- presubject=presubject)
+ presubject=presubject,
+ with_notes=with_notes)
base_commit, _, _, _, shortlog, diffstat = get_series_details(start_commit=start_commit,
usebranch=usebranch)
@@ -1767,7 +1768,8 @@ def get_prep_branch_as_patches(movefrom: bool = True, thread: bool = True, addtr
return alltos, allccs, tag_msg, patches
-def get_sent_tag_as_patches(tagname: str, revision: int, presubject: str = None) \
+def get_sent_tag_as_patches(tagname: str, revision: int, presubject: str = None,
+ with_notes: bool = False) \
-> Tuple[List[Tuple[str, str]], List[Tuple[str, str]], List[Tuple[str, EmailMessage]]]:
cover, base_commit, change_id = get_base_changeid_from_tag(tagname)
@@ -1784,7 +1786,8 @@ def get_sent_tag_as_patches(tagname: str, revision: int, presubject: str = None)
msgid_tpt=msgid_tpt,
seriests=seriests,
mailfrom=mailfrom,
- presubject=presubject)
+ presubject=presubject,
+ with_notes=with_notes)
alltos, allccs, cbody = get_cover_dests(cbody)
if len(patches) == 1:
@@ -1796,8 +1799,11 @@ def get_sent_tag_as_patches(tagname: str, revision: int, presubject: str = None)
def format_patch(output_dir: str) -> None:
+ config = b4.get_main_config()
+ with_notes = config.get('send-notes', '').lower() in {'yes', 'true', 'y'}
try:
- _, _, _, patches = get_prep_branch_as_patches(thread=False, movefrom=False, addtracking=False)
+ _, _, _, patches = get_prep_branch_as_patches(thread=False, movefrom=False, addtracking=False,
+ with_notes=with_notes)
except RuntimeError as ex:
logger.critical('CRITICAL: Failed to convert range to patches: %s', ex)
sys.exit(1)
@@ -1916,6 +1922,11 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
config = b4.get_main_config()
+ if cmdargs.send_notes is not None:
+ with_notes = cmdargs.send_notes
+ else:
+ with_notes = config.get('send-notes', '').lower() in {'yes', 'true', 'y'}
+
tag_msg = None
cl_msgid = None
_, tracking = load_cover(strip_comments=True)
@@ -1942,8 +1953,9 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
presubject = tracking['series'].get('presubject', None)
try:
- todests, ccdests, patches = get_sent_tag_as_patches(tagname, revision=revision,
- presubject=presubject)
+ todests, ccdests, patches = get_sent_tag_as_patches(tagname, revision=revision,
+ presubject=presubject,
+ with_notes=with_notes)
except RuntimeError as ex:
logger.critical('CRITICAL: Failed to convert tag to patches: %s', ex)
sys.exit(1)
@@ -1963,7 +1975,8 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
prefixes = None
try:
- todests, ccdests, tag_msg, patches = get_prep_branch_as_patches(prefixes=prefixes)
+ todests, ccdests, tag_msg, patches = get_prep_branch_as_patches(prefixes=prefixes,
+ with_notes=with_notes)
except RuntimeError as ex:
logger.critical('CRITICAL: Failed to convert range to patches: %s', ex)
sys.exit(1)
---
base-commit: 477734000555ffc24bf873952e40367deee26f17
change-id: 20260224-add-git-notes-1b1c3c5bda1f
Best regards,
--
Vishal Verma <vishal.l.verma@intel.com>
next reply other threads:[~2026-02-25 1:02 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-25 1:01 Vishal Verma [this message]
2026-02-25 2:54 ` [PATCH b4] b4: Add option to b4-send to include git-notes Konstantin Ryabitsev
2026-02-25 3:46 ` Verma, Vishal L
2026-02-25 4:07 ` konstantin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260224-add-git-notes-v1-1-9b7d3ab24b61@intel.com \
--to=vishal.l.verma@intel.com \
--cc=konstantin@linuxfoundation.org \
--cc=tools@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox