Community程式設計與開發github.com

Daniyal12333/claude-code-skills

根據本地 Git 歷史記錄,將程式碼歸因於其作者、票證、分支和 Pull Request。當使用者詢問「誰寫了這個」、「誰修改了這行程式碼」、「這是哪個票證新增的」等問題時使用。

claude-code-skills 是什麼?

這項技能讓 AI Agent 無需離開終端機,即可透過本地 Git 歷史回答「誰撰寫了這段程式碼、屬於哪個票證、何時完成」等問題。它支援 GitHub、GitLab、Bitbucket 等程式碼託管平台,並自動輸出作者姓名、提交雜湊值、票證編號、分支名稱、日期、PR 編號以及可點選的提交和 PR 連結。技能背後的核心是一套 Shell 腳本,提供全檔案和行範圍兩種模式,並包含智慧型函式名稱解析與行號範圍推算邏輯。此外,它還加入了信心標籤機制(如「本地尚未合併」、「低信心度(無票證)」、「壓縮合併」等),讓 AI 能夠誠實報告歸因結果,避免猜測作者或票證。它也能處理長期存在的整合分支,區分「經由哪個 PR 合併」與「在哪個 PR 中撰寫」。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Daniyal12333/claude-code-skills/tree/HEAD/who-changed

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Who Changed

無需離開終端機即可回答「誰建構了這個、屬於哪個票證、何時完成」。所有需要的資訊都已存在於本地 Git 歷史中。程式碼託管平台唯一額外提供的是 PR 敘述,而輸出結果會提供該敘述的連結。

它取代了手動的循環流程:開啟檔案、找到功能、開啟 blame 檢視、複製雜湊值、貼到程式碼託管平台、點擊進入 PR、讀取票證和作者。

使用者獲得什麼

作者姓名、提交雜湊值、票證編號、分支名稱、日期、PR 編號,以及可點選的提交和 PR 連結。範圍的主要判定結果,以及觸及該範圍的每個提交的表格。

執行腳本

bash ~/.claude/skills/who-changed/scripts/who-changed.sh <file> [start end] [raw]

如果技能是按專案安裝的,則路徑為 .claude/skills/who-changed/scripts/who-changed.sh。

  • <file> 單獨使用:全檔案模式。顯示主要貢獻者以及最近 12 個提交。
  • <file> <start> <end>(或單一行號):行範圍模式。顯示每個提交擁有的行數。
  • 附加 raw:不使用 -w -C -M 進行 blame,用於使用者想要位元組級別的真實情況時。

環境變數覆寫:WHO_CHANGED_BASE 設定 PR 查詢走向的參考(預設值:origin/HEAD,然後 origin/main、origin/master、main、master);WHO_CHANGED_TICKET_REGEX 更改票證模式(預設值:[A-Z][A-Z0-9]+-[0-9]+)。

該腳本會輸出一個以 Tab 分隔的報告,且絕不會寫入儲存庫或網路。請為使用者重新格式化該報告,不要直接貼出原始 TSV。

步驟 1:將目標解析為行範圍

