# Version control in pictures

> What version control is, and what a repository, commit, diff, branch, merge, conflict, push, pull and pull request are, explained with pictures you can play step by step. No experience needed.

Source: https://zaryn.xyz/docs/en/version-control-in-pictures

New to all this? Start here. Each idea below has a picture first and a few lines of text after it. Pictures with numbered steps play by themselves: press **▶** to watch again, or tap a step to stop on it. Tap any commit or device to read more about it.

> **Tip:** you don't need to remember the commands yet. Get the picture first. The [Quick start](/docs/en/quickstart) has you typing them in five minutes.

## Why version control exists

```diagram
type: cards
title: Without it, and with it
---
😩 | report_final_v2_REALLY_final.docx | Copies everywhere, and nobody knows which one is right | bad
🕳️ | "It worked yesterday" | No way to see what changed since, or to go back | bad
📨 | Emailing files back and forth | Two people edit the same file, one person's work is lost | bad
🕰️ | Every saved version, forever | One project folder; go back to any moment you saved | good
🔍 | Exactly what changed | Line by line, who changed it and why | good
🤝 | Work together safely | Everyone works on their own line, then the work is combined | good
```

A **version control system** (VCS) is a tool that remembers every version of your project you choose to save, so you can see what changed, go back, and work with other people without overwriting each other. **zev** is a version control system; **Zaryn** is the website where you share what zev saves.

Think of a video game's save points: you save before the hard part, and if things go wrong, you load the save. Version control gives your project save points, each with a note saying what you did.

## A repository: your project, with a memory

```diagram
type: graph
title: What's inside a repository
height: 56
alt: A project folder holds your files and a hidden history; the history holds every commit
---
node folder | my-site/ | 12 24 | folder | accent | The repository: an ordinary folder you work in
node f1 | index.html | 42 6 | file | | A file you edit, like any other
node f2 | style.css | 42 20 | file | | Another file
node f3 | photo.jpg | 42 34 | file | | Big files too: pictures, data, models
node hist | history | 42 47 | log | good | Hidden inside the folder: every saved version of every file, with who saved it and why
node c | 128 commits | 74 47 | commit | | Each save point is a commit
link folder f1
link folder f2
link folder f3
link folder hist | hidden | ghost
link hist c | | path
```

A **repository** (or *repo*) is a project folder that zev looks after. It looks like a normal folder full of your files, plus a hidden history of every version you saved. You make one with `zev init` in a folder you have, `zev new` to start fresh, or `zev clone` to download one from Zaryn.

## Three places your work lives

```diagram
type: flow
title: From an edit to a save point
loop: edit, add, commit, again and again
---
Working folder | The files you see and edit. zev notices what's changed | | ✏️
~ zev add
Staging area | The changes you've picked for the next save point | accent | 📥
~ zev commit
History | A save point, kept forever, with your message | good | 🕰️
```

Why the middle step? Say you fixed a bug and also started a new page. `zev add` lets you put just the bug fix in this save point and keep the half-done page for the next one, so each save point is one clear change. `zev status` tells you what's in each place at any moment.

## A commit: one save point

```diagram
type: cards
title: What one commit holds
---
📸 | A snapshot | Every file as it was when you committed, not just the changes | accent
💬 | A message | Your note: "Add a contact form". Write it for your future self |
👤 | Who and when | Your name, your Zaryn account, the date and time |
⬅️ | Its parent | The commit before it: that's how commits form a history |
#️⃣ | A fingerprint | A hash made from all of the above, like `7f3a9c2`. Change one letter and it changes | good
```

A **commit** is one save point. Commits line up, each pointing back at the one before, and that line is your project's **history**. Watch a few being made:

```diagram
type: history
title: A history, one commit at a time
start: A new repository
caption: Each dot is a commit. The tag above the newest one is the branch name, main, which always moves to your latest commit.
---
branch main | accent
commit A main | First page | info Made with `zev commit -m "First page"`
step Commit | You add a style sheet and commit. B points back at A.
commit B main | Add colours | info Its parent is A
step Commit | You fix a typo and commit again.
commit C main | Fix a typo | info Its parent is B
step Commit | A contact form. History grows to the right; nothing before is ever changed.
commit D main | Contact form | info The newest commit: main points here
step Tag a release | You give C a name that never moves, v1.0, so you can always find the version you published.
tag C | v1.0
mark C | accent
```

