Version control · Git · Workflow

Version Control, Git and Branching Strategies: Which Workflow Fits Which Team

Khairul Alam·October 2026·~30 min read
GitVersion controlBranchingGit FlowTrunk-basedTools

Every team that writes code needs to answer three questions: where does the history live, how do we work on things in parallel, and how does finished work reach users? Version control answers the first, Git is the tool most teams pick, and a branching strategy answers the other two. This article covers all three, with diagrams, and ends with the tools you can use to drive Git every day.

The whole post in 60 seconds
  • A version control system (VCS) records every change to your files, who made it and why, so you can go back, compare and work in parallel.
  • There are three generations: local, centralized (Subversion, Perforce) and distributed (Git, Mercurial). Git is the default today.
  • Git stores snapshots, not diffs, and moves work through three areas: working directory, staging area, repository.
  • Alternatives exist and some are better for special cases: Perforce or Unity Version Control for huge binary assets, Fossil for tiny self-contained projects, Jujutsu as a friendlier front end to Git.
  • There is no single best branching strategy. Pick by how you release: GitHub Flow or trunk-based for continuous delivery, Git Flow or release branches for versioned software, fork and pull request for open source.
  • Whatever you choose: short-lived branches, small pull requests, a protected main branch, and automated tests on every change.
  • Tools: the command line is the foundation; add a GUI or your IDE for the visual parts, and a hosting service for sharing and review.
Contents
  1. Version control overview
  2. Git: how it works
  3. The commands you use every day
  4. Alternatives to Git
  5. Branching and merging basics
  6. Branching strategies
  7. Choosing a strategy for your situation
  8. Software for Git operations
  9. Habits that work with any strategy
  10. Common mistakes
  11. Takeaways and glossary

1. Version control overview

Without version control, a project folder fills up with report_final.docx, report_final_v2.docx and report_REALLY_final.docx. With two people editing, someone overwrites someone else. With a bug in production, nobody can say which change caused it.

A version control system fixes this by keeping a complete, searchable history of a project. Each saved state is a commit with an author, a time and a message. The system lets you:

Analogy. Think of the edit history in a shared document, but for a whole folder of files, with the power to take a copy, try something risky in it, and then fold the good parts back in.

Three generations of version control

1. Local 2. Centralized 3. Distributed One computer Working files Version database RCS, SCCS Central serverthe only history Dev A Dev B Dev C CVS, Subversion, Perforce Shared remote Dev Afull history Dev Bfull history Git, Mercurial, Fossil
In the first two kinds the history lives in one place. In a distributed system every clone is a complete backup and can work offline.
KindHow it worksStrengthWeakness
LocalVersions are stored in a database on your machine.Simple; no server.No team work; one disk failure loses everything.
CentralizedOne server holds the history. You check out files, edit and commit back.Easy to understand; fine-grained access control; file locking.Needs the network to commit or view history; the server is a single point of failure.
DistributedEvery clone holds the full history. You commit locally, then share with push and pull.Fast, offline, cheap branching, many backups.More concepts to learn; large binary files and huge monorepos need extra care.

Words you will meet in every VCS

TermMeaning
RepositoryThe project plus its whole history.
CommitA saved state of the project, with a message.
BranchA line of development that can move on independently.
MergeCombining the changes of one branch into another.
CloneA full copy of a repository on your machine.
TagA permanent name for one commit, such as v2.4.0.

2. Git: how it works

Git (official site: git-scm.com) was written in 2005 by Linus Torvalds to manage the Linux kernel, after the tool the kernel team had been using became unavailable to them. It was designed to be fast, to handle thousands of parallel branches, and to need no central server. It is now the default choice, used by most open source projects and most companies.

Snapshots, not differences

Older systems stored each version as a list of changes to a file. Git thinks differently: every commit is a snapshot of the whole project at that moment (files that did not change are stored once and shared). A commit points to its parent, so the history is a chain, and a merge is a commit with two parents. Each commit has a unique ID, a hash such as 9fceb02. Because the ID is computed from the content and the parent, history cannot be changed silently.

The four places your work lives

Workingdirectory Staging areathe index Localrepository Remoteorigin on GitHub etc. addcommitpush pull = fetch + merge into your branch fetch only downloads. checkout / switch / restore refresh the working directory from the repository.
Work moves left to right when you save and share it, and right to left when you update.

A branch is only a label

In Git a branch is a small pointer to a commit. Creating one costs almost nothing, which is why Git encourages branching for every task. HEAD says which branch you are on.

A B C M D F1 F2 main feature/login merge commit (two parents) time →
The feature branch started at B. Meanwhile main moved on to C. The merge commit M joins both lines of work.

3. The commands you use every day

# start
git clone https://github.com/you/project.git
git switch -c feature/login          # create and move to a new branch

