🌿 Branching Strategies and Workflows
Branching is the feature that made Git famous. In a few milliseconds you can spin off a parallel line of development, experiment freely, and either fold your work back in or throw it away — all without touching the code your teammates depend on. This lesson takes you from "what is a branch, really?" to the four workflows real teams argue about.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Explain what a Git branch actually is under the hood — a movable pointer — and the role of the HEAD pointer
- Perform every core branching operation: create, list, switch, merge, rename, and delete
- Compare the four dominant workflows — GitFlow, GitHub Flow, Trunk-Based Development, and Release Flow
- Choose an appropriate strategy for a given team, release cadence, and risk profile
- Apply naming conventions and branch-protection rules that keep a shared repository healthy
Estimated Time: 35–45 minutes • Difficulty: Intermediate
Hands-on: Build a two-feature history from scratch and merge both branches into main.
In This Lesson
Why Branching Matters
In the previous lesson you learned Git's core commands — add, commit, status, log. Those let you record history on a single line of development. But real projects are never a single line. Two people fix two different bugs at once; you want to try a risky rewrite without endangering the version that ships tomorrow; a hotfix has to go out while a big feature is half-finished. Branching is how Git handles all of that gracefully.
💡 A useful analogy: A branch is a parallel universe for your code. You step into it, make whatever changes you like, and the "main timeline" is completely untouched until you deliberately merge the two universes back together. If the experiment fails, you delete the universe and no one ever knows it existed.
Here's the simplest possible branch-and-merge story: split off a feature branch, do some work, and bring it home.
The reason Git can do this so cheaply — and why it changed how the industry works — is that a branch is almost nothing. Let's see exactly what.
What a Branch Really Is
In many older version-control systems, "branching" meant copying every file into a new folder — slow and heavy. In Git, a branch is just a 40-byte file containing the hash of one commit. Creating a branch creates that tiny pointer and nothing else. That's why it's instant.
Think of a branch as a sticky note placed on a specific commit. When you make a new commit while standing on that branch, Git peels the sticky note off the old commit and moves it forward to the new one — automatically.
The HEAD pointer
Alongside your branch pointers, Git keeps one special pointer called HEAD. HEAD answers the question "which branch am I currently on?" When you check out a branch, HEAD attaches to it; when you commit, the branch HEAD points to moves forward.
If you check out a raw commit hash instead of a branch, HEAD points directly at that commit — a state Git calls detached HEAD. New commits made there belong to no branch and can be garbage-collected later, so if you want to keep them, create a branch first.
📖 Key Terms
Branch: a lightweight, movable pointer to a commit.
HEAD: a pointer to the branch you currently have checked out.
Detached HEAD: the state where HEAD points at a commit directly, not a branch — useful for looking around, dangerous for committing.
Core Branching Commands
Modern Git (2.23 and newer) split the overloaded git checkout into two clearer verbs: git switch for moving between branches and git restore for discarding file changes. Both the old and new commands still work; we'll show the modern form first and note the classic equivalent.
Create, list, and switch
# Create a branch (does NOT move you onto it)
git branch feature-login
# List branches — the current one is marked with *
git branch # local branches
git branch -r # remote-tracking branches
git branch -a # all branches, local and remote
# Switch onto a branch
git switch feature-login # modern
git checkout feature-login # classic equivalent
# Create AND switch in one step
git switch -c feature-login # modern
git checkout -b feature-login # classic equivalent
Rename, merge, and delete
# Rename the branch you are currently on
git branch -m new-name
# Rename a branch you are NOT on
git branch -m old-name new-name
# Merge another branch INTO your current branch
git switch main
git merge feature-login
# Delete a branch (safe: refuses if it has unmerged work)
git branch -d feature-login
# Force-delete, even with unmerged work (be sure!)
git branch -D feature-login
⚠️ Watch the direction of a merge
git merge always merges the named branch into the branch you are standing on. Before merging, run git status to confirm HEAD is on the target (usually main). Merging into the wrong branch is one of the most common beginner mistakes.
The Four Workflows
The mechanics above are universal. What differs between teams is the convention — which branches exist, how long they live, and how work flows between them. These conventions are called branching strategies. Here are the four you will meet most often.
1. GitFlow
Introduced by Vincent Driessen in 2010, GitFlow is a structured model organized around scheduled releases. It uses long-lived main and develop branches plus short-lived feature/*, release/*, and hotfix/* branches.
| Branch | Purpose |
|---|---|
main | Always production-ready; every commit is a shipped version |
develop | Integration branch — the staging area for the next release |
feature/* | Branch off develop, merge back into develop |
release/* | Final polish and bug-fixing before a release; merges into both main and develop |
hotfix/* | Emergency fix branched off main; merges back into both main and develop |
Strengths: clear roles, strong support for parallel features and multiple maintained versions. Weaknesses: heavy for small teams, slow to integrate, and poorly suited to continuous delivery — main can drift far behind reality between releases.
# Start and finish a feature under GitFlow
git switch develop
git switch -c feature/user-login
# ...work and commit...
git switch develop
git merge feature/user-login
git branch -d feature/user-login
2. GitHub Flow
A radically simpler model built for continuous delivery. There is one long-lived branch — main, always deployable — and short-lived branches off it, each reviewed via a pull request and deployed the moment it merges.
The whole workflow is: branch off main → commit and push → open a pull request → review and run CI → merge → deploy immediately. Strengths: dead simple, fast iteration, few conflicts thanks to tiny branches. Weaknesses: little built-in support for maintaining several released versions, and it leans hard on solid automated testing and deployment.
git switch main
git pull
git switch -c feature/add-login
# ...work...
git add .
git commit -m "Add login form"
git push -u origin feature/add-login
# open a pull request, get it reviewed, merge, deploy
3. Trunk-Based Development
Here everyone integrates into a single branch ("the trunk", usually main) many times a day. Branches, if used at all, live only hours. Incomplete work hides behind feature flags so main stays releasable at all times.
Strengths: minimal branch management, tiny and rare conflicts, and it's the foundation of true continuous integration. Weaknesses: demands excellent automated test coverage and disciplined developers; feature-flag sprawl can become its own maintenance burden.
4. Release Flow (Microsoft's model)
A pragmatic middle ground that Microsoft's engineering teams adopted. Day-to-day work looks like GitHub Flow — feature branches off a healthy main, merged via pull requests. When it's time to ship, a release/* branch is cut from main; fixes needed on that release are made there and cherry-picked back to main.
Strengths: combines GitHub Flow's simplicity with GitFlow's ability to support scheduled releases and multiple live versions. Weaknesses: cherry-picking is error-prone and needs discipline and good tooling.
✅ The pattern behind all four
Every strategy answers the same three questions differently: which branches live long?, where does new work start?, and how do fixes reach released versions? Once you can answer those for a strategy, you understand it.
Choosing a Strategy
There is no single "best" workflow — only the best fit for your team, cadence, and risk. Weigh these factors:
- Team size & distribution — larger, more distributed teams benefit from more structure.
- Release cadence — deploying many times a day pushes you toward GitHub Flow or Trunk-Based; scheduled quarterly releases suit GitFlow or Release Flow.
- Number of maintained versions — supporting several live versions needs release branches.
- Test automation maturity — Trunk-Based Development is only safe with strong automated tests.
- Regulatory / audit needs — heavily regulated industries value the explicit trail that GitFlow and Release Flow provide.
| Context | Recommended | Why |
|---|---|---|
| Startup / small team | GitHub Flow or Trunk-Based | Low overhead, fast iteration, easy communication |
| Enterprise product, batched releases | GitFlow or Release Flow | Structure for multiple versions and audit trails |
| Web app, continuous delivery | GitHub Flow or Trunk-Based | Rapid, frequent deployment |
| Open-source project | GitHub Flow (or GitFlow if complex) | Clear structure for outside contributors |
These are templates, not laws. Plenty of teams run hybrids — GitHub Flow plus occasional release branches for major versions, or Trunk-Based with slightly longer branches for big changes. The single most important thing is that the whole team follows the same convention consistently.
Naming & Branch Protection
Naming conventions
A consistent prefix tells everyone a branch's purpose at a glance. Use kebab-case after the prefix:
| Prefix | Use for | Example |
|---|---|---|
feature/ | New functionality | feature/user-authentication |
bugfix/ | Non-critical fixes | bugfix/login-validation |
hotfix/ | Urgent production fixes | hotfix/payment-timeout |
release/ | Release preparation | release/1.4.0 |
docs/ | Documentation only | docs/api-reference |
Branch protection
Hosting platforms (GitHub, GitLab, Bitbucket) let you enforce your workflow with branch protection rules on important branches like main:
- Require pull-request review before merging (block direct pushes)
- Require status checks — tests and CI must pass first
- Restrict who may push
- Require a linear history (force rebase/squash over merge commits)
- Automatically delete branches once merged
Set up the modern defaults when you start a repo:
# New repos default to a 'main' branch (Git 2.28+)
git config --global init.defaultBranch main
# Initialize a repo with main directly
git init -b main
# Prune remote-tracking branches that were deleted upstream
git fetch --prune
Hands-on Exercise
🏋️ Build a Two-Feature History
Objective: Create two feature branches from main, develop them independently, and merge both back — then read the graph you produced.
Instructions:
- Create an empty repository and an
index.html, then commit it tomain. - Create and switch to
feature/header; add a header element and commit. - Switch back to
main, then createfeature/footer; add a footer (a different part of the file so it won't conflict) and commit. - Switch to
mainand mergefeature/header, then mergefeature/footer. - Run
git log --graph --oneline --alland describe the shape you see.
💡 Hint
Because the two features touch different regions of the file, the first merge is a fast-forward and the second is a true (three-way) merge that creates a merge commit. Watch how the graph branches then rejoins.
✅ Solution
mkdir branch-demo && cd branch-demo
git init -b main
printf '<body>\n</body>\n' > index.html
git add index.html
git commit -m "Add empty page skeleton"
git switch -c feature/header
# insert <header>Site Title</header> near the top of index.html
git commit -am "Add page header"
git switch main
git switch -c feature/footer
# insert <footer>© 2026</footer> near the bottom of index.html
git commit -am "Add page footer"
git switch main
git merge feature/header # fast-forward
git merge feature/footer # creates a merge commit
git log --graph --oneline --all
The final graph shows main advancing straight through the header commit, then splitting to the footer branch and rejoining at a merge commit.
🎯 Quick Quiz
Question 1: Under the hood, what is a Git branch?
Question 2: Which workflow keeps one always-deployable main branch and ships each pull request the moment it merges?
Question 3: You run git switch main then git merge feature. What happens?
Best Practices
✅ Do
- Keep branches focused and short-lived — one clear purpose, merged within days.
- Commit often with meaningful messages; consider Conventional Commits.
- Sync with
mainregularly so conflicts stay small. - Use pull requests for review and enforce branch protection on shared branches.
- Delete branches after merging and prune remotes to keep the repo tidy.
⚠️ Don't
- Let a "development-hell" branch live for months with hundreds of commits — it becomes a merge nightmare.
- Force-push over shared branches; if you must, use
--force-with-leaseso you never clobber a teammate's work. - Mix unrelated changes in one branch — it makes review and revert harder.
- Adopt a strategy no one wrote down; document it in
CONTRIBUTING.md.
Example of a well-formed commit message that pairs beautifully with any branching strategy:
feat(auth): add password-reset flow
Send a time-limited token by email and validate it when the user
clicks the reset link, so users can recover accounts without support.
Resolves: #123
Summary & Quiz
🎉 Key Takeaways
- A branch is a movable pointer to a commit; HEAD points at the branch you're on. That's why branching is instant.
- The core verbs are
git switch/checkout,git branch, andgit merge; merge pulls the named branch into your current one. - The four dominant workflows — GitFlow, GitHub Flow, Trunk-Based, Release Flow — differ only in which branches live long, where work starts, and how fixes reach releases.
- Choose by team size, release cadence, versions maintained, and test maturity — then document and apply it consistently.
- Naming conventions and branch protection keep shared repositories healthy.
📚 Further Reading
- A Successful Git Branching Model (GitFlow)
- GitHub Flow
- Trunk-Based Development
- Pro Git — Branching Workflows
- Martin Fowler — Patterns for Managing Source Code Branches
🚀 What's Next?
You can now create branches and pick a workflow. Next we go deep on the moment two branches come back together: the mechanics of merging vs. rebasing, and how to resolve the conflicts that inevitably arise.
🎉 Nice work!
You've mastered how work diverges. Time to learn how it converges again.