`zev log` lists the history; `zev show` shows one commit in full. Because every commit is a full snapshot with a fingerprint, you can always get any of them back exactly as it was, and nobody can quietly change an old one.

## A diff: what changed

```diagram
type: diff
title: The changes between two commits
file: index.html
---
@@ -3 +3 @@
  <body>
-   <h1>Welcom to my site</h1>
+   <h1>Welcome to my site</h1>
> The typo fix: one line removed (red), its new version added (green)
    <p>Hello!</p>
+   <a href="contact.html">Contact me</a>
> A brand new line: only green
  </body>
```

A **diff** is the difference between two versions: red lines were removed, green lines were added, and plain lines are unchanged context so you can find your place. A changed line shows up as one red and one green. Try **Side by side** above to see the old and new versions next to each other.

- `zev diff` shows what you changed but haven't staged.
- `zev diff --staged` shows what's in the staging area, the next commit.
- `zev show` shows the diff a commit made.

zev also understands code: a [semantic diff](/docs/en/semantic-diff) tells you when a change only moved or reformatted code, so you can review what really changed.

## A branch: try things without breaking anything

```diagram
type: history
title: A branch is a separate line of work
start: main only
---
branch main | accent
branch new-search | good | from C
commit A main | First page
commit B main | Add colours
commit C main | Fix a typo | info The commit the branch starts from
step zev checkout -b new-search | A new name at C. Nothing is copied: a branch is just a name pointing at a commit.
step Commit on the branch | You build a search box. main doesn't have D; your live site is untouched.
commit D new-search | Search box | info Only on new-search
step Keep going | Another commit on the branch.
commit E new-search | Search results | info Only on new-search
step Meanwhile on main | Someone fixes the footer on main. Two lines of work now, side by side.
commit F main | Fix footer | info Only on main
```

A **branch** is a named line of commits. Every repository starts with `main`. When you want to try something, make a branch: your commits go on it, and `main` stays exactly as it was until you decide to bring the work in. Switch between branches with `zev checkout <branch>`; your files change to match. See [Branches and merging](/docs/en/branches).

## A merge: bring the work back

When the branch is ready, you **merge** it into `main`. There are two cases.

**If `main` didn't move**, merging just moves the name `main` forward to the branch's newest commit (a *fast-forward*):

```diagram
type: history
title: Merge when main didn't change
start: Before
---
branch main | accent
branch new-search | good | from C
commit A main | First page
commit B main | Add colours
commit C main | Fix a typo
commit D new-search | Search box
commit E new-search | Search results
step zev merge new-search | On main. Nothing new happened on main, so main simply moves to E. Done.
point main | E
```

**If `main` moved too**, zev puts `main`'s own new commits back on top of the branch's, so the history stays one straight line with both sides' work:

```diagram
type: history
title: Merge when both sides changed
start: Before
---
branch main | accent
branch new-search | good | from C
commit A main | First page
commit B main | Add colours
commit C main | Fix a typo
commit D new-search | Search box
commit E new-search | Search results
commit F main | Fix footer | info main's own new commit
step zev merge new-search | zev replays F on top of E as a new commit, F′: the same change, a new place in history.
commit F′ main | Fix footer | after E | copy F | info The same change as F, replayed after E
mark F | faded
step The result | `main` is now `A → B → C → D → E → F′`: both the search and the footer fix, in one line.
mark F′ | good
```

## A conflict: when both changed the same lines

```diagram
type: diff
title: What a conflict looks like in the file
file: index.html
---
  <h1>
+ <<<<<<< main
+ Welcome to my site
+ =======
+ Welcome! Search below
+ >>>>>>> new-search
> zev marks the spot: main's version on top, the branch's version below
  </h1>
```

If `main` and your branch changed **the same lines**, zev can't guess which one you want, so it stops and changes nothing. That's a **conflict**, and it's normal. You fix it by hand:

```diagram
type: flow
title: Fixing a conflict
---
Mark | `zev merge new-search --resolve` marks every place both sides changed | warn | ⚠️
~ edit
Choose | Keep one side, the other or a mix; delete the marker lines | | ✏️
~ zev add
Stage | Tell zev the file is fixed | | ➕
~ zev merge --continue
Done | The merge finishes | good | ✓
? Changed your mind? `zev merge --abort` puts everything back
```

