Hazem Azzam

All posts
Writing

How to Write Git Issues Like a Professional

A good issue is a contract: it tells the assignee what done looks like before they write a line of code. This post covers titles, bug reports, feature requests, acceptance criteria, labels, and triage habits that keep backlogs actionable instead of overwhelming.

5 min read
gitgithubissuesproject-managementworkflow

Why issues matter

An issue is the atomic unit of planned work. Before there is a branch, a commit, or a pull request, there is usually an issue — or there should be.

Professional issues reduce ambiguity. They answer: what is broken or missing, who is affected, what "fixed" looks like, and how a developer can verify success. Vague issues ("fix login", "improve performance", "make it better") create meetings, duplicate work, and PRs that solve the wrong problem.

Well-written issues let anyone on the team pick up work cold. That is the bar.

The issue title

Titles appear in backlogs, sprint boards, and search results. Treat them like headlines: specific and action-oriented.

WeakStrong
Bug in APIPOST /orders returns 500 when quantity is zero
Login brokenOAuth callback fails on Safari with state mismatch
Add dark modeAdd system-preference dark theme to settings page
PerformanceDashboard home loads in >8s with 10k+ records

For bugs: describe the symptom and where it happens.

For features: describe the user-visible outcome, not the implementation.

Avoid titles that only reference internal jargon unless your team truly lives in that vocabulary.

Bug reports — make them reproducible

A bug issue without reproduction steps is a guess, not a ticket. Reviewers and assignees should be able to follow your steps and see the same failure.

Use this structure:

## Summary
One sentence: what is wrong.

## Steps to reproduce
1. Log in as a user with an empty cart
2. Navigate to /checkout
3. Submit the form with quantity set to 0

## Expected behavior
Checkout rejects the submission with a validation message.

## Actual behavior
Server returns HTTP 500; user sees a generic error page.

## Environment
- Browser: Safari 17.2 / Chrome 120
- OS: macOS 14.2
- App version / commit: v2.4.1 (abc1234)
- Environment: staging

## Logs / screenshots
(paste stack trace, network response, or screenshot)

Include evidence

Stack traces, HAR files, screenshots, and screen recordings turn "it broke for me once" into something a developer can debug. Redact secrets — never paste production tokens or customer data.

One bug per issue

If you find three unrelated failures while testing, open three issues. Bundling makes triage, assignment, and closing messy.

Feature requests — define done upfront

Feature issues fail when "done" is subjective. Fix that with acceptance criteria: observable conditions that must be true before the issue can close.

## Problem
Users cannot reset passwords without contacting support. This creates support load and blocks self-service recovery.

## Proposed solution
Add a "Forgot password?" flow on the login page that sends a time-limited reset link by email.

## Acceptance criteria
- [ ] "Forgot password?" link visible on /login
- [ ] Submitting a registered email sends a reset link (generic success message either way — no email enumeration)
- [ ] Reset link expires after 30 minutes
- [ ] Successful reset invalidates existing sessions
- [ ] Flow covered by integration tests

## Out of scope
- SMS-based reset
- Admin-initiated password resets

## Design / references
(link to mockup, RFC, or similar product in the wild)

Out of scope is as important as scope

Saying what you are not doing prevents scope creep in PR review. "We are not building SMS reset in this ticket" saves a week of debate.

User stories (optional)

Some teams prefix with: "As a [role], I want [capability], so that [benefit]." That is fine if it adds clarity — skip it if it becomes filler.

Labels, priority, and metadata

Consistent labels make backlogs searchable and triage faster. You do not need fifty labels — you need a small set everyone understands.

Label typeExamplesPurpose
Typebug, feature, chore, docsWhat kind of work
Areaauth, billing, frontendWho likely owns it
PriorityP0, P1, P2 or critical, high, lowUrgency
Effortgood first issue, needs designRouting hints

Priority should mean something. If everything is P0, nothing is. Agree as a team: P0 = production down or data loss; P1 = major user impact with workaround; P2 = everything else.

Assign issues when someone has committed to work on them. An unassigned backlog is fine; a falsely assigned issue that sits for weeks is not.

Issue templates

If your team files the same kinds of issues repeatedly, add GitHub issue templates (or equivalent in GitLab/Linear). Templates enforce the sections above so blank issues become rare.

Keep templates short. A six-page form guarantees people will skip fields. The bug and feature structures in this post are enough for most teams.

Writing for the assignee, not yourself

You already know the context because you lived the bug or requested the feature. The assignee does not.

Ask yourself:

  • Could a new teammate implement this without a meeting?
  • Is there a clear definition of done?
  • Are dependencies called out? ("Blocked by #201 — API schema change")

If any answer is no, add detail.

Linking issues to PRs

When work starts, reference the issue in the branch name or PR (fix/142-zero-quantity-checkout, Fixes #142). That creates an audit trail from requirement → implementation → merge.

For large features, use parent/child issues or a tracking issue with a checklist of sub-tasks. One mega-issue with forty comments is hard to navigate.

Triage habits

Professional backlogs are groomed, not hoarded.

  • Duplicate? Close with a link to the original.
  • Cannot reproduce? Ask for steps once, then close if silent — stale issues rot trust in the backlog.
  • Too vague? Send back with a comment listing exactly what is missing.
  • Wrong repo? Transfer or close politely.

Schedule regular triage (weekly is common) so new issues do not sit unlabeled for a month.

Anti-patterns to avoid

  • Solution disguised as a problem: "Rewrite checkout in Rust" — say what user pain that solves first.
  • No acceptance criteria on features: leads to endless "is this done?" debate.
  • Screenshot-only bugs with no steps: the image helps, but steps make it reproducible.
  • Comment threads instead of updates: edit the issue description when requirements change; do not bury the spec in 30 comments.
  • Using issues as a chat room: long back-and-forth belongs in Slack or a call; summarize decisions in the issue body.

Epics, milestones, and when to escalate

Not every piece of work fits one issue. Multi-week efforts deserve:

  • A tracking issue or epic with links to child issues
  • A milestone or release target
  • Explicit ordering ("Phase 1: read path, Phase 2: write path")

Escalate to a design doc or RFC when acceptance criteria cannot be written yet because architecture is unsettled. The issue should say: "RFC needed: choose between X and Y" — not pretend the path is obvious.

Summary

Professional git issues have clear titles, reproducible bug reports, and feature requests with acceptance criteria and explicit out-of-scope notes. They use labels consistently, link cleanly to PRs, and stay maintained through regular triage.

The test is simple: if you assigned this issue to someone on vacation, could they return and finish it from the description alone? Write issues that pass that test — and your backlog becomes a tool instead of a graveyard.


Rate this post

All fields are optional. Just stars is fine.

No ratings yet