mcpField
A
author-contributions

author-contributions

github.com/microsoft开发194.4k3.0k 次安装今天更新
代码仓库

关于 author-contributions

author-contributions 是面向代码审查与分支分析的技能,用于识别指定作者在分支合并差异中的文件贡献。它追踪跨多次重命名的文件,并以表格汇总状态和行数变化。

主要功能

  1. 01核对作者的 Git 身份
  2. 02汇总作者提交涉及的文件
  3. 03跨提交追踪文件重命名
  4. 04仅筛选合并差异中的文件
  5. 05输出文件状态及行数统计

适用场景

  1. 01审查分支合并时某位作者的贡献
  2. 02追踪作者修改后经重命名的文件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/vscode --skill author-contributions

安装后在 Claude Code 中输入/author-contributions确认已加载。

详细介绍

当被要求查找某位作者在某个分支上(与 main 或其他上游分支相比)参与过的所有文件时,请按以下流程操作。目标是生成一个简单的表格,便于人类和大模型读取。

作为子 Agent 运行

此技能需要依次运行许多 git 命令。请将其委派给子 Agent,并使用类似以下提示词:

找出作者“Full Name”在分支 <branch> 上相较于 <upstream> 参与过的每个文件。追踪文件重命名前的贡献。返回一个 Markdown 表格,列包括:状态(DIRECT 或 VIA_RENAME)、文件路径和行数(+/-)。最后附上一行摘要。

流程

1. 确定作者准确的 git 身份
git log --format="%an <%ae>" <upstream>..<branch> | sort -u

将请求中的人员与其准确的 --author= 字符串匹配。不要猜测——简短的用户名可能无法匹配完整的显示名称(请通过 git log 或 GitHub MCP get_me 工具进行确认)。

2. 收集作者直接提交过的所有文件
git log --author="<Exact Name>" --format="%H" <upstream>..<branch>

对于每个提交哈希,提取涉及的文件:

git diff-tree --no-commit-id --name-only -r <hash>

将所有结果合并为一个集合(author_files)。

3. 构建整个分支的重命名映射

对分支上的每个提交(不只是作者的提交)提取重命名:

git diff-tree --no-commit-id -r -M <hash>

解析状态为 R 的行,构建映射:new_path → {old_paths}。

4. 获取合并差异中的文件列表
git diff --name-only <upstream>..<branch>

这些文件将在分支合并时实际进入上游。

5. 对合并差异中的每个文件进行分类

对于步骤 4 中的每个文件:

  • 如果它在 author_files 中 → DIRECT
  • 否则,沿重命名映射进行传递追踪(沿链追踪:当前路径 → 旧路径 → 更早的路径),检查是否有任何祖先路径在 author_files 中 → VIA_RENAME
  • 否则,该文件不属于此作者的贡献
6. 获取差异统计信息
git diff --stat <upstream>..<branch> -- <file1> <file2> ...
7. 返回表格

将结果格式化为 Markdown 表格:

| Status | File | +/- |
|--------|------|-----|
| DIRECT | src/vs/foo/bar.ts | +120/-5 |
| VIA_RENAME | src/vs/baz/qux.ts | +300 |
| ... | ... | ... |

**Total: N files, +X/-Y lines**

重要说明

  • 使用 Python 处理繁重工作。 在 zsh 中,带内联注释的 Shell 循环会出错。请编写临时 .py 脚本,运行后再删除。
  • 作者匹配必须精确。 始终先运行步骤 1。--author 会进行子字符串匹配,但必须确认匹配的是正确的人(例如,查找“Josh S.”时不要匹配到“Joshua Smith”)。请使用 GitHub MCP get_me 工具或 git log 输出确认正确的全名。
  • 重命名可能经过多次转换。 文件可能从 contrib/chat/ 移动到 agentSessions/,再移动到 sessions/。必须沿重命名映射进行传递追踪。
  • 只报告合并差异中的文件(步骤 4)。作者参与过但之后被彻底删除的文件不应出现——它们不会进入上游。
  • 重命名映射必须包含所有作者的提交,不能只包含目标作者的提交。其他人经常负责重命名提交(例如批量重构或移动文件)。

Python 脚本示例

import subprocess, os

os.chdir('<repo_root>')
UPSTREAM = 'main'
AUTHOR = '<Author Name>'  # Resolve via `git log` or GitHub MCP `get_me`

# Step 2: author's files
commits = subprocess.check_output(
    ['git', 'log', f'--author={AUTHOR}', '--format=%H', f'{UPSTREAM}..HEAD'],
    text=True).strip().split('\n')
author_files = set()
for h in (c for c in commits if c):
    files = subprocess.check_output(
        ['git', 'diff-tree', '--no-commit-id', '--name-only', '-r', h],
        text=True).strip().split('\n')
    author_files.update(f for f in files if f)

# Step 3: rename map from ALL commits
all_commits = subprocess.check_output(
    ['git', 'log', '--format=%H', f'{UPSTREAM}..HEAD'],
    text=True).strip().split('\n')
rename_map = {}  # new_name -> set(old_names)
for h in (c for c in all_commits if c):
    out = subprocess.check_output(
        ['git', 'diff-tree', '--no-commit-id', '-r', '-M', h],
        text=True, timeout=5).strip()
    for line in out.split('\n'):
        if not line:
            continue
        parts = line.split('\t')
        if len(parts) >= 3 and 'R' in parts[0]:
            rename_map.setdefault(parts[2], set()).add(parts[1])

# Step 4: merge diff
diff_files = subprocess.check_output(
    ['git', 'diff', '--name-only', f'{UPSTREAM}..HEAD'],
    text=True).strip().split('\n')

# Step 5: classify
results = []
for f in (x for x in diff_files if x):
    if f in author_files:
        results.append(('DIRECT', f))
    else:
        # walk rename chain
        chain, to_check = set(), [f]
        while to_check:
            cur = to_check.pop()
            if cur in chain:
                continue
            chain.add(cur)
            to_check.extend(rename_map.get(cur, []))
        chain.discard(f)
        if chain & author_files:
            results.append(('VIA_RENAME', f))

# Step 6: stats
if results:
    stat = subprocess.check_output(
        ['git', 'diff', '--stat', f'{UPSTREAM}..HEAD', '--'] +
        [f for _, f in results], text=True)
    print(stat)

# Step 7: table
for kind, f in sorted(results, key=lambda x: x[1]):
    print(f'| {kind:12s} | {f} |')
print(f'\nTotal: {len(results)} files')
替代脚本

完成上述流程后,运行此脚本,对照分支差异交叉检查作者参与过的文件。可以同时检查包含和不包含 src/vs/sessions 的情况。

AUTHOR=""

# 1. Find commits by author on this branch (not on main)
git log main...HEAD --author="$AUTHOR" --format="%H"

# 2. Get unique files touched across all those commits, excluding src/vs/sessions/
git log main...HEAD --author="$AUTHOR" --format="%H" \
  | xargs -I{} git diff-tree --no-commit-id -r --name-only {} \
  | sort -u \
  | grep -v '^src/vs/sessions/'

# 3. Cross-reference with branch diff to keep only files still changed vs main
git log main...HEAD --author="$AUTHOR" --format="%H" \
  | xargs -I{} git diff-tree --no-commit-id -r --name-only {} \
  | sort -u \
  | grep -v '^src/vs/sessions/' \
  | while read f; do git diff main...HEAD --name-only -- "$f" 2>/dev/null; done \
  | sort -u

评论

支持 Markdown