# save work
git status                           # what changed?
git add src/Login.kt                 # stage one file (or: git add -p to pick pieces)
git commit -m "Add login form validation"

# share and update
git fetch                            # download new commits, change nothing
git pull --rebase                    # update your branch on top of the remote
git push -u origin feature/login     # publish the branch

# combine
git switch main
git merge --no-ff feature/login      # or merge through a pull request

# look around
git log --oneline --graph --all
git diff                             # unstaged changes
git blame src/Login.kt               # who changed each line, and in which commit

Undoing things safely

SituationCommandSafe on shared history?
Discard edits in a filegit restore fileYes (but the edits are gone)
Unstage a filegit restore --staged fileYes
Fix the last commit message or add a forgotten filegit commit --amendOnly before you push
Undo a pushed commitgit revert <commit> (adds a new opposite commit)Yes
Move the branch back and drop commitsgit reset --hard <commit>No, not after pushing
Set work aside for a momentgit stash and git stash popYes (local only)
Copy one commit to another branchgit cherry-pick <commit>Yes
Find the commit that broke somethinggit bisectYes (read only)
“I lost a commit!”git reflog, then git switch -c rescue <id>Yes

Git rarely destroys committed work. git reflog remembers where your branches were for a few months, so most “disasters” are recoverable if you have committed.

Two files belong in every repository. A .gitignore lists what Git must not track (build output, node_modules, IDE settings, and above all secrets such as .env). A README.md tells a newcomer what the project is and how to run it. If a secret is ever committed, treat it as leaked and rotate it; deleting it in a later commit does not remove it from history.

4. Alternatives to Git

Git is the right default, but it is not the only option, and knowing the others helps you understand Git’s design and spot the cases where it is a poor fit.

SystemTypeBest known forConsider it when
Subversion (SVN)CentralizedSimple model, one revision number for the whole repo, path-based permissions.You maintain an existing SVN project, or non-programmers need a simple “check out, edit, commit” flow.
Perforce Helix Core (P4)CentralizedHuge repositories, large binary files, exclusive file locking, fine-grained control.Game studios and hardware teams with gigabytes of art, models and builds.
Unity Version Control (formerly Plastic SCM)Distributed and centralizedHandles big binaries, has a visual branch explorer and locking, friendly to artists.Unity projects, mixed teams of artists and programmers.
Mercurial (hg)DistributedSimilar power to Git with a more consistent, simpler command set.You inherit a Mercurial repository. New projects rarely choose it, as most hosts now focus on Git.
SaplingDistributedBuilt at Meta for very large monorepos; stacked commits; can work with Git repositories.You want to try stacked-commit workflows against a Git host.
Jujutsu (jj)DistributedStores data in a Git repository, but treats your working copy as a commit and makes rewriting history and resolving conflicts gentler.You like Git’s ecosystem but find its commands and the staging area awkward. Teammates can keep using plain Git.
FossilDistributedOne small program and one file per repository that also includes a wiki, bug tracker and web UI. Made for SQLite.A small, self-contained project with no need for GitHub-style hosting.
PijulDistributedA research-driven design based on patches rather than snapshots, with a different approach to merging.You are curious about alternatives to the snapshot model. It has a small community.

Older systems you may still meet in legacy code bases: CVS, Visual SourceSafe (retired) and TFVC, the centralized option in Azure DevOps (Microsoft recommends Git for new projects).

Why Git won
  • Fast and offline: nearly every action is local.
  • Cheap branches make the pull request workflow natural.
  • A huge ecosystem: hosting, CI services, IDE support, tutorials and people who already know it.
  • Free and open source, with no vendor tied to the data.
Where Git struggles
  • Large binary files (video, textures, builds): every version is stored in history. Use Git LFS, or a tool like Perforce.
  • Exclusive locks: two people cannot merge a binary scene file. Git LFS has locking, but it is not as smooth as Perforce.
  • Gigantic monorepos: clones become slow. Partial clone, sparse checkout and tools like Scalar help.
  • Learning curve: the commands are many and the names are not always intuitive.

5. Branching and merging basics

A branching strategy is a team agreement about which branches exist, what each is for, and how work flows between them. To compare strategies you first need the three ways to bring a branch back, and a few guard rails.

Three ways to integrate a branch

MethodWhat happensHistory looks likeUse it when
Merge commitAdds a commit that joins two histories.Branches and joins are visible. Nothing is rewritten.You want a faithful record, or the branch is shared by several people.
Squash mergeAll commits of the branch become one commit on the target.One commit per pull request on main. Easy to read and to revert.Branch commits are messy (“wip”, “fix typo”). The most common choice for small PRs.
RebaseReplays your commits on top of the latest target, giving them new IDs.A straight line, no merge commits.Tidying your own branch before review. Never rebase commits others already pulled.

