SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-09-06

Claude Code 會在提交中寫入哪些內容?

Claude Code 會加入 Co-authored-by trailer;cloud 工作階段還會寫入 claude.ai 連結。了解如何用 git 讀取,並在推送前控制這些內容。

Claude Code 在提交中寫入的內容

Claude Code 會在其建立的提交訊息結尾加入 Co-authored-by: trailer,並在其開啟的 pull request 說明中加入署名行。在雲端或透過 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: 都是建立在同一套機制上的慣例,而 forge,也就是 GitHub 或 GitLab 等代管儲存庫的網站,會讀取這些內容,以決定提交頁面要顯示什麼。

Git 對該區塊的位置要求嚴格。git interpret-trailers 的文件指出,這個群組前面必須有一行以上的空白行,且必須位於訊息結尾,或緊接在以 --- 開頭的行之前。此外,該群組必須全部由 trailer 組成,或「至少包含一個由 Git 產生或由使用者設定的 trailer,且其中至少 25% 是 trailer」。

最後一項規則在這裡很重要。最後一個區塊中的單獨 URL 或一般文字行都不是 trailer;非 trailer 行過多時,整個區塊就不會被解析為 trailer。這就是為什麼某個提交看似包含 Co-authored-by: 行,但所有正確讀取 trailer 的工具都會判定其中沒有任何內容。

如何讀取歷史記錄中已有的 trailers?

先查看最近一次提交的原始訊息。

git log -1 --format=%B

%B 會依儲存內容原樣輸出標題與本文,不換行,也不重新格式化。這份輸出才是實際內容。代管平台顯示的任何內容都只是對它的呈現。

接著詢問 git 將哪些行視為 trailers。

git log -1 --format=%B | git interpret-trailers --parse

--parse--only-trailers --only-input --unfold 的簡寫,因此輸出內容只有 trailer 區塊。正常結果是每個 trailer 各占一行。如果你明明看得到 Co-authored-by: 行,卻得到空白輸出,表示該區塊未符合前述位置規則。

若要掃描整個歷史記錄,請依 key 查詢 trailer。

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 會忽略大小寫。這點很重要,因為不同工具對這個 trailer 的大小寫方式並不一致。在推送前,應將查詢範圍縮小為尚未送出的提交。

git log origin/main..HEAD --format=%B

這些提交仍在本機,因此現在仍可低成本修改。

Co-authored-by: 會如何影響 GitHub 上的歸屬資訊?

GitHub 會讀取此 trailer,並在提交頁面上顯示第二位作者。只有在該電子郵件地址屬於某個帳戶時,GitHub 才會將這位作者連結至個人檔案。GitHub 官方文件指出,提交必須「使用與 GitHub 帳戶連結的電子郵件地址建立」,才會顯示在貢獻圖表中。因此,不屬於任何帳戶的地址無法連結至個人檔案。對雙人協作而言,這正是其用途:同事的地址已連結至其帳戶,而該提交會同時計入你們兩人的貢獻。若沒有任何帳戶擁有該地址,trailer 只會改變提交頁面上的顯示內容,不會改變儲存庫的貢獻者清單。

Git 本身會完全忽略此 trailer。git shortlog -sngit log --author 會讀取 author 標頭,其中包含你的姓名與電子郵件,因此本機的任何統計都不會顯示共同作者。這裡的歸屬資訊是建構在純文字慣例之上的 forge 功能,這就是 git 本身與你所使用的 forge 之間的差異。

工作階段連結是另一個問題

片尾會標示共同作者。工作階段 URL 則是指向逐字記錄的連結。Claude Code 設定參考文件將 attribution.sessionUrl 說明為可省略「來自雲端與 Remote Control commit 的 claude.ai 工作階段連結」的設定,這也說明了連結的來源:網頁上的工作階段,以及透過 Remote Control 操作的工作階段。

這個連結不是憑證。任何人能否開啟該工作階段,取決於帳戶存取權,而不是 URL 是否保持未知。之所以不應將它放在公開儲存庫中,原因很簡單:它是永久公開的文字,會標示內部工作階段 ID,並指向一份原本不是為公開讀者撰寫的工作記錄。對私有儲存庫而言,理由則相反,因為審查者可以開啟連結,了解變更是如何完成的。這些工作記錄儲存在哪裡,以及會保留多久,請參閱Claude Code 如何儲存工作階段並繼續工作

控制 Claude Code commit 歸屬資訊的設定