Merging often keeps conflicts small and rare. The full walkthrough is in [Branches and merging](/docs/en/branches#when-both-changed-the-same-lines).

## Your computer and Zaryn: clone, push, pull

```diagram
type: sequence
title: One project, two computers, one place in between
lanes: You | Zaryn | A teammate
alt: The teammate clones from Zaryn; you push commits; they pull them and push their own; you pull those back
---
== Getting a copy ==
A teammate -> Zaryn : zev clone
Zaryn --> A teammate : the whole history
== Sharing your work ==
You -> Zaryn : zev push: your new commits
note Zaryn : every commit is checked against its fingerprint | good
A teammate -> Zaryn : zev pull
Zaryn --> A teammate : only the commits they don't have
== Getting theirs ==
A teammate -> Zaryn : zev push
You -> Zaryn : zev pull
```

- **Clone**: download a repository, with its whole history, to your computer.
- **Push**: send your new commits up to Zaryn.
- **Pull**: get commits other people pushed, and update your files.

Your computer has the full history too, so you can commit, look at the history and make branches without internet. You only need a connection to push and pull. More in [Pushing and pulling](/docs/en/pushing-and-pulling).

## A pull request: ask before you merge

```diagram
type: flow
title: The life of a pull request
---
Branch | Do the work on a branch and push it | | 🌿
~ zev pr
Pull request | "Please merge new-search into main", with its diff | accent | 📬
~ review and checks
Review | Teammates comment; CI runs the tests | warn | 👀
? Changes asked? Push more commits: the pull request updates itself
~ approve
Merge | The work lands on main | good | ✓
```

A **pull request** (PR) asks to merge one branch into another, with room to talk first. It shows the diff, runs the [CI checks](/docs/en/memoized-ci), and lets teammates comment on any line. When everyone's happy, someone presses **Merge** (or runs `zev pr merge <number>`). On your own project it's still useful: a PR is a checklist before your work goes live.

## Two more you'll meet

```diagram
type: cards
---
🏷️ | Tag | A name that stays on one commit forever, like `v1.0`, for releases. `zev tag v1.0` | accent
🧺 | Stash | Put unfinished changes aside to switch branches, and take them back later. `zev stash`, `zev stash pop` |
↩️ | Restore | Undo changes to a file you haven't committed. `zev restore <file>` |
🍴 | Fork | Your own copy of someone else's repository on Zaryn, to change freely and send back with a PR |
```

## The whole picture

```diagram
type: graph
title: Everything on this page, together
height: 58
alt: You edit files, add and commit them to your local history, push to Zaryn, open a pull request, and teammates pull your work
---
node edit | Your files | 8 22 | file | | The working folder: edit freely
node stage | Staging | 26 22 | folder | | `zev add` picks changes for the next commit
node hist | Your history | 44 22 | log | accent | `zev commit` saves a snapshot; branches and merges happen here, offline
node zaryn | Zaryn | 66 22 | cloud | good | `zev push` shares commits; pull requests, reviews and CI live here
node mate | A teammate | 90 22 | laptop | | `zev clone` and `zev pull` bring your work to them
node pr | Pull request | 66 46 | branch | warn | Review the diff, run checks, merge
link edit stage | zev add | path
link stage hist | zev commit | path
link hist zaryn | zev push | path
link zaryn mate | zev pull | path2
link zaryn pr | review
```

## Words in one line each

| Word | In one line | Command |
|---|---|---|
| Repository | A project folder with its full history | `zev init`, `zev clone` |
| Commit | One save point: a snapshot, a message, who and when | `zev commit -m "…"` |
| Staging area | The changes picked for the next commit | `zev add` |
| History | All commits, each pointing at the one before | `zev log` |
| Diff | What changed between two versions, red and green | `zev diff` |
| Branch | A named line of commits for separate work | `zev checkout -b <name>` |
| Merge | Bring one branch's work into another | `zev merge <branch>` |
| Conflict | Both sides changed the same lines; you choose | `zev merge --resolve` |
| Clone / push / pull | Download / send / get commits from Zaryn | `zev clone`, `zev push`, `zev pull` |
| Pull request | Ask for a review before merging | `zev pr` |
| Tag | A fixed name for one commit, for releases | `zev tag` |

Ready? Follow the [Quick start](/docs/en/quickstart), keep the [words list](/docs/en/glossary) nearby, and when you're stuck, [How do I…?](/docs/en/how-do-i) has short answers.
