> 通过 gh CLI 管理 GitHub 仓库协作者,理解组织仓库与个人仓库的权限模型。
# Ubuntu/Debian
(type -p wget >/dev/null || sudo apt update && sudo apt install wget -y) \
&& sudo mkdir -p -m 755 /etc/apt/keyrings \
&& wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -y
# 验证安装
gh --version
# 基于浏览器的交互式认证(推荐)
gh auth login
# 基于令牌的认证(无头环境)
gh auth login --with-token < /home/user/.config/gh/token.txt
# 检查当前认证状态
gh auth status
管理协作者所需的最小令牌权限范围:
repo -- 对私有仓库的完全控制(向私有仓库添加协作者所需)admin:org -- 管理组织成员资格(用于组织仓库)read:user -- 读取用户资料数据
# 创建具有指定权限范围的令牌
gh auth token # 显示当前令牌(已脱敏)
# 添加协作者(发送邀请)
gh api \
-X PUT \
/repos/:owner/:repo/collaborators/:username \
-f permission=push
# 实际示例
gh api \
-X PUT \
/repos/BuckHuang/WebServer/collaborators/developer-name \
-f permission=push
个人仓库的权限级别:
| 权限 | 访问范围 |
|---|---|
read |
拉取代码、查看 issues/wiki |
triage |
读取 + 管理 issues/PR |
write |
推送代码、管理 issues/PR |
maintain |
写入 + 管理仓库设置(无法执行破坏性操作) |
admin |
完全控制 |
# 移除协作者
gh api \
-X DELETE \
/repos/:owner/:repo/collaborators/:username
# 实际示例
gh api -X DELETE /repos/BuckHuang/WebServer/collaborators/developer-name
# 列出所有协作者
gh api /repos/BuckHuang/WebServer/collaborators --jq '.[].login'
# 列出协作者及其权限
gh api /repos/BuckHuang/WebServer/collaborators \
--jq '.[] | "\(.login): \(.permissions | to_entries | map(select(.value == true) | .key) | join(", "))"'
# 列出待处理的邀请
gh api /repos/BuckHuang/WebServer/invitations --jq '.[].invitee.login'
# 查看仓库的所有待处理邀请
gh api /repos/BuckHuang/WebServer/invitations
# 接受邀请(以被邀请用户身份执行)
gh api -X PATCH /user/repository_invitations/:invitation_id
# 拒绝邀请
gh api -X DELETE /user/repository_invitations/:invitation_id
# 查看仓库详情
gh repo view BuckHuang/WebServer
# 克隆仓库
gh repo clone BuckHuang/WebServer
# 创建新仓库
gh repo create my-new-repo --private --clone
# Fork 仓库
gh repo fork owner/repo --clone
# 添加协作者(邀请)
gh api -X PUT repos/BuckHuang/WebServer/collaborators/username \
-f permission=push
# 更新协作者权限
gh api -X PUT repos/BuckHuang/WebServer/collaborators/username \
-f permission=admin
# 移除协作者
gh api -X DELETE repos/BuckHuang/WebServer/collaborators/username
# 检查用户是否为协作者
gh api repos/BuckHuang/WebServer/collaborators/username
# 返回 204 表示是协作者,返回 404 表示不是
#!/bin/bash
# batch-add-collaborators.sh -- 向所有 FPGA 仓库批量添加协作者
REPOS=("Common" "Top" "WebServer" "Sensor" "Camera")
OWNER="BuckHuang"
PERMISSION="push"
# 从文件中读取用户名(每行一个)
USERNAMES_FILE="$1"
if [ ! -f "$USERNAMES_FILE" ]; then
echo "用法:$0 <用户名文件>"
exit 1
fi
while IFS= read -r username; do
[ -z "$username" ] && continue
echo "=== 正在将 $username 添加到所有仓库 ==="
for repo in "${REPOS[@]}"; do
echo -n " BuckHuang/$repo ... "
response=$(gh api -X PUT "repos/$OWNER/$repo/collaborators/$username" \
-f permission="$PERMISSION" 2>&1)
rc=$?
if [ $rc -eq 0 ] || echo "$response" | grep -q "already"; then
echo "正常"
else
echo "失败:$(echo "$response" | head -1)"
fi
done
done < "$USERNAMES_FILE"
# 详细输出
gh api --verbose /repos/BuckHuang/WebServer/collaborators
# 显示响应头
gh api --include /repos/BuckHuang/WebServer
# 使用 curl 等效方式进行测试
gh api /repos/BuckHuang/WebServer/collaborators --jq '.'
| 令牌类型 | 使用场景 | 过期时间 |
|---|---|---|
| 细粒度令牌(新版) | 仓库专用、限定权限范围 | 最长 1 年 |
| 经典令牌(旧版) | 跨所有仓库的广泛权限 | 自定义/不限过期 |
| OAuth(gh auth login) | 完整 CLI 访问权限 | 刷新令牌 |
仓库权限:
- Contents(内容): 读和写
- Metadata(元数据): 只读(必选)
- Pull requests(拉取请求): 读和写
- Administration(管理): 读和写(管理协作者所需)
组织权限(如果管理组织仓库):
- Members(成员): 读和写
# 检查令牌有效性和权限范围
gh auth status
# 验证特定权限
gh api /user --jq '.login'
gh api /repos/BuckHuang/WebServer --jq '.permissions'
# 检查协作者管理功能是否正常
gh api /repos/BuckHuang/WebServer/collaborators > /dev/null && echo "正常" || echo "权限不足"
# gh 将令牌存储在配置文件中
ls -la /home/user/.config/gh/
# 手动令牌存储(用于脚本)
echo "ghp_xxxxxxxxxxxxxxxxxxxx" > /home/user/.config/gh/token.txt
chmod 600 /home/user/.config/gh/token.txt
# 使用环境变量
export GITHUB_TOKEN=$(cat /home/user/.config/gh/token.txt)
gh auth status
安全规则:
600
所有者:BuckHuang
├── 协作者 A(push)
├── 协作者 B(admin)
└── 协作者 C(read)
添加协作者直接授予其仓库级别的访问权限。
组织:BuckHuang-Org
├── 团队:FPGA-Devs → 包含仓库:Common、Top、WebServer
│ ├── 成员 A(maintain)
│ └── 成员 B(write)
├── 团队:External → 包含仓库:Sensor
│ └── 外部顾问(read)
└── 团队:Admins → 包含所有仓库
└── BuckHuang(admin)
组织权限在团队级别进行管理,而非按仓库逐个管理。
| 特性 | 个人仓库 | 组织仓库 |
|---|---|---|
| 邀请方式 | 直接邀请到仓库 | 通过团队成员资格 |
| 粒度 | 按仓库 | 通过团队按仓库 |
| 管理员 | admin 权限 |
团队维护者或组织所有者 |
| 外部协作者 | 直接添加到仓库 | 作为外部协作者添加到组织 |
| GitHub 免费版 | 协作者数量不限 | 免费版功能受限 |
| 适用场景 | 个人开发/小团队 | 团队/公司项目 |
# 列出组织团队
gh api /orgs/BuckHuang-Org/teams --jq '.[].name'
# 列出团队成员
gh api /orgs/BuckHuang-Org/teams/fpga-devs/members --jq '.[].login'
# 向团队添加成员
gh api -X PUT /orgs/BuckHuang-Org/teams/fpga-devs/memberships/username \
-f role=member
# 向团队添加仓库
gh api -X PUT /orgs/BuckHuang-Org/teams/fpga-devs/repos/BuckHuang-Org/WebServer \
-f permission=push
# 检查团队的仓库访问权限
gh api /orgs/BuckHuang-Org/teams/fpga-devs/repos --jq '.[].full_name'
git-share skill 提供一个简化的接口,用于向私有仓库添加/移除 GitHub 协作者。它将 gh api 命令封装在一个用户友好的界面之下。
# 添加协作者
git-share add <用户名> --repo <仓库名> [--permission push]
git-share add john-doe --repo WebServer
# 移除协作者
git-share remove <用户名> --repo <仓库名>
git-share remove john-doe --repo WebServer
# 列出协作者
git-share list --repo <仓库名>
git-share list --repo WebServer
# 添加到所有 5 个 FPGA 仓库
git-share add john-doe --all-fpga
/home/user/.local/bin/git-share
#!/bin/bash
# git-share -- 私有仓库的 GitHub 协作者管理
# 用法:git-share <add|remove|list> <用户名> --repo <仓库> [--permission push]
set -euo pipefail
# 配置
OWNER="BuckHuang"
DEFAULT_PERMISSION="push"
FPGA_REPOS=("Common" "Top" "WebServer" "Sensor" "Camera")
REPOS_CONF="/home/user/.local/share/multi-repo/repos.conf"
# 颜色定义
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
usage() {
cat << EOF
用法:git-share <命令> [选项]
命令:
add <用户名> --repo <仓库> [--permission push|read|admin] 添加协作者
add <用户名> --all-fpga [--permission push] 添加到所有 FPGA 仓库
remove <用户名> --repo <仓库> 移除协作者
list --repo <仓库> 列出协作者
check --repo <仓库> [用户名] 检查协作者状态
选项:
--repo <名称> 仓库短名称(例如:WebServer、Common)
--all-fpga 应用到所有 5 个 FPGA 仓库
--permission <级别> push | read | triage | maintain | admin(默认:push)
EOF
exit 1
}
# 将短名称解析为完整的仓库 full_name
resolve_repo() {
local name="$1"
echo "$OWNER/$name"
}
# 向单个仓库添加协作者
add_collaborator() {
local username="$1"
local repo="$2"
local permission="$3"
local full_repo; full_repo="$(resolve_repo "$repo")"
echo -n " ${repo} ... "
# 检查是否已经是协作者
status=$(gh api "repos/$full_repo/collaborators/$username" 2>&1)
if [ $? -eq 0 ]; then
echo -e "${YELLOW}已存在${NC}"
return 0
fi
# 添加协作者
response=$(gh api -X PUT "repos/$full_repo/collaborators/$username" \
-f permission="$permission" 2>&1)
rc=$?
if [ $rc -eq 0 ]; then
echo -e "${GREEN}已邀请${NC}(权限:$permission)"
elif echo "$response" | grep -qi "already"; then
echo -e "${YELLOW}已存在${NC}"
else
echo -e "${RED}失败${NC}:$(echo "$response" | jq -r '.message // "未知错误"')"
return 1
fi
}
# 从单个仓库移除协作者
remove_collaborator() {
local username="$1"
local repo="$2"
local full_repo; full_repo="$(resolve_repo "$repo")"
echo -n " ${repo} ... "
response=$(gh api -X DELETE "repos/$full_repo/collaborators/$username" 2>&1)
rc=$?
if [ $rc -eq 0 ]; then
echo -e "${GREEN}已移除${NC}"
elif [ $rc -eq 4 ]; then
echo -e "${YELLOW}未找到${NC}"
else
echo -e "${RED}失败${NC}:$(echo "$response" | jq -r '.message // "未知错误"')"
return 1
fi
}
# 列出协作者
list_collaborators() {
local repo="$1"
local full_repo; full_repo="$(resolve_repo "$repo")"
echo -e "=== ${full_repo} 的协作者 ==="
gh api "repos/$full_repo/collaborators" \
--jq '.[] | " \(.login) (\(.permissions | to_entries | map(select(.value == true) | .key) | join(", ")))"'
echo ""
echo "=== 待处理邀请 ==="
invitations=$(gh api "repos/$full_repo/invitations" --jq '.[].invitee.login' 2>/dev/null)
if [ -z "$invitations" ]; then
echo " (无)"
else
echo "$invitations" | while read -r user; do
echo " $user(等待接受)"
done
fi
}
# 检查协作者状态
check_collaborator() {
local repo="$1"
local username="$2"
local full_repo; full_repo="$(resolve_repo "$repo")"
if gh api "repos/$full_repo/collaborators/$username" >/dev/null 2>&1; then
local perms; perms=$(gh api "repos/$full_repo/collaborators/$username" \
--jq '.permissions | to_entries | map(select(.value == true) | .key) | join(", ")')
echo -e "${GREEN}是${NC} — $username 是 $full_repo 的协作者"
echo " 权限:$perms"
else
echo -e "${RED}否${NC} — $username 不是 $full_repo 的协作者"
fi
}
# ======== 主程序 ========
COMMAND="${1:-}"
shift || true
case "$COMMAND" in
add)
USERNAME="$1"; shift
PERMISSION="$DEFAULT_PERMISSION"
TARGET_REPO=""
ALL_FPGA=false
while [ $# -gt 0 ]; do
case "$1" in
--repo) TARGET_REPO="$2"; shift 2 ;;
--permission) PERMISSION="$2"; shift 2 ;;
--all-fpga) ALL_FPGA=true; shift ;;
*) usage ;;
esac
done
if $ALL_FPGA; then
echo -e "正在将 ${USERNAME} 共享到所有 5 个 FPGA 仓库(${PERMISSION})..."
for repo in "${FPGA_REPOS[@]}"; do
add_collaborator "$USERNAME" "$repo" "$PERMISSION"
done
elif [ -n "$TARGET_REPO" ]; then
echo -e "正在将 ${TARGET_REPO} 共享给 ${USERNAME}(${PERMISSION})..."
add_collaborator "$USERNAME" "$TARGET_REPO" "$PERMISSION"
else
usage
fi
;;
remove)
USERNAME="$1"; shift
TARGET_REPO=""
while [ $# -gt 0 ]; do
case "$1" in
--repo) TARGET_REPO="$2"; shift 2 ;;
*) usage ;;
esac
done
if [ -n "$TARGET_REPO" ]; then
echo -e "正在从 ${TARGET_REPO} 移除 ${USERNAME}..."
remove_collaborator "$USERNAME" "$TARGET_REPO"
else
usage
fi
;;
list)
TARGET_REPO=""
while [ $# -gt 0 ]; do
case "$1" in
--repo) TARGET_REPO="$2"; shift 2 ;;
*) usage ;;
esac
done
[ -z "$TARGET_REPO" ] && usage
list_collaborators "$TARGET_REPO"
;;
check)
TARGET_REPO=""
USERNAME=""
while [ $# -gt 0 ]; do
case "$1" in
--repo) TARGET_REPO="$2"; shift 2 ;;
*) USERNAME="$1"; shift ;;
esac
done
[ -z "$TARGET_REPO" ] && usage
check_collaborator "$TARGET_REPO" "$USERNAME"
;;
*)
usage
;;
esac
chmod +x /home/user/.local/bin/git-share
Claude 的 git-share skill 封装了这个脚本:
Skill:git-share
用途:管理 GitHub 私有仓库的协作者共享
参数:通过自然语言描述要执行的操作
例如:"将 john 添加为 WebServer 的管理员"
"从所有仓库中移除 alice"
"列出 Common 的协作者"
实现方式:
1. 解析用户请求以提取:操作、用户名、仓库、权限
2. 使用 repos.conf 映射解析仓库短名称
3. 使用适当的参数执行 git-share 脚本
4. 向用户报告结果
| 错误 | 原因 | 解决方法 |
|---|---|---|
gh auth status 显示"未登录" |
令牌已过期或未设置 | gh auth login |
Resource not accessible by integration |
细粒度令牌缺少仓库访问权限 | 在令牌设置中添加仓库 |
Must have admin rights |
当前用户没有管理员权限 | 需要仓库所有者授予权限 |
Invitation already exists |
用户已收到邀请(等待处理中) | 重新发送或检查待处理列表 |
Not Found (404) |
仓库名拼写错误或仓库是私有的 | 检查 owner/repo 拼写 |
# 端到端测试
git-share list --repo WebServer
git-share check --repo WebServer some-user
git-share add test-collaborator --repo WebServer --permission read
git-share list --repo WebServer # 应该显示新的邀请
git-share remove test-collaborator --repo WebServer
# 查看当前登录用户
gh auth status
# 列出我的仓库
gh repo list BuckHuang --limit 30
# 向单个仓库添加协作者
git-share add <用户> --repo <名称> [--permission push]
# 向所有 FPGA 仓库添加协作者
git-share add <用户> --all-fpga
# 移除协作者
git-share remove <用户> --repo <名称>
# 列出协作者
git-share list --repo <名称>
# 检查某人是否有访问权限
git-share check --repo <名称> <用户>