截至 2026 年 9 月 1 日,這些設定鍵已根據 Claude Code settings reference 核對,並列在「Git and attribution」標題下:

  • attribution:「自訂 Claude Code 加入 commits 和 pull requests 的歸屬資訊」
  • attribution.commit:「變更或隱藏 Claude Code 加入 commits 的 trailer」
  • attribution.pr:「變更或隱藏 pull request 描述中的歸屬資訊行」
  • attribution.sessionUrl:「省略 Claude Code 加入 cloud 和 Remote Control commits 的 claude.ai 工作階段連結」
  • includeGitInstructions:「從 system prompt 移除內建的 commit 和 PR 指示」
  • includeCoAuthoredBy:已標示為 deprecated,並附註「使用 attribution 隱藏或變更 commit 和 PR 歸屬資訊」

每個設定鍵可接受的值,應以設定參考文件中該鍵自己的項目為準,不要以指南為準。鍵名保持穩定。可接受的值與預設值會變動;設定檔即使鍵名拼寫正確,只要值拼寫錯誤,也會靜默失敗。

設定寫入的位置會決定套用對象。~/.claude/settings.json 適用於你開啟的每個專案。在儲存庫頂層提交的 .claude/settings.json 會套用至所有複製該儲存庫的人。.claude/settings.local.json 只屬於你在該專案中的設定。Claude Code 第一次寫入該檔案時,會將它加入你的 global git excludes,因此不會出現在你的 commits 中。優先順序依序為 managed settings、command line、project local、shared project、user。隊友的 local file 因此會覆寫你提交的檔案,所以應將已提交的設定視為預設值,而不是保證。

接著驗證設定,因為你相信某項設定,不代表它已生效。讓 Claude Code 依平常方式建立下一個 commit,再讀取結果確認。

git log -1 --format=%B
git log -1 --format=%B | git interpret-trailers --parse

如果 trailer 仍然出現,表示變更尚未套用至該工作階段。在判定鍵已損壞之前,先確認你編輯的是哪個檔案,並檢查上述優先順序。

不依賴設定的控制措施

設定只能配置一項工具。儲存庫規則必須能在貢獻者使用不同工具,或完全不使用 agent 時仍然有效。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 在沒有工作可做時會提早結束,因此一般提交幾乎不會增加負擔。第二個會移除符合的那一行,再將訊息寫回檔案。請比對一個完全相符的 token,不要移除所有 trailer,因為寫成「刪除最後一個區塊」的篩選器,也會刪除專案要求保留的 Signed-off-by: 行。

.git/hooks 不屬於儲存庫,因此放在其中的 hook 不會傳給其他人。core.hooksPath 會將 git 指向一個可以提交的目錄,而每個人仍須自行執行那一行 git config。Git 不會替他們設定,這是刻意的:如果儲存庫能在 clone 時安裝自己的可執行檔,就可能藉此在你的電腦上執行程式碼。

如果要拒絕提交,而不是改寫提交訊息,請將訊息輸出至 standard error,並在 hook 中執行 exit 1。在共用儲存庫中,拒絕提交是誠實的做法,因為默默編輯他人的提交訊息只會隱藏規則,而不是讓對方了解規則。這與 agent 自身的 hook 屬於不同層級;agent 的 hook 會在 git 完全介入前,於工具呼叫時觸發。Claude Code hook 如何比對工具並封鎖工具呼叫 說明了這一層。

這兩種方式都無法處理來自 fork 的 pull request,因為 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 會讓 agent 與人員收到相同說明,而 CI 檢查則確保規則確實生效。

推送前移除結尾欄位

針對剛才建立的 commit:

git log -1 --format=%B | grep -vi '^co-authored-by: claude' | git commit --amend -F -

-F -會從 standard input 讀取新的訊息。Git 會移除以此方式提供的訊息開頭與結尾空白行,因此刪除 trailer 後留下的空白行會自動消失。繼續之前,使用 git log -1 --format=%B 讀回結果。

若要修改分支上的多個 commit,請以即將合併的分支為基準執行 interactive rebase,並將每個要修改訊息的 commit 標記為 reword

git rebase -i origin/main

從最早被編輯的 commit 起,後續每個 commit 都會取得新的 hash,因為 commit 的 hash 涵蓋其訊息與 parent。這些 commit 尚未離開本機時,重新計算 hash 的成本很低;一旦已經公開,成本就會提高。

推送後移除 trailer

在只有你使用的分支上,依照上述方式重寫歷史,然後以重寫後的內容覆寫遠端分支。

git push --force-with-lease

如果遠端分支自上次 fetch 後已有變更,--force-with-lease 會拒絕推送,因此不會悄悄丟棄其他人新增的 commit。一般的 --force 沒有這項檢查。

