git-issue-hierarchy

v2026.09.24

GitHub sub-issues and blocked_by/blocking links. Use when breaking an issue into sub-tasks, checking parent progress, or viewing a dependency graph.

GitHub
安装命令
npx skhub add laurigates/git-issue-hierarchy
Markdown
SKILL.md

When to Use This Skill

Use this skill when...Use the alternative when...
Adding/removing native GitHub sub-issues to a parent issueUse git-issue-manage for transfer, pin, lock, develop-branch operations
Marking issue A as blocked_by issue B (or unblocking)Use github-issue-writing to create well-structured issue bodies in the first place
Viewing a parent issue's sub-issue completion progress and dependency graphUse git-issue to actually start working on issues end-to-end
Checking the dependency graph before starting work on a multi-issue featureUse gh-cli-agentic for raw gh issue --json queries without hierarchy logic

Context

  • Repo: !git remote -v
  • Parent issue: (parsed from arguments)

Parameters

Parse these parameters from the command:

Every issue argument — <parent-issue> and each <N> flag value below — is accepted as a bare number, #N, or a full GitHub issue URL, and normalized to a (number, repo) pair in Step 0.

ParameterDescription
<parent-issue>Parent issue as a bare number, #N, or full GitHub issue URL (https://github.com/<owner>/<repo>/issues/<N>) — see Step 0
--add <N...>Add existing issues as sub-issues (each N as number, #N, or URL)
--create "<title>"Create a new issue and add it as sub-issue
--remove <N...>Remove sub-issues from parent (each N as number, #N, or URL)
--statusShow sub-issue completion progress
--listList all sub-issues of the parent
--depsShow dependency graph (blocked_by + blocking + sub-issues) for the issue
--blockingList issues the parent is blocking
--block <N>Mark issue N as blocked by the parent (parent blocks N); N as number, #N, or URL
--blocked-by <N>Mark the parent as blocked by issue N; N as number, #N, or URL
--unblock <N>Remove blocking relationship with issue N in either direction; N as number, #N, or URL

When to Use

Use this skill when...Use X instead when...
Breaking issues into sub-tasksCreating standalone issues (github-issue-writing)
Checking sub-issue completion progressImplementing/processing issues (git:issue)
Recording blocked_by / blocking dependenciesAuto-detecting related issues (github-issue-autodetect)
Viewing a blocker graph before picking workSearching for OSS solutions (github-issue-search)

Sub-issues vs. dependencies vs. "related to"

GitHub ships three distinct ways to link issues. Pick the right one — they're not interchangeable:

RelationshipWhen to useAPI surface
Sub-issue (parent ↔ child)Child issue is a part of the parent's scope. Completing all children fulfils the parent.issues/{N}/sub_issues
Blocked by (hard dependency)Parent cannot start or ship until the other issue closes. Makes the blocked issue render a "Blocked" badge on boards.issues/{N}/dependencies/blocked_by
Blocking (read-only inverse)You want to see everything this issue gates. Managed by creating blocked_by links on the other side.issues/{N}/dependencies/blocking
"Related to #N" in bodySoft cross-reference, no lifecycle coupling, no board indicator.Plain markdown — no API needed

Sub-issues express composition ("is part of"). Dependencies express ordering ("must happen before"). The same two issues should rarely use both — a sub-issue is implicitly ordered by its parent's scope.

Execution

Execute the requested issue hierarchy operation.

Step 0: Normalize issue references

Before any API call, normalize <parent-issue> and every issue value passed to a flag (--add, --remove, --block, --blocked-by, --unblock) into a (number, repo) pair. Accept these forms:

Input formExtract
123number 123, repo = current remote
#123number 123, repo = current remote
https://github.com/<owner>/<repo>/issues/123number 123, repo = <owner>/<repo>
.../issues/123#issuecomment-...number 123 (drop the #... fragment), repo = <owner>/<repo>

Rules:

  1. Strip a leading #; strip a URL #... fragment after the number. A token is an issue ref only if, after stripping, it is all digits or matches the /issues/<digits> URL shape (require trailing digits — a /pull/<N>, /discussions/<N>, or bare /issues list URL is not a ref).
  2. For the plural flags (--add/--remove, which take <N...>), normalize each space-separated value independently; never split a single URL into two refs.
  3. For a URL whose <owner>/<repo> differs from the current remote (Step 1 REPO), record it as cross-repo and carry -R <owner>/<repo> on every gh issue call and target repos/<owner>/<repo>/… on every gh api call for that issue. Sub-issue and dependency links require both endpoints to live in the same repo — if a normalized ref points at a different repo than the parent, surface that rather than issuing a mismatched cross-repo link.

Downstream steps use the normalized $PARENT, $N, and $CHILD numbers; where a ref was cross-repo, substitute its <owner>/<repo> for $OWNER/$REPO_NAME and add -R <owner>/<repo> to the corresponding gh issue call.

Step 1: Resolve Repository Context

REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
OWNER=$(echo "$REPO" | cut -d/ -f1)
REPO_NAME=$(echo "$REPO" | cut -d/ -f2)

If Step 0 normalized <parent-issue> to a cross-repo URL, use that URL's <owner>/<repo> as $OWNER/$REPO_NAME (and pass -R <owner>/<repo> to the gh issue view below) instead of the current remote.

Verify the parent issue exists:

gh issue view $PARENT --json number,title,state,subIssuesSummary

Step 2: Branch on Operation Mode

Determine which operation to perform based on parsed parameters.

If --status (or no flags): Display sub-issue summary and list.

If --add: Add existing issues as sub-issues.

If --create: Create new issue, then add as sub-issue.

If --remove: Remove specified sub-issues.

If --list: List all sub-issues with their states.

If --deps, --blocking, --block, --blocked-by, --unblock: Manage native GitHub issue dependencies via the dependencies/blocked_by and dependencies/blocking API endpoints.

Step 3: Execute API Calls

Sub-Issue Status

# Get summary
gh issue view $PARENT --json title,state,subIssuesSummary

# List all sub-issues with details
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/sub_issues \
  --jq '.[] | "#\(.number) \(.state) \(.title)"'

Report format:

Issue #42: Refactor authentication system
Sub-issues: 3/5 completed (60%)

  #43 ✓ Extract token validation
  #44 ✓ Add refresh token support
  #45 ✓ Update OAuth provider
  #46 ○ Migrate session storage
  #47 ○ Update API documentation

Add Sub-Issues

For each issue number in --add:

# Get the issue's node ID (required for sub_issue_id)
CHILD_ID=$(gh api repos/$OWNER/$REPO_NAME/issues/$CHILD --jq '.id')

# Add as sub-issue
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/sub_issues \
  -f sub_issue_id=$CHILD_ID

Verify each was added successfully. Report any errors (e.g., issue not found, already a sub-issue, sub-issues not enabled).

Create and Add Sub-Issue

# Create the new issue
NEW_ISSUE=$(gh issue create --title "$TITLE" --body "Parent: #$PARENT" --json number --jq '.number')

# Get its ID
NEW_ID=$(gh api repos/$OWNER/$REPO_NAME/issues/$NEW_ISSUE --jq '.id')

# Add as sub-issue
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/sub_issues \
  -f sub_issue_id=$NEW_ID

Remove Sub-Issues

For each issue number in --remove:

# Get the sub-issue ID from the sub-issues list
SUB_ISSUE_ID=$(gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/sub_issues \
  --jq ".[] | select(.number == $CHILD) | .id")

# Remove it
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/sub_issues/$SUB_ISSUE_ID -X DELETE

Dependency Management

Dependencies use GitHub's native dependencies/blocked_by and dependencies/blocking endpoints. They appear in the issue sidebar under "Relationships" and mark the blocked issue with a "Blocked" badge on project boards. Both endpoints require the target issue's node id (.id on the issue payload), not the human-readable issue number.

Add "blocked by" relationship (--blocked-by <N>): parent is blocked by N

# Resolve the blocker's node id
BLOCKER_ID=$(gh api repos/$OWNER/$REPO_NAME/issues/$N --jq '.id')

# Record the dependency on the parent
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/dependencies/blocked_by \
  -f issue_id=$BLOCKER_ID

Add "blocks" relationship (--block <N>): parent blocks issue N

The API is one-directional — write the relationship on the blocked side:

# Resolve the parent's node id
PARENT_ID=$(gh api repos/$OWNER/$REPO_NAME/issues/$PARENT --jq '.id')

# Record on issue N that it is blocked by the parent
gh api repos/$OWNER/$REPO_NAME/issues/$N/dependencies/blocked_by \
  -f issue_id=$PARENT_ID

Remove relationship (--unblock <N>):

Look up which side carries the link, then delete it. The DELETE path takes the stored dependency's {issue_id} segment:

# Is the parent blocked by N?
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/dependencies/blocked_by \
  --jq ".[] | select(.number == $N) | .id"

# Or does the parent block N?
gh api repos/$OWNER/$REPO_NAME/issues/$N/dependencies/blocked_by \
  --jq ".[] | select(.number == $PARENT) | .id"

# Delete whichever is present
gh api repos/$OWNER/$REPO_NAME/issues/$ISSUE/dependencies/blocked_by/$DEP_ID \
  -X DELETE

List what the parent blocks (--blocking):

gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/dependencies/blocking \
  --jq '.[] | "#\(.number) \(.state) \(.title)"'

Show dependency graph (--deps):

Combine both dependency endpoints with the sub-issues summary. Do not parse issue bodies — the native API is authoritative:

# What blocks the parent
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/dependencies/blocked_by \
  --jq '.[] | "#\(.number) \(.state) \(.title)"'

# What the parent blocks
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/dependencies/blocking \
  --jq '.[] | "#\(.number) \(.state) \(.title)"'

# Sub-issues (composition, not ordering)
gh api repos/$OWNER/$REPO_NAME/issues/$PARENT/sub_issues \
  --jq '.[] | "#\(.number) \(.state) \(.title)"'

Render output as:

#42 Refactor authentication
├── Blocked by: #40 Database migration (✓ closed)
├── Blocks:     #45 Deploy auth v2 (○ open)
└── Sub-issues:
    ├── #43 ✓ Extract token validation
    └── #44 ○ Add refresh token support

Surface Blocked by entries that are still open prominently — those are what prevent the parent from starting.

Step 4: Report Results

Report what was done:

OperationReport Format
--statusSummary with completion percentage and sub-issue list
--addConfirmation of each added sub-issue
--createNew issue number + confirmation added as sub-issue
--removeConfirmation of each removed sub-issue
--depsDependency tree visualization (blocked_by + blocking + sub-issues)
--blockingList of issues the parent blocks
--block/--blocked-byConfirmation of relationship added, rendered with direction
--unblockConfirmation of relationship removed

Error Handling

ErrorCauseAction
404 on sub_issues endpointSub-issues not enabled for repoReport: "Sub-issues are not available for this repository. Enable them in repository settings."
404 on dependencies endpointIssue dependencies feature not enabled for repo/orgReport: "Issue dependencies are not available for this repository. Ask an owner to enable them under Repository settings → Features → Issues."
422 on add sub-issueIssue already a sub-issue or circular referenceReport the specific error
422 on add dependencyCircular dependency, already linked, or self-referenceReport the specific error
Issue not foundInvalid issue numberReport which issue number was not found

Agentic Optimizations

ContextCommand
Quick sub-issue statusgh issue view N --json title,subIssuesSummary
List sub-issuesgh api repos/{o}/{r}/issues/{N}/sub_issues --jq '.[].number'
Add sub-issuegh api repos/{o}/{r}/issues/{N}/sub_issues -f sub_issue_id=M
Remove sub-issuegh api repos/{o}/{r}/issues/{N}/sub_issues/M -X DELETE
List blockersgh api repos/{o}/{r}/issues/{N}/dependencies/blocked_by --jq '.[].number'
List blocked-by-megh api repos/{o}/{r}/issues/{N}/dependencies/blocking --jq '.[].number'
Add blockergh api repos/{o}/{r}/issues/{N}/dependencies/blocked_by -f issue_id=<node-id>
Remove blockergh api repos/{o}/{r}/issues/{N}/dependencies/blocked_by/{dep_id} -X DELETE
Resolve node idgh api repos/{o}/{r}/issues/{N} --jq '.id'

See Also

  • github-issue-writing skill for creating standalone issues
  • git:issue skill for implementing/processing issues
  • gh-cli-agentic skill for raw API patterns
发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

git-plugin/skills/git-issue-hierarchy

默认分支

main

最新提交

1668324

Tree SHA

b2d4cc3