腳本接收數字參數,因此函式名稱必須先轉換為一個範圍。Git 的 -L :functionName: 快捷方式依賴於特定語言的函式模式,而對於許多語言(尤其是 TypeScript 類別成員),它會失敗並顯示 no match。請自行解析範圍:

  1. 搜尋宣告,例如 ^\s*(public|private|protected)?\s*(async\s+)?<name>\s*[(<] 和 <name>\s*[:=]\s*(function|\() 用於箭頭函式屬性。對於 HTML 或 CSS,搜尋文字選擇器、鍵或區塊。
  2. 從該行開始讀取,並從第一個 { 開始進行大括號匹配,以找到結束行。
  3. 如果名稱在多個位置匹配,列出所有匹配項並詢問使用者是哪一個。 絕不要默默選擇第一個——常見名稱通常存在於多個檔案中。

行號來自工作目錄樹,因此與使用者在編輯器中看到的行號一致。

如果給定了明確的範圍(285-300、285、L285-L300),則直接使用。如果只給定檔案路徑,則使用全檔案模式。

步驟 2:讀取輸出

## meta 區塊包含 base(PR 查詢走向的參考)、base_tip_date、web 和 host(連結基礎,從 git remote 推導)、blame 模式,以及檔案是否有未提交的變更。

## commits 中的行按擁有的行數排序。判定結果是第一行——擁有該範圍最多行的提交。當範圍確實被多人共享時,請提及第二名的貢獻者;一個由四人在三年內共同建構的函式不應被報告為屬於一個人。

腳本已經為 Bitbucket、GitHub 和 GitLab 遠端倉庫建構了 commit_url 和 pr_url。當它們是 - 時,表示沒有可識別的遠端倉庫——請直接說明並省略連結,而不是憑空虛構一個主機。

按以下方式呈現(以下名稱均為虛構):

### calculateTotal - src/cart/cart.service.ts:42-61

**Alice Moreno** · `a1b2c3d` · 2023-02-08 · 擁有 20 行中的 13 行
票證 SHOP-88 · 分支 `SHOP-88-cart-totals` · PR #41

| 行數 | 作者 | 提交 | 日期 | 票證 | 分支 | PR |
|---|---|---|---|---|---|---|
| 13 | Alice Moreno | a1b2c3d | 2023-02-08 | SHOP-88 | SHOP-88-cart-totals | #41 |
| 6 | Ben Carter | 9f8e7d6 | 2026-03-11 | SHOP-310 | SHOP-310-rounding-fix | 尚未合併 |
| 1 | Chen Wei | 4c5d6e7 | 2024-06-20 | — | release-2024-06 | #112 |

然後是連結,接著每當有信心標記觸發時,都加上一行說明。

信心標籤以及應如何對使用者說明

標籤含義告訴使用者
ok票證分支已透過 PR 合併無需說明
local-only提交尚未存在於 base 上「尚未合併到基礎分支」——沒有 PR
no-pr-merge在主線上,但沒有 PR 合併承載它直接提交到主線,或者合併主旨不符合慣例
squash從 (#123) 後綴讀取 PR 編號採用壓縮合併,因此該 PR 內的逐行歷史已被扁平化
low-no-ticket提交訊息或分支中都沒有票證需說明未記錄任何票證。 不要猜測一個
low-integration-branch透過一個名稱中沒有票證的分支合併這個 PR 是整合分支被合併的地方,不是程式碼被撰寫的地方。信心度低
uncommittedNot Committed Yet本地的未提交編輯;排除在判定結果之外

較舊的程式碼通常透過長期存在的整合分支(develop、release-*、ui-dev)到達。對於這些情況,誠實的回答是「經由 PR #112 合併到主線,但該 PR 是一個整合分支——這不是撰寫此程式碼的 PR。」

為什麼 -w -C -M 是預設值

-w 忽略空白字元,-M 追蹤在檔案內移動的行,-C 追蹤從另一個檔案複製進來的行。這並非僅是修飾。以一個於 2023 年撰寫、僅在 2026 年重新縮排的區塊為例(數字為說明用):

  • 智慧模式(-w -C -M):9 行中的 9 行歸於原始作者,2023 年——正確
  • 原始模式:9 行中的 8 行歸於重新縮排的人,2026 年——將舊程式碼歸功於他們

因此,命名的作者是最後一個更改行為的人,而不是最後一個觸碰位元組的人。必要時請說明這一點,並提供 raw 作為後續選項。

誠實規則

  • 絕不要虛構票證 ID。 提交訊息或分支中沒有票證:報告 — 並說明未記錄任何票證。
  • 絕不要虛構作者。 如果 blame 結果不明確,則說明哪些提交是候選項。
  • 每當低信心度標記觸發時,區分「經由某處合併」與「在某處撰寫」。
  • 如果 base_tip_date 看起來過時,請說明基礎參考近期未被擷取,可能會錯過最近的合併。建議 git fetch origin——但不要在未經要求的情況下執行它。

有相關性時應說明的限制

  • 「為什麼」不在 git 中。 PR 描述、審查者和票證標題需要程式碼託管平台或追蹤器的 API 和憑證。PR 連結是交接點。
  • 壓縮合併會扁平化歷史記錄。 如果一個 PR 被壓縮合併,一個提交將擁有整個功能,而其中的逐行歸因將消失。
  • --ancestry-path 選擇第一個將提交帶入主線的合併。 對於巢狀功能分支,這可能是一個中間合併,而不是票證本身的 PR。
  • 全檔案貢獻者不會追蹤重新命名。 git shortlog 沒有 --follow;提交列表會追蹤重新命名,但貢獻者統計不會。
  • -C 偶爾會產生意外結果,將複製貼上的程式碼歸因於其來源檔案。
  • PR 偵測能辨識三種合併訊息樣式: Bitbucket(Merged in <branch> (pull request #N))、GitHub(Merge pull request #N from ...)和壓縮合併(... (#N))。其他樣式會落入 no-pr-merge。

腳本不可用時的備用方案

git blame -w -C -M -L <start>,<end> --date=short -- <file>
git log -1 --date=short --pretty=format:"%H%n%an%n%ad%n%s%n%b" <sha>
git merge-base --is-ancestor <sha> origin/main     # 不是祖先 -> 未合併
git log --merges --ancestry-path --reverse --pretty=format:"%h|%s" <sha>..origin/main | grep -m1 "pull request"
git branch --contains <sha>                        # 未合併的情況

解析合併主旨以取得分支和 PR 編號。有兩個陷阱:git shortlog 需要明確的 HEAD,否則會靜默地讀取標準輸入且不回傳任何內容;分支名稱可能有前綴(feature/SHOP-88-...),因此不要將票證正規表示式錨定到字串開頭。

相關技能