Git, CI/CD & GitOpsVIII · BranchingBranching
Branch naming and organization — patterns that signal intent to the team
What you'll learn
- Recognise the conventional prefixes (feature/, bugfix/, release/, hotfix/) and what each one signals about lifetime and merge target
- Apply slash-namespaces in branch names and understand how they map to the refs/heads/ directory
- Read a branch name and infer the merge strategy, review requirements, and deletion window without checking the branch contents
- Choose between long-lived trunk-based branches and short-lived feature branches based on team size and release cadence
- Recognise the failure modes of poor naming (no naming convention, ambiguous prefixes, ticket-id-only names)
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
A branch name is the smallest possible unit of project
documentation. Before a reviewer opens the diff, before CI runs
the tests, before the merge button is offered, the branch name
is the only information the team has about a line of work. A
name like feature/iam-rotation carries four signals: the kind
of work (feature), the area of the system (iam), the specific
change (rotation), and an implicit merge target (the trunk). A
name like wip or test or john-branch carries none of those
signals and forces the reviewer to read the commit log to find
out. In production, the branch name is the cheapest piece of
documentation the team can write. The discipline is to write
names that document themselves.
Conventional prefixes
Four prefixes cover the vast majority of branch lifetimes in a production workflow:
feature/<name>— A new capability or non-urgent change. Created from the trunk (typicallymain), merged back via a pull request, deleted after merge. Lifetime: days to weeks.bugfix/<name>— A bug fix that does not need to ship immediately. Created from the trunk, merged via a PR with a test plan attached, deleted after merge. Lifetime: hours to days.release/<name>— A stabilisation branch cut from the trunk when a release candidate is being prepared. Accepts only bug fixes and version bumps; new features are forbidden. Lifetime: days to weeks, until the release ships.hotfix/<name>— An emergency fix that must ship immediately, bypassing the normal release cadence. Created from a tagged release commit, merged back to both the trunk and the release branch, deleted after merge. Lifetime: hours.
# Conventional names
git switch -c feature/iam-key-rotation
git switch -c bugfix/cert-renewal-fails-on-renew
git switch -c release/v1.4.0
git switch -c hotfix/prod-503-ingress
The signal each name carries:
| Prefix | Source | Merge target | Lifetime |
|---|---|---|---|
| feature/ | trunk | trunk via PR | days-weeks |
| bugfix/ | trunk | trunk via PR | hours-days |
| release/ | trunk at cut point | trunk after ship | days-weeks |
| hotfix/ | tagged release | trunk + release branch | hours |
A reviewer who sees feature/iam-key-rotation knows it is a new
capability that should land via PR into main and can be deleted
after the merge. The same reviewer who sees hotfix/prod-503
knows it is an emergency change that may have skipped the
ordinary review cadence and must be scrutinised carefully. The
prefix is a routing rule.
flowchart LR
A["main"] --> B["feature/iam-rotation"]
B --> C["PR into main"]
C --> D["merged"]
A --> E["release/v1.4.0"]
E --> F["bugfix/cert-renewal"]
F --> G["PR into release/v1.4.0"]
G --> H["shipped"]
I["v1.3.0 tag"] --> J["hotfix/prod-503"]
J --> K["merged into main + v1.3.1 tag"]
The diagram shows the four conventional flows. feature/ and
bugfix/ branches return to main; release/ branches accept
bugfixes and ship; hotfix/ branches fork from a tag and merge
back to both the trunk and the live release.
Slash-namespaces and ref storage
A branch name with slashes is not just a convention; it is a
hierarchical ref name that maps directly to the directory layout
under .git/refs/heads/:
git branch -a
# feature/iam-rotation
# hotfix/prod-503
# release/v1.4.0
On disk:
ls "$GIT_DIR/refs/heads"
# feature
# hotfix
# main
# release
ls "$GIT_DIR/refs/heads/feature"
# iam-rotation
ls "$GIT_DIR/refs/heads/release"
# v1.4.0
The slash becomes a directory separator. A branch named
feature/iam-rotation is a file at .git/refs/heads/feature/iam-rotation;
a branch named feature/iam/key-rotation would be a file at
.git/refs/heads/feature/iam/key-rotation. The hierarchy is
real, and git branch --list 'feature/*' exploits it to match
every branch under the feature/ namespace.
The hierarchy can be as deep as the team finds useful. Common patterns:
# Flat: one level of prefix
feature/iam-rotation
bugfix/cert-renewal
# Two-level: subsystem grouping
feature/iam/key-rotation
feature/network/policy-update
bugfix/storage/s3-permission-denied
# Three-level: subsystem + component
feature/iam/keys/rotation-cron
bugfix/network/policy/egress-block
The deeper the hierarchy, the more the namespace can be matched
with glob patterns. --list 'feature/iam/*' returns every
feature branch in the IAM subsystem; --list 'release/v*'
returns every release branch whose name starts with v.
What a good branch name documents
The four properties a good branch name carries, in priority order:
- Lifetime. Is this a feature, a bug fix, a release, or a hotfix? The prefix answers this question and tells the reviewer the expected merge target and deletion window.
- Area. Which subsystem does this touch? The first path
component after the prefix (
iam,network,storage) scopes the change and lets CI run only the relevant test suite. - Specific change. What is the change in plain English? The
remaining path components describe what the change is. A
name like
iam-rotationis descriptive; a name likefix-bugis not. - Ticket reference. What tracking-system entry is this
change tied to? The trailing path component (often a JIRA
key like
INFRA-1234or a GitHub issue number) links the branch to the issue tracker.
# All four properties in one name
feature/iam/key-rotation-INFRA-1234
# Three properties (no ticket)
bugfix/storage/s3-permission-denied
# Two properties (no subsystem grouping)
hotfix/prod-503
# One property (just a prefix)
feature/wip
The last example is the failure mode: a prefix with no documentation. The reviewer cannot scope the change, cannot link it to a ticket, and cannot predict the merge target.
Patterns for trunk-based versus feature-branch workflows
The branch naming convention interacts with the team’s branching strategy. Two ends of the spectrum:
-
Trunk-based development. Most work happens on the trunk itself, behind feature flags. Branches are short-lived (hours), names are minimal (
eng-name/initials), and the merge target is always the trunk. The discipline is “branch per change, merge within the day”. -
Feature-branch workflow. Each significant change lives on its own branch until reviewed. Names are descriptive (
feature/<area>/<change>-<ticket>), branches live for days or weeks, and the merge target is the trunk via a PR. The discipline is “branch per PR, merge when reviewed”.
# Trunk-based naming: short-lived, minimal
git switch -c jdoe/flag-iam-rotation
git switch -c jdoe/cleanup-cert-handling
# Feature-branch naming: long-lived, descriptive
git switch -c feature/iam/key-rotation-INFRA-1234
git switch -c bugfix/network/policy-update-INFRA-1235
Trunk-based naming is faster to write but requires the team to have strong feature-flag discipline to keep the trunk shippable. Feature-branch naming is slower to write but allows the trunk to be protected by branch protection and required reviews. The choice depends on team size, release cadence, and the cost of a broken trunk — not on personal preference.
Production discipline
- Adopt a documented prefix convention. The first ticket in the team’s onboarding doc should be “the branch prefixes we use and what they mean”. Without documentation, the convention is folklore and is followed inconsistently.
- Include a ticket ID in the branch name when one exists. The ticket ID is the link from the commit to the discussion, the acceptance criteria, and the closing record. A branch without a ticket ID is a branch whose rationale is not recorded anywhere outside the commit message.
- Scope CI on the prefix. CI that detects the prefix
(
feature/iam/*) can run the IAM test suite only, not the full battery. The naming convention is the routing key. - Delete branches after merge. A
feature/branch that has been merged into the trunk is a branch whose work is in the trunk and whose existence serves no purpose. Thegit-cicd-gitops-viii-02lifecycle lesson covers the safe deletion pattern.
Cross-course references
- Ansible for Production Sysadmins - Part XXXVIII (Review)
uses
feature/<area>/<change>-<ticket>as the standard Ansible repository convention. The prefix is matched by the Ansible lint configuration to scope playbook reviews. - GitOps with Argo CD - Part IV (AppSources) discusses slash-namespaces in the context of multi-source applications, where each source has its own branch prefix and the controller uses the prefix to route sync policies.
- Terraform for Production Sysadmins - Part XII (State) draws the analogy between branch prefixes and Terraform module prefixes: both are routing keys that signal which test suite, review cadence, and deletion window apply.
Quiz
Knowledge check · 4 questions
Q1. A branch named `hotfix/prod-503-ingress` is opened. Which of the following statements is correct?
Q2. A branch named `feature/iam/key-rotation-INFRA-1234` is stored on disk as a single file at `.git/refs/heads/feature/iam/key-rotation-INFRA-1234`.
Q3. What four properties does a good branch name carry, and what is the failure mode when a name carries none of them?
Q4. Recommend a branch naming convention for an infrastructure team and defend it against two common objections.
An infrastructure team of 12 engineers has been using ad-hoc branch names (`wip`, `test`, `john-fix`, `INFRA-1234`) for 18 months. The on-call rotation reports that incident postmortems frequently cannot link a production change to a named branch because the branch was named ambiguously. The team lead asks for a recommended convention. Two senior engineers object: one says 'conventions slow us down', the other says 'the JIRA ID alone is enough, the prefix is noise'.
Passing score: 75%. Answers are checked in this browser.