Guard rails

6. Branching strategies

Three strategies cover most teams. Each is a different answer to one question: how long may work stay off the main line? The shorter the answer, the simpler the process and the easier the merges, but the more you rely on tests and feature flags.

A. GitHub Flow: one main branch, short feature branches

Everything on main is deployable. For each task you branch from main, commit, open a pull request, get review and passing tests, merge, and deploy.

feature/search fix/null-crash feature/profile main PR mergedPR mergedPR merged each merge is deployed
Branches live for hours or a few days. Every merge goes through review and CI, and main is always releasable.
Good for
  • Web apps and services with one live version, deployed continuously.
  • Small and mid-sized teams, and anyone new to branching.
Weak at
  • Supporting several released versions at once.
  • Code that cannot reach users the moment it merges (app stores, scheduled releases) unless you add release tags or branches.

B. Git Flow: structured branches for versioned releases

Introduced by Vincent Driessen in 2010, Git Flow uses long-lived main (only released code, tagged) and develop (the next release being assembled). Short feature/* branches come off develop, release/* branches stabilise a version, and hotfix/* branches patch production directly.

mainhotfixreleasedevelopfeature v1.0 v1.0.1 v2.0 urgent fix stabilise 2.0 feature work merged when done
Two permanent branches (main and develop) and three kinds of temporary ones. Releases and hotfixes are merged into both permanent branches so nothing is lost.
Good for
  • Software shipped as numbered versions: desktop apps, libraries, firmware, on-premise products.
  • Teams that must maintain more than one released version, or run a formal QA phase.
Weak at
  • Continuous delivery: develop and main drift apart, and long feature branches make painful merges.
  • Ceremony. For a web app that deploys daily it is usually too much; its author has said as much himself.

C. Trunk-based development: everyone integrates into one trunk

Developers commit to main (the trunk) at least daily, either directly or through very short-lived branches that last hours. Unfinished features are hidden behind feature flags so incomplete code can be merged and still stay off for users. When a release is needed you tag the trunk, or cut a short release/* branch that receives only bug fixes cherry-picked from the trunk.

hours, not weeks trunk release/2.3 (only fixes, then tag) cherry-pick fix Unfinished work is merged but switched off with a feature flag.
The trunk is the only long-lived branch. Release branches, when needed, are short-lived and only receive fixes.
Good for
  • Teams with strong automated tests and CI who want to release often.
  • Large organisations and monorepos: it avoids merge debt across many teams.
  • It is the practice most associated with high-performing delivery teams in the DORA research.
Weak at
  • Teams without reliable tests or fast CI: a bad commit hurts everyone at once.
  • Needs discipline with feature flags, which must be cleaned up later.

Other patterns worth knowing

7. Choosing a strategy for your situation

Start from how your software reaches users, not from what is popular.

How does your softwarereach users? Deployed oftenwebsite, API, SaaSone live version,no review wait Numbered versionslibrary, desktop,firmware, on-prem,old versions supported Store review delayiOS, Android,staged rollouts,fixes need a new build Outside contributorsopen source,no write accessfor most people GitHub Flowor trunk-basedwith feature flags Git Flowor a release branchper supported version Trunk + releasebranch cut per build,hotfix off the release Fork + pullrequest, maintainersreview and merge
Start with the way you release. Team size and test quality then decide how strict to be.

Situation by situation

SituationRecommended approachWhy, and what to watch
Solo project or learningmain plus a short branch per idea. Tag the versions you finish.Branching is free and lets you throw away experiments. No ceremony needed.
Small team, web app, deploy dailyGitHub Flow with squash merge, CI required, auto-deploy on merge.Keep PRs small (under a few hundred lines). Use feature flags for risky work.
Mature team with solid CI, many deploys a dayTrunk-based development with feature flags.Needs fast tests, flag clean-up and a rule that a broken trunk is fixed first.
Mobile app (store review)Trunk-based or GitHub Flow, plus a release/x.y branch cut for each store build. Fix bugs in main, cherry-pick to the release branch.The live app is weeks old, so you must be able to patch exactly that version. Remote config and flags help.
Library or SDK with several supported versionsTrunk or develop for the next version, plus maintenance branches release/1.x, release/2.x. Tag every release.Back-port security fixes with cherry-pick. Document which versions are supported.
Scheduled releases with a QA phaseGit Flow, or GitHub Flow with a release branch frozen for testing.Keep the freeze short. Merge fixes back to main right away.
Production is on fireBranch hotfix/* from the exact production tag, fix, test, release, then merge into main too.Forgetting the merge back is how the same bug returns in the next release.
Open sourceFork and pull request; maintainers merge. Protect main; use labels and a CONTRIBUTING.md.Ask contributors to rebase on the latest main. Use squash merge to keep history clean.
Large refactor or migration that takes weeksPrefer branch by abstraction: hide the new path behind a flag and merge in small steps. If you must use a long branch, merge main into it every day.The longer a branch lives, the more painful the final merge. Time-box it.
Several teams in one monorepoTrunk-based, with code owners, path-based CI and sparse checkout.Long-lived team branches turn into integration crises.
Regulated industry (audit, sign-off)GitHub Flow or GitLab Flow with protected branches, required reviewers, signed commits and linked tickets.The Git history becomes the audit trail. Never force-push to shared branches.
Several environments (dev, staging, production)One build promoted through environments. Avoid separate code per environment.Environment branches that drift apart cause “works on staging” bugs. Prefer config over code differences.
A sensible default

If you are unsure, begin with GitHub Flow: protected main, short branches, small pull requests, squash merge, CI on every PR, tags for releases. Add a release/* branch only when you need to patch an old version, and move toward trunk-based development as your tests and feature flags mature.

8. Software for Git operations

Git itself is a command-line program that keeps data in a .git folder. Everything else is a layer on top of it. Pick one tool from each layer that you enjoy; they all work on the same repository, so you can mix them.

Hosting and collaboration GitHub GitLab Bitbucket Gitea / Forgejo push, pull, pull requests (HTTPS or SSH) Clients: how you give commands Command linegit, gh, glab Desktop GUIsFork, GitKraken, Tower IDE built-inVS Code, JetBrains Terminal UIslazygit, gitui Git engine and the .git folder on your diskhistory, branches, staging area, hooks, plus Git LFS for large files
Clients all talk to the same Git engine. Hosting services are where the team shares, reviews and automates.

Clients

ToolKindPlatformsGood for
git (command line)CLI, the referenceAllEverything. Needed for scripts, servers and fixing odd states. Learn it first.
GitHub CLI (gh), GitLab CLI (glab)CLI for the hostAllCreate pull requests, review, check CI and manage issues without leaving the terminal.
VS Code Source ControlEditor built-inAllStage by line, inline diffs and conflict editor. Extensions such as GitLens add blame and history.
JetBrains IDEs (IntelliJ, Android Studio, PyCharm)IDE built-inAllExcellent diff and three-way merge, local history, shelve changes, per-line history.
Xcode, Visual StudioIDE built-inmacOS, WindowsEveryday commit and branch work inside the platform IDE.
GitHub DesktopGUI, freemacOS, WindowsThe easiest start for beginners using GitHub.
SourcetreeGUI, freemacOS, WindowsVisual branch graph; works with any host.
ForkGUI, paid licencemacOS, WindowsFast, clean interface, interactive rebase and conflict tools.
GitKrakenGUI, free tier and paidAllPolished commit graph, integrations with hosts and issue trackers.
TowerGUI, paidmacOS, WindowsStrong undo and guidance for less experienced users.
SmartGitGUI, free for non-commercial useAllFeature-rich, includes SVN support.
TortoiseGit, Git ExtensionsGUI, freeWindowsExplorer integration for Windows users.
lazygit, gituiTerminal UI, freeAllKeyboard-driven staging, rebase and branch work over SSH or in a terminal you already live in.

Hosting services

ServiceNotes
GitHubThe largest community; pull requests, Actions CI, Pages, code search. Default for open source.
GitLabAll-in-one DevOps platform with built-in CI/CD and issue boards. Can be self-hosted.
BitbucketAtlassian product; tight integration with Jira and Pipelines.
Azure DevOps ReposPart of Microsoft’s suite with boards and pipelines; common in Microsoft-centred companies.
Gitea, ForgejoLightweight, self-hosted, open source. Codeberg runs on Forgejo.
AWS CodeCommitClosed to new customers in 2024, so choose another host for new work.

Helpers worth adding

Which should I install?

Install git and learn the ten commands in section 3. Add the GUI or IDE integration you find most comfortable for diffs and conflicts, plus gh or glab if you live in the terminal. When a GUI does something unexpected, the command line is how you see what really happened.

9. Habits that work with any strategy

10. Common mistakes

11. Takeaways and glossary

TermIn plain words
VCSSoftware that records the history of changes to files.
Staging areaWhere you assemble the next commit before saving it.
HEADThe commit or branch you are currently on.
originThe usual name of the remote you cloned from.
Pull request (PR)A request to merge a branch, with review and checks. GitLab calls it a merge request.
Fast-forwardA merge where the target simply moves ahead because it has no new commits of its own.
RebaseReplaying your commits on a new base, creating new commits.
Cherry-pickCopying a single commit onto another branch.
Feature flagA switch that turns unfinished code on or off without a new deploy.
TrunkThe main line of development that everyone integrates into.
HotfixAn urgent fix to the code that is live in production.
MonorepoOne repository that holds many projects.
← Back to all writing