Version Control Manual v1.
0
Written by: Ivan Reeve Lopez
Updated: September 7, 2025
Note: This manual is intended for developers who want to contribute code to the project. This
document contains guidelines, frameworks, and best practices for maintaining the project
through the use of version control software. I encourage the system designer and business
analyst to read this handout.
Notably, this document addresses the following topics:
1. Our branching strategy
2. Project directory structure
3. Commit conventions
4. Contribution workflows
5. Semantic versioning
Version Control Software
The version control software that the team will use for the project is Git.
What is Git?
Git is a free and open-source distributed version control system designed to handle everything
from small to very large projects with speed and efficiency. It allows multiple people to work on a
project simultaneously, tracks changes to files over time, and makes it easy to collaborate,
branch, and merge code.
For starters, I recommend going through this no-bullshit guide on the basic Git workflow. After
going through the handout, get your hands dirty by creating a private repository and using what
you have learned to play with it.
1. Branching Strategy
The branching strategy the team will use for version control is feature branching.
Feature branching is a version control strategy where each new feature, bug fix, or task
is developed in its own dedicated branch, isolated from the main branch (main or
develop). Developers create a new branch when they begin working on a feature,
commit changes there, and only merge it back into the main branch once the work is
complete, reviewed, and tested.
Why use this branching strategy? Feature branching
enables parallel development by allowing developers to
work on different things at the same time. Developers
can work on different features nondestructively.
Since each feature is developed in its own branch,
work-in-progress won’t disrupt the stability of the main
branch. Pull requests are more focused and easier to
review because each branch targets a specific feature
or fix. That helps maintain high code quality.
This strategy synergizes with the project’s lean agile
scrum methodology by empowering the team to develop
and ship features extremely fast.
Branch Prefixing
Branches are prefixed by type:
Prefix Description
feat/ Used for developing new capabilities or enhancements
to the project, keeping them separate until they’re
complete.
fix/ Dedicated to fixing bugs or defects, often tied to a
specific issue or ticket in Jira.
hotfix/ Intended for urgent fixes that need to be applied
directly to production code to resolve critical issues.
chore/ Used for routine maintenance tasks such as updating
dependencies, configuring CI, or polishing
documentation, not directly related to features or fixes.
Examples:
● feat/123-add-login-page
● fix/456-fix-registration-error
● hotfix/urgent-payment-bug
● chore/update-dependencies
● release/v1.2.0
Branch Naming Conventions
Kebab-case (lowercase words separated
by hyphens) is widely recommended for
branch names thanks to its exceptional
readability, consistency, and compatibility
with scripts, URLs, and team workflows.
2. Project Directory Structure
📂 Repository Structure & Key Files
● .github/workflows/ – Contains CI/CD automation workflows (e.g., GitHub
Actions).
○ Useful for enforcing tests, linting, or deployment pipelines.
● public/ – Static assets directory (images, fonts, etc.) that Next.js serves directly.
● src/app/ – Core application source folder. This follows the Next.js App Router
convention, where routes and components live.
⚙️ Configuration & Setup Files
● .gitattributes – Defines repository attributes like line endings normalization.
Helps maintain consistency across different dev environments.
● .gitignore – Lists files/folders Git should ignore (e.g., node_modules, build
outputs). Prevents unnecessary or sensitive files from being committed.
● eslint.config.mjs – Configures ESLint for code quality and style enforcement.
Helps maintain consistent formatting and catch issues early.
● next.config.ts – Next.js project configuration (custom builds, rewrites, env
settings).
● package.json – Defines project metadata, dependencies, and scripts (dev,
build, lint, etc.). Central to managing the project.
● pnpm-lock.yaml – Lockfile for deterministic dependency installs using pnpm.
Ensures all developers use the same versions.
● postcss.config.mjs – Configures PostCSS (e.g., Tailwind CSS, autoprefixer).
Handles CSS transformations.
● tsconfig.json – TypeScript configuration (compiler options, path aliases,
strictness settings).
📄 Documentation & Licensing
● CONTRIBUTING.md – Instructions for how contributors should engage with the
project (branching strategy, PR guidelines, coding standards).
● LICENSE.md – Defines legal usage of the project (open-source license terms).
● README.md – Main documentation: project purpose, setup instructions, usage,
and links. Serves as the first touchpoint for new developers.
3. Commit Conventions
To maintain clarity, consistency, and automation across our repository, we follow a
Conventional Commits style combined with Gitmoji prefixes. Each commit aligns
with a specific category, marked by an emoji and a conventional commit type, optionally
including a scope. This approach enhances readability and supports tools like
semantic-release or changelog generators.
Structure
<gitmoji> <type>(<scope>): <Short description>
● <gitmoji> – A standardized emoji indicating the nature of the change.
● <type> – Conventional commit type
● <scope> (optional) – Context such as ci, repo, eslint, etc.
● <Short description> – Concise, imperative summary of the change.
Commit Types
Type When to use
feat Add a new user-facing feature.
fix Correct a bug or faulty behavior.
docs Change documentation only.
style Code style/formatting changes with no logic impact.
refactor Restructure code without changing behavior.
perf Improve performance without altering features.
test Add, update, or remove tests.
build Modify build system, tooling, or dependencies.
ci Update CI configuration or workflows.
chore Routine tasks that don’t affect src or tests (e.g., configs).
revert Revert a previous commit.
Examples (inspired by actual commits):
○ 🛠 chore(ci): clarify PR source branch check
○ 📝 docs(repo): add initial project docs and license
○ 💄 style(eslint): enforce consistent code formatting
These mappings align with Gitmoji standards and improve visual scanning of commit
history.
For automated commit message generation, I recommend my tool for turning git
patches into descriptive commits. More instructions here.
4. Contribution Workflows
This section explains exactly how to create pull requests (PRs) and merge them, aligned
with our feature-branching strategy and the branch protection rules on develop and
main. It also covers the GitHub Actions check that restricts PRs targeting main.
4. Contribution Workflows
This section explains exactly how to create pull requests (PRs) and merge them, aligned
with our feature-branching strategy and the branch protection rules on develop and
main. It also covers the GitHub Actions check that restricts PRs targeting main.
Overview: Which branch for what?
● Work branches: create a short-lived branch per task using the prefixes feat/,
fix/, hotfix/, or chore/ (e.g., feat/123-add-login-page).
● Integration branch: develop — all features/fixes merge here via PR. On
develop, only rebase merges are allowed and CODEOWNERS review is
required.
● Production branch: main — releases land here via a PR from develop only.
On main, merge commits are allowed (not rebase/squash), CODEOWNERS
review is required, and a required status check named check-branch must
pass.
Why only develop → main? A required GitHub Action (Restrict PRs to
main) blocks any PR to main unless the source branch is exactly develop (it fails
with “Only pull requests from 'develop' branch can be merged into 'main'.”). The
same check is enforced as a required status check on main.
Standard flow: Feature/Fix → develop
1. Branch off develop.
1. Commit following our Conventional Commits + Gitmoji convention.
2. Push and open a PR with base = develop.
3. Pass reviews & policies. On develop, PRs require
○ CODEOWNERS review (required), and stale reviews auto-dismiss if you
push again.
○ Merge method = rebase (fast-forward history; no merge commits).
4. Merge using “Rebase and merge.” (UI will only offer rebase on develop.)
Release flow: develop → main
1. Prepare develop. Ensure it contains everything you want to ship and is green.
2. Open a PR with base = main and compare = develop.
○ The check-branch required status check must pass (it verifies the
source branch is develop).
○ CODEOWNERS review is required; stale reviews auto-dismiss on new
pushes.
○ Merge method = merge commit (squash/rebase are not allowed on
main).
3. Merge using “Create a merge commit.”
4. (Optional) Tag/release per Semantic Versioning in Section 5.
Hotfix flow (urgent production fix)
Because main only accepts PRs from develop, hotfixes still move through develop:
1. Branch from main: hotfix/urgent-payment-bug.
2. Fix → PR into develop → rebase-merge.
3. Open develop → main PR and merge (the check-branch rule will permit it).
(Direct hotfix PRs to main will be blocked by the action and required status check.)
Rules that can block your PR (and how to fix them)
Wrong source for main: If your PR to main doesn’t come from develop, the
check-branch status check will fail. Fix: retarget to develop, or merge your
branch into develop first, then open develop → main.
Missing CODEOWNERS approval: Both develop and main require
CODEOWNERS review. Fix: request review from the correct owners. (Note:
approvals are dismissed if you push changes.)
Wrong merge method:
○ develop only allows rebase merge.
main only allows a merge commit.
Fix: choose the permitted method in the PR UI.
Protected branch safety: develop and main block force-push
(non-fast-forward) and deletion. Fix: don’t force-push; update via PR.
Quick PR checklists
For any feature/fix PR to develop:
● Branch name uses the correct prefix (e.g., feat/…, fix/…).
● Clean commit history and message style follow our conventions.
Request CODEOWNERS review; expect dismissal if you push new
commits.
● Merge via Rebase and merge.
For a release PR develop → main:
● Source branch is exactly develop (required).
● check-branch status check is green.
● CODEOWNERS approved.
● Merge via Create a merge commit.
Policy summary (for quick recall)
● Strategy: feature branches → PR to develop → PR develop → main to
release.
● develop protection: code-owner review required; rebase-only merges; no
deletion/force-push.
● main protection: code-owner review required; merge commits only; required
status check check-branch must pass; no deletion/force-push.
● Action: PRs to main are restricted to develop as the source branch.
This workflow keeps develop linear and fast for team integration, while main remains a
protected, review-gated release branch.
5. Semantic Versioning (SemVer)
We version releases as MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD], following
SemVer 2.0.0.
Examples: 2.4.1, 1.3.0-rc.2, 3.0.0-beta.1+20250907.
What each part means
● MAJOR – incompatible API changes or behavior that requires user action.
● MINOR – backward-compatible feature additions or improvements.
● PATCH – backward-compatible bug fixes, docs-only tweaks, or internal refactors
that do not change behavior.
Compatibility Promise
● Within a given MAJOR line (e.g., all 1.x.y), public APIs, CLIs, and
on-disk/over-the-wire formats remain compatible.
● Any planned break will be deprecated first (warning in release notes) and
removed in the next MAJOR.
When to Bump What
● MAJOR
○ Removing/renaming public API
○ Changing default behavior in a way that could break existing workflows
○ Incompatible schema/protocol changes
● MINOR
○ New public API/CLI, opt-in features, new config keys with safe defaults
○ Performance improvements that don’t change outputs
● PATCH
○ Bug fix, security patch, dependency bump with no behavior change,
doc/site updates
Pre-releases
Use a hyphen and label: -alpha.N, -beta.N, -rc.N (N starts at 1).
Ordering (lowest → highest): alpha < beta < rc < final.
Example precedence:
1.0.0-alpha.1 < 1.0.0-alpha.2 < 1.0.0-beta.1 < 1.0.0-rc.1 <
1.0.0.
Cheat Sheet
● “Fix a bug” → bump PATCH
● “Add a new, optional feature” → bump MINOR
● “Change or remove something users rely on” → bump MAJOR
“Cut a preview build” → append -alpha.N/-beta.N/-rc.N
Tip: If unsure, default to MINOR for new behavior that’s off by default;
MAJOR if any existing code/config might break.