Issues¶
Until now, the homelab to-do list lived in the README, and discussions about the servers happened by text message, then got lost. On GitHub, each piece of work gets its own issue: a page where it is described, discussed, assigned, and finally closed.
What is an issue?¶
An issue is a message attached to a repository, used to track:
- problems to fix: a bug, something broken;
- tasks: a change to make, a piece of documentation to write;
- plans and ideas: a feature request, a proposal;
- other communications: a question, a decision to make.
Each issue has a number, unique in the repository (#1, #2...), a title, a description, and a timeline of comments and events. Issues are listed in the Issues tab, which also shows how many are open. An issue is either open (to do, or in progress) or closed (done, or abandoned).
stateDiagram-v2
[*] --> Open: New issue
Open --> Open: comments, assignees, labels
Open --> Closed: completed, not planned, duplicate
Closed --> Open: Reopen issue
Closed --> [*]
Issues and pull requests share numbers
Pull requests are numbered in the same sequence as issues: if #1 and #2 are issues, the next pull request is #3.
Creating an issue¶
- Open the Issues tab, and click New issue. If the repository has issue templates, choose one, or a Blank issue.
- Fill in the title: short and specific (
Back up the NAS off-site, notBackups). - Write the description, in Markdown, with a Write tab and a Preview tab. Images and files can be dragged into the text.
- Optionally, fill in the side panel (see below).
- Click Create (Submit new issue in older versions of the interface).
Sam opens the first issue of the homelab:
## Spring maintenance
Hi @alex-martin, here are the tasks before the summer:
- [ ] Replace the NAS fan
- [ ] Update Pi-hole to the latest version
- [ ] Remove the old `web00` line from the inventory
A task list in the description is displayed as checkboxes that can be ticked directly on the issue page, and the issue shows its progress (0 of 3 tasks) in the issue list.
The side panel¶
| Field | Purpose |
|---|---|
| Assignees | Who works on the issue. Up to 10 people with access to the repository |
| Labels | Categories: bug, documentation, enhancement... |
| Type | A type defined by the organization (Bug, Task, Feature); organizations only |
| Projects | Add the issue to a GitHub Project board |
| Milestone | A target: a version or a date (Summer 2026) |
| Development | The branches and pull requests linked to this issue |
Every new repository has nine default labels: bug, documentation, duplicate, enhancement, good first issue, help wanted, invalid, question, and wontfix. Labels are managed in Issues > Labels.
Assigning and mentioning¶
Two different ways of involving someone:
| Assign | Mention (tag) | |
|---|---|---|
| How | Assignees in the side panel (or assign yourself) | Type @ followed by the username in a description or comment: @alex-martin |
| Meaning | This person works on the issue | This person should read this |
| Effect | They are listed on the issue, and the issue appears in their assigned issues | They receive a notification |
| Who | Only people with access to the repository | Anyone, including teams of an organization: @homelab-club/admins |
Sam assigns the issue to Alex, and mentions Alex in the description so that the notification arrives straight away.
Discussing¶
Below the description, the comment box works like the description: Markdown, preview, attachments. The Comment button posts the comment. Each comment can receive reactions (thumbs up, heart...), which avoid "+1" comments, and can be edited later by its author; the edit history stays visible.
Linking issues and pull requests¶
Type # followed by a number to reference another issue or pull request of the same repository: #2. GitHub turns it into a link, and shows its title and state on hover. Typing # alone opens a list of suggestions to choose from.
| Reference | Points to |
|---|---|
#2 |
Issue or pull request 2 of the same repository |
sam-rivera/homelab#2 |
Issue or pull request 2 of another repository |
A commit hash, such as a8c9f40 |
The commit |
The referenced issue receives an event in its timeline (alex-martin mentioned this issue), so both sides know about each other.
Quoting a comment¶
To reply to a precise part of a comment, quote it: in the comment's ... menu, choose Quote reply. GitHub copies the text into the comment box, with each line starting with >:
> We should also review the changes we made to the NAS in #2
Agreed, I will look at #2 first.
Selecting part of a comment then choosing Quote reply (or pressing the R key) quotes only the selection.
Closing an issue¶
When the work is done, close the issue: the Close issue button, at the bottom of the page. If the comment box contains text, the button becomes Close with comment, which posts the comment and closes in one click.
The arrow next to the button chooses the reason:
| Reason | Use it when | Icon |
|---|---|---|
| Close as completed (default) | The work is done | Purple check |
| Close as not planned | It will not be done: won't fix, out of scope, stale | Grey |
| Close as duplicate | Another issue already covers it; GitHub asks which one | Grey |
A closed issue can be reopened with Reopen issue. Closing never deletes anything: the issue, its comments, and its history stay readable. (Deleting an issue is possible, for administrators, but rarely the right choice.)
Closing automatically¶
An issue can also be closed by a change: put a closing keyword followed by the issue number in the description of a pull request, or in a commit message:
Closes #4
Fixes #4
Resolves #4
The keywords are close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved, in any case. The issue closes as completed when the pull request is merged into the default branch, or when the commit reaches the default branch. The issue and the pull request are linked in the Development section of both.
Finding issues¶
The search bar of the Issues tab accepts filters, combined with spaces:
| Filter | Shows |
|---|---|
is:issue is:open |
Open issues (the default) |
is:closed reason:completed |
Issues closed as completed |
is:closed reason:"not planned" |
Issues closed as not planned |
assignee:@me |
Issues assigned to you |
no:assignee |
Issues nobody works on |
label:bug |
Issues with the label bug |
mentions:alex-martin |
Issues that mention Alex |
author:sam-rivera |
Issues opened by Sam |
Summary¶
| Action | How |
|---|---|
| Create an issue | Issues > New issue |
| Track sub-tasks | A task list - [ ] in the description |
| Give the work to someone | Assignees (up to 10) |
| Notify someone | @username in the text |
| Link another issue or pull request | #number |
| Quote a comment | ... > Quote reply |
| Close | Close issue (or Close with comment), with a reason |
| Close with a change | Closes #N in a pull request description or a commit message, merged into the default branch |
Common mistakes¶
- Vague titles.
Problemsays nothing;pi-dns does not resolve local names after rebootdoes. - Assigning someone to make them read. Mention them; assign only who does the work.
- Several unrelated tasks in one issue. One issue per piece of work, so each can be closed on its own.
- A closing keyword in a pull request that targets another branch. The issue only closes when the change reaches the default branch.
- Closing without explanation. Add a comment, and choose the right reason.
Hands-on labs¶
Three labs, from guided to more autonomous. They need your GitHub account and a browser only. Replace <username> with your GitHub username.
Setup for all three labs: on GitHub, create a public repository homelab-practice-9 with a README. Issues are enabled by default.
Lab 1: the life of an issue¶
Objective: create an issue with a task list, assign it, discuss it, link it to another issue, and close it.
Prerequisites and initial state: homelab-practice-9, with no issues.
Tasks:
- Create an issue titled
Spring maintenance, with a short sentence and a task list of three tasks (replace the NAS fan, update Pi-hole, clean the inventory). Assign it to yourself and add the labelenhancement. - Tick the first task directly on the issue page. Check the progress shown in the issue list.
- Create a second issue titled
NAS fan is noisy, with the labelbug. - In issue 1, add a comment that links to issue 2. Then open issue 2 and find the trace of this link.
- In issue 1, quote your previous comment, and answer below the quote.
- Close issue 2 as completed, with the comment
Fan replaced.in a single click. - Tick the remaining tasks of issue 1, and close it as completed.
Expected result and verification:
- Task 2: the issue list shows 1 of 3 tasks for
Spring maintenance. - Task 4: issue 2's timeline shows that you mentioned it from issue 1.
- Task 5: the new comment starts with a quoted block.
- Task 6: issue 2 shows Fan replaced. followed by closed this as completed.
- At the end, the filter
is:issue is:closedlists both issues, andis:issue is:openlists none.
Solution
-
Issues > New issue; description:
Tasks before the summer: - [ ] Replace the NAS fan - [ ] Update Pi-hole - [ ] Clean the inventoryAssignees > assign yourself, Labels >
enhancement, then Create. -
Comment:
The fan problem is tracked in #2.(type#and pick the issue from the list). - ... on your comment > Quote reply, then write your answer below the
>lines. -
In issue 2, type
Fan replaced.in the comment box, then Close with comment. -
Ticking a task edits the description: it appears in the issue's edit history.
- A link written as
#2stays valid if the issue's title changes.
Lab 2: reasons, regrets, and automatic closing¶
Objective: use every closing reason, reopen an issue, and close one automatically from a commit.
Prerequisites and initial state: homelab-practice-9, with the two closed issues of Lab 1 (or none: the numbers below will differ).
Tasks:
- Create three issues:
Add a printer to the inventory(#3),Install Grafana(#4), andSet up monitoring dashboards(#5). - You decide not to buy a printer: close #3 with the right reason. Then you change your mind: reopen it.
-
5 covers the same thing as #4: close #5 as a duplicate of #4.¶
- Create
inventory.csvon GitHub, with the lineprinter01,192.168.1.30,printer, committed directly tomainwith the messageAdd printer to inventoryand the extended descriptionCloses #3. - Open #3. Then filter the issue list to see the issues closed as not planned, then as completed.
Expected result and verification:
- Task 2: #3 shows closed this as not planned, then reopened this.
- Task 3: #5 shows that it was closed as a duplicate of #4.
- Task 4: #3 is closed automatically, as completed, with a reference to the commit in its timeline.
- Task 5:
is:closed reason:"not planned"lists nothing (#3 was reopened, then completed);is:closed reason:completedlists #3 (and the issues of Lab 1).
Solution
- Arrow next to Close issue > Close as not planned; then Reopen issue.
- In #5: arrow next to Close issue > Close as duplicate, and select #4.
-
Add file > Create new file
inventory.csv; Commit changes...: messageAdd printer to inventory, extended descriptionCloses #3, Commit directly to themainbranch. -
The keyword works in the body of the commit message too, not only in its first line.
- The commit closed #3 because it was made on
main, the default branch. On another branch, nothing would happen until it is merged. - A duplicate closure keeps both issues, and links them: people who find #5 are sent to #4.
Lab 3: triage the backlog¶
Objective: organize a set of issues as a maintainer would: label, assign, and find what needs attention.
Prerequisites and initial state: homelab-practice-9. You play Sam, who comes back from holidays and finds new issues.
Tasks:
-
Create these five issues, as if other people had opened them:
Title Description DNS does not resolve local namesSince yesterday, pi-dns cannot resolve nas.home.Document the backup jobThe README does not explain how backups work.Add a UPSCould we add a UPS for the NAS?How do I add a machine?Which file should I edit to add a new server?DNS brokenLocal names do not work anymore. -
Triage them: give each issue the most fitting default label; close the duplicate with the right reason; answer the question in a comment, then close it as completed.
- Assign yourself to the bug, and create a milestone
Summer 2026(Issues > Milestones) containing the bug and the documentation task. - Using only search filters, find: the open bugs; the open issues nobody is assigned to; the issues of the milestone.
Expected result and verification:
- Labels:
bugfor the DNS issue,documentationfor the backup job,enhancementfor the UPS,questionfor the question;DNS brokenclosed as a duplicate ofDNS does not resolve local names. is:open label:buglists one issue;is:open no:assigneelistsDocument the backup jobandAdd a UPS(plus any open issue from earlier labs);milestone:"Summer 2026"lists the bug and the documentation task.
Solution
- The duplicate is the less precise one: keep the issue with the clearest description, close the other as a duplicate.
- Answer to the question:
Add a line to inventory.csv, in the form hostname,ip,role., then Close with comment. - Milestone: Issues > Milestones > New milestone, title
Summer 2026; then Milestone in the side panel of each issue.
is:open label:bug
is:open no:assignee
milestone:"Summer 2026"
- Labels and milestones make a backlog searchable; a good triage leaves no open issue without a label.
Clean up when you are done: delete homelab-practice-9 on GitHub (Settings > General > Danger Zone). Its issues are deleted with it.