Skip to content

GitHub Issues 使用教程:从缺陷反馈到 Issue 驱动开发 ​

GitHub Issues 是仓库的工作跟踪单元:一个编号条目,携带标题、正文、讨论串和一组规划字段(类型、标签、负责人、里程碑、子 issue)。在提问者视角 issue 是反馈入口,在维护者视角是看板上的任务;对自动化来说,issue 还是可订阅的事件源——Pull Request 用关键字关闭 issue,Actions 响应 issue 的 opened/closed 事件运行工作流,REST API 和 Webhook 把 issue 接入外部工具链。

issue types、sub-issues 与高级搜索于 2025-04-09 正式可用,自定义 issue fields 于 2026-07-02 正式可用——这些新对象已经进了 REST 与 Webhook,老教程里的字段模型不再完整。

前置条件 ​

  • 有一个可提交的仓库;公开仓库的 issue 任何已登录用户都能创建(仓库在 Settings → Features 的 Issues 下拉里选了 "Collaborators only" 时除外),私有仓库需要账户有相应访问权限。
  • 仓库 Settings → Issues 功能已启用(禁用只阻止新建 issue,已有 issue 保留,重新启用后可继续访问)。
  • 想在组织仓库上使用 issue types / fields:需要组织管理员先在组织层面启用并配置类型。
  • 使用 gh CLI 需已 gh auth login;调用 REST 写接口需要对应权限的 token。

Issue 的对象模型 ​

一条 issue 由三层内容组成:

层成员说明
内容标题、Markdown 正文、任务清单、附件正文支持 - [ ] 复选框任务清单
规划字段issue type、labels、assignees、milestone、projects、sub-issues、blocked by/blocking、自定义 fields都是筛选与自动化条件
状态open / closed(completed、not_planned、duplicate 三种关闭原因)、locked、pinned关闭原因在 API 中是 state_reason 字段

模型里新加入的对象值得先看清:

  • 默认 issue type 是 Task、Bug、Feature 三种,组织在 Settings → Planning → Issue types 增删自定义类型,全组织最多 25 个,删除是永久操作。类型是单值字段,取代了"用 type/bug 标签凑数"的旧惯例。
  • Sub-issue 在 issue 之间建立父子关系,每个父 issue 最多挂 100 个子项、关系可嵌套八层;配合 blocked by / blocking,仓库内就能表达依赖图。
  • Issue fields 是组织级启用的自定义字段,按类型配置显示;Webhook 与 on: issues 事件也随之新增了 field_added / field_removed 动作类型。
  • 一个 issue 最多 10 个 assignees、最多一个 milestone(REST 的 milestone 参数是单值),labels 可以多选。

最短可用路径 ​

以"提交一个 bug 并用 PR 关闭"为主线:

  1. 仓库页面 Issues → New issue,或直接 gh issue create:
bash
gh issue create \
  --title "导出 CSV 在大数据量下超时" \
  --body "复现步骤与期望行为……" \
  --type Bug \
  --label needs-triage \
  --assignee @me
  1. 修复分支上提交代码,在 Pull Request 描述里写关联关键字:
text
Closes #123
  1. PR 合并进默认分支的瞬间,issue #123 自动关闭,Closed this as completed 记录在时间线上,PR 与 issue 两侧的 "Development" 区域互见。

成功信号:gh issue view 123 --json state --jq .state 输出 CLOSED;PR 详情页 "Development" 区域显示该 issue 并带勾;时间线上出现关闭事件与关联 PR 链接。

关闭关键字完整清单:close、closes、closed、fix、fixes、fixed、resolve、resolves、resolved,文档化语法只有两种:关键字 #123 和 关键字 OWNER/REPO#123。以下两个条件必须同时成立:关键字写在 PR 描述或 PR 内某条 commit 的 message 里;PR 的目标分支是仓库默认分支。目标为其它分支时不会自动关闭——这是"关键字失效"排错的第一检查点。跨仓库自动关闭要用 OWNER/REPO#123 语法;手动关联则相反——PR 侧 Development 栏只能关联同仓库 issue,从 issue 侧栏可以把其它仓库的 PR/分支关联进来。

