通过 gh CLI 创建、分类、标签、分配 GitHub Issue
创建、搜索、分类和管理 GitHub Issues。每个部分先展示 gh,再展示 curl 备选方案。
github-auth skill)
if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
AUTH="gh"
else
AUTH="git"
if [ -z "$GITHUB_TOKEN" ]; then
if [ -f ~/.hermes/.env ] && grep -q "^GITHUB_TOKEN=" ~/.hermes/.env; then
GITHUB_TOKEN=$(grep "^GITHUB_TOKEN=" ~/.hermes/.env | head -1 | cut -d= -f2 | tr -d 'nr')
elif grep -q "github.com" ~/.git-credentials 2>/dev/null; then
GITHUB_TOKEN=$(grep "github.com" ~/.git-credentials 2>/dev/null | head -1 | sed 's|https://[^:]*:([^@]*)@.*|1|')
fi
fi
fi
REMOTE_URL=$(git remote get-url origin)
OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's|.*github.com[:/]||; s|.git$||')
OWNER=$(echo "$OWNER_REPO" | cut -d/ -f1)
REPO=$(echo "$OWNER_REPO" | cut -d/ -f2)
---
用 gh:
gh issue list
gh issue list --state open --label "bug"
gh issue list --assignee @me
gh issue list --search "authentication error" --state all
gh issue view 42
用 curl:
# 列出 open issues
curl -s
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/repos/$OWNER/$REPO/issues?state=open&per_page=20"
| python3 -c "
import sys, json
for i in json.load(sys.stdin):
if 'pull_request' not in i: # GitHub API 在 /issues 中也返回 PR
labels = ', '.join(l['name'] for l in i['labels'])
print(f"#{i['number']:5} {i['state']:6} {labels:30} {i['title']}")"
# 按标签过滤
curl -s
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/repos/$OWNER/$REPO/issues?state=open&labels=bug&per_page=20"
| python3 -c "
import sys, json
for i in json.load(sys.stdin):
if 'pull_request' not in i:
print(f"#{i['number']} {i['title']}")"
# 查看特定 issue
curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues/42
| python3 -c "
import sys, json
i = json.load(sys.stdin)
labels = ', '.join(l['name'] for l in i['labels'])
assignees = ', '.join(a['login'] for a in i['assignees'])
print(f"#{i['number']}: {i['title']}")
print(f"State: {i['state']} Labels: {labels} Assignees: {assignees}")
print(f"Author: {i['user']['login']} Created: {i['created_at']}")
print(f"n{i['body']}")"
# 搜索 issues
curl -s
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/search/issues?q=authentication+error+repo:$OWNER/$REPO"
| python3 -c "
import sys, json
for i in json.load(sys.stdin)['items']:
print(f"#{i['number']} {i['state']:6} {i['title']}")"
用 gh:
gh issue create
--title "Login redirect ignores ?next= parameter"
--body "## Description
After logging in, users always land on /dashboard.
## Steps to Reproduce
1. Navigate to /settings while logged out
2. Get redirected to /login?next=/settings
3. Log in
4. Actual: redirected to /dashboard (should go to /settings)
## Expected Behavior
Respect the ?next= query parameter."
--label "bug,backend"
--assignee "username"
用 curl:
curl -s -X POST
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues
-d '{
"title": "Login redirect ignores ?next= parameter",
"body": "## DescriptionnAfter logging in, users always land on /dashboard.nn## Steps to Reproducen1. Navigate to /settings while logged outn2. Get redirected to /login?next=/settingsn3. Log inn4. Actual: redirected to /dashboardnn## Expected BehaviornRespect the ?next= query parameter.",
"labels": ["bug", "backend"],
"assignees": ["username"]
}'
## Bug Description <发生了什么> ## Steps to Reproduce 1. <步骤> 2. <步骤> ## Expected Behavior <应该发生什么> ## Actual Behavior <实际发生了什么> ## Environment - OS: <系统> - Version: <版本>
## Feature Description <你想要什么> ## Motivation <为什么这会有用> ## Proposed Solution <如何实现> ## Alternatives Considered <其他方案>
用 gh:
gh issue edit 42 --add-label "priority:high,bug"
gh issue edit 42 --remove-label "needs-triage"
用 curl:
# 添加标签
curl -s -X POST
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues/42/labels
-d '{"labels": ["priority:high", "bug"]}'
# 删除标签
curl -s -X DELETE
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues/42/labels/needs-triage
# 列出仓库中可用的标签
curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/labels
| python3 -c "
import sys, json
for l in json.load(sys.stdin):
print(f" {l['name']:30} {l.get('description', '')}")"
用 gh:
gh issue edit 42 --add-assignee username
gh issue edit 42 --add-assignee @me
用 curl:
curl -s -X POST
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues/42/assignees
-d '{"assignees": ["username"]}'
用 gh:
gh issue comment 42 --body "Investigated — root cause is in auth middleware. Working on a fix."
用 curl:
curl -s -X POST
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues/42/comments
-d '{"body": "Investigated — root cause is in auth middleware. Working on a fix."}'
用 gh:
gh issue close 42
gh issue close 42 --reason "not planned"
gh issue reopen 42
用 curl:
# 关闭
curl -s -X PATCH
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues/42
-d '{"state": "closed", "state_reason": "completed"}'
# 重新打开
curl -s -X PATCH
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues/42
-d '{"state": "open"}'
当 PR 合并且 body 中包含正确关键词时,Issue 自动关闭:
Closes #42 Fixes #42 Resolves #42
从 Issue 创建分支:
用 gh:
gh issue develop 42 --checkout
用 git(手动等效):
git checkout main && git pull origin main
git checkout -b fix/issue-42-login-redirect
被要求对 issues 进行分类时:
# 用 gh
gh issue list --label "needs-triage" --state open
# 用 curl
curl -s
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/repos/$OWNER/$REPO/issues?labels=needs-triage&state=open"
| python3 -c "
import sys, json
for i in json.load(sys.stdin):
if 'pull_request' not in i:
print(f"#{i['number']} {i['title']}")"
对于批量操作,将 API 调用与 shell 脚本结合:
用 gh:
# 关闭所有带特定标签的 issues
gh issue list --label "wontfix" --json number --jq '.[].number' |
xargs -I {} gh issue close {} --reason "not planned"
用 curl:
# 列出带标签的 issue 编号,然后关闭每个
curl -s
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/repos/$OWNER/$REPO/issues?labels=wontfix&state=open"
| python3 -c "import sys,json; [print(i['number']) for i in json.load(sys.stdin)]"
| while read num; do
curl -s -X PATCH
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/issues/$num
-d '{"state": "closed", "state_reason": "not_planned"}'
echo "Closed #$num"
done
| 操作 | gh | curl 端点 |
| 列出 issues | `gh issue list` | `GET /repos/{o}/{r}/issues` |
| 查看 issue | `gh issue view N` | `GET /repos/{o}/{r}/issues/N` |
| 创建 issue | `gh issue create ...` | `POST /repos/{o}/{r}/issues` |
| 添加标签 | `gh issue edit N --add-label ...` | `POST /repos/{o}/{r}/issues/N/labels` |
| 分配 | `gh issue edit N --add-assignee ...` | `POST /repos/{o}/{r}/issues/N/assignees` |
| 评论 | `gh issue comment N --body ...` | `POST /repos/{o}/{r}/issues/N/comments` |
| 关闭 | `gh issue close N` | `PATCH /repos/{o}/{r}/issues/N` |
| 搜索 | `gh issue list --search "..."` | `GET /search/issues?q=...` |
评论区