Git Workflows
A Git workflow is the set of rules your team agrees on for how you create branches, merge changes, and ship code to production. Git itself does not force any one way of working, so picking a workflow is really about matching your branching habits to how often you deploy. Choose well and code moves to users smoothly. Choose badly and you get long-lived branches, painful merges, and slow releases. This page compares the three workflows almost every team uses — GitFlow, GitHub Flow, and trunk-based development — and helps you pick the right one.
First, a quick definition. A branch is a separate line of work in your repository; you can change files on it without affecting the main code. CI/CD means Continuous Integration / Continuous Deployment — automation that builds, tests, and deploys your code every time you push. Deployment frequency is simply how often you release to production (a few times a year, weekly, or many times a day). The workflow you pick should follow your deployment frequency, not fight it.
The three workflows at a glance
| Workflow | Branches used | Best deployment frequency | Complexity | Best for |
|---|---|---|---|---|
| GitFlow | main, develop, feature/*, release/*, hotfix/* | Scheduled (monthly/quarterly) | High | Versioned/desktop software, regulated releases |
| GitHub Flow | main + short-lived feature/* | Continuous (daily) | Low | Web apps and SaaS with CI/CD |
| Trunk-based | main (trunk) + very short branches | Continuous (many per day) | Low–Medium | High-velocity teams, strong test automation |
The big idea: the more often you deploy, the fewer and shorter your branches should be. GitFlow has the most branches and suits slow, scheduled releases. Trunk-based has the fewest and suits teams shipping many times a day.
GitFlow
GitFlow uses two permanent branches — main (always reflects production) and develop (the integration branch where finished features collect). Work happens on feature/* branches cut from develop. When you are ready to ship, you cut a release/* branch to stabilize, then merge it into both main and develop. Urgent production bugs get a hotfix/* branch off main.
# Start a new feature off develop
git checkout develop
git pull origin develop
git checkout -b feature/user-export
# ...commit your work, then merge back into develop
git checkout develop
git merge --no-ff feature/user-export
git push origin develop
Output:
Switched to a new branch 'feature/user-export'
Merge made by the 'recursive' strategy.
src/export.js | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
When to use GitFlow: you ship on a schedule, support multiple released versions at once, or have a formal QA/sign-off step (common in enterprise, desktop, or regulated software). When NOT to use it: if you deploy continuously. The develop and release branches add overhead that slows fast teams down, and long-lived branches drift apart and cause merge conflicts.
Long-lived branches are the number one cause of merge pain. Every day a branch lives away from
main, it diverges further. GitFlow’sdevelopbranch can hide bugs that only appear when many features finally merge together.
GitHub Flow
GitHub Flow is deliberately simple. There is one permanent branch — main — and it is always deployable. To do any work you branch off main, push, open a pull request (a PR is a request to merge your branch, where teammates review the code), let CI run the tests, get an approval, and merge. After merge you deploy main.
git checkout main
git pull origin main
git checkout -b feature/dark-mode
# ...make changes and commit...
git push -u origin feature/dark-mode
# Then open a pull request on GitHub/GitLab for review + CI
Output:
Branch 'feature/dark-mode' set up to track remote branch 'feature/dark-mode' from 'origin'.
remote: Create a pull request for 'feature/dark-mode' on GitHub by visiting:
remote: https://github.com/acme/app/pull/new/feature/dark-mode
When to use GitHub Flow: web apps and SaaS with solid automated tests and CI/CD, deploying daily or several times a week. It is the easiest workflow to teach a new team. When NOT to use it: if you must maintain several old versions in parallel, or you have no automated tests — without CI guarding main, “always deployable” becomes a promise you cannot keep.
Trunk-based development
In trunk-based development everyone commits to one branch — the trunk (your main) — at least once a day. Branches, if used at all, live only a few hours and merge fast. Because changes are tiny and frequent, integration problems surface immediately instead of building up. Features that are not finished are hidden behind feature flags (config switches that turn code on or off at runtime) so unfinished work can sit safely in production without users seeing it.
# Pull the latest trunk, make a small change, rebase, push
git checkout main
git pull --rebase origin main
# ...one small, tested change...
git commit -am "Add CSV export header row"
git pull --rebase origin main # stay current before pushing
git push origin main
Output:
Successfully rebased and updated refs/heads/main.
To github.com:acme/app.git
a1b2c3d..e4f5g6h main -> main
When to use trunk-based: high-velocity teams deploying many times a day, with strong automated tests and feature flags. It is the workflow behind elite DevOps performers (DORA research consistently links it to higher deployment frequency and lower failure rates). When NOT to use it: if your test coverage is weak. Pushing small changes straight to trunk only works when automation catches mistakes before they reach users.
Which should you choose?
Tie the decision to deployment frequency:
- Deploy a few times a year, with formal release gates → GitFlow.
- Deploy daily/weekly, web app, good CI → GitHub Flow.
- Deploy many times a day, strong tests, feature flags → trunk-based.
For most modern CI/CD-heavy teams, GitHub Flow or trunk-based development is the right answer. They keep branches short, merge to main constantly, and let your pipeline — not a heavyweight branch structure — guarantee quality. GitFlow remains valuable, but mainly for software that genuinely ships on a schedule.
Best Practices
- Keep branches short-lived — aim to merge within a day or two to avoid divergence and conflicts.
- Protect
main(ordevelop) with branch protection rules: require passing CI and at least one review before merge. - Make every commit small and focused; small changes are easier to review and safer to roll back.
- Use feature flags so unfinished work can merge without exposing it to users.
- Always
git pull --rebasebefore pushing to keep history linear and current. - Tag releases (e.g.
v2.4.0) so you can reproduce and roll back any deployed version. - Match the workflow to your real deployment cadence — do not adopt GitFlow’s complexity if you deploy every day.