生命周期操作 ​

操作权限说明
关闭 / 重开参与者关闭时可选 Completed / Not planned / Duplicate(选 Duplicate 需指定被重复的 issue),API 对应 state_reason
转移 transfer两仓库均为 write 及以上只能转移处于 open 状态的 issue;源与目标须同属一个账号或组织;gh issue transfer 123 other/repo,评论与 assignee 保留,标签按名称匹配保留,里程碑须名称与截止日期同时匹配才保留;旧链接自动重定向。私有仓库的 issue 不能转移到公开仓库
锁定 lock写权限原因枚举两套写法:REST lock_reason 为 off-topic、too heated、resolved、spam(连字符/空格),gh issue lock --reason 为 off_topic、too_heated、resolved、spam(下划线);锁定后非协作参与者不能评论,有写权限者可解锁
置顶 pin—每仓库最多 3 个,常用于"必读公告"
转 discussiontriage 及以上提问类 issue 一键转为 GitHub Discussions 帖子,帖子内容取自原 issue
删除admin / owner(组织仓库还须 org 拥有者先启用删除策略)Web UI 侧栏的 Delete issue 可永久删除:个人仓库由账户本人操作;REST 没有删除 issue 本体的端点,gh CLI 提供 gh issue delete {number} --yes;删除后协作参与者访问原 URL 只显示页面不存在。日常误建仍建议用关闭(not_planned)处置

规划与检索 ​

Labels:仓库级定义(名称、颜色、描述),Settings → Labels 管理;issue 可多选。label 事件(labeled / unlabeled)是自动化最常用的钩子之一。

Milestone:一组 issue 的目标版本或时间节点,带截止日和进度统计;一个 issue 只属于一个 milestone。

搜索与批量:issue 列表搜索框就是搜索引擎,常用限定符:

text
is:issue is:open label:"bug" type:Task
assignee:@me involves:octocat no:assignee no:label
linked:issue              # 已关联可关闭 issue 的 PR;未关联的用 is:pr -linked:issue
milestone:"v1.0" created:>2026-09-01

2025-04 起的高级搜索支持嵌套布尔表达式。

模板:让提交者把信息一次说全 ​

issue 模板只认 .github/ISSUE_TEMPLATE/ 目录(根目录或 docs/ 下的模板文件只对 Pull Request 模板成立)。放进去后,"New issue" 按钮变成模板选择页。两种格式:

Markdown 模板——frontmatter 预设元数据:

markdown
---
name: Bug report
about: 报告功能缺陷
title: "[BUG] "
labels: [bug, needs-triage]
type: Bug
assignees: []
---

## 复现步骤
1. …

## 期望行为

YAML 表单——结构化输入,提交内容按节渲染:

yaml
name: Bug report
description: 报告功能缺陷
labels: ["bug"]
type: Bug
body:
  - type: markdown
    attributes:
      value: 请填写以下信息
  - type: input
    id: version
    attributes:
      label: 软件版本
    validations:
      required: true
  - type: dropdown
    id: browsers
    attributes:
      label: 影响平台
      multiple: true
      options: [Linux, macOS, Windows]
  - type: textarea
    id: logs
    attributes:
      label: 相关日志
      render: shell
    validations:
      required: true

表单元素只有六类:markdown、input、textarea、dropdown、checkboxes、upload(附件上传)。validations 挂在各元素之下而非表单顶层,目前只文档化了 required 一项,且文档标注该字段只对公开仓库生效(upload 元素另有 accept 限定文件扩展名);长度与正则校验仍是社区未实现的功能请求,需要格式约束时,用后文"Actions 自动化"一节的机器人 workflow 在提交后二次检查并回帖提示。checkboxes 常被用作"发布前检查清单"。

config.yml 控制选择页外观:blank_issues_enabled: false 强制普通提交者走模板、维护者仍保留空白 issue 入口;contact_links 挂"提问去 Discussions / 安全问题看 SECURITY.md"之类的外部入口。

