Manage GitHub Issues Safely with gh issue
The fastest way to trigger an awkward Slack message is running gh issue close against the wrong repository. gh issue makes that mix-up easy unless you are deliberate about the target, and this guide creates, finds, inspects, updates and closes issues from a shell without it. The examples use GitHub CLI 2.87.3, installed here in February 2026.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 10 minutes for the first run. You need the gh package, a GitHub account with access to the repository, and an authenticated CLI session. These commands change shared project data, so use a test repository while you are learning.
1. Select the repository deliberately
Run the command from a checked-out repository when you can: gh then uses the repository tied to the current directory. Use -R to make the target explicit instead. Its value is [HOST/]OWNER/REPO; the host part is only needed for a GitHub Enterprise Server instance.
gh issue list -R OWNER/REPO --limit 10
Replace OWNER/REPO with the real repository name. The list command returns open issues by default, so an empty result can mean no open issues just as easily as an unreachable repository.
Checkpoint
Confirm the repository name in the command and read the first few issue titles before creating or editing anything.
2. Find the issue that needs attention
Use filters to narrow the list. Labels, assignees, authors and milestones can be supplied more than once where the option accepts a list. Add --state all when a closed issue matters too:
gh issue list -R OWNER/REPO --label bug --state open
gh issue list -R OWNER/REPO --assignee @me --limit 50
gh issue list -R OWNER/REPO --search "error no:assignee sort:created-asc"
The search string uses GitHub issue search syntax, so keep it quoted: the shell has to pass it as one argument. For scripts, ask for named JSON fields instead of parsing the human-readable table:
gh issue list -R OWNER/REPO --state all --limit 20 \
--json number,title,state,url
That returns JSON containing only the requested fields, which is easier to hand to another tool than a display table whose columns can change.
3. Inspect before you act
An issue can be identified by its number, such as 123, or by its full issue URL. View the body first, and only add comments once you have checked the context:
gh issue view 123 -R OWNER/REPO --comments
For a stable, machine-readable result, ask for fields such as number, title, body, state and url:
gh issue view 123 -R OWNER/REPO --json number,title,body,state,url
Right issue, checked context: add a comment with a body supplied on the command line. Keep sensitive material out of issue bodies and comments; repository collaborators can often read them, and GitHub notifications can copy the text elsewhere.
gh issue comment 123 -R OWNER/REPO \
--body "Reproduced on Ubuntu 24.04 with package version 1.2.3."
For longer text, put it in a local file and use --body-file. Check the file before sending it: without a supplied body, the command prompts for one interactively instead.
4. Create an issue without an interactive prompt
Supply a title and body explicitly once the issue is ready. Labels, a milestone and assignees are optional, and the special assignee @me means your current GitHub identity:
gh issue create -R OWNER/REPO \
--title "Login fails after certificate renewal" \
--body "Observed after renewing the staging certificate.\n\nSteps to reproduce:\n1. Sign in.\n2. Open the dashboard.\n3. Submit a report." \
--label bug
On success, gh prints the new issue URL. Save it if another person or automation needs an unambiguous reference. Omit title or body and the command prompts for them instead, which is fine interactively but can stall a script.
Adding an issue to a project needs authorisation with the project scope. Use --project and the CLI may ask you to refresh that scope: treat that prompt as a deliberate security decision, not an obstacle to route around.
5. Edit and close with a recovery path
Edits change the existing issue immediately. Make one focused change at a time and view the result afterwards:
gh issue edit 123 -R OWNER/REPO \
--title "Login fails after staging certificate renewal" \
--add-label bug
gh issue view 123 -R OWNER/REPO --json title,labels,state
- Undo a label or assignee with
--remove-label,--remove-assigneeor--remove-milestone. - Restore an overwritten title or body by running
gh issue editagain with the previous text, if you kept a copy of it.
Warning
Closing is a shared-state change. Close only after checking the issue number and repository. You can reopen a closed issue with gh issue reopen, but deletion is a separate, destructive operation: do not use gh issue delete as a substitute for closing unless permanent removal has actually been agreed.
gh issue close 123 -R OWNER/REPO --reason completed \
--comment "Fixed in release 2.4.0."
gh issue view 123 -R OWNER/REPO --json state,stateReason
The close command accepts completed or not planned as its reason. Decision changes: reopen the issue and explain why in a new comment.
Common traps
- Wrong repository. A command can succeed against whatever repository the current directory selects. Add
-Rfor scripts and high-impact changes. - Missing issues.
gh issue listshows open issues by default. Add--state allwhen you are checking history. - Unexpected prompts. Create and comment both prompt when their body or title is missing. Supply
--title,--bodyor a body file in automation. - Shell expansion. Quote search expressions, URLs and any prose containing spaces or shell characters.
- Permission errors. An authenticated account can still lack repository access or the required project scope. Check the target and account before touching credentials.
Done means
- Target identified. An explicit repository and issue number or URL, not an assumed one.
- State checked first.
listorviewconfirmed the current state before you acted. - Change verified. The URL, title or state printed after a change matched expectations.
- Recovery path known. You know how to undo an association, reopen a closed issue, or restore recorded text.
- Nothing sensitive leaked. No credentials, tokens or private operational details went into an issue.