如果 trailer 分散在很長的歷史中,git filter-repo 會在一次操作中重寫每則訊息。請從現有 working copy 內執行 clone,這樣會直接使用既有 remote 的 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"))
'

callback 會以 bytes 接收每則訊息,並回傳要儲存的訊息,因此其中每個字串都帶有 b 前綴。除非傳入 --force,否則 filter-repo 不會對不是 fresh clone 的 repository 執行;完成後也會移除 origin remote,避免你意外將重寫後的歷史推送回去。請刻意重新加入 remote,再執行 force-push,然後要求所有人重新 clone,因為他們目前持有的每個 hash 都已經失效。

請明確了解重寫無法處理的範圍。它只會變更你手上的 repository,不會影響 forks、現有 clones、mirrors、已引用該訊息的 pull request 頁面,也不會影響上週已爬取你的 code search index。若洩漏的是 secret,正確作法是輪替 secret,重寫則用於清理歷史。disclosure trailer 不是 secret,因此應衡量完整歷史重寫的代價;代價包括所有開啟中的 pull request 都必須重新建立。

另一端的審查者期待什麼

維護者對此沒有共識,而這正是你在移除任何內容前必須先確認的原因。有些專案需要保留揭露資訊,會要求你加回去,因為審查者看待機器產生的修補程式時,會採用不同的判斷方式。有些專案則禁止這麼做,通常爭議在於誰在法律上是變更的作者。使用 DCO(developer certificate of origin)的專案要求加入 Signed-off-by: 行,這表示你聲明自己有權提交該程式碼;粗略處理的訊息篩選器可能會連同作者標示一起移除。

先閱讀 CONTRIBUTING.md。如果專案沒有說明,請為該儲存庫選定一項規則並記錄下來,因為只有一半提交包含該 trailer,比採用任一種做法都更糟:這會讓同一段歷史看起來像是來自兩個專案。

如果你是在伺服器上執行 agent,而不是在筆記型電腦上執行,同一個問題還會往下延伸一層。在 VPS 上以專用帳號執行 Claude Code決定它究竟能存取哪些儲存庫,而coding agent 傳出機器的內容則涵蓋那些不會出現在提交訊息中的網路流量。

FAQ

Co-authored-by 中的 Claude 貢獻標記會計入我儲存庫的貢獻者統計嗎?

不會。GitHub 會透過與 GitHub 帳戶連結的電子郵件地址,將提交關聯至個人檔案,並依此計算貢獻。若某個地址不屬於任何帳戶,就無法建立關聯,因此該標記只會修改提交頁面,不會改變貢獻者清單。Git 本身不會讀取這些標記。git shortlog -sn 會計算 author header,因此共同作者不會出現在其中。

如何找出已經包含該標記的所有提交?

git log -i --grep='^Co-authored-by:' --format='%h %an %s' 會以不區分大小寫的方式,在完整歷史記錄中列出這些提交。在較新的 git 版本中,git log --format='%h %(trailers:key=Co-authored-by,valueonly)' 會使用 git 自己的 trailer parser 讀取值,而不是比對原始文字。若只要查看尚未推送的提交,請加入範圍:git log origin/main..HEAD --format=%B

可以從已經推送的提交中移除該標記嗎?

可以,但需要改寫歷史記錄,代價也確實存在。在只有你使用的分支上,可以 amend 或 rebase,然後執行 git push --force-with-lease。在共用分支上,從最早修改的提交開始,後續每個提交都會產生新的 hash,因此每個 clone 和每個已開啟的 pull request 都必須重新建立。改寫也永遠不會套用到 fork、mirror,或他人昨天建立的 clone。

提交訊息中的 claude.ai 工作階段連結有安全性風險嗎?

它不是 credential,而工作階段的存取權限取決於帳戶,不是取決於 URL 是否難以猜測。問題在於,它是永久公開的文字,指向一份以工作筆記形式撰寫的逐字稿。Claude Code settings reference 將 attribution.sessionUrl 記載為可從 cloud 和 Remote Control 提交中省略該連結的設定;而 commit-msg hook 則會從該設定未涵蓋的內容中移除連結。

是否應該完全關閉 attribution?

這取決於儲存庫,而不是個人偏好。在公開專案中,請遵循 CONTRIBUTING.md,因為若維護者需要揭露資訊,會要求恢復該設定。在公司儲存庫中,保留該標記通常很有用,因為它能讓一年後的審查者了解某項變更為何呈現目前的樣子。請為整個儲存庫統一決定一次,並在 CI 中強制執行,讓歷史記錄保持一致。

#claude-code#git#commit-messages#attribution#privacy