Version control, also called source control, is the practice and tooling for recording every change to a set of files over time, together with who made it, when and why, so that any earlier state can be compared, restored or combined with other work. Among development tools, a version control system is the foundation on which branching, code review, continuous integration and release management are built.
In Programming, version control turns a folder of source code into a history of snapshots. It lets many developers work on the same code base in parallel, isolates experimental work, and provides an audit trail that explains how the software reached its current form.
How version control records changes
A version control system stores the project in a repository, a database of versions plus metadata. A developer edits files in a working copy, selects the changes to keep and records them as a commit (also called a revision or changeset). Each commit has an identifier, an author, a timestamp, a message and a reference to its parent commit, so the history forms a chain or, with branches and merges, a directed acyclic graph.
Systems differ in how they store data internally. Older tools such as RCS and CVS stored per-file deltas. Git stores content-addressed snapshots: every file version, directory tree and commit is identified by a cryptographic hash of its content, historically SHA-1 and optionally SHA-256 in newer repositories. Identical content is stored once, and any corruption or tampering changes the hash and is detected.
The core operations are shared across almost all systems, as the table shows.
| Operation | What it does | Git example |
|---|---|---|
| Commit | Records a snapshot with a message | git commit |
| Branch | Starts an independent line of work | git branch or git switch -c |
| Merge | Combines changes from two lines | git merge |
| Diff | Shows differences between versions | git diff |
| Revert | Creates a commit that undoes another | git revert |
| Tag | Names a specific version, such as a release | git tag v2.1.0 |
| Blame | Shows the last change to each line | git blame |
Centralized and distributed models
Version control systems follow one of two architectures. In a centralized system, such as Subversion or Perforce, a single server holds the authoritative history and clients check out working copies. In a distributed system, such as Git or Mercurial, every clone contains the full history, so commits, branching and log searches happen locally and offline, and synchronization happens through push and pull.
| Aspect | Centralized (Subversion, Perforce) | Distributed (Git, Mercurial) |
|---|---|---|
| History location | Central server only | Every clone |
| Offline commits | Not possible | Fully supported |
| Branch cost | Heavier, often directory copies | Very cheap pointers |
| Large binary files | Handled well, with file locking | Needs extensions such as Git LFS |
| Access control | Fine-grained per path | Mostly per repository |
| Typical users | Game studios, large monorepos | Most software teams and open source |
Git has become the de facto standard for software development, and hosting platforms such as GitHub and GitLab add pull requests, code review, issue tracking and pipelines on top of it. Centralized tools remain common where repositories contain very large binary assets, such as textures and video in game development.
Branching, merging and workflows
Branching is what makes version control a collaboration tool rather than only a backup. A branch lets a developer build a feature or fix in isolation, and a merge or rebase integrates it back. When two branches change the same lines differently, the system cannot decide automatically and reports a merge conflict, which a person must resolve.
Teams agree on a branching workflow that fits their release cadence. The table compares the most widely used ones.
| Workflow | How it works | Suits |
|---|---|---|
| Trunk-based development | Short-lived branches merged to main within a day or two | Continuous delivery, frequent deploys |
| GitHub flow | Feature branch, pull request, merge to main, deploy | Web services with one live version |
| Git flow | Separate develop, release and hotfix branches | Scheduled releases, several supported versions |
| Release branches | Main for development, branches per release line | Products with long-term support versions |
| Forking workflow | Contributors work in their own copies | Open source projects |
Shorter-lived branches mean fewer and smaller conflicts. Long-running branches that diverge for weeks are the most common source of painful integrations.
Good practice in everyday use
Version control is only as useful as the history it contains. Small, focused commits with descriptive messages make it possible to review, bisect and revert changes precisely. A message such as “Fix rounding error in invoice totals” explains intent; “misc changes” does not.
- Commit one logical change at a time, so it can be reviewed and reverted on its own.
- Write messages that explain why, with a short summary line of about 50 characters.
- Never commit secrets, such as passwords or API keys; removing them later requires rewriting history.
- Use an ignore file to exclude build output, dependencies and local configuration.
- Protect the main branch with required reviews and passing automated checks.
- Tag every release, so the exact shipped code can always be rebuilt.
Limitations and common mistakes
Version control tracks text changes very well but is weaker with binary files, whose differences cannot be shown line by line and whose conflicts cannot be merged automatically. It also does not replace backups of databases, user uploads or production configuration that lives outside the repository.
| Problem | Cause | Remedy |
|---|---|---|
| Repository grows to gigabytes | Large binaries committed directly | Use Git LFS or external storage |
| Lost work after force push | Shared history rewritten | Forbid force pushes on shared branches |
| Constant merge conflicts | Long-lived diverging branches | Integrate daily, keep branches short |
| Unclear history | Vague messages, huge commits | Small commits, meaningful messages |
| Leaked credentials | Secrets stored in tracked files | Revoke secrets, add secret scanning |
In plain words
Version control is like a detailed save history for a shared project. Every time someone finishes a piece of work, the system takes a labeled snapshot. If something breaks, the team can see exactly what changed and go back to any earlier snapshot.
It also lets several people work on separate copies at the same time and then combine their work safely, pointing out the few places where two people changed the same thing.
A real-world example
A team of eight developers maintains an online booking system. On a Friday afternoon, customers report that discounts are no longer applied at checkout. Because the team uses Git with small commits and tagged releases, an engineer compares the current release tag with the previous one and finds about thirty commits.
Using git bisect, which tests commits in a binary search, the engineer identifies the faulty commit in five test runs. It changed a rounding rule in the pricing module. The team runs git revert on that single commit, the pipeline deploys the fix within twenty minutes, and the original author later reworks the change on a new branch with an added test. No other work had to be rolled back.