Read this as a study guide instead

Git

Commits, branches, merges, and the model under the commands.

Scenario
Second branch
a local commit graph — commits chain back to their parentsc1mainHEAD -> maininitial commit c1 on main — a snapshot with no parent

Check your own machine

These commands only read information — they change nothing. Run the block for your OS, then use the table to read your own numbers against the ideas above.

Windows

Git's areas and history on Windows PowerShell
git --version
git status
git log --oneline --graph -10

What you should see git --version prints the installed Git for Windows suite version on one line; git status reports the current branch with staged, unstaged, and untracked changes, or a clean working tree; git log --oneline --graph -10 draws up to the last ten commits as a compact text graph.

Note Run these inside a git repository (a directory with a .git store); all three only read and never change your files, and the git commands are identical across operating systems.

macOS

Git's areas and history on macOS zsh
git --version
git status
git log --oneline --graph -10

What you should see git --version prints the installed Git suite version, which on macOS may be the Apple-supplied build; git status reports the current branch with staged, unstaged, and untracked changes, or a clean working tree; git log --oneline --graph -10 draws up to the last ten commits as a compact text graph.

Note Run these inside a git repository (a directory with a .git store); all three only read and never change your files, and the git commands are identical across operating systems.

Linux

Git's areas and history on Linux bash
git --version
git status
git log --oneline --graph -10

What you should see git --version prints the installed Git suite version on one line; git status reports the current branch and splits your changes into staged, unstaged, and untracked, or says the working tree is clean; git log --oneline --graph -10 draws up to the last ten commits as a compact text graph, one abbreviated hash and message per line.

Note Run these inside a git repository (a directory with a .git store); all three only read and never change your files, and the git commands are identical across operating systems.

Where each idea shows up in your output
ConceptWindowsmacOSLinux
Installed git versiongit --versiongit --versiongit --version
Working-tree and staging statusgit statusgit statusgit status
Recent commit historygit log --oneline --graph -10git log --oneline --graph -10git log --oneline --graph -10

The same ideas, as prose

These are the exact fragments the model serves — also available as an ordered study guide.

A time machine for your files

Git records snapshots of a project over time. Every time you save your work into git, it keeps a complete picture of the files as they were at that moment, so you can see what changed between any two points and return to an earlier one whenever you need to. Version control is that ability made reliable: a full, ordered history of a project instead of a single ever-changing copy.

The habit git replaces is copying the whole folder. You have seen the result of the manual version: a directory full of project-final, project-final-2, and project-really-final, none of them dated, none of them explaining what is different. Git does the same job without the mess, keeping one working folder and one tidy history beside it, each saved point labeled with a message and a time.

The rest of this concept is what that history is made of: the repository git watches, the three areas a change passes through, the commits that record each snapshot, and the branches that let more than one line of work sit side by side.

The folder git watches

A repository is a project directory that git tracks. It looks like an ordinary folder full of your files, but alongside them git keeps a hidden store — a subdirectory named .git — that holds the project's entire history: every recorded snapshot and the information tying them together. Delete that hidden store and you are left with just the current files and no history; keep it, and the whole past travels with the folder.

You get a repository one of two ways. Running git init inside a project directory creates the .git store from scratch, turning a plain folder into one git watches. Running git clone instead makes a local copy of an existing repository, history and all, so you land in a folder that already has a past. From then on git watches that directory, noticing which files have changed since the last recorded snapshot and standing ready to record the next one.

Everything else in git happens inside a repository. The areas, the commits, the branches — all of it is bookkeeping git does within that one tracked folder and its hidden store.

Working, staged, committed

working directory files you edit staging area the index: next snapshot repository committed history git add stages a change git commit records snapshot
A changed file moves from the working directory to the staging area with git add, then the staged snapshot moves into the repository with git commit.

A change in git moves through three areas before it becomes part of history. The first is the working directory, also called the working tree: the ordinary files you open and edit, a single checkout of one version of the project. The second is the staging area, whose technical name is the index: a holding place where you assemble exactly the changes that will go into the next snapshot. The third is the repository itself, the committed history kept in the hidden .git store.

The staging area is what makes git deliberate rather than automatic. Editing a file changes it in the working directory only; git does nothing with that change until you run git add, which stages it — marks that version of the file to go into your next snapshot. You can stage some changes and leave others, so a single messy afternoon of edits becomes several clean, separate snapshots. Staging is like a tray where you set out only the items that go in the next box, keeping them separate from the still-cluttered desk, letting you choose what goes into the next recorded point instead of committing everything at once.

So the path is always the same: edit in the working directory, move chosen changes to the staging area with git add, and then record the staged set into the repository. Three areas, two moves between them, and full control over what lands in history at each step.

A snapshot with a name

9f2c1a4 initial commit c0ad3e1 add readme 7b41d90 fix typo e83f6b2 add feature each commit points back to its parent oldest newest
History is a chain of commits, each a snapshot with a short hash and message that points back to its parent commit.

