Based on: GitHub Flow + Conventional Commits + Squash Merge + Semantic Versioning
- One permanent branch:
main - All work happens in short-lived branches
- No direct push to
main - Pull Requests are required for all production changes
- Clean, linear history via Squash and Merge
- Branches are deleted after merge or rejection
- Releases are tagged from
main - Experimental work is isolated from production history
The repository uses a main-first development model:
main
|
+-- short-lived branches
|
+-- merge into main
|
+-- or delete if rejected
| Prefix | Purpose | Commit Type |
|---|---|---|
feature/ |
New functionality intended for production | feat |
bugfix/ |
Fixing non-critical bugs | fix |
hotfix/ |
Critical production fixes | fix |
experiment/ |
Research, evaluation, uncertain changes | experiment |
spike/ |
Short technical investigation / proof of concept | spike |
prototype/ |
Early prototype implementation | prototype |
chore/ |
Maintenance, dependencies, cleanup | chore |
docs/ |
Documentation updates | docs |
refactor/ |
Code restructuring without behavior change | refactor |
test/ |
Adding or updating tests | test |
ci/ |
CI/CD pipeline changes | ci |
perf/ |
Performance improvements | perf |
build/ |
Build system changes | build |
security/ |
Security-related fixes | security |
release/ |
Release stabilization (temporary) | — |
These branches contain changes expected to reach main.
Examples:
feature/login
bugfix/fix-parser
hotfix/security-patch
Lifecycle:
feature branch → push → PR → review → squash merge → main → delete branch
Experimental branches are used for work where the final decision is unknown.
Examples:
experiment/viewer-integration
experiment/new-parser
experiment/wasm-threading
Typical use cases:
- Evaluating a new library
- Testing a new architecture
- Performance investigation
- Technology comparison
- Proof of concept
- Temporary prototypes
Experimental branches:
- May never be merged
- Do not require a clean commit history
- Can contain incomplete code
- Can be deleted at any time
Lifecycle:
experiment branch
|
|
+---- successful
| |
| v
| create feature branch
| |
| v
| PR + squash merge
|
|
+---- rejected
|
v
delete branch
A spike is a very short technical investigation.
Examples:
spike/test-viewer-performance
spike/evaluate-wasm-memory
spike/test-rust-parser
Purpose:
Answer technical questions quickly:
- Is this possible?
- Is the performance acceptable?
- Does this library fit our architecture?
A spike usually produces:
- Knowledge
- Benchmarks
- Prototype code
It does not necessarily produce production code.
Use:
feature/
when:
"We believe this belongs in the product."
Use:
experiment/
when:
"We need to learn whether this belongs in the product."
Example:
experiment/viewer-integration
After validation:
feature/viewer
is created with only the required production-quality code.
- Use lowercase
- Use kebab-case
- Keep names short and descriptive
Good:
feature/file-browser
experiment/viewer-integration
spike/test-reader
Bad:
Feature/NewFileBrowser
my_test_branch
experimentalStuff
Before the team starts, configure these on GitHub:
- ✔ Branch Protection Rule on
main(block direct push) - ✔ Required Reviewers (minimum 1 approval before merge)
- ✔ Required CI checks must pass before merge
- ✔ Auto-delete branches after merge
- ✔ PR Template (
.github/PULL_REQUEST_TEMPLATE.md) - ✔ CODEOWNERS (
.github/CODEOWNERS) for automatic reviewer assignment
git checkout main
git pull
git checkout -b feature/logingit commit -m "feat: add login system"git push -u origin feature/login- Use Draft PR for incomplete work
- Mark Ready for Review when complete
Requirements:
- Code review approved
- Tests passed
- CI successful
feature branch
|
v
squash merge
|
v
main
The branch is automatically deleted after merge.
Experimental branches do not always require PR merge.
Example:
git checkout main
git pull
git checkout -b experiment/viewer-integrationCommit:
git commit -m "experiment: evaluate viewer integration"Push:
git push -u origin experiment/viewer-integrationPossible outcomes:
Create a production feature:
git checkout main
git checkout -b feature/file-browserMove only production-ready code.
Delete the branch:
git push origin --delete experiment/viewer-integrationThe experiment remains only in Git history if needed.
For critical production bugs.
main → hotfix/* → PR → squash merge → main → tag
- Branch directly from
main:
git checkout main && git pull
git checkout -b hotfix/fix-critical-crash-
Apply the fix
-
Open PR to
main(expedited review — minimum 1 reviewer) -
Squash and Merge
-
Tag immediately on
main:
git tag v1.4.3
git push origin v1.4.3Most modern teams release directly from main using tags.
Release branches are optional — use them only when stabilization requires multiple coordinated fixes.
feature PR → squash merge → main → tag → release
git tag v1.2.0
git push origin v1.2.0main → release/v1.2.0 → final fixes → merge back to main → tag → delete
- Create release branch from
main:
git checkout -b release/v1.2.0-
Apply only bugfixes — no new features
-
Merge back into
main:
git checkout main
git merge release/v1.2.0
git push- Tag on
main:
git tag v1.2.0
git push origin v1.2.0- Delete release branch:
git branch -d release/v1.2.0
git push origin --delete release/v1.2.0
release/*is temporary. It exists only for stabilization, then it is deleted.
type(scope): description
or:
type: description
- ✔ lowercase
- ✔ imperative mood (
add,fix,update) - ✔ no period at end
- ❌ no uppercase types
- ❌ no full sentences
| Type | Meaning |
|---|---|
feat |
New feature |
fix |
Bug fix |
experiment |
Experimental investigation |
spike |
Technical exploration |
prototype |
Prototype implementation |
chore |
Maintenance |
refactor |
Code restructuring |
docs |
Documentation |
test |
Tests |
ci |
CI/CD |
perf |
Performance |
build |
Build system |
security |
Security fixes |
Examples:
feat: add genome browser
fix: handle empty vcf file
experiment: evaluate viewer integration
spike: benchmark wasm parser
chore: update dependencies
refactor: simplify parser interface
docs: update architecture guide
feat!: redesign authentication API
BREAKING CHANGE: token format has changed from JWT to opaque token
git tag v1.2.0
git push origin v1.2.0MAJOR.MINOR.PATCH
| Change Type | Version Update | Example |
|---|---|---|
fix |
PATCH | 1.4.2 → 1.4.3 |
feat |
MINOR | 1.4.2 → 1.5.0 |
| Breaking change | MAJOR | 1.4.2 → 2.0.0 |
Reference: https://keepachangelog.com/en/1.1.0/
Example:
## [1.2.0] - 2026-06-12
### Added
- login system via OAuth
### Fixed
- crash on startup with empty config (#102)
### Security
- patched XSS vulnerability in input fieldsmain
|
+-- feature/*
| |
| +-- PR
| +-- squash merge
|
+-- bugfix/*
|
+-- hotfix/*
|
+-- experiment/*
| |
| +-- convert to feature
| +-- or delete
|
+-- spike/*
|
+-- knowledge gained
+-- prototype discarded
| Practice | Recommendation |
|---|---|
| Branching model | GitHub Flow |
| Permanent branches | main only |
| Feature development | feature/* |
| Research work | experiment/* |
| Technical investigation | spike/* |
| Merge strategy | Squash and Merge |
| Commit format | Conventional Commits |
| Versioning | Semantic Versioning |
| Changelog | Keep a Changelog |
| Release | Tag from main (release branch optional) |
| Branch protection | Required on main |
| PR review | Minimum 1 reviewer |