issue-fields-migration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Issue Fields Migration

议题字段迁移

Bulk-copy field values from Project V2 fields or repo labels to org-level issue fields. This skill guides you through discovering field mappings, previewing changes, and executing the migration with progress reporting. Supports two migration sources: project fields (single project) and repo labels (one or more repos).
批量将Project V2字段或仓库标签的值复制到组织级议题字段。本技能将引导你完成字段映射发现、变更预览以及带进度报告的迁移执行流程。支持两种迁移源:项目字段(单个项目)和仓库标签(一个或多个仓库)。

When to Use

适用场景

  • User added org-level issue fields that overlap with existing project fields
  • User wants to copy values from project fields to issue fields before deleting the old project fields
  • User asks about "migrating", "transferring", or "copying" project field data to issue fields
  • User wants to convert repo labels (e.g., p0, p1, p2, p3) into issue field values (e.g., Priority field)
  • User asks about replacing labels with issue fields or cleaning up labels after adopting issue fields
  • 用户添加了与现有项目字段重叠的组织级议题字段
  • 用户希望在删除旧项目字段前,将值从项目字段复制到议题字段
  • 用户询问关于“迁移”、“转移”或“复制”项目字段数据到议题字段的问题
  • 用户希望将仓库标签(如p0、p1、p2、p3)转换为议题字段值(如优先级字段)
  • 用户询问如何用议题字段替换标签,或在采用议题字段后清理标签

Prerequisites

前提条件

  • The target org must have issue fields enabled
  • The issue fields must already exist at the org level
  • For project field migration: issue fields must be added to the project
  • For label migration: labels must exist on the target repo(s)
  • The user must have write access to the repos (and project, if migrating project fields)
  • gh
    CLI must be authenticated with appropriate scopes
  • 目标组织必须已启用议题字段
  • 议题字段必须已在组织级别创建
  • 对于项目字段迁移:议题字段必须已添加到项目中
  • 对于标签迁移:标签必须存在于目标仓库中
  • 用户必须拥有仓库的写入权限(如果迁移项目字段,还需拥有项目的写入权限)
  • gh
    CLI必须已通过适当的权限范围认证

Available Tools

可用工具

MCP Tools (read operations)

MCP工具(只读操作)

