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: 均是基於同一機制建立的慣例,而代碼託管平台(如 GitHub 或 GitLab)會讀取這些資訊,以決定在提交頁面上顯示的內容。
Git 對該區塊的位置有嚴格要求。git interpret-trailers 的說明文件指出,該群組前必須有一個空白行,定義為「空行或僅包含空白字元的行」。該區塊必須位於訊息末尾,而訊息的終止點為輸入結束,或是遇到以 --- 開頭(後接空格或行尾)的行之前的最後非空白行。此外,該群組必須全為 trailer,或是「至少包含一個由 Git 產生或使用者設定的 trailer,且 trailer 佔比至少 25%」的群組。
最後這條規則至關重要。位於最後區塊內的純 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 -sn 和 git log --author 會讀取 author 標頭,其中包含你的姓名與電子郵件,因此本機的任何統計都不會顯示共同作者。這裡的歸屬資訊是建構在純文字慣例之上的 forge 功能,這就是 git 本身與你所使用的 forge 之間的差異。
Session 連結是另一個問題
Trailer 用於標註共同作者,而 session URL 則是指向對話紀錄的指標。Claude Code 設定參考文件將 attribution.sessionUrl 記錄為用於「從雲端與 Remote Control 提交中省略 claude.ai session 連結」的鍵值,這也說明了連結的來源:網頁版 session 與透過 Remote Control 執行的 session。同一份參考文件指出,該連結會以 Claude-Session trailer 的形式寫入提交,並以連結形式出現在合併請求(pull request)說明中,因此 git log --format='%h %(trailers:key=Claude-Session,valueonly)' 會列出所有包含此連結的提交。
該連結並非憑證。任何人能否開啟該 session 取決於帳號存取權限,而非 URL 是否保密。將其排除在公開儲存庫之外的原因很單純:它是永久公開的文字,包含內部 session ID,且指向一份並非為公開閱讀而撰寫的工作紀錄。在私人儲存庫中則持相反觀點,因為審查者可以透過連結追蹤變更的達成過程。這些紀錄的儲存位置及其存續時間,請參閱 Claude Code 如何儲存與恢復 session。
控制 Claude Code 提交歸屬的設定
截至 2026 年 10 月 11 日,經對照 Claude Code 設定參考文件,這些鍵值記錄於「Git and attribution」標題下:
attribution:「自訂 Claude Code 新增至提交與合併請求的歸屬資訊」attribution.commit:「變更或隱藏 Claude Code 新增至提交的 trailer」attribution.pr:「變更或隱藏合併請求說明中的歸屬行」attribution.sessionUrl:「從雲端與 Remote Control 提交中省略 claude.ai session 連結」includeGitInstructions:「從 Claude 的上下文移除內建的提交與 PR 指示」includeCoAuthoredBy:標記為已棄用,註記為「使用attribution來隱藏或變更提交與 PR 歸屬」
請從 設定參考文件 的個別項目中取得各鍵值可接受的數值,而非參考指南。鍵值名稱是穩定的,但可接受的數值與預設值會變動;若設定檔中的鍵值拼寫正確但數值錯誤,系統會靜默失敗。
設定的寫入位置決定了其適用範圍。~/.claude/settings.json 適用於您開啟的每個專案。提交至儲存庫根目錄的 .claude/settings.json 會影響所有 clone 該儲存庫的使用者。.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 仍持續印出,代表變更未正確套用至 session。在判定鍵值失效前,請檢查您編輯的檔案以及上述的優先順序。
不依賴設定的控制措施
設定只能配置一項工具。儲存庫規則必須能在貢獻者使用不同工具,或完全不使用 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 中強制執行,讓歷史記錄保持一致。