gh CLI 日常工作面 ​

bash
gh issue list --state open --label bug --json number,title,issueType,updatedAt
gh issue create --template "Bug report" --title "..."   # --template 取模板 name,不是文件名
gh issue develop 123 --checkout        # 为 issue 创建并签出关联分支
gh issue comment 123 --body "已定位根因"
gh issue edit 123 --add-label triaged --parent 100
gh issue close 123 --reason "not planned"
gh issue transfer 123 other-org/repo

gh issue develop 值得单独注意:develop 子命令按仓库配置生成分支(可 --base、--branch-repo 跨仓库),分支名出现在 issue 侧栏,并会被之后的 gh pr create 用作 base 分支;但 issue 与 PR 的正式关联仍靠 PR 正文里的 Closes #123 这类关键字,develop 本身不创建 PR 也不自动关联。gh issue create 支持 --type、--parent、--blocked-by、--assignee @me,gh issue list --json 可输出 issueType、subIssues、blockedBy、stateReason 等 27 个字段,适合脚本化盘点。

REST API 与 Webhook ​

核心端点(全部以 /repos/{owner}/{repo} 为前缀,另有组织级 GET /orgs/{org}/issues):

端点用途
GET/POST /issues列表 / 创建
GET/PATCH /issues/{issue_number}详情 / 改标题、正文、状态、state_reason
POST /issues/{issue_number}/comments评论
POST/DELETE /issues/{issue_number}/labels 等标签增删与替换
GET/POST /issues/{n}/sub_issues、DELETE /issues/{n}/sub_issue(单数)、PATCH /issues/{n}/sub_issues/priority、GET /issues/{n}/parent子 issue 关系;设置父级走父 issue 的 POST /sub_issues,查询父级用 GET .../parent(当前 API 版本 2026-03-10)
PUT/DELETE /issues/{n}/lock锁定
GET /issues/{n}/timeline事件时间线

鉴权:fine-grained token 的仓库权限 Issues: read/write 覆盖 issue、评论、标签、milestone;classic token 对私有仓库需 repo scope。速率:认证用户 5,000 请求/小时;Actions 内 GITHUB_TOKEN 为每仓库 1,000 请求/小时,写机器人工作流要按这个预算设计轮询频率。

Webhook issues 事件的 action 集合与 on: issues 类型一致:opened、edited、deleted、transferred、pinned、unpinned、closed、reopened、assigned、unassigned、labeled、unlabeled、locked、unlocked、milestoned、demilestoned、typed、untyped、field_added、field_removed。外部系统对接一般是订阅 issues + issue_comment 两个事件起步,写回评论和状态走 REST。

Actions 自动化 ​

.github/workflows/issue-triage.yml——新 issue 自动打标签并回帖引导:

yaml
name: Issue triage

on:
  issues:
    types: [opened]

permissions:
  issues: write

jobs:
  label:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.addLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              labels: ['needs-triage']
            })
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: '已收到,维护者会在一周内回复。'
            })

以下规则最容易踩空:

  1. 触发用的 workflow 文件必须存在于默认分支,特性分支上的同名文件不触发 issue 事件。
  2. 机器人要写 issue(评论、打标、关闭),必须显式 permissions: issues: write;GITHUB_TOKEN 的初始权限取自企业/组织/仓库的默认设置,不是可依赖的常量。
  3. on: issues 若不写 types,所有动作都会触发,机器人打标或编辑 issue 又会引发新一轮 labeled/edited,容易自我循环;按需收窄类型并在脚本里判断 actor。

issue_comment 事件支持 created / edited / deleted 等动作类型,配合 if: github.event.issue.pull_request 可以区分"给 PR 留评论",实现 @bot retest 这类口头触发。