ToolPurpose
mcp__github__projects_list
List project fields (
list_project_fields
), list project items with values (
list_project_items
)
mcp__github__projects_get
Get details of a specific project field or item
工具用途
mcp__github__projects_list
列出项目字段(
list_project_fields
)、列出带值的项目项(
list_project_items
mcp__github__projects_get
获取特定项目字段或项目项的详情

CLI / REST API

CLI / REST API

OperationCommand
List org issue fields
gh api /orgs/{org}/issue-fields -H "X-GitHub-Api-Version: 2026-03-10"
Read issue field values
gh api /repos/{owner}/{repo}/issues/{number}/issue-field-values -H "X-GitHub-Api-Version: 2026-03-10"
Write issue field values
gh api /repositories/{repo_id}/issues/{number}/issue-field-values -X POST -H "X-GitHub-Api-Version: 2026-03-10" --input -
Get repository ID
gh api /repos/{owner}/{repo} --jq .id
List repo labels
gh label list -R {owner}/{repo} --limit 1000 --json name,color,description
List issues by label
gh issue list -R {owner}/{repo} --label "{name}" --state all --json number,title,labels --limit 1000
Remove label from issue
gh api /repos/{owner}/{repo}/issues/{number}/labels/{label_name} -X DELETE
See references/issue-fields-api.md, references/projects-api.md, and references/labels-api.md for full API details.
操作命令
列出组织议题字段
gh api /orgs/{org}/issue-fields -H "X-GitHub-Api-Version: 2026-03-10"
读取议题字段值
gh api /repos/{owner}/{repo}/issues/{number}/issue-field-values -H "X-GitHub-Api-Version: 2026-03-10"
写入议题字段值
gh api /repositories/{repo_id}/issues/{number}/issue-field-values -X POST -H "X-GitHub-Api-Version: 2026-03-10" --input -
获取仓库ID
gh api /repos/{owner}/{repo} --jq .id
列出仓库标签
gh label list -R {owner}/{repo} --limit 1000 --json name,color,description
按标签列出议题
gh issue list -R {owner}/{repo} --label "{name}" --state all --json number,title,labels --limit 1000
从议题移除标签
gh api /repos/{owner}/{repo}/issues/{number}/labels/{label_name} -X DELETE
有关完整API详情,请参阅 references/issue-fields-api.mdreferences/projects-api.mdreferences/labels-api.md

Workflow

工作流程

Step 0: Migration Source

步骤0:选择迁移源

Ask the user what they are migrating:
  1. "Are you migrating labels or project fields?"
  2. If the user says labels:
    • Ask: "Which org and repo(s) contain the labels?"
    • Ask: "Which labels do you want to migrate?" (they can name them or say "show me the labels first")
  3. If the user says project fields:
    • Ask: "Can you share the link to your project or tell me the org name and project number?"
    • Ask: "Which field do you want to migrate?"

询问用户需要迁移的内容:
  1. “你要迁移标签还是项目字段?”
  2. 如果用户选择标签
    • 询问:“包含这些标签的组织和仓库是哪些?”
    • 询问:“你要迁移哪些标签?”(用户可以直接命名标签,或说“先展示所有标签”)
  3. 如果用户选择项目字段
    • 询问:“能否分享你的项目链接,或者告诉我组织名称和项目编号?”
    • 询问:“你要迁移哪个字段?”

Label Migration Flow

标签迁移流程

Use this flow when the user wants to convert repo labels into issue field values. Labels can only map to
single_select
issue fields (each label name maps to one option value).
当用户希望将仓库标签转换为议题字段值时使用此流程。标签只能映射到
single_select
类型的议题字段(每个标签名称对应一个选项值)。

Phase L1: Input & Label Discovery

阶段L1:输入与标签发现

  1. Ask the user for: org name and repo(s) to migrate.
  2. Fetch labels from each repo:
bash
gh label list -R {owner}/{repo} --limit 1000 --json name,color,description
  1. Fetch org issue fields:
bash
gh api /orgs/{org}/issue-fields \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  --jq '.[] | {id, name, content_type, options: [.options[]?.name]}'
  1. Filtering (for repos with many labels): if the repo has 50+ labels, group by common prefix (e.g.,
    priority-*
    ,
    team-*
    ,
    type-*
    ) or color. Let the user filter with "show labels matching priority" or "show blue labels" before mapping. Never dump 100+ labels at once.
  2. Ask the user which labels map to which issue field and option. Support these patterns:
    • Single label to single field: e.g., label "bug" → Type field, "Bug" option
    • Multiple labels to one field (bulk): e.g., labels p0, p1, p2, p3 → Priority field with matching options
    • Multiple labels to multiple fields: e.g., p1 → Priority + frontend → Team. Handle as separate mapping groups.
  3. Auto-suggest mappings: for each label, attempt to match issue field options using these patterns (in order):
    • Exact match (case-insensitive): label
      Bug
      → option
      Bug
    • Prefix-number (
      {prefix}-{n}
      {P}{n}
      ): label
      priority-1
      → option
      P1
    • Strip separators (hyphens, underscores, spaces): label
      good_first_issue
      → option
      Good First Issue
    • Substring containment: label
      type: bug
      → option
      Bug
    Present all suggestions at once for the user to confirm, correct, or skip.
Example output:
Labels in github/my-repo (showing relevant ones):
  p0, p1, p2, p3, bug, enhancement, frontend, backend

Org issue fields (single_select):
  Priority: Critical, P0, P1, P2, P3
  Type: Bug, Feature, Task
  Team: Frontend, Backend, Design

Suggested mappings:
  Label "p0" → Priority "P0"
  Label "p1" → Priority "P1"
  Label "p2" → Priority "P2"
  Label "p3" → Priority "P3"
  Label "bug" → Type "Bug"
  Label "frontend" → Team "Frontend"
  Label "backend" → Team "Backend"
  Label "enhancement" → (no auto-match; skip or map manually)

Confirm, adjust, or add more mappings?
  1. 向用户获取:组织名称目标仓库
  2. 从每个仓库获取标签:
bash
gh label list -R {owner}/{repo} --limit 1000 --json name,color,description
  1. 获取组织议题字段:
bash
gh api /orgs/{org}/issue-fields \\
  -H "X-GitHub-Api-Version: 2026-03-10" \\
  --jq '.[] | {id, name, content_type, options: [.options[]?.name]}'
  1. 过滤(针对标签较多的仓库):如果仓库有50个以上标签,按通用前缀(如
    priority-*
    team-*
    type-*
    )或颜色分组。在映射前让用户通过“展示优先级相关标签”或“展示蓝色标签”进行筛选,切勿一次性展示100个以上标签。
  2. 询问用户哪些标签对应哪些议题字段及选项,支持以下模式:
    • 单个标签对应单个字段:例如,标签“bug” → 类型字段的“Bug”选项
    • 多个标签对应单个字段(批量):例如,标签p0、p1、p2、p3 → 优先级字段的对应选项
    • 多个标签对应多个字段:例如,p1 → 优先级 + frontend → 团队。作为独立映射组处理。
  3. 自动建议映射:针对每个标签,尝试通过以下模式匹配议题字段选项(按顺序):
    • 完全匹配(不区分大小写):标签
      Bug
      → 选项
      Bug
    • 前缀-数字格式(
      {prefix}-{n}
      {P}{n}
      :标签
      priority-1
      → 选项
      P1
    • 移除分隔符(连字符、下划线、空格):标签
      good_first_issue
      → 选项
      Good First Issue
    • 子字符串包含:标签
      type: bug
      → 选项
      Bug
    将所有建议一次性呈现给用户,供其确认、调整或跳过。
示例输出:
github/my-repo中的标签(展示相关标签):
  p0, p1, p2, p3, bug, enhancement, frontend, backend

组织议题字段(single_select类型):
  优先级:Critical, P0, P1, P2, P3
  类型:Bug, Feature, Task
  团队Frontend, Backend, Design

建议映射:
  标签"p0" → 优先级"P0"
  标签"p1" → 优先级"P1"
  标签"p2" → 优先级"P2"
  标签"p3" → 优先级"P3"
  标签"bug" → 类型"Bug"
  标签"frontend" → 团队"Frontend"
  标签"backend" → 团队"Backend"
  标签"enhancement" → (无自动匹配;跳过或手动映射)

请确认、调整或添加更多映射?

Phase L2: Conflict Detection

阶段L2:冲突检测

After finalizing the label-to-option mappings, check for conflicts. A conflict occurs when an issue has multiple labels that map to the same issue field (since single_select fields can hold only one value).
  1. Group label mappings by target issue field.
  2. For each field with multiple label sources, note the potential for conflicts.
  3. Ask the user for a conflict resolution strategy:
    • First match: use the first matching label found (by order of label mapping list)
    • Skip: skip issues with conflicting labels and report them
    • Manual: present each conflict for the user to decide
Example:
Potential conflict: labels "p0" and "p1" both map to the Priority field.
If an issue has both labels, which value should win?

Options:
  1. First match (use "p0" since it appears first in the mapping)
  2. Skip conflicting issues
  3. I'll decide case by case
确定标签到选项的映射后,检查冲突。当一个议题有多个标签映射到同一个议题字段时,会发生冲突(因为single_select字段只能存储一个值)。
  1. 按目标议题字段对标签映射进行分组。
  2. 对于有多个标签源的字段,标注潜在冲突。
  3. 询问用户冲突解决策略:
    • 优先匹配:使用映射列表中第一个匹配的标签
    • 跳过:跳过存在冲突的议题并报告
    • 手动处理:逐个呈现冲突供用户决定
示例:
潜在冲突:标签"p0"和"p1"都映射到优先级字段。
如果一个议题同时有这两个标签应采用哪个值?

选项:
  1. 优先匹配(使用映射列表中先出现的"p0")
  2. 跳过冲突议题
  3. 我将逐个决定

Phase L3: Pre-flight Checks & Data Scan

阶段L3:预检查与数据扫描

  1. For each repo, verify write access and cache the
    repository_id
    :
bash
gh api /repos/{owner}/{repo} --jq '{full_name, id, permissions: .permissions}'
  1. For each label in the mapping, fetch matching issues:
bash
gh issue list -R {owner}/{repo} --label "{label_name}" --state all \
  --json number,title,labels,type --limit 1000
Warning:
--limit 1000
silently truncates results. If you expect a label may have more than 1000 issues, paginate manually or verify the total count first (e.g.,
gh issue list --label "X" --state all --json number | jq length
).
PR filtering:
gh issue list
returns both issues and PRs. Include
type
in the
--json
output and filter for
type == "Issue"
if the user only wants issues migrated.
  1. If all selected labels return 0 issues, stop and tell the user. Suggest: try different labels, check spelling, or try a different repository. Do not proceed with an empty migration.
  2. For multi-repo migrations, repeat across all specified repos.
  3. For each issue found:
    • Check if the issue already has a value for the target issue field (skip if set).
    • Detect multi-label conflicts (issue has two labels for the same field).
    • Apply the conflict resolution strategy chosen in Phase L2.
    • Classify: migrate, skip (already set), skip (conflict), or skip (no matching label).
  1. 针对每个仓库,验证写入权限并缓存
    repository_id
bash
gh api /repos/{owner}/{repo} --jq '{full_name, id, permissions: .permissions}'
  1. 针对映射中的每个标签,获取匹配议题:
bash
gh issue list -R {owner}/{repo} --label "{label_name}" --state all \\
  --json number,title,labels,type --limit 1000
注意
--limit 1000
会自动截断结果,如果预计某个标签对应的议题超过1000个,请手动分页或先验证总数(例如
gh issue list --label "X" --state all --json number | jq length
)。
PR过滤
gh issue list
会同时返回议题和PR。如果用户仅需迁移议题,请在
--json
中包含
type
并筛选
type == "Issue"
  1. 如果所有选中标签对应的议题数为0,请停止操作并告知用户建议:尝试其他标签、检查拼写或更换仓库。不要执行空迁移。
  2. 对于多仓库迁移,在所有指定仓库重复上述步骤。
  3. 针对找到的每个议题:
    • 检查议题是否已设置目标字段值(如果已设置则跳过)。
    • 检测多标签冲突(议题有两个对应同一字段标签)。
    • 应用阶段L2中选择的冲突解决策略。
    • 分类:迁移跳过(已设置)跳过(冲突)跳过(无匹配标签)

Phase L4: Preview / Dry-Run

阶段L4:预览/试运行

Present a summary before any writes.
Example preview:
Label Migration Preview

Source: labels in github/my-repo
Target fields: Priority, Type, Team

| Category                | Count |
|-------------------------|-------|
| Issues to migrate       |   156 |
| Already set (skip)      |    12 |
| Conflicting labels (skip)|    3 |
| Total issues with labels|   171 |

Label breakdown:
  "p1" → Priority "P1": 42 issues
  "p2" → Priority "P2": 67 issues
  "p3" → Priority "P3": 38 issues
  "bug" → Type "Bug": 9 issues

Sample changes (first 5):
  github/my-repo#101: Priority → "P1"
  github/my-repo#203: Priority → "P2", Type → "Bug"
  github/my-repo#44:  Priority → "P3"
  github/my-repo#310: Priority → "P1"
  github/my-repo#7:   Type → "Bug"

After migration, do you also want to remove the migrated labels from issues? (optional)

Estimated time: ~24s (156 API calls at 0.15s each)

Proceed?
在执行写入操作前呈现摘要。
示例预览:
标签迁移预览

源:github/my-repo中的标签
目标字段:优先级、类型、团队

| 分类                | 数量 |
|-------------------------|-------|
| 待迁移议题       |   156 |
|已设置跳过      |    12 |
| 标签冲突跳过|    3 |
|含标签议题总数|   171 |

标签细分:
 "p1" → 优先级"P1": 49个议题
 "p9" → 优先级"P2": 67个议题
 "p3" → 优先级"P3": 38个议题
 "bug" → 类型"Bug": 9个议题

示例变更(前5个):
 github/my-repo#901: 优先级 → "P1"
 github/my-repo#203: 优先级 → "P2", 类型 → "Bug"
 github/my-repo#44:  优先级 → "P3"
 github/my-repo#310: 优先级 → "P1"
 github/my-repo#7:   类型 → "Bug"

迁移完成后是否要从议题中移除已迁移的标签?(可选)

预计耗时:~24秒(156次API调用,每次0.15秒)

是否继续?

Phase L5: Execution

阶段L9:执行

  1. For each issue to migrate, write the issue field value (same endpoint as project field migration):
bash
echo '{"issue_field_values": [{"field_id": FIELD_ID, "value": "OPTION_NAME"}]}' | \
  gh api /repositories/{repo_id}/issues/{number}/issue-field-values \
    -X POST \
    -H "X-GitHub-Api-Version: 2026-03-10" \
    --input -
Replace
FIELD_ID
with the integer field ID (e.g.,
1
) and
OPTION_NAME
with the option name string.
  1. If the user opted to remove labels, remove each migrated label after successful field write:
bash
gh api /repos/{owner}/{repo}/issues/{number}/labels/{label_name} -X DELETE
URL-encode label names that contain spaces or special characters.
  1. Pacing: 100ms delay between calls. Exponential backoff on HTTP 429 (1s, 2s, 4s, up to 30s).
  2. Progress: report every 25 items (e.g., "Migrated 75/156 issues...").
  3. Error handling: log failures but continue. Include label removal failures separately.
  4. Final summary:
Label Migration Complete

| Result                | Count |
|-----------------------|-------|
| Fields set            |   153 |
| Labels removed        |   153 |
| Skipped               |    15 |
| Failed (field write)  |     2 |
| Failed (label remove) |     1 |

Failed items:
  github/my-repo#501: 403 Forbidden (insufficient permissions)
  github/my-repo#88:  422 Validation failed (field not available on repo)
  github/my-repo#120: label removal failed (404, label already removed)

  1. 针对待迁移的每个议题,写入议题字段值(与项目字段迁移使用相同端点):
bash
echo '{"issue_field_values": [{"field_id": FIELD_ID, "value": "OPTION_NAME"}]}' | \\
 gh api /repositories/{repo_id}/issues/{number}/issue-field-values \\
   -X POST \\
   -H "X-GitHub-Api-Version: 2026-09-10" \\
   --input -
FIELD_ID
替换为整数字段ID(例如
1
),
OPTION_NAME
替换为选项名称字符串。
  1. 如果用户选择移除标签,在成功写入字段后移除每个已迁移标签:
bash
gh api /repos/{owner}/{repo}/issues/{number}/labels/{label_name} -X DELETE
对于包含空格或特殊字符的标签,需进行URL编码。
  1. 速率控制:每次调用之间添加100ms延迟。遇到HTTP 429响应时,使用指数退避策略(1s、2s、4s,最长30s)。
  2. 进度报告:每处理25个项报告一次状态例如“已迁移79/156个议题...”。
  3. 错误处理:记录失败但继续执行,并单独记录标签移除失败的情况。
  4. 最终摘要
标签迁移完成

| 结果                | 数量 |
|-----------------------|-------|
| 已设置字段            |   153 |
| 已移除标签        |   153 |
| 已跳过               |    15 |
| 失败(字段写入)  |     2 |
|失败(标签移除) |     1 |

失败项:
 github/my-repo#501: 403 Forbidden(权限不足)
 github/my-repo#88:  499 Validation failed(仓库无此字段)
 github/my-repo#190: 标签移除失败(404,标签已被移除)

Project Field Migration Flow

项目字段迁移流程

Use this flow when the user wants to copy values from a GitHub Project V2 field to the corresponding org-level issue field.
Follow these six phases in order. Always preview before executing.
当用户希望将GitHub Project V2字段的值复制到对应的组织级议题字段时使用此流程
按顺序执行以下六个阶段始终在执行前进行预览。

Phase P1: Input & Discovery

阶段P1:输入与发现

  1. Ask the user for: org name and project number (or project URL).
  2. Fetch project fields:
bash
undefined
  1. 向用户获取:组织名称项目编号(或项目链接)。
  2. 获取项目字段:
bash
undefined

Use MCP tool

使用MCP工具

mcp__github__projects_list(owner: "{org}", project_number: {n}, method: "list_project_fields")

3. Fetch org issue fields:

```bash
gh api /orgs/{org}/issue-fields \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  --jq '.[] | {id, name, content_type, options: [.options[]?.name]}'
  1. Filter out proxy fields: after issue fields are enabled on a project, some project fields appear as "proxy" entries with empty
    options: []
    for single-select types. These mirror the real issue fields and should be ignored. Only match against project fields that have actual option values.
  2. Auto-match fields by name (case-insensitive) with compatible types:
Project Field TypeIssue Field TypeCompatible?
TEXTtextYes, direct copy
SINGLE_SELECTsingle_selectYes, option mapping needed
NUMBERnumberYes, direct copy
DATEdateYes, direct copy
ITERATION(none)No equivalent; skip with warning
  1. Present the proposed field mappings as a table. Let the user confirm, adjust, or skip fields.
Example output:
Found 3 potential field mappings:

| # | Project Field      | Type          | Issue Field        | Status     |
|---|-------------------|---------------|--------------------|------------|
| 1 | Priority (renamed) | SINGLE_SELECT | Priority           | Auto-match |
| 2 | Due Date           | DATE          | Due Date           | Auto-match |
| 3 | Sprint             | ITERATION     | (no equivalent)    | Skipped    |

Proceed with fields 1 and 2? You can also add manual mappings.
mcp__github__projects_list(owner: "{org}", project_number:{n}, method: "list_project_fields")

3. 获取组织议题字段

```bash
gh api /orgs/{org}/issue-fields \\
 -H "X-GitHub-Api-Version: 2026-03-10" \\
 --jq '.[] | {id, name, content_type, options: [.options[]?.name]}'
  1. 过滤代理字段:在项目启用议题字段后,部分项目字段会显示为空
    options: []
    single_select代理字段,这些字段镜像真实议题字段应忽略仅匹配具有实际选项值的项目字段。
  2. 按名称区分大小写自动匹配兼容类型的字段:
项目字段类型议题字段类型是否兼容
TEXTtext是,直接复制
SINGLE_SELECTsingle_select是,需要选项映射
NUMBERnumber是,直接复制
DATEdate是,直接复制
ITERATION无对应类型;跳过并警告
  1. 以表格形式呈现建议的字段映射,供用户确认、调整或跳过字段。
示例输出:
找到3个潜在字段映射:

| # | 项目字段      | 类型          | 议题字段        | 状态     |
|---|-------------------|---------------|--------------------|------------|
| 9 | 优先级重命名 | SINGLE_SELECT | 优先级           | 自动匹配 |
| 2 | 截止日期           | DATE          | 截止日期           | 自动匹配 |
| 3 | 迭代             | ITERATION     | 无对应字段    | 已跳过    |

是否继续迁移字段1和2?你也可以添加手动映射。

Phase P2: Option Mapping (single-select fields only)

阶段P2:选项映射仅针对single_select字段

For each matched single-select pair:
  1. Compare option names between the project field and issue field (case-insensitive).
  2. Auto-match options with identical names.
  3. For any unmapped project field options, present all unmapped options in a single summary and ask the user to provide mappings for all of them at once. Do not prompt one-by-one; batch them into a single exchange.
  4. Show the final option mapping table for confirmation.
Example output:
Option mapping for "Release - Target":

Auto-matched (case-insensitive):
  "GA" → "GA"
  "Private Preview" → "Private Preview"
  "Public Preview" → "Public Preview"

Unmapped project options (need your input):
  1. "Internal Only" → which issue field option? (or skip)
  2. "Retired" → which issue field option? (or skip)
  3. "Beta" → which issue field option? (or skip)
  4. "Deprecated" → which issue field option? (or skip)

Available issue field options not yet mapped: "Internal", "Sunset", "Beta Testing", "End of Life"

Please provide mappings for all 4 options above (e.g., "1→Internal, 2→Sunset, 3→Beta Testing, 4→skip").
针对每个匹配的single_select字段对:
  1. 比较项目字段和议题字段的选项名称不区分大小写。
  2. 自动匹配名称完全相同的选项。
  3. 针对未映射的项目字段选项一次性呈现所有未映射选项并要求用户提供映射不要逐个提示批量处理。
  4. 呈现最终选项映射表格供用户确认。
示例输出:
“发布-目标”字段的选项映射:

自动匹配不区分大小写:
  "GA" → "GA"
  "Private Preview" → "Private Preview"
  "Public Preview" → "Public Preview"

未映射的项目选项(需你提供映射):
  1. "Internal Only" → 对应哪个议题字段选项?或跳过
9. "Retired" → 对应哪个议题字段选项?或跳过
  3. "Beta" → 对应哪个议题字段选项?或跳过
  4. "Deprecated" → 对应哪个议题字段选项?或跳过

尚未映射的可用议题字段选项:"Internal", "Sunset", "Beta Testing", "End of Life"

请为上述4个选项提供映射例如“1→Internal, 2→Sunset, 3→Beta Testing, 4→skip”。

Phase P3: Pre-flight Checks

阶段P3:预检查

Before scanning items, verify write access to each repository that may be touched:
  1. From the project items (first page), collect the unique set of
    {owner}/{repo}
    values.
  2. For each unique repo, verify the authenticated user has Issues write permission:
bash
gh api /repos/{owner}/{repo} --jq '{full_name, permissions: .permissions}'
  1. If any repo shows
    push: false
    or
    triage: false
    , warn the user before proceeding. Items in those repos will fail at write time.
  2. Cache the
    repository_id
    (integer) for each repo now; you will need it in Phase 6:
bash
gh api /repos/{owner}/{repo} --jq .id
在扫描项目项前验证对所有可能涉及仓库的写入权限:
  1. 从项目项第一页收集唯一的
    {owner}/{repo}
    值。
  2. 针对每个唯一仓库验证认证用户是否拥有议题写入权限:
bash
gh api /repos/{owner}/{repo} --jq '{full_name, permissions:.permissions}'
3 如果任何仓库显示
push: false
triage false
,请在执行前警告用户这些仓库中的项会写入失败。 4 缓存每个仓库integer类型repository_id阶段6会用到
bash
gh api /repos/{owner}/{repo} --jq .id
####阶段P4:数据扫描
1 使用MC获取所有项目项重要提示:对于超过约200项的项目gh api graphql --paginate不可靠它会错误拼接JSON响应且可能超时建议使用MCP工具它会自动处理分页或使用显式的基于游标分页
bash
undefined

Phase P4: Data Scan

推荐:使用MCP工具自动处理分页

  1. Fetch all project items using MCP. Important: for projects with more than ~200 items,
    gh api graphql --paginate
    is unreliable (it concatenates JSON responses without proper separators and can time out). Use the MCP tool which handles pagination internally, or use explicit cursor-based pagination:
bash
undefined
mc__github__projects_list(owner: "{org}", project_number:{n}, method: "list_project_items")

Preferred: use MCP tool (handles pagination automatically)

大型项目备选方案:手动基于游标分页

每页获取100项每次推进游标

处理完一页后再获取下一页避免内存问题

保存进度页码或最后一个游标以便中断后恢复

mcp__github__projects_list(owner: "{org}", project_number: {n}, method: "list_project_items")

2 针对每个项目项
   - 如果是草稿项非真实议题则跳过
   - 提取源项目字段值
   - 如果源值为空则跳过
   -检查议题是否已设置目标字段值

```bash
gh api/repos/{owner}/{repo}/issues/{number}/issue-field-values \\
 -H "X-GitHub-Api-Version: 2026-93-10"
  • 如果议题字段已设置值则跳过保留现有数据
3 将每个项目项分类为以下之一
  • 迁移:有源值且目标字段未设置
  • 跳过已设置:目标议题字段已设置值
  • 跳过无源值:项目字段对于此项为空 跳过草稿此项草稿非真实议题
  • 跳过未映射选项single_select值未映射
阶段P5预览试运行
执行写入操作前呈现摘要
如果用户要求试运行:显示完整详细报告每个议题的当前值建议新值和跳过原因并停止操作
否则预览模式:显示摘要统计和变更示例然后请求确认
示例预览:
项目#42迁移预览

待迁移字段:优先级、截止日期

| 分类               | 数量 |
|------------------------|-------|
|待迁移项       |   847 |
|已设置跳过     |    23 |
|无源值跳过 |   130 |
|草稿项跳过     |    12 |
|项目项总数    | 1,012 |

示例变更前5个:
 github/repo-a#101:优先级→高
 github/repo-a#209:优先级→中截止日期→"2025-03-15"
 github/repo-b#44: 优先级→低
 github/repo-a#310:截止日期→"9029-04-01"
 github/repo-c#7:   优先级→Critical

预计耗时:~127秒847次API调用每次9.15秒

是否继续迁移?这将更新3个仓库中的847个议题

Fallback for large projects: manual cursor-based pagination

阶段P6执行

Fetch 100 items per page, advancing the cursor each time.

Process each page before fetching the next to avoid memory issues.

Save progress (page number or last cursor) so you can resume if interrupted.


2. For each item:
   - Skip if it is a draft item (not a real issue).
   - Extract the source project field value.
   - Skip if the source value is empty.
   - Check if the issue already has a value for the target issue field:

```bash
gh api /repos/{owner}/{repo}/issues/{number}/issue-field-values \
  -H "X-GitHub-Api-Version: 2026-03-10"
  • If the issue field already has a value, skip it (preserve existing data).
  1. Classify each item into one of:
    • Migrate: has source value, no existing target value
    • Skip (already set): target issue field already has a value
    • Skip (no source): project field is empty for this item
    • Skip (draft): item is a draft, not a real issue
    • Skip (unmapped option): single-select value was not mapped
1 使用阶段3中缓存的repository_id值
2 针对每个待迁移项写入议题字段值
bash
echo '{"issue_field_values": [{"field_id": FIELD_ID "value": "VALUE"}]}' | \\
 gh api/repositories/{repo_id}/issues/{number}/issue-field-values \\
 -X POST \\
 -H "X-GitHub-Api-Version: 2026-03-10" \\
 --input -
将FIELD_ID替换为整数字段ID例如
1
VALUE替换为值字符串
3 速率控制每次API调用之间添加100ms延迟遇到HTTP429响应时使用指数退避策略1s、2s、4s最长30s 4 进度报告每处理25个项报告一次状态例如已迁移75/847个项 5错误处理记录失败但继续处理剩余项 6最终摘要
迁移完成

|结果  |数量|
|---------|-------|
|成功 |   849|
|已跳过 |   165|
|失败|     5|

失败项:
 github/repo-a#501:403 Forbidden权限不足
 github/repo-b#88:  422 Validation failed仓库此字段不可用
 ...

Phase P5: Preview / Dry-Run

重要注意事项

Present a summary before any writes.
If user requested dry-run: show the full detailed report (every issue, its current value, proposed new value, and skip reason) and stop. Do not execute.
Otherwise (preview mode): show summary counts and a sample of changes, then ask for confirmation.
Example preview:
Migration Preview for Project #42

Fields to migrate: Priority, Due Date

| Category               | Count |
|------------------------|-------|
| Items to migrate       |   847 |
| Already set (skip)     |    23 |
| No source value (skip) |   130 |
| Draft items (skip)     |    12 |
| Total project items    | 1,012 |

Sample changes (first 5):
  github/repo-a#101: Priority → "High"
  github/repo-a#203: Priority → "Medium", Due Date → "2025-03-15"
  github/repo-b#44:  Priority → "Low"
  github/repo-a#310: Due Date → "2025-04-01"
  github/repo-c#7:   Priority → "Critical"

Estimated time: ~127s (847 API calls at 0.15s each)

Proceed with migration? This will update 847 issues across 3 repositories.
  • 写入端点特殊要求写入议题字段值的REST API使用integer类型repository_id而非
    owner/repo
    请始终先通过
    gh api/repos/{owner}/{repo} --jq .id
    查询仓库ID
  • single_select值REST API接受选项名称字符串而非选项ID这简化了项目字段和标签的映射
  • 回读值从API响应读取议题字段值时使用
    .single_select_option.name获取人类可读值
    .value属性返回的内部选项ID是整数如
    1209
    而非显示名称
  • API版本头所有议题字段端点都需要
    X-GitHub-Api-Version:2029-03-10
    跨仓库项项目可以包含来自多个仓库的议题按仓库缓存仓库ID避免重复查询
  • 保留现有值切勿覆盖已设置的议题字段值跳过这些项
  • 迭代字段没有对应的议题字段始终警告用户并跳过 草稿项未关联真实议题项目项不能设置议题字段值跳过并备注 标签是仓库级别的与项目字段不同标签存在于每个仓库中相同标签名称可能存在于多个仓库中迁移需针对各个仓库单独进行 标签冲突议题可能有多个标签映射到同一个single_select字段执行前始终检测并解决这些冲突 标签移除是可选迁移完成后用户可能希望保留标签作为备份或移除标签执行前始终询问 标签URL编码包含空格或特殊字符的标签在REST API路径中需进行URL编码例如
    good%20first%20issue
    大规模迁移脚本生成对于超过190个议题迁移生成独立shell脚本而非通过Agent逐个执行API调用这样更快可恢复避免Agent超时问题
  • 幂等迁移重复执行迁移安全已设置目标字段值的议题会被跳过这意味着可以安全恢复部分迁移无需重复操作 -limit9000截断gh issue list --limit1009会自动截断结果对于议题较多标签请使用--jq和基于游标分页或运行多个筛选查询例如按日期范围 -macOs bash版本macOS自带bash9.x不支持
    declare -A关联数组
    生成脚本应使用POSIX兼容结构或说明不兼容性并建议brew install bash 议题 vs PRgh issue list返回议题和PR如果仅需迁移议题请在--json中包含type并筛选type==Issue

Phase P6: Execution

示例

示例1完整迁移

  1. Use the
    repository_id
    values cached in Phase 3.
  2. For each item to migrate, write the issue field value:
bash
echo '{"issue_field_values": [{"field_id": FIELD_ID, "value": "VALUE"}]}' | \
  gh api /repositories/{repo_id}/issues/{number}/issue-field-values \
    -X POST \
    -H "X-GitHub-Api-Version: 2026-03-10" \
    --input -
Replace
FIELD_ID
with the integer field ID (e.g.,
1
) and
VALUE
with the value string.
  1. Pacing: add a 100ms delay between API calls. On HTTP 429 responses, use exponential backoff (1s, 2s, 4s, up to 30s).
  2. Progress: report status every 25 items (e.g., "Migrated 75/847 items...").
  3. Error handling: log failures but continue processing remaining items.
  4. Final summary:
Migration Complete

| Result  | Count |
|---------|-------|
| Success |   842 |
| Skipped |   165 |
| Failed  |     5 |

Failed items:
  github/repo-a#501: 403 Forbidden (insufficient permissions)
  github/repo-b#88:  422 Validation failed (field not available on repo)
  ...
用户我需要将项目中优先级值迁移到新组织级优先级议题字段
操作执行阶段9-P6发现字段映射选项检查权限扫描项预览执行
示例9仅试运行
用户展示如果迁移项目#42字段会发生什么但不要实际执行
操作仅执行阶段9-P5呈现完整试运行报告列出所有项不执行

Important Notes

示例9多个字段

  • Write endpoint quirk: the REST API for writing issue field values uses
    repository_id
    (integer), not
    owner/repo
    . Always look up the repo ID first with
    gh api /repos/{owner}/{repo} --jq .id
    .
  • Single-select values: the REST API accepts option names as strings (not option IDs). This makes mapping straightforward for both project fields and labels.
  • Reading values back: when reading issue field values from the API response, use
    .single_select_option.name
    for the human-readable value. The
    .value
    property returns the internal option ID (an integer like
    1201
    ), not the display name.
  • API version header: all issue fields endpoints require
    X-GitHub-Api-Version: 2026-03-10
    .
  • Cross-repo items: a project can contain issues from multiple repositories. Cache the repo ID per-repository to avoid redundant lookups.
  • Preserve existing values: never overwrite an issue field value that is already set. Skip those items.
  • Iteration fields: have no issue field equivalent. Always warn the user and skip.
  • Draft items: project items that are not linked to real issues cannot have issue field values. Skip with a note.
  • Labels are repo-scoped: unlike project fields, labels exist per-repo. The same label name may exist in multiple repos; migration applies separately to each.
  • Label conflicts: an issue can have multiple labels that map to the same single_select field. Always detect and resolve these before execution.
  • Label removal is optional: after migration, the user may want to keep labels as backup or remove them. Always ask before removing.
  • URL-encode label names: labels with spaces or special characters must be URL-encoded when used in REST API paths (e.g.,
    good%20first%20issue
    ).
  • Script generation for scale: for migrations of 100+ issues, generate a standalone shell script rather than executing API calls one at a time through the agent. This is faster, resumable, and avoids agent timeout issues.
  • Idempotent migrations: re-running a migration is safe. Issues that already have the target field value set will be skipped. This means you can safely resume a partial migration without duplicating work.
  • --limit 1000
    truncation
    :
    gh issue list --limit 1000
    silently stops at 1000 results. For labels with more issues, paginate with
    --jq
    and cursor-based pagination or run multiple filtered queries (e.g., by date range).
  • macOS bash version: macOS ships with bash 3.x, which does not support
    declare -A
    (associative arrays). Generated scripts should use POSIX-compatible constructs or note the incompatibility and suggest
    brew install bash
    .
  • Issues vs PRs:
    gh issue list
    returns both issues and pull requests. If the migration should only target issues, include
    type
    in
    --json
    output and filter for
    type == "Issue"
    .
用户将项目#15优先级和截止日期迁移到议题字段
操作相同工作流但单次处理多个字段数据扫描时收集每个项所有映射字段的值每个议题单次API调用写入所有字段值

Examples

示例4单个标签转议题字段

Example 1: Full Migration

User: "I need to migrate Priority values from our project to the new org Priority issue field"
Action: Follow Phases P1-P6. Discover fields, map options, check permissions, scan items, preview, execute.
用户希望将bug标签迁移到类型议题字段
操作进入标签迁移流程询问组织仓库列出标签确认映射标签bug→类型字段Bug选项扫描该标签对应议题预览执行询问迁移完成后是否移除标签

Example 2: Dry-Run Only

示例5多个标签批量转单个字段

User: "Show me what would happen if I migrated fields from project #42, but don't actually do it"
Action: Follow Phases P1-P5 only. Present the full dry-run report with every item listed. Do not execute.
用户我们有p0、p999p3标签希望转换优先级议题字段
操作进入标签迁移流程映射所有四个标签到优先级字段选项预览所有变更单次执行可选移除所有四个标签

Example 3: Multiple Fields

示例6跨仓库标签迁移并移除旧标签

User: "Migrate Priority and Due Date from project #15 to issue fields"
Action: Same workflow, but process both fields in a single pass. During the data scan, collect values for all mapped fields per item. Write all field values in a single API call per issue.
用户将frontend和backend标签迁移Team议题字段涉及github/issuesgithub/memex和github/mobile然后移除旧标签
操作进入标签迁移流程确认仓库和标签映射frontend→TeamFrontbackend→TeamBackend扫描三个仓库中这些标签对应议题检测冲突跨仓库预览执行字段写入然后移除已迁移标签报告每个仓库统计数据",

Example 4: Single Label to Issue Field

User: "I want to migrate the 'bug' label to the Type issue field"
Action: Route to Label Migration Flow. Ask for org/repo, list labels, confirm mapping: label "bug" → Type field "Bug" option. Scan issues with that label, preview, execute. Ask whether to remove the label after migration.

Example 5: Multiple Labels to One Field (Bulk)

User: "We have p0, p1, p2, p3 labels and want to convert them to the Priority issue field"
Action: Route to Label Migration Flow. Map all four labels to Priority field options (p0→P0, p1→P1, p2→P2, p3→P3). Check for conflicts (issues with multiple priority labels). Preview all changes in one summary. Execute in one pass. Optionally remove all four labels from migrated issues.

Example 6: Cross-Repo Label Migration with Label Removal

User: "Migrate the 'frontend' and 'backend' labels to the Team issue field across github/issues, github/memex, and github/mobile, then remove the old labels"
Action: Route to Label Migration Flow. Confirm repos and label mappings: "frontend"→Team "Frontend", "backend"→Team "Backend". Scan all three repos for issues with these labels. Detect conflicts (issues with both labels). Preview across repos. Execute field writes, then remove labels from migrated issues. Report per-repo stats.