Version Control

Imagine you are three weeks into a coding coursework. You had a working program on Tuesday, you changed a dozen files since, and now nothing runs. Which change broke it? What did the working version even look like? And your project partner has just emailed you their copy — how do you combine their work with yours without one of you clobbering the other's edits?

Version control is the tool built to solve exactly these problems. It is a system that records the history of a project as a series of saved snapshots, each with a note explaining what changed. With that history you can see what changed and when, jump back to any earlier version, try out risky ideas safely, and — crucially for teamwork — let several people edit the same project at once and then combine their work cleanly. The most widely used version-control system in the world is Git, and it is the one we will use here.

The vocabulary: repository, commit, history

A repository (usually shortened to repo) is a project folder that Git is watching. Alongside your files, Git keeps a hidden record of every snapshot you have ever saved. Turning an ordinary folder into a repository is a single command:

git init # start tracking this folder

A commit is one of those snapshots: a frozen picture of every tracked file at one moment, stamped with the author, the date, and — most importantly — a commit message written by you saying what you changed and why. You do not commit constantly; you commit at meaningful points ("added login form", "fixed off-by-one in the loop"). The typical rhythm is stage the files you want to include, then commit them:

git add login.py # stage the change git commit -m "Add login form" # snapshot it, with a message

Every commit points back to the one before it, so the commits form a chain — a history, also called the log. Reading the log tells the whole story of the project. Because each commit is a complete recoverable point, you can also travel back to any of them if a later change goes wrong.

git log # list the commit history, newest first

Branches: working without stepping on each other

So far the history is a single straight line. But suppose you want to try adding a new feature without disturbing the version that already works — or two people want to build two different features at the same time. This is what a branch is for. A branch is a movable line of development that splits off from the main history so that commits made on it do not affect the main line. The default main branch is usually called main.

git branch feature-search # create a branch git checkout feature-search # switch to it # ... edit files, commit as normal — these commits live only on the branch ...

Two teammates can each take their own branch from the same starting commit and work in parallel. Nobody overwrites anybody, because each set of changes lives on its own line until it is deliberately brought together.

Merging: bringing the work back together

When a branch's work is finished and tested, you merge it back into main. Merging combines the commits from both lines into one history, so the feature becomes part of the main project. Git is clever about this: if the two branches changed different files (or different parts of the same file), it stitches them together automatically.

git checkout main # go back to the main branch git merge feature-search # fold the branch's work in

The diagram below tells the whole story: a straight main line, a branch splitting off for a new feature, both lines gaining their own commits, and finally a merge commit that ties them back together. Step through it.

If both branches change the same line of the same file in different ways, Git cannot know which one you meant — this is a merge conflict. Git does not guess and it does not silently pick one; instead it pauses the merge and marks the clashing section in the file (with <<<<<<< / ======= / >>>>>>> markers) so a human can choose. You edit the file to the version you want, then commit the resolution. Conflicts sound scary but are routine, and they are the mechanism that stops one person's work from silently destroying another's.

Remote repositories: sharing and backing up

Everything so far happens on your own machine. A remote repository is a copy of the repo hosted on a server — most commonly on a platform like GitHub (others include GitLab and Bitbucket). The remote is the shared meeting point: each person pushes their commits up to it and pulls other people's commits down, so everyone's histories stay in sync. To start on someone else's project you clone the remote, which copies the entire history to your machine.

git clone https://github.com/team/project.git # copy an existing remote git push # send your commits to the remote git pull # fetch and merge others' commits

Remotes are what turn version control into real collaboration: a team scattered across different computers — even different countries — can all contribute to one project, with the complete, ordered history living safely on the server as well as on every member's machine.

Why this matters

Professional software is almost never written alone, and almost never written correctly the first time. Version control is the backbone that makes both realities workable: it is an infinite, labelled undo across a whole project; a safe sandbox for experiments you might throw away; a precise record of who changed what and why; and the coordination layer that lets a whole team build one thing at once. It is not an optional extra — it is a core part of how modern programming is actually done, which is why you will meet it in every serious codebase.

Version control is not the same as a backup. A backup is a single copy of your files "as they are right now" — if a bug crept in yesterday, your backup faithfully preserves the bug. Version control instead records the sequence of changes, each with a message and a timestamp, so you can see precisely what changed, blame the exact commit that introduced a fault, and step back to the last good version. That power depends entirely on good habits: commit frequently at meaningful points, and write clear, honest messages ("Fix crash when username is empty", not "stuff" or "asdf"). A history full of vague one-word messages is nearly as useless as no history at all — the tool only pays you back the care you put into your commits.