git-project
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGitHub Project Management
GitHub 项目管理
Primary skill for organizing a repository's issues into an epic-based roadmap on a GitHub Project (v2) and running the day-to-day on it. Covers setup (project, fields, views, native workflows) and operations (create epics with sub-issues, drive Status, move work, prioritize). GitHub-only, via + (REST sub-issues + GraphQL).
gh projectgh apiThe conventions here are non-obvious and easy to get half-right: the UI nests issues by native parent/child links and tracks progress on a separate board Status field -- neither of which a markdown checklist or a closed issue touches. Get those two wrong and the work looks done while the structure silently drifts. This skill makes the flow correct-by-default.
核心技能:将仓库议题组织为GitHub Project (v2) 中基于Epic的路线图,并进行日常管理。 涵盖设置(项目、字段、视图、原生工作流)与操作(创建包含子议题的Epic、推动状态流转、移动工作、确定优先级)。仅适用于GitHub,通过 + (REST子议题 + GraphQL)实现。
gh projectgh api这里的约定并不直观,很容易只做对一半:UI通过原生父/子链接嵌套议题,并通过独立的看板状态字段跟踪进度——这两者都不受Markdown任务列表或已关闭议题的影响。如果这两点处理错误,工作看起来已完成,但结构会悄然偏离。本技能让工作流默认保持正确。
When to Use
适用场景
- Setting up a project/roadmap -- create the Project, fields (Status, Priority), the Epic + Upcoming views, enable native workflows
- Creating an epic with issues -- "make an epic X with these issues", "group these under an epic"
- Filing / moving work -- attach an issue under an epic, move an issue between epics, add new work
- Driving the board -- pick up an issue (-> In Progress), close one (-> Done), (re)prioritize
- Classifying work -- set native issue Types (Task/Bug/Feature) instead of type labels
- Milestone scoping -- create a milestone for a deliverable, assign issues, close it out; resolve "current milestone" / "milestone N"
- Migrating an existing repo's loose issues into this structure
- Configuring tool allowlists -- auto-approval patterns for read-only commands
gh project
- 设置项目/路线图——创建项目、字段(状态、优先级)、Epic + 待办视图,启用原生工作流
- 创建包含议题的Epic——“创建包含这些议题的Epic X”、“将这些议题归到一个Epic下”
- 提交/移动工作——将议题关联到Epic下,在Epic之间移动议题,添加新工作
- 推动看板流转——接手议题(→ 进行中)、关闭议题(→ 已完成)、(重新)确定优先级
- 分类工作——设置原生议题类型(任务/漏洞/功能)而非类型标签
- 里程碑规划——为交付成果创建里程碑、分配议题、完成收尾;确定“当前里程碑”/“里程碑N”
- 迁移——将现有仓库的零散议题迁移到该结构中
- 配置工具允许列表——为只读命令设置自动审批规则
gh project
Critical Rules
关键规则
These are the traps -- each is a place where the obvious action leaves the structure wrong.
- Epics nest by native sub-issues, NOT markdown checklists. A bullet is cosmetic; it does not create the parent/child link the UI and roadmap read. Link natively:
- [ ] #123/gh issue edit <epic> --add-sub-issue <child>(gh >= 2.94), or the REST sub-issues API. Seegh issue create --parent <epic>.references/sub-issues.md - Moving an issue between epics = re-parent the native link. One command: (replaces the old parent), then tidy body text. Editing bullets alone leaves it under the old epic -- the most common "looks moved but isn't" miss.
gh issue edit <child> --parent <newEpic> - The board Status is not automatic. Closing an issue does not set unless the native Item closed workflow is enabled. Set Status explicitly, or enable the native workflows once (see
Done).references/project-setup.md - Single-selects (Status, Priority) are set by option ID, not name. Look up field IDs + option IDs first (), then
gh project field-list <num> --owner @me --format json. Names silently no-op.item-edit - Views and workflow-enabling are one-time UI; everything else is scripted. There is no API to create/rename a view or toggle a workflow. Do those once in the UI (or copy a template); script the rest.
- Type and Milestone are issue metadata, NOT project fields. Set them on the issue (); the board mirrors them as built-in columns for grouping/filtering, but
gh issue edit <n> --type Bug --milestone "v1.0"cannot touch them and they never appear ingh project item-edit. Issue types exist only in org repos. Seefield-list.references/types-and-milestones.md
这些是容易踩的陷阱——每个都是看似合理的操作却会导致结构错误的地方。
- Epic通过原生子议题嵌套,而非Markdown任务列表。 这类项目符号仅为装饰性,不会创建UI和路线图识别的父/子链接。需通过原生方式链接:
- [ ] #123/gh issue edit <epic> --add-sub-issue <child>(gh >= 2.94),或REST子议题API。详见gh issue create --parent <epic>。references/sub-issues.md - 在Epic之间移动议题 = 重新设置原生父链接。 只需一条命令:(会替换旧的父议题),然后整理正文内容。仅编辑项目符号会导致议题仍归属于旧Epic——这是最常见的“看起来已移动但实际未移动”错误。
gh issue edit <child> --parent <newEpic> - 看板状态不会自动更新。 除非启用了原生“议题关闭”工作流,否则关闭议题不会将状态设为“已完成”。需显式设置状态,或一次性启用原生工作流(详见)。
references/project-setup.md - 单选字段(状态、优先级)通过选项ID设置,而非名称。 需先查询字段ID + 选项ID(),再执行
gh project field-list <num> --owner @me --format json。使用名称会静默失效。item-edit - 视图与工作流启用仅需在UI中操作一次;其余操作均可脚本化。 没有API可用于创建/重命名视图或切换工作流。只需在UI中操作一次(或复制模板);其余操作通过脚本实现。
- 类型与里程碑是议题元数据,而非项目字段。 在议题上设置();看板会将它们作为内置列进行镜像,用于分组/筛选,但
gh issue edit <n> --type Bug --milestone "v1.0"无法修改它们,且它们不会出现在gh project item-edit中。议题类型仅存在于组织仓库中。详见field-list。references/types-and-milestones.md
Prerequisites
前提条件
- GitHub only -- Projects v2 has no GitLab equivalent.
- >= 2.94 for the native issue flags used here (
gh,--type,--milestone,--parent); older--add-sub-issuefalls back to the REST recipes in the references.gh - Token scopes gate what works. shows them.
gh auth statuscommands and anygh projectGraphQL need theprojectV2scope (project);gh auth refresh -s projectalone is enough for read-only queries. Without the scope these fail with auth/permission errors even though everythingread:project-scoped works -- the classic "project features seem missing" trap. Issues, sub-issues, types, and milestones ride on the ordinaryreposcope; org-owned project access also relies onrepo.read:org - Projects are addressed by number under an (
--owneror an org login). The repo and project may have different owners. For an org-owned project, pass the org login to@me, and in GraphQL reads use--ownerinstead oforganization(login: "ORG") { projectV2 }(seeviewer { projectV2 }).references/cli-and-graphql.md
- 仅适用于GitHub——Projects v2在GitLab中没有等效功能。
- >= 2.94——才能使用此处的原生议题参数(
gh、--type、--milestone、--parent);旧版本--add-sub-issue需参考参考文档中的REST方案。gh - 令牌权限范围决定可用功能。 可查看权限范围。
gh auth status命令及任何gh projectGraphQL需要projectV2权限范围(project);仅gh auth refresh -s project权限足够用于只读查询。如果没有该权限范围,即使所有read:project权限范围的功能都正常,这些操作也会因权限错误失败——这是典型的“项目功能似乎缺失”陷阱。议题、子议题、类型和里程碑依赖常规repo权限范围;组织所属项目的访问还依赖repo权限。read:org - 项目通过(
--owner或组织登录名)下的编号标识。仓库和项目可能属于不同所有者。对于组织所属项目,需将组织登录名传递给@me,并在GraphQL查询中使用--owner替代organization(login: "ORG") { projectV2 }(详见viewer { projectV2 })。references/cli-and-graphql.md
The Model
模型
| Layer | What it is | Mechanism |
|---|---|---|
| Epic | A big work item -- an issue titled | |
| Sub-issue | A unit of work homed under exactly one epic | native parent/child link ( |
| Type | What kind of work: Task / Bug / Feature (org repos only) | native issue type ( |
| Milestone | A dated, closeable scope -- a release or delivery slice, often cross-epic | repo milestone ( |
| Board state | Where each item sits + its priority | Project fields: Status (Todo/In Progress/Done), Priority (single-select) |
Every issue is homed under an epic (or is one). Priority lives on the Project field (set via ) and kind lives on the native issue Type -- neither is a label. That keeps label noise near zero: the only label in play is (identifies epics for filtering/grouping; if the org defines a custom issue type, prefer that and drop even this label). Epics answer "what theme does this belong to"; milestones answer "when does this scope ship" -- an issue typically has both. The Epic view shows the tree; the Upcoming view filters out Done and sorts by Priority.
Priorityitem-editepicEpic| 层级 | 定义 | 实现方式 |
|---|---|---|
| Epic | 大型工作项——标题为 | |
| 子议题 | 归属于唯一Epic的工作单元 | 原生父/子链接( |
| 类型 | 工作类型:任务/漏洞/功能(仅组织仓库可用) | 原生议题类型( |
| 里程碑 | 带日期、可关闭的范围——版本发布或交付片段,通常跨Epic | 仓库里程碑( |
| 看板状态 | 每个工作项的位置 + 优先级 | 项目字段:状态(待办中/进行中/已完成)、优先级(单选) |
每个议题都归属于某个Epic(或本身就是Epic)。优先级存储在项目字段中(通过设置),工作类型存储在原生议题类型中——两者都不是标签。这将标签数量降至最低:唯一使用的标签是(用于筛选/分组识别Epic;如果组织定义了自定义议题类型,优先使用该类型并移除该标签)。Epic回答“该工作属于哪个主题”;里程碑回答“该范围何时交付”——一个议题通常同时具备两者。Epic视图显示树形结构;待办视图过滤掉已完成项并按优先级排序。
Priorityitem-editepicEpicOperations (Playbooks)
操作流程(操作手册)
Concrete sequences. are filled by gh from the current repo; is the project number. ID-discovery details are in .
{owner}/{repo}<num>references/cli-and-graphql.md具体步骤。由gh从当前仓库自动填充;是项目编号。ID查询细节见。
{owner}/{repo}<num>references/cli-and-graphql.mdCreate an epic with issues
创建包含议题的Epic
bash
undefinedbash
undefinedEpic issue (gh issue create prints the URL; the number is its last path segment)
创建Epic议题(gh issue create会输出URL;编号是URL的最后一段)
epic=$(gh issue create --title "Epic: <name>" --label epic --body "<goal>"); epic=${epic##*/}
epic=$(gh issue create --title "Epic: <name>" --label epic --body "<goal>"); epic=${epic##*/}
Link existing issues as NATIVE sub-issues (flag repeats; on a partial GraphQL failure re-run -- it's a
将现有议题链接为原生子议题(参数可重复;如果GraphQL部分失败,重新执行即可——这是临时的子议题请求限制,已链接的子议题不受影响)
transient sub-issue burst limit, and already-linked children are unaffected)
—
gh issue edit $epic --add-sub-issue <existing#> --add-sub-issue <existing#>
gh issue edit $epic --add-sub-issue <existing#> --add-sub-issue <existing#>
New work goes straight under the epic, typed and scoped at creation
新工作直接归到Epic下,创建时设置类型和范围
(--type is org-only: DROP it on personal repos or the whole command fails with 'type not found')
(--type仅组织仓库可用:个人仓库需移除该参数,否则整个命令会因'type not found'失败)
gh issue create --title "<task>" --type Task --milestone "<title>" --parent $epic --body "<detail>"
gh issue create --title "<task>" --type Task --milestone "<title>" --parent $epic --body "<detail>"
Put the epic on the board; its children auto-join IF the native "Auto-add sub-issues" workflow is on
将Epic添加到看板;如果启用了原生“自动添加子议题”工作流,其子议题会自动加入
gh project item-add <num> --owner @me --url "$(gh issue view $epic --json url --jq .url)"
gh project item-add <num> --owner @me --url "$(gh issue view $epic --json url --jq .url)"
(if that workflow is off, item-add each child's URL too)
(如果该工作流未启用,需逐个添加每个子议题的URL)
undefinedundefinedAdd an issue to an existing epic
将议题添加到现有Epic
bash
gh issue edit <epic> --add-sub-issue <child> # by number or URL; also re-parents if homed elsewherebash
gh issue edit <epic> --add-sub-issue <child> # 通过编号或URL;如果议题已归属于其他Epic,会重新设置父议题Move an issue between epics (re-parent -- rule 2)
在Epic之间移动议题(重新设置父议题——规则2)
bash
gh issue edit <child> --parent <newEpic> # replaces the old parent in one stepbash
gh issue edit <child> --parent <newEpic> # 一步替换旧的父议题then tidy any body bullets that referenced the old epic
然后整理正文中引用旧Epic的项目符号
undefinedundefinedClassify and scope (Type + Milestone -- rule 6)
分类与范围设置(类型 + 里程碑——规则6)
bash
gh issue edit <n> --type Bug # org repos only; Task/Bug/Feature (+ org customs)
gh issue edit <n> --milestone "v1.0" # by TITLE; --remove-milestone / --remove-type to unset
gh issue list --milestone "v1.0" --json number,title,state # -m takes a title or the milestone NUMBERbash
gh issue edit <n> --type Bug # 仅组织仓库可用;任务/漏洞/功能(+ 组织自定义类型)
gh issue edit <n> --milestone "v1.0" # 通过标题;使用--remove-milestone / --remove-type取消设置
gh issue list --milestone "v1.0" --json number,title,state # -m可接受标题或里程碑编号Milestones (create, resolve "current", close out a scope)
里程碑(创建、确定“当前里程碑”、完成范围收尾)
"Current milestone" = the open milestone with the smallest due date -- past-due included, that's the most urgent one. "Milestone N" = the milestone with number N (the URL segment), never "the Nth open one".
/milestone/Nbash
undefined“当前里程碑” = 具有最早截止日期的开放里程碑——包括已过期的里程碑,这是最紧急的一个。“里程碑N” = 编号为N的里程碑(URL中的段),而非“第N个开放里程碑”。
/milestone/Nbash
undefinedcreate (no gh subcommand -- REST)
创建(无gh子命令——使用REST)
gh api --method POST repos/{owner}/{repo}/milestones -f title="v1.0" -f due_on="2026-08-01T00:00:00Z" -f description="<scope>"
gh api --method POST repos/{owner}/{repo}/milestones -f title="v1.0" -f due_on="2026-08-01T00:00:00Z" -f description="<scope>"
current milestone (open only; undated ones sort last)
获取当前里程碑(仅开放状态;未设置日期的排在最后)
gh api repos/{owner}/{repo}/milestones --jq 'sort_by(.due_on // "9999-12-31") | first | {number, title, due_on}'
gh api repos/{owner}/{repo}/milestones --jq 'sort_by(.due_on // "9999-12-31") | first | {number, title, due_on}'
close out the scope once nothing is left open in it
当范围内无开放议题时,完成收尾
gh api repos/{owner}/{repo}/milestones/<N> --jq '{title, open_issues}' # expect open_issues: 0
gh api --method PATCH repos/{owner}/{repo}/milestones/<N> -f state=closed
undefinedgh api repos/{owner}/{repo}/milestones/<N> --jq '{title, open_issues}' # 预期open_issues: 0
gh api --method PATCH repos/{owner}/{repo}/milestones/<N> -f state=closed
undefinedPick up / finish / prioritize (board Status + Priority)
接手/完成/确定优先级(看板状态 + 优先级)
bash
undefinedbash
undefinedDiscover the item id + field/option ids once (see references/cli-and-graphql.md), then:
先查询项目项ID + 字段/选项ID(详见references/cli-and-graphql.md),然后:
pick up
接手工作
gh project item-edit --id <item> --project-id <proj> --field-id <statusField> --single-select-option-id <inProgress>
gh project item-edit --id <item> --project-id <proj> --field-id <statusField> --single-select-option-id <inProgress>
finish -- close the issue (pick ONE close form; the plain one means "completed"):
完成工作——关闭议题(选择一种关闭方式;普通关闭表示“已完成”):
gh issue close <issue> # done as planned
gh issue close <issue> --reason "not planned" # abandoned
gh issue close <issue> --duplicate-of <original> # duplicate; links it natively to the original (gh >= 2.88)
gh issue close <issue> # 按计划完成
gh issue close <issue> --reason "not planned" # 已放弃
gh issue close <issue> --duplicate-of <original> # 重复议题;将其原生链接到原始议题(gh >= 2.88)
closing normally advances the board via the native "Item closed" workflow -- nothing more to do.
正常关闭会通过原生“议题关闭”工作流更新看板状态——无需额外操作。
ONLY IF that workflow is off, set Status manually:
仅当该工作流未启用时,才需手动设置状态:
gh project item-edit --id <item> --project-id <proj> --field-id <statusField> --single-select-option-id <done>
gh project item-edit --id <item> --project-id <proj> --field-id <statusField> --single-select-option-id <done>
(re)prioritize
(重新)确定优先级
gh project item-edit --id <item> --project-id <proj> --field-id <priorityField> --single-select-option-id <p1>
> **Reference**: `references/cli-and-graphql.md` -- full command set, getting `<item>`/`<proj>`/field+option ids (`field-list`/`item-list --format json`), and `updateProjectV2ItemPosition` for roadmap ordering. `references/sub-issues.md` -- native link flags, the REST fallback (database-id requirement), re-parenting, and the ~25/request batch limit. `references/types-and-milestones.md` -- org issue types, milestone CRUD, and the current-milestone / milestone-N conventions in full.gh project item-edit --id <item> --project-id <proj> --field-id <priorityField> --single-select-option-id <p1>
> **参考文档**:`references/cli-and-graphql.md`——完整命令集、获取`<item>`/`<proj>`/字段+选项ID的方法(`field-list`/`item-list --format json`),以及用于路线图排序的`updateProjectV2ItemPosition`。`references/sub-issues.md`——原生链接参数、REST回退方案(需要数据库ID)、重新设置父议题,以及约25个/请求的批量限制。`references/types-and-milestones.md`——组织议题类型、里程碑增删改查,以及完整的当前里程碑/里程碑N约定。Setup (one-time)
初始设置(一次性操作)
Reference:-- end to end: create the Project, addreferences/project-setup.md/Status(and optionalPriority) fields, build the Epic and Upcoming views (UI -- no API), enable the native workflows (Item added, Auto-add sub-issues, Item closed -> Done), the optional template-copy fast-path, and the migration playbook for an existing repo.Stage
Quick shape:
bash
gh project create --owner @me --title "Roadmap"
gh project field-create <num> --owner @me --name "Priority" --data-type SINGLE_SELECT \
--single-select-options "P0,P1,P2,P3"
gh label create epic --color B60205 --description "Roadmap epic"Then, once in the UI: the Epic + Upcoming views and Settings -> Workflows toggles (these have no API).
参考文档:——端到端流程:创建项目、添加references/project-setup.md/Status(及可选Priority)字段、构建Epic和待办视图(UI操作——无API)、启用原生工作流(“添加项目项”、“自动添加子议题”、“议题关闭→已完成”)、可选的模板复制快速路径,以及现有仓库的迁移操作手册。Stage
快速步骤:
bash
gh project create --owner @me --title "Roadmap"
gh project field-create <num> --owner @me --name "Priority" --data-type SINGLE_SELECT \
--single-select-options "P0,P1,P2,P3"
gh label create epic --color B60205 --description "Roadmap epic"然后,在UI中完成:创建Epic + 待办视图,以及设置→工作流开关(这些无API支持)。
Read-Only vs Write Classification
只读与写入操作分类
- Read-only (safe to auto-approve): , GraphQL read queries,
gh project list/view/field-list/item-list,gh label list, milestone reads (gh issue list/view), issue-type reads (gh api repos/{owner}/{repo}/milestones)gh api orgs/{org}/issue-types - Write (require approval): ,
gh project create/copy/edit/link/field-create/item-add/item-edit/item-archive/item-delete,gh label create(incl.gh issue create/edit), milestone--type/--milestone/--parent/--add-sub-issue/POST/PATCH, sub-issueDELETE/POST, GraphQL mutationsDELETE
Reference: Seefor read-onlyreferences/allowlist.mdpatterns and the opt-in write set.gh project
- 只读(可安全自动审批):、GraphQL查询、
gh project list/view/field-list/item-list、gh label list、里程碑查询(gh issue list/view)、议题类型查询(gh api repos/{owner}/{repo}/milestones)gh api orgs/{org}/issue-types - 写入(需要审批):、
gh project create/copy/edit/link/field-create/item-add/item-edit/item-archive/item-delete、gh label create(包括gh issue create/edit)、里程碑--type/--milestone/--parent/--add-sub-issue/POST/PATCH、子议题DELETE/POST、GraphQL变更DELETE
参考文档:详见获取只读references/allowlist.md模式及可选写入操作集。gh project
Key Gotchas
关键注意事项
- Native links, not checklists -- the tree is built from sub-issue links; bullets are decoration (rule 1).
- Re-parent to move -- ; body edits alone don't move it (rule 2).
gh issue edit <child> --parent <newEpic> - REST sub-issues take the database -- if you drop to
id, fetch it withgh api .../sub_issues; the issue number won't work (the native--jq .idflags take numbers/URLs).gh - Single-selects set by option id -- discover ids with before
field-list --format json.item-edit - Views + workflow toggles are UI-only -- no API; do them once (or copy a template) (rule 5).
- Sub-issue mutations batch ~25/request -- larger batches hit ; a multi-
RESOURCE_LIMITS_EXCEEDEDedit can partially fail on the same limit -- re-running is safe.--add-sub-issue - Type/Milestone are not project fields -- set on the issue, mirrored on the board; can't set them and
item-editwon't show them (rule 6). Types are org-only (field-liston a personal repo:--type-- fall back to labels there).type "..." not found; available types: - "Current milestone" = smallest due date among open (past-due included); "milestone N" = number N, not the Nth open (see ).
references/types-and-milestones.md
- 使用原生链接,而非任务列表——树形结构由子议题链接构建;项目符号仅为装饰(规则1)。
- 重新设置父议题以移动——使用;仅编辑正文不会移动议题(规则2)。
gh issue edit <child> --parent <newEpic> - REST子议题需要数据库——如果使用
id,需通过gh api .../sub_issues获取;议题编号无效(原生--jq .id参数支持编号/URL)。gh - 单选字段通过选项ID设置——执行前,通过
item-edit查询ID。field-list --format json - 视图 + 工作流开关仅能在UI中操作——无API支持;只需操作一次(或复制模板)(规则5)。
- 子议题变更批量限制约25个/请求——更大批量会触发;多
RESOURCE_LIMITS_EXCEEDED编辑可能因同一限制部分失败——重新执行是安全的。--add-sub-issue - 类型/里程碑不是项目字段——在议题上设置,在看板上镜像显示;无法修改,
item-edit不会显示(规则6)。类型仅组织仓库可用(个人仓库使用field-list会提示--type——此时需回退到标签)。type "..." not found; available types: - “当前里程碑”= 开放里程碑中截止日期最早的一个(包括已过期);“里程碑N”= 编号为N的里程碑,而非第N个开放里程碑(详见)。
references/types-and-milestones.md