A commit records the staged snapshot as a permanent point in history. Running git commit takes whatever is in the staging area and writes it into the repository along with a short message you supply, the author's name and email, and a timestamp. The message is the part your future self will thank you for: it says what this snapshot is and why it exists, in a way a bare folder copy never could.

Each commit is identified by a hash — a string git computes from the commit's contents, so the same content always produces the same identifier and any change produces a different one. Historically that hash function is SHA-1, and git also supports SHA-256 as a newer alternative; either way the commit's name is derived from what it contains rather than assigned by hand. Every commit also points back to the one before it, its parent, so the commits form a chain: history is a linked sequence of snapshots running from the first commit up to the latest. Commits are like save points in a game that you can always return to, each one a complete state rather than a list of moves to replay, each a complete picture of the project you can return to rather than a diff you have to replay from the start.

That chain is the backbone of everything else. Branches point into it, merges join two strands of it, and the whole record of who changed what, and when, and why, is just commits read in order.

Parallel lines of work

common commit: history diverges here main feature HEAD current branch
The main and feature branch pointers mark two lines of commits that share a common history and diverge after a common commit, with HEAD pointing at the current branch.

A branch is a lightweight movable pointer to a commit. That is the whole definition: not a copy of the files, not a separate folder, just a name that refers to one commit in the history. Because commits chain back to their parents, naming the latest commit is enough to name the entire line of work leading up to it.

The pointer moves on its own. Each time you commit while on a branch, the branch advances to the new commit, so it always marks the tip of that line. A branch is like a bookmark that slides forward as you read further, so several bookmarks can mark different places at once, sliding forward as the story grows rather than staying pinned to one page. Because a branch is only a pointer, making a new one is cheap and instant, which is what lets you keep more than one line of work going at once: one branch steady while another explores a change that may or may not pan out.

To track which branch you are working on, git keeps a special pointer called HEAD that points to the current branch. Commit, and HEAD's branch moves forward with you; switch branches, and HEAD points somewhere else and your working directory changes to match. All of this happens locally, on your own machine, in your own repository — several parallel lines of work, and one marker for where you are standing among them.

Bringing branches back together

Merging brings one branch's commits into another. Work explored on a side branch eventually has to rejoin the main line, and merging is how git folds the two histories back into one. What git does depends entirely on whether the two branches have diverged since they parted.

If the branch you are merging into has not moved since the other branch started — nothing new happened on it — git has no real merging to do. It simply slides the pointer forward to the newer commit, since that commit already sits on top of the existing history. This is called a fast-forward, and it is the quiet, uneventful case. When both branches have advanced, though, the two lines have genuinely diverged, and git builds a new commit that ties them together. This is a merge commit, and it is special in one way: instead of a single parent it has more than one, recording that history came together here from two lines at once.

Most merges finish on their own, because git can combine changes to different parts of the files without help. A conflict happens only when the same lines were changed in both branches: git cannot know which version you meant, so it stops and marks the clash for you to resolve, and the merge completes once you decide. All of this is local — two branches in one repository joined back into one line, before any of it goes anywhere else.

Reading and rewinding

A recorded history is only useful if you can read it. Git lets you list the commits in order to see who changed what and when, and it lets you ask for the exact differences between any two snapshots — the lines added and removed as a project moved from one commit to the next. git log walks the chain of commits and prints them, and git status reports the current state of the working directory and staging area against the latest snapshot. Together they answer the two questions you ask most: what has happened, and what is different right now.

Because history is a chain of complete snapshots, returning to an earlier one is just a matter of pointing at it. You can bring the working directory back to how it looked at any past commit, so a change you regret is not a catastrophe — it is a commit you step back from.

The reason this feels safe is that git almost never throws committed data away. Nearly everything git does adds to its store rather than overwriting it, so once a snapshot is committed it is very hard to truly lose; even a branch pointer you move by mistake usually leaves the underlying commit sitting there, recoverable. Committed work is durable, and that durability is what turns mistakes from disasters into small, reversible steps.

The habit under everything else

Git is the ground almost every project stands on. The code for a personal site, a team's tool, an automated pipeline, a home lab's configuration — it lives in a git repository, and the projects you build here are no exception. Learning git is not a side skill; it is the container the rest of the work goes into.

What makes it load-bearing is the habit, not the commands. A steady rhythm of small, well-described commits gives you a history you can actually read, a safety net you can fall back on, and a record of your own reasoning weeks after you have forgotten it. The three areas and the branch pointer stop being trivia the moment you use them daily; they become the way you think about a project's state.

That habit is also the foundation everything heavier is built on. Working with others, and the automation that tests and ships code on its own, all assume a repository full of clean commits underneath them. Get the local habit right first, and the rest has something solid to stand on.