From: Jason Gunthorpe <jgg@nvidia.com>
To: Mark Brown <broonie@kernel.org>
Cc: Leon Romanovsky <leonro@nvidia.com>,
linux-kernel@vger.kernel.org, linux-next@vger.kernel.org
Subject: Re: Missing signoff in the rdma tree
Date: Mon, 6 Apr 2026 14:30:18 -0300 [thread overview]
Message-ID: <20260406173018.GO310919@nvidia.com> (raw)
In-Reply-To: <df6f8a58-5c8d-437e-aad6-fee85a89f5e6@sirena.org.uk>
On Mon, Apr 06, 2026 at 05:38:14PM +0100, Mark Brown wrote:
> > are missing a Signed-off-by from their committers
>
> This issue is still present today.
When Leon fixed the previous mistake with rebase it caused all of
this. filter-repo isn't good about not changing commits it doesn't
have to change, so it isn't so useful when merges are present.
rebase -r will reset the commiter for other commits.
Couldn't find a built in alternative and got tired of this, so I ended
up using AI to build a script based on an commit editor I already had
to fix it. I've included it below incase anyone else finds it useful
someday.
$ python3 edit_committer.py refs/heads/k.o/for-next \
"Jason Gunthorpe" "jgg@nvidia.com" \
v7.0-rc1 \
eb15cffa15201b 485a21c14b4133 9ed273bbe66370 \
0edac801a2693e 4e99362444a2f6 f0579e330b7736 \
9db6a217ba5ddf ce150a8376e1ee d59f007207b394 \
ac4bb15208d1f0 12c73bee531336 ac593f5b66c9d1 \
6df3a6414d7364 42d2a291ef4748 f1cac281b42456 \
4ac738c6a7b906 715eccd4798ec7 ea08d8cb8b5203 \
8e886928a19d70
Processing 2536 commits from v7.0-rc1 to 69db255d5faf
8e886928a19d -> 38a6e5579d0d (target)
ea08d8cb8b52 -> b51caeb24aad (target)
715eccd4798e -> 1de9287ece44 (target)
4ac738c6a7b9 -> dbf6491bb98d (target)
f1cac281b424 -> 14badc323ed7 (target)
42d2a291ef47 -> 4c379ba04c11 (target)
6df3a6414d73 -> 5ebe8832ef90 (target)
ac593f5b66c9 -> b33d860a13b4 (target)
12c73bee5313 -> 3f6b103c4bf2 (target)
ac4bb15208d1 -> 0cee3acab27a (target)
d59f007207b3 -> bc30311e492e (target)
ce150a8376e1 -> bed686d8dcd4 (target)
9db6a217ba5d -> 613713f251c8 (target)
f0579e330b77 -> eee6268421a2 (target)
4e99362444a2 -> 13f9a813eee5 (target)
0edac801a269 -> 1234a9d8aebb (target)
9ed273bbe663 -> 3d4a42360c33 (target)
485a21c14b41 -> cec5157b6c73 (target)
eb15cffa1520 -> a06165a705ee (target)
8db7b7d9ba17 -> 1dc469f669fe (parent changed)
33960c206db2 -> 553dfa8cbd0c (parent changed)
e86b2bf1c311 -> 797291a66ce3 (parent changed)
932f1eef09ec -> ff85a2ebacbd (parent changed)
f39003e8fa8c -> 3a0b171302ee (parent changed)
5c3f6de46d6a -> 4707bf5f6c86 (parent changed)
353b3bbdb2c4 -> 2afa8b9f5ff8 (parent changed)
76ae14db9058 -> 1b50f42049d8 (parent changed)
120ad1fd5914 -> 56521f587704 (parent changed)
ba8c700185d6 -> 786ee8ddf47a (parent changed)
e2849b392974 -> 679eb25de4ee (parent changed)
2ad64eeaefd2 -> 0fed679e0862 (parent changed)
1487bad4ea51 -> 6be4ca0ab3a2 (parent changed)
5122be2a19aa -> 5aeb6e039972 (parent changed)
4ae130ccec08 -> 9d6ba4ced734 (parent changed)
dfd4d5a38e65 -> f3cf74933c9c (parent changed)
a8f6ced534c0 -> 2bb02691df65 (parent changed)
cdb802af06d6 -> 5aa437c93d90 (parent changed)
ffdf34ca1a47 -> a60e3f3d6fba (parent changed)
c8cc77c8418f -> 13f2a53c2a71 (parent changed)
e5ef99e3401c -> f1327abd6abe (parent changed)
a7a49104859d -> e01027cab38a (parent changed)
a2347bc64b89 -> 6c45efd8f9bb (parent changed)
ada307fd98db -> ce68351be075 (parent changed)
b8934c5c3f83 -> dc76086a2d94 (parent changed)
f0c62197416b -> b247ed6f60bd (parent changed)
c291b1133360 -> 2b2f078236a4 (parent changed)
d8d84ea1abcc -> 345f842771ff (parent changed)
933153ef70b8 -> e69609c5d469 (parent changed)
f9616c93912e -> 2f49e1590344 (parent changed)
09220f0b8388 -> adc09d7fbbb9 (parent changed)
b5bc2b6ef6fe -> e6fd24917897 (parent changed)
997f21ed1e93 -> 179b32095854 (parent changed)
578cb2be0db2 -> 911e5ca3e169 (parent changed)
f968d01f47d0 -> dbeb256e8dd8 (parent changed)
74e2711bb2af -> cef2842c922c (parent changed)
7a8b545a8012 -> ae638288b202 (parent changed)
e81275b67f59 -> 8d7573b19402 (parent changed)
092585a85a19 -> e910d98dc440 (parent changed)
7fde9cc10f60 -> 54b3bce97211 (parent changed)
56f6ff43f486 -> 3268330fa84f (parent changed)
4698e4c4a163 -> c8f9a7a96e9a (parent changed)
d21477adfa80 -> 530b251b0f7a (parent changed)
9b4e46b8cce6 -> f899787095cd (parent changed)
fda720ddb439 -> 0453bf09a68b (parent changed)
ab214eefaac1 -> d5c8f2f39907 (parent changed)
03f4c8090204 -> 604caebc7f06 (parent changed)
7186189cfa22 -> 676b570707be (parent changed)
16d0d9d4e2e9 -> 67820de31679 (parent changed)
5af7526eeb73 -> 69309e17293c (parent changed)
a9cd442a5347 -> 8e3e07cca004 (parent changed)
69db255d5faf -> fdcbddcd3aa1 (parent changed)
71 commits rewritten
Updating refs/heads/k.o/for-next from 69db255d5faf to fdcbddcd3aa1
#!/usr/bin/env python3
"""Change the committer on specific commits without altering unmodified commits.
"""
import re
import subprocess
import sys
import tempfile
IDRE = re.compile(rb"^[0-9a-fA-F]{40}$")
def git_output(args, mode=None):
o = subprocess.check_output(["git"] + args)
if mode == "lines":
return o.splitlines()
return o.strip()
def git_read_commit(commit_id):
"""Read a commit object and return (raw_keys, desc_lines)"""
lines = git_output(["cat-file", "commit", commit_id], mode="lines")
keys = []
itr = iter(lines)
for line in itr:
stripped = line.rstrip()
if not stripped:
break
# Indented lines (e.g. gpgsig continuation) belong to previous key
if line.startswith(b" "):
keys[-1] = (keys[-1][0], keys[-1][1] + b"\n" + line)
continue
kv = stripped.partition(b" ")
keys.append((kv[0], kv[2]))
desc = list(itr)
return keys, desc
def rebuild_commit(keys, desc):
"""Rebuild a commit object and return its new hash"""
with tempfile.NamedTemporaryFile() as f:
for k, v in keys:
f.write(k + b" " + v + b"\n")
f.write(b"\n")
for line in desc:
f.write(line + b"\n")
f.flush()
return git_output(["hash-object", "-t", "commit", "-w", f.name]).decode()
def get_commit_list(ancestor, newest):
"""Return commit IDs from newest to ancestor (exclusive), topological order"""
ids = git_output(["rev-list", "--topo-order", newest, "^" + ancestor],
mode="lines")
return [i.decode() for i in ids]
def main():
ref = sys.argv[1]
new_committer_name = sys.argv[2]
new_committer_email = sys.argv[3]
ancestor = sys.argv[4]
target_prefixes = sys.argv[5:]
if not target_prefixes:
print("Usage: edit_committer.py <ref> <name> <email> <ancestor> <commit-prefix>...")
sys.exit(1)
newest = git_output(["rev-parse", ref]).decode()
commit_ids = get_commit_list(ancestor, newest)
print(f"Processing {len(commit_ids)} commits from {ancestor[:12]} to {newest[:12]}")
# Process oldest first
commit_ids.reverse()
commit_map = {}
changed = 0
for cid in commit_ids:
keys, desc = git_read_commit(cid)
# Check if this commit is a target for committer rewrite
is_target = any(cid.startswith(prefix) for prefix in target_prefixes)
# Update parent pointers if any parents were rewritten
new_keys = []
parents_changed = False
for k, v in keys:
if k == b"parent":
old_parent = v.decode()
new_parent = commit_map.get(old_parent, old_parent)
if new_parent != old_parent:
parents_changed = True
new_keys.append((k, new_parent.encode()))
elif is_target and k == b"committer":
# Rewrite committer, preserving the date portion
old_val = v.decode()
# Format: "Name <email> timestamp timezone"
m = re.match(r".*>(.+)$", old_val)
date_part = m.group(1) if m else ""
new_val = f"{new_committer_name} <{new_committer_email}>{date_part}"
new_keys.append((k, new_val.encode()))
parents_changed = True # force rebuild
else:
new_keys.append((k, v))
if not parents_changed and not is_target:
commit_map[cid] = cid
continue
new_id = rebuild_commit(new_keys, desc)
commit_map[cid] = new_id
if new_id != cid:
changed += 1
label = "(target)" if is_target else "(parent changed)"
print(f" {cid[:12]} -> {new_id[:12]} {label}")
new_head = commit_map.get(newest, newest)
if new_head == newest:
print("No changes needed.")
else:
# Verify trees match
diff = git_output(["diff-tree", "-r", newest, new_head])
assert diff == b"", f"Tree mismatch!\n{diff}"
print(f"\n{changed} commits rewritten")
print(f"Updating {ref} from {newest[:12]} to {new_head[:12]}")
subprocess.check_call(
["git", "update-ref", "-m", "edit_committer", ref, new_head, newest])
return 0
if __name__ == "__main__":
sys.exit(main())
next prev parent reply other threads:[~2026-04-06 17:30 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-09 11:10 Missing signoff in the rdma tree Mark Brown
2026-03-09 11:40 ` Leon Romanovsky
2026-03-09 11:46 ` Mark Brown
2026-03-09 11:52 ` Leon Romanovsky
2026-03-09 12:43 ` Mark Brown
2026-03-09 12:48 ` Jason Gunthorpe
2026-04-06 16:38 ` Mark Brown
2026-04-06 17:30 ` Jason Gunthorpe [this message]
-- strict thread matches above, loose matches on Subject: below --
2026-03-23 13:25 Mark Brown
2026-03-30 22:10 ` Mark Brown
2026-03-31 4:59 ` Leon Romanovsky
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=20260406173018.GO310919@nvidia.com \
--to=jgg@nvidia.com \
--cc=broonie@kernel.org \
--cc=leonro@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-next@vger.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