Claude Code 会在 Git 提交中写入什么?
Claude Code 会添加 Co-authored-by 尾注,云端会话还会写入 claude.ai 链接。本文教您读取提交原文、识别 Git 尾注,并在推送前控制这些内容。
Claude Code 在提交中写入的内容
Claude Code 会在其创建的提交消息末尾添加 Co-authored-by: trailer,并在其创建的拉取请求描述中添加归属行。在云端或通过 Remote Control 运行的会话还会附加指向 claude.ai 上该会话的链接。所有这些内容都是存储在 git 历史记录中的纯文本。将其推送到公共仓库后,这些内容就会公开,并会一直保留,直到有人重写历史记录。
不同版本中的确切措辞可能有所变化,因此不要相信任何指南(包括本文)中打印的 trailer 副本。请直接读取您自己的提交。下面的 git 命令是本主题中长期稳定的部分:git 对 trailer 的处理方式多年来一直未变;即使下一个版本修改了文本,这种处理方式仍会继续有效。
Git trailer 的实际含义
Trailer 是提交消息最后一个区块中的一行,格式类似 Token: value。Git 不提供固定的 token 列表。Signed-off-by:、Reviewed-by:、Fixes: 和 Co-authored-by: 都是基于同一机制形成的约定;代码托管平台(即托管代码仓库的网站,例如 GitHub 或 GitLab)会读取这些 trailer,以决定在提交页面上显示什么内容。
Git 对该区块的位置要求严格。git interpret-trailers 的文档说明,该组内容前面必须有一个或多个空行,必须位于消息末尾,或紧接在以 --- 开头的行之前;同时,该组内容必须全部由 trailer 组成,或者“至少包含一个由 Git 生成或由用户配置的 trailer,且 trailer 至少占全部行数的 25%”。
最后一条规则在这里很重要。最后一个区块中的单独 URL 或说明性文字都不是 trailer;如果非 trailer 行过多,整个区块就无法按 trailer 解析。因此,某个提交看起来可能包含 Co-authored-by: 行,但任何正确读取 trailer 的工具都会认为其中没有内容。
如何读取历史记录中已有的尾注?
先查看最近一次提交的原始消息。
git log -1 --format=%B%B 会按原样输出主题和正文,不换行,也不重新格式化。该输出是事实依据。代码托管平台显示的任何内容都只是对它的渲染。
现在让 git 判断其中哪些行会被视为尾注。
git log -1 --format=%B | git interpret-trailers --parse--parse 是 --only-trailers --only-input --unfold 的简写,因此输出内容只有尾注块。正常情况下,每个尾注占一行。如果能清楚看到 Co-authored-by: 行,但输出为空,说明该尾注块未通过上述位置规则。
要扫描完整历史记录,请按键名查询尾注。
git log --format='%h %(trailers:key=Co-authored-by,valueonly)'较旧版本的 git 不支持 %(trailers) 的 key= 选项。对消息文本执行搜索则在所有版本中都可用。
git log -i --grep='^Co-authored-by:' --format='%h %an %s'--grep 用于匹配提交消息,-i 使匹配不区分大小写。这一点很重要,因为不同工具对该尾注的大小写处理并不一致。在推送前,应将查询范围缩小到尚未发送的内容。
git log origin/main..HEAD --format=%B这些提交仍在本地,因此现在修改它们的成本仍然很低。
Co-authored-by: 会如何影响 GitHub 上的署名?
GitHub 会读取该尾部信息,并在提交页面上显示第二位作者。只有在该电子邮件地址属于某个账户时,GitHub 才会将这位作者链接到其个人资料。GitHub 的文档说明,只有提交“使用与 GitHub 账户关联的电子邮件地址完成”时,提交才会显示在贡献图中。因此,不属于任何人的地址无法关联到个人资料。对于人工协作的两位作者,这正是该功能的用途:您同事的地址已关联其账户,因此该提交会同时计入你们两人的贡献。对于不属于任何账户的地址,尾部信息会改变提交页面的显示内容,但不会改变仓库的贡献者列表。
Git 本身完全忽略该尾部信息。git shortlog -sn 和 git log --author 读取作者标头,其中包含您的姓名和电子邮件地址,因此本地统计永远不会显示共同作者。这里的署名是代码托管平台基于纯文本约定提供的功能,体现了git 本身与您使用的代码托管平台之间的区别。
会话链接是另一个问题
页尾署名会列出共同作者。会话 URL 则指向一份转录记录。Claude Code 设置参考文档将 attribution.sessionUrl 说明为用于省略“来自云端和 Remote Control 提交中的 claude.ai 会话链接”的配置项。这也说明了链接的来源:Web 上的会话,以及通过 Remote Control 驱动的会话。
该链接不是凭据。任何人能否打开该会话,取决于帐户访问权限,而不是 URL 是否保持未知。将它排除在公共仓库之外的原因更简单:它是包含内部会话 ID 的永久公开文本,并且指向一份原本就不是面向公众编写的工作转录记录。对于私有仓库,理由则相反,因为审阅者可以打开链接,了解变更是如何完成的。相关转录记录存储在哪里,以及会保留多长时间,请参阅 Claude Code 如何存储会话并恢复会话。
控制 Claude Code 提交归属信息的设置
根据 2026 年 9 月 1 日查阅的 Claude Code 设置参考,这些键位于“Git 和归属信息”标题下:
attribution:“自定义 Claude Code 添加到提交和拉取请求中的归属信息”attribution.commit:“更改或隐藏 Claude Code 添加到提交中的 trailer”attribution.pr:“更改或隐藏拉取请求描述中的归属信息行”attribution.sessionUrl:“从云端和 Remote Control 提交中省略 claude.ai 会话链接”includeGitInstructions:“从系统提示中移除内置的提交和 PR 指令”includeCoAuthoredBy:已标记为弃用,并注明“使用attribution隐藏或更改提交和 PR 归属信息”
每个键接受的值,应从其在设置参考中的条目获取,而不是从指南中获取。键名是稳定的。可接受的值和默认值会变化,设置文件即使键名拼写正确,只要值拼写错误,也会静默失败。
写入位置决定设置的作用范围。~/.claude/settings.json 适用于你打开的每个项目。在仓库顶层提交的 .claude/settings.json 会应用于所有克隆该仓库的人。.claude/settings.local.json 只属于该项目,并且 Claude Code 第一次写入此文件时,会将其添加到你的全局 git excludes 中,因此不会出现在你的提交中。优先级依次为托管设置、命令行、项目本地设置、共享项目设置和用户设置。因此,队友的本地文件会覆盖你提交的文件。应将已提交的设置视为默认值,而不是保证。
然后验证设置,因为你认为某项设置生效并不等于它确实生效。让 Claude Code 按正常方式创建下一次提交,然后读取结果。
git log -1 --format=%B
git log -1 --format=%B | git interpret-trailers --parse如果 trailer 仍然输出,说明更改没有应用到当前会话。确认你编辑的是哪个文件,并检查上面的优先级顺序,然后再判断该键是否损坏。
不依赖设置的控制措施
设置只能配置一个工具。仓库规则必须能够约束使用其他工具或完全不使用代理的贡献者。Git 提供了存放这类规则的位置:commit-msg hook 会将消息文件路径作为第一个参数运行,并可编辑该文件,或直接拒绝提交。
#!/bin/sh
# .githooks/commit-msg
grep -qi '^co-authored-by: claude' "$1" || exit 0
grep -vi '^co-authored-by: claude' "$1" > "$1.new" && mv "$1.new" "$1"chmod +x .githooks/commit-msg
git config core.hooksPath .githooks第一个 grep 在无事可做时会提前退出,因此普通提交几乎不会增加开销。第二个会删除不包含匹配行的消息后,再将消息写回。应匹配一个确切的标记,而不是所有 trailer,因为写成“删除最后一个区块”的过滤器也会删除项目要求保留的 Signed-off-by: 行。
.git/hooks 不属于仓库,因此放在那里的 hook 不会传递给其他人。core.hooksPath 会让 git 使用一个可以提交到仓库的目录,但每个人仍需自行运行一次 git config 命令。Git 不会替他们设置该目录,这是有意为之:如果仓库可以在克隆时安装自己的可执行文件,就可能借此在你的计算机上运行代码。
如果要拒绝提交而不是重写提交消息,请将消息输出到标准错误,并在 hook 中执行 exit 1。在共享仓库中,拒绝提交是更诚实的做法,因为静默修改他人的提交消息会隐藏规则,而不是帮助对方理解规则。这与代理自身的 hook 属于不同层级;代理自身的 hook 会在 git 介入之前、工具调用时触发。Claude Code hook 如何匹配工具并阻止工具调用介绍了这一层。
这两种方式都无法处理来自 fork 的拉取请求,因为 hook 位于你无法控制的计算机上。CI(持续集成)中的检查是唯一能在合并前看到每个提交的层级。
if git log --format=%B "origin/${BASE_BRANCH:-main}..HEAD" | grep -qi '^co-authored-by: claude'; then
echo "Attribution trailer found. Rewrite the branch before merging." >&2
exit 1
fi除了强制执行规则,也要将规则写明。放在可读的 CONTRIBUTING.md 旁边的 AGENTS.md 会向代理和人员传达相同的信息,而 CI 检查负责确保规则真正生效。
推送前删除尾部内容
对于刚刚创建的提交:
git log -1 --format=%B | grep -vi '^co-authored-by: claude' | git commit --amend -F --F -会从标准输入读取新消息。Git 会删除以这种方式提供的消息开头和结尾的空行,因此,删除尾部内容后留下的空行会自动消失。继续操作前,使用 git log -1 --format=%B 重新读取结果。
如果要修改分支上的多个提交,请针对将要合并到的分支执行交互式 rebase,并将每条需要修改的提交消息标记为 reword。
git rebase -i origin/main从最早被编辑的提交开始,之后的每个提交都会获得新的哈希值,因为提交的哈希值包含其消息和父提交。在提交仍位于本地时,这样做不会产生额外成本;提交被共享后,代价会很高。
推送后删除 trailer
仅供自己使用的分支可以按上述方式重写,然后覆盖推送。
git push --force-with-lease如果远程仓库在上次获取后发生了变化,--force-with-lease 会拒绝推送,因此不会静默丢弃其他人新增的提交。普通的 --force 没有此检查。
如果 trailer 分布在很长的历史记录中,git filter-repo 会一次性重写每条消息。请从现有工作副本内部运行克隆命令,这样 URL 会直接使用已有的远程仓库配置。
pip install git-filter-repo
git clone "$(git remote get-url origin)" ../project-rewrite
cd ../project-rewrite
git filter-repo --message-callback '
return b"\n".join(l for l in message.split(b"\n") if not l.lower().startswith(b"co-authored-by: claude"))
'回调函数接收每条消息的字节内容,并返回要存储的消息,因此其中的每个字符串都带有 b 前缀。如果仓库不是全新克隆,filter-repo 会拒绝运行,除非传入 --force;完成后它还会删除 origin 远程仓库,避免您误将重写结果推送回去。请有意重新添加远程仓库并强制推送,然后通知所有人重新克隆,因为他们持有的每个哈希现在都已失效。
请明确重写无法解决的问题。它只会修改您的仓库副本,不会影响派生仓库、现有克隆、副本镜像、已经引用该消息的拉取请求页面,也不会影响上周抓取过您的代码搜索索引。对于泄露的密钥,正确的修复方式是轮换密钥,重写只是清理措施。披露信息的 trailer 不是密钥,因此应权衡完整历史重写的代价;其结果是所有未合并的拉取请求都需要重新构建。
另一方的评审者期望什么
维护者对此并无共识,而这正是你在删除任何内容前必须先确认的原因。有些项目希望保留这项披露,并会要求你恢复它,因为评审者看待机器生成的补丁时,视角不同。有些项目则禁止这样做,通常是因为变更的法律作者归属存在争议。采用 DCO(开发者来源证书)的项目要求包含 Signed-off-by: 行。该行声明你有权提交这段代码,而粗略的消息过滤器可能会连同署名信息一起删除它。
先阅读 CONTRIBUTING.md。如果项目没有说明,请为该仓库确定一条规则并记录下来。因为只出现在一半提交中的尾注,比两种明确的做法都更糟:它会让同一段历史看起来像是由两个项目产生的。
如果你是在服务器而不是笔记本电脑上运行该代理,同一个问题还会向下延伸一层。在 VPS 上使用其专用账户运行 Claude Code决定了它到底能访问哪些仓库,而编码代理会将哪些内容发送到机器外部涵盖了不会出现在提交消息中的网络流量。
FAQ
Co-authored-by 的 Claude 署名是否会计入仓库的贡献者统计?
不会。GitHub 根据与 GitHub 账户关联的电子邮件地址,将提交关联到个人资料,并以此统计贡献。未关联任何账户的地址无法建立关联,因此该署名只会改变提交页面,不会改变贡献者列表。Git 本身不会读取署名。git shortlog -sn 统计的是 author 标头,因此其中不会显示共同作者。
如何查找所有已经包含该署名的提交?
git log -i --grep='^Co-authored-by:' --format='%h %an %s' 会以不区分大小写的方式,在完整历史记录中列出这些提交。在较新的 git 中,git log --format='%h %(trailers:key=Co-authored-by,valueonly)' 会通过 git 自带的 trailer 解析器读取值,而不是匹配原始文本。若只想查看尚未推送的提交,请添加范围:git log origin/main..HEAD --format=%B。
可以从已经推送的提交中删除该署名吗?
可以,但需要重写历史,代价很大。如果分支仅供您使用,可以执行 amend 或 rebase,然后运行 git push --force-with-lease。如果是共享分支,从最早被修改的提交开始,之后的每个提交都会获得新的哈希值,因此每个克隆仓库和每个已打开的拉取请求都必须重新构建。重写也不会影响 fork、镜像或其他人在昨天创建的克隆仓库。
提交消息中的 claude.ai 会话链接是否存在安全风险?
它不是凭据,会话访问权限由账户决定,而不是由 URL 是否难以猜测决定。问题在于,该链接是永久公开的文本,并指向一份以工作笔记形式撰写的记录。Claude Code 设置参考文档将 attribution.sessionUrl 记为从云端提交和 Remote Control 提交中省略该链接的关键设置;commit-msg hook 则会从该设置未覆盖的内容中删除链接。
是否应该完全关闭署名?
这取决于仓库,而不是个人偏好。对于公共项目,请遵循 CONTRIBUTING.md,因为如果维护者需要保留披露信息,他们会要求恢复。对于公司仓库,保留该署名通常很有用,因为它能让审阅者在一年后了解某项更改为何采用当前形式。请为整个仓库统一决定,并在 CI 中强制执行,以保持历史记录一致。