能基于 Issues 做什么 ​

  • Issue 驱动开发:每个任务先建 issue 定验收标准,gh issue develop 开分支(develop 与 PR 关联的边界见上文 gh CLI 一节),PR 正文用 Closes # 收尾,合并即销账;从需求来源到实现落点的整个过程都留在仓库时间线里。
  • 结构化反馈表单是 triage 的第一道闸:YAML form 可以把版本、日志、复现步骤设成必填,配合 blank_issues_enabled: false 的强制策略(细节见上文模板一节),省掉反复追问的往返。
  • 机器人分诊与通知:opened 触发时按表单答案打标签、指派值班,经 webhook 推到团队聊天频道;typed、field_added 等事件可还原谁在何时改了状态,作为审计数据源。
  • Epic 可以直接拆在仓库里:父 issue 页面展示其 sub-issues 清单,blocked by / blocking 表达依赖,不用再引外部工具。
  • 看板与发布联动:新版 Projects 的状态、负责人字段与 issue 联动,Roadmaps 视图按日期字段排时间线;上一版本之后合并的 PR 会被 Releases 的自动生成发布说明汇总进草稿(细节见 Releases 教程)。

不适合的场景:问答与长期讨论放 Discussions(issue 有锁定成本且搜索语义偏任务);敏感漏洞用 Private Vulnerability Reporting / SECURITY.md,不要公开发 issue;需要私有不可见的内部任务别用公开仓库 issue。

权限与配额边界 ​

角色能做什么
匿名/只读用户公开仓库浏览、搜索、查看反应计数(添加反应等写操作需认证)
任何登录用户公开仓库提 issue、评论(仓库未启用 "Collaborators only" 限制时)
triage打标签、分配负责人、设置里程碑、关闭任意 issue、转 Discussions
write转移 issue(目标仓库也需 write)、锁定、编辑模板与标签定义、运行机器人 workflow
admin启用/禁用 Issues 功能、仓库安全与合并策略

issue types 与 fields 都在组织级 Settings → Planning 配置,启用后组织名下仓库通用;fields 按类型决定出现在哪些 issue 上。自定义类型删除为永久操作,经验上建议先在相关 issue 上清除该类型引用再回收。API 配额见上一节;批量脚本注意二级限流(内容生成类请求有独立预算),不要对大仓库做无过滤的全量 GET /issues 轮询。

故障处理 ​

症状原因与处理
PR 合并了但 issue 没自动关关键字不在 PR 描述(评论里不算);PR 目标不是默认分支;引用格式写成了 #123 OWNER/REPO 混用。若本次合并不会再触发,直接由维护者手动关闭并在评论里注明对应 PR
新 issue 不触发 workflowworkflow 文件不在默认分支;on.issues.types 拼写或漏 opened;仓库禁用了 Actions
机器人评论报 403忘写 permissions: issues: write,或外部 token 没有 fine-grained Issues 写权限
模板选择页不出现文件不在 .github/ISSUE_TEMPLATE/ 下(issue 模板放根目录或 docs/ 不生效,那里只用于 PR 模板);YAML form 顶层缺 name/description/body
--type Bug 报错组织未启用 issue types,或该类型被禁用、名称拼写不符;用 gh api /repos/{o}/{r}/issue-types --jq '.[].name' 核对
sub-issue 加不上已达每父 100 上限;关系最多嵌套八层
搜索 label:bug 搜不到标签实际是 type: Bug(新模型)或名称含空格需加引号 label:"help wanted"
webhook 收不到事件订阅方没勾 issues 事件;消费端若对 action 做严格枚举校验,需先补上 typed、field_added 等新值

验收清单 ​

  • [ ] 每个模板都能产出可复现、可分诊的信息;公开仓库的 YAML form 必填项生效,私有仓库用提交后的机器人检查兜底。
  • [ ] 团队 PR 规范包含 Closes #,抽查最近 10 个合并 PR 均有关联。
  • [ ] 机器人 workflow 显式收窄 types 并设最小 permissions。
  • [ ] issue types / labels 职责不重复:类型表达"是什么",标签表达"怎么流转"。
  • [ ] 外部同步脚本按 GITHUB_TOKEN 1,000/h 或 PAT 5,000/h 预算设计频率。
  • [ ] 提问类 issue 有转 Discussions 的处理路径。

参考资料 ​

全部公开文章由同一个站点构建和发布。