Git Curriculum
Phase 1 of a video curriculum on Git's model: content-addressed objects, commits as snapshots, branches as pointers, the three places, merging and rebasing, remotes. Idea map, one unit card and script per idea.

Git Curriculum

Phase 1 output under the Video Curriculum Guide. Every unit is one video plus one post and carries exactly one idea.

What the series is. Git as a data model, for people who already run Git commands and still find them surprising. The claim of the series is that about two dozen ideas explain every command: objects named by their content, commits as snapshots with parents, branches as movable pointers, three places that commands move content between, and remotes as other repositories with their own pointers. Commands appear only as the thing that moves a pointer or copies content between places. No unit teaches a workflow.

Recorded source statements. Every claim in the scripts rests on one of these, quoted from the Pro Git book (second edition, git-scm.com, read 2026-10-20) or the Git reference manual at git-scm.com/docs.

    Pro Git 1.3 "What is Git?": "Git thinks of its data more like a series of snapshots of a miniature filesystem. With Git, every time you commit, or save the state of your project, Git basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot. To be efficient, if files have not changed, Git doesn't store the file again, just a link to the previous identical file it has already stored." "Everything in Git is checksummed before it is stored and is then referred to by that checksum. This means it's impossible to change the contents of any file or directory without Git knowing about it." "When you do actions in Git, nearly all of them only add data to the Git database." The three states: modified, staged, committed; "the working tree, the staging area, and the Git directory"; "Its technical name in Git parlance is the 'index', but the phrase 'staging area' works just as well."

    Pro Git 10.2 "Git Objects": "Git is a content-addressable filesystem... a simple key-value data store." "The output from the above command is a 40-character checksum hash. This is the SHA-1 hash, a checksum of the content you're storing plus a header." A blob stores "just the content", not the filename. "A single tree object contains one or more entries, each of which is the SHA-1 hash of a blob or subtree with its associated mode, type, and filename." A commit "specifies the top-level tree for the snapshot of the project at that point; the parent commits if any; the author/committer information... and then the commit message."

    Git manual, hash-function-transition: Git "uses the SHA-1 hash function to name content"; the project "picked SHA-256 as its successor hash"; SHA-256 repositories are supported and interoperate with SHA-1 servers.

    Pro Git 10.4 "Packfiles": "although you added only a single line to the end of a 400-line file, Git stored that new content as a completely new object." "When Git packs objects, it looks for files that are named and sized similarly, and stores just the deltas from one version of the file to the next." "the second version of the file is the one that is stored intact, whereas the original version is stored as a delta." "Git does this if you have too many loose objects around, if you run the git gc command manually, or if you push to a remote server."

    Pro Git 3.1 "Branches in a Nutshell": a commit holds "pointers to the commit or commits that directly came before this commit (its parent or parents): zero parents for the initial commit, one parent for a normal commit, and multiple parents for a commit that results from a merge of two or more branches." "A branch in Git is simply a lightweight movable pointer to one of these commits." "Because a branch in Git is actually a simple file that contains the 40 character SHA-1 checksum of the commit it points to, branches are cheap to create and destroy. Creating a new branch is as quick and simple as writing 41 bytes to a file (40 characters and a newline)." HEAD is "a pointer to the local branch you're currently on."

    Pro Git 10.3 "Git References": "Usually the HEAD file is a symbolic reference to the branch you're currently on... it contains a pointer to another reference." "When you run git commit, it creates the commit object, specifying the parent of that commit object to be whatever SHA-1 value the reference in HEAD points to." A lightweight tag is "a reference that never moves"; for an annotated tag "Git creates a tag object and then writes a reference to point to it rather than directly to the commit." Remote references "are considered read-only... Git manages them as bookmarks to the last known state of where those branches were on those servers."

    Git manual, git-checkout, DETACHED HEAD: "HEAD refers to a specific commit, as opposed to referring to a named branch." After committing there: "There is now a new commit e, but it is referenced only by HEAD." "Eventually commit f (and by extension commit e) will be deleted by the routine Git garbage collection process, unless we create a reference before that happens." Creating a branch or tag at that commit keeps it.

    Pro Git 7.7 "Reset Demystified": "HEAD is the pointer to the current branch reference, which is in turn a pointer to the last commit made on that branch." "The index is your proposed next commit." The working directory is "a sandbox, where you can try changes out before committing them to your staging area (index) and then to history." "git commit... takes the contents of the index and saves it as a permanent snapshot, creates a commit object which points to that snapshot, and updates master to point to that commit." Checkout "changes HEAD to point to the new branch ref, populates your index with the snapshot of that commit, then copies the contents of the index into your working directory." Reset: "1. Move the branch HEAD points to (stop here if --soft). 2. Make the index look like HEAD (stop here unless --hard). 3. Make the working directory look like the index."

    Git manual, git-commit: "Create a new commit containing the current contents of the index and the given log message... The new commit is a direct child of HEAD, usually the tip of the current branch, and the branch is updated to point to it." --amend: "Replace the tip of the current branch by creating a new commit... The new commit has the same parents and author as the current one." "You should understand the implications of rewriting history if you amend a commit that has already been published."

    Git manual, gitglossary: "unreachable object: An object which is not reachable from a branch, tag, or any other reference." "reflog: A reflog shows the local 'history' of a ref." "fast-forward: A fast-forward is a special type of merge where you have a revision and you are 'merging' another branch's changes that happen to be a descendant of what you have. In such a case, you do not make a new merge commit but instead just update your branch to point at the same revision as the branch you are merging." "rebase: To reapply a series of changes from a branch to a different base, and reset the head of that branch to the result." "remote-tracking branch: A ref that is used to follow changes from another repository... should not contain direct modifications or have local commits made to it."

    Pro Git 10.7 "Maintenance and Data Recovery": "As you're working, Git silently records what your HEAD is every time you change it. Each time you commit or change branches, the reflog is updated." gc "removes objects that aren't reachable from any commit and are a few months old." Git manual, git-gc: "git reflog expire removes reflog entries older than this time; defaults to 90 days." gc calls "prune --expire 2.weeks.ago". "git gc tries very hard not to delete objects that are referenced anywhere in your repository. In particular, it will keep not only objects referenced by your current set of branches and tags, but also objects referenced by the index, remote-tracking branches, reflogs (which may reference commits in branches that were later amended or rewound)."

    Pro Git 3.2 "Basic Branching and Merging": fast-forward: "when you try to merge one commit with a commit that can be reached by following the first commit's history, Git simplifies things by moving the pointer forward because there is no divergent work to merge together." Three-way: "Git does a simple three-way merge, using the two snapshots pointed to by the branch tips and the common ancestor of the two." "Git creates a new snapshot that results from this three-way merge and automatically creates a new commit that points to it. This is referred to as a merge commit, and is special in that it has more than one parent." Conflicts: "Git hasn't automatically created a new merge commit. It has paused the process while you resolve the conflict." "Git adds standard conflict-resolution markers to the files that have conflicts." "run git add on each file to mark it as resolved... you can type git commit to finalize the merge commit."

    Git manual, git-cherry-pick: "Given one or more existing commits, apply the change each one introduces, recording a new commit for each."

    Pro Git 3.6 "Rebasing": rebase works "by going to the common ancestor of the two branches..., getting the diff introduced by each commit of the branch you're on, saving those diffs to temporary files, resetting the current branch to the same commit as the branch you are rebasing onto, and finally applying each change in turn." "the snapshot pointed to by the final commit you end up with, whether it's the last of the rebased commits for a rebase or the final merge commit after a merge, is the same snapshot; it's only the history that is different." "it looks like a linear history." "Do not rebase commits that exist outside your repository and that people may have based work on." "When you rebase stuff, you're abandoning existing commits and creating new ones that are similar but different. If you push commits somewhere and others pull them down and base work on them, and then you rewrite those commits with git rebase and push them up again, your collaborators will have to re-merge their work and things will get messy."

    Pro Git 2.5 "Working with Remotes": "Remote repositories are versions of your project that are hosted on the Internet or network somewhere." Fetch "pulls down all the data from that remote project that you don't have yet... it doesn't automatically merge it with any of your work or modify what you're currently working on." Pull: "automatically fetch and then merge that remote branch into your current branch." Push "works only if... nobody has pushed in the meantime. If you and someone else clone at the same time and they push upstream and then you push upstream, your push will rightly be rejected. You'll have to fetch their work first and incorporate it into yours before you'll be allowed to push."

    Git manual, git-checkout: switching with local changes that would be overwritten prints "error: Your local changes to the following files would be overwritten by checkout... Please commit your changes or stash them before you switch branches. Aborting" (verified, git 2.54).

    Git manual, git-diff: "--staged is a synonym of --cached", comparing the index with the HEAD commit; plain git diff compares the working tree with the index (verified: after git add, git diff is empty and git diff --staged shows the change).

    Pro Git 10.7 and verified: the reflog lives in .git/logs and is not transferred by clone (a fresh clone's reflog holds one entry).

    Git manual, git-gc: "gc.reflogExpireUnreachable... defaults to 30 days" for reflog entries not reachable from the current tip; gc.reflogExpire 90 days applies to reachable entries.

    Git manual, git-merge: "--no-ff: Create a merge commit even when the merge resolves as a fast-forward."

    Git manual, git-cherry-pick and verified: the new commit keeps the original author and message and gets a new object name.

    Git manual, git-pull: "--rebase... rebase the current branch on top of the upstream branch after fetching"; pull.rebase configures it.

    Git manual, git-push: a successful push updates the corresponding remote-tracking branch (verified: the origin/main reflog records "update by push"); "Usually, git push will refuse to update a branch that is not an ancestor of the commit being pushed"; tags are sent only with --tags, --follow-tags or by name (verified: plain pushes left new tags behind).

    Pro Git 10.3 and gitglossary: an annotated tag object holds "a tagger, a date, a message, and a pointer", and may carry a signature; the object types are "commit, tree, tag or blob".

    Git manual, git-clone: "Clones a repository into a newly created directory, creates remote-tracking branches for each branch in the cloned repository..., and creates and checks out an initial branch that is forked from the cloned repository's currently active branch." Shallow and partial clones are the named exceptions to copying the full history.

Scope. Git's data model and the commands that move pointers or content. Not covered: workflows (feature branches, pull requests, trunk-based), hosting services, hooks, stash, bisect, worktrees, submodules, signing, partial and shallow clones, packfile and index internals, the SHA-256 transition beyond one sentence, configuration.

Status. Revision 2, 2026-10-20, after the independent text review. Twenty-nine accuracy findings and twelve structural flags were resolved: three wrong claims fixed, the rewrite rule moved after push, a staging definition added, a metaphor beat added to the merge unit, seven verified claims recorded as sources. See "Review notes".

Idea map


    A commit is a photo, not a list of changes. Every commit is a complete snapshot; unchanged files are links to existing copies; diffs are computed. needs: nothing

    Everything is named by its content. The name of an object is the hash of its bytes; same content, same name anywhere; one byte changes the name; tampering is detectable. needs: nothing

    Three kinds of object. The three main kinds: blob (file content, no name), tree (names to blobs and trees), commit (tree, parents, author, message). needs: 1, 2

    One copy of each file, and packs underneath. Identical content is stored once; packs keep the newest version whole and older ones as deltas; snapshots are the model, deltas are storage. needs: 2, 3

    History is a chain of pointers to parents. A commit names its parent; arrows point backward; a name covers its whole history; merges have two parents. needs: 3

    A branch is a note on a commit. A 41-byte file holding a commit name; moves on commit; cheap to make and delete; commits are untouched. needs: 5

    HEAD says where you are. HEAD points at a branch; commit moves that branch only; switching moves HEAD and rewrites the files; HEAD is itself a one-line file. needs: 6

    Three places: your files, the tray, the last commit. Working tree, index, HEAD; add copies into the index; commit photographs the index and moves the branch. needs: 7

    Every diff compares two of the three places. diff is files vs index; diff --staged is index vs HEAD; status reports both gaps. needs: 8

    HEAD can point at a commit with no note. Detached HEAD; commits made there have no branch; make a branch to keep them. needs: 7

    Commits never change. Amend makes a new commit and moves the note; the old one stays, unreferenced; every rewrite works this way. needs: 5, 6

    The reflog remembers where the notes have been. Every move of HEAD and branches is logged locally and never travels; about thirty days for unreached commits; recovery by pointing a branch at the old commit. needs: 11

    Reset moves the note; the flags say what follows. Step one moves the branch; mixed also resets the index; hard also resets the files; only uncommitted work can be lost. needs: 8, 12

    A merge starts from the common ancestor. Find the merge base; apply both sets of changes; a commit with two parents. needs: 5, 6

    Fast-forward: nothing to merge. When the other tip already contains yours, the note just moves; no merge commit unless asked. needs: 14

    A conflict is two changes to the same lines. Git stops, writes both versions between markers; you edit, add to resolve, commit to finish. needs: 14

    Cherry-pick copies a change, not a commit. The diff against the parent is applied on HEAD as a new commit with a new name; the original stays. needs: 11

    Rebase replays your commits on a new base. Cherry-pick each commit onto the new tip, move the note; old commits stay unreferenced; same files as a merge, straight history. needs: 17, 14

    A clone is the whole repository. Everything is in .git; clone copies every object; works offline; origin is a name for the source; no master copy. needs: 6, 12

    origin/main is your memory of their note. Remote-tracking branches are read-only bookmarks of the remote's branches at last contact. needs: 19

    Fetch downloads. Pull also merges. Fetch gets objects and moves bookmarks only; pull is fetch plus merge or rebase into your branch. needs: 20, 15

    Push asks the remote to move its note. Push sends objects and asks for a fast-forward; refused if someone pushed first; force skips the check and strands commits. needs: 21

    Do not rewrite commits others have. Rewriting abandons commits others built on; their merge brings both back; rewrite only commits nobody else has built on. needs: 18, 21, 22

    A tag is a note that never moves. Pinned to one commit; lightweight is a pointer; annotated is a fourth kind of object with message and signature. needs: 3, 6

Parts: 1 to 5 objects; 6 to 13 pointers and places; 14 to 18 combining histories; 19 to 23 other repositories; 24 tags.

Parking list. Stash; bisect; worktrees; submodules; hooks; .gitignore; signing commits; SHA-256 repositories; shallow and partial clones; the index file format; pack and delta internals; interactive rebase; revert; blame; log formatting; configuration; hosting services and pull requests; workflows.

Shared visual language


    A commit is a circle with a four-character name inside. A parent arrow leaves a commit and points at its parent, always backward.

    A note is a rounded label with a branch name, hanging on one commit. HEAD is a smaller purple label that points at a note, or at a commit when detached. A tag (unit 24) is a note with a pin.

    A photo is a commit's snapshot: a framed card holding small file cards.

    A file card is a card with a filename and a few lines. A blob is the same card with no filename and a name strip. A tree is a list of names with arrows.

    The three places are three columns: your files, the tray (the index), and the last commit.

    A repository is a box. The remote is a second box labelled origin. A bookmark is a note drawn in the remote's colour.

    A dimmed commit is one no note points at.

Breaks, each said once in the script: a fingerprint names the content, not its maker (unit 2); a note only moves when Git moves it (unit 6).

Units

Unit 1: A commit is a photo, not a list of changes


    Idea. A commit is a complete snapshot of every file; unchanged files are links to copies Git already has; the changes you see are computed by comparing two snapshots.

    Why it matters. Almost every Git surprise comes from picturing a list of patches. Picture photos and the rest of the series follows.

    Context assumed. Nothing.

    Metaphor. A photo of all your files versus a notebook of changes. Breaks: a photo cannot be shared between two albums; the link to an existing copy is said outright.

    Misconception. Git stores diffs. Addressed at beat 2 and again at beat 5.

    Visual language. Notebook, photo, file cards, diff.

    Target length. 55 to 70 seconds.

    Check question. Git shows you a one-line change between two commits. What does Git actually store: the change, or the two photos?

Script:

    Most people picture Git as a list of changes. Add this line. Remove that one. (Screen: a notebook listing three changes.)

    That is not what Git stores. A commit is a photo of every file in the project. All of them, at once. (Screen: one photo holding four files.)

    Three commits are three photos. Each one is complete on its own. (Screen: three photos in a row.)

    A file that did not change is not copied again. The new photo points at the copy it already has. (Screen: second photo points at the first for one unchanged file.)

    When Git shows you a change, it compares two photos. The change is worked out on the spot. The photo is what is stored. (Screen: a diff appears between two photos.)

Unit 2: Everything is named by its content


    Idea. An object's name is the hash of its bytes, so identical content has the same name everywhere, any change produces a new name, and tampering can always be proved.

    Why it matters. This is why clones agree, why commits are immutable, and why a name is a guarantee.

    Context assumed. Nothing.

    Metaphor. A fingerprint. Break, spoken: it is a fingerprint of the content, not of who made it.

    Misconception. Hashes are ids a server assigns. Addressed at beat 2.

    Visual language. File card, hash funnel, name strip, two machines.

    Target length. 50 to 65 seconds.

    Check question. Two people commit the same file on different machines. What can you say about the file's name in each repository?

Script:

    Give Git a file. It runs the content through a hash function. Out come forty characters. (Screen: a file goes into a hash, a name comes out.)

    That is the file's name inside Git. Not a number Git picked. A fingerprint of the content. Not of who made it. (Screen: the name under the file; the word fingerprint.)

    The same content gives the same name. On your laptop. On a server. In ten years. (Screen: two machines, the same file, the same name.)

    Change one byte, and the name changes completely. (Screen: one byte changed, a different name.)

    So nothing can be altered quietly. If the content differs, the name no longer matches. Git can prove it. (Screen: the file's name no longer matches its content.)

Unit 3: Three kinds of object


    Idea. Git's three main objects are blobs (file content without a name), trees (names mapped to blobs and trees), and commits (a tree, parents, author, message), all named by content.

    Why it matters. Knowing that filenames live in trees and content in blobs explains renames, empty directories, and what a commit really points at.

    Context assumed. Units 1 and 2.

    Metaphor. None; the objects are shown as themselves.

    Misconception. A commit contains the files. It points at a tree that points at blobs. Addressed at beat 4.

    Visual language. Blob card, tree list, commit card.

    Target length. 50 to 60 seconds.

    Check question. Where is a filename stored?

Script:

    Git stores three main kinds of thing. All of them named by content. Blob. Tree. Commit. (Screen: three shapes: blob, tree, commit.)

    A blob is the content of one file. Just the bytes. No filename. (Screen: a blob: bytes, no filename.)

    A tree is a folder. It lists names, and for each name, the blob or tree it points at. (Screen: a tree: names, each pointing at a blob or tree.)

    A commit is the photo. It points at one tree. It names its parent commit, the author, and a message. (Screen: a commit card: tree, parent, message.)

    Three kinds. Everything in your history is built from them. (Screen: commit to tree to blobs, linked.)

Unit 4: One copy of each file, and packs underneath


    Idea. Snapshots do not multiply storage: identical content is stored once, and packs store the newest version of a file whole and older versions as deltas.

    Why it matters. It removes the main objection to the snapshot model and explains why repositories stay small.

    Context assumed. Units 1 to 3.

    Metaphor. The photo stack. Breaks: none needed.

    Misconception. "So Git does store diffs after all." Addressed at beat 5: deltas are a storage detail under an unchanged model.

    Visual language. Photo stack, blob, pack.

    Target length. 55 to 65 seconds.

    Check question. You commit ten times without touching a large image. How many copies of the image does Git hold?

Script:

    A photo of every file, every commit. That sounds like a lot of space. (Screen: ten photos stacked.)

    It is not. Identical content has the identical name. So Git keeps one copy, and every photo points at it. (Screen: ten photos point at one blob.)

    A file you edit does get a new blob. One line added to a long file, a whole new copy. (Screen: a long file, one line added, a second blob.)

    Now and then Git packs. It keeps the newest version whole. Older versions are stored as differences from it. (Screen: a pack: newest copy whole, older ones as small differences.)

    So photos are what you see. Differences are a storage trick underneath. You never have to think about them. (Screen: photos above, the pack below.)

Unit 5: History is a chain of pointers to parents


    Idea. A commit names its parent, the parent's name is part of the child's content, so one name covers a whole history; arrows always point backward; merges have two parents.

    Why it matters. Every graph you will ever draw of Git has its arrows this way round, and the "name covers history" fact is why a commit id can be trusted.

    Context assumed. Units 2 and 3.

    Metaphor. A chain where each link is stamped with the previous link's fingerprint.

    Misconception. A commit knows its children. Addressed at beat 2.

    Visual language. Commit circles, parent arrows, nested names.

    Target length. 50 to 65 seconds.

    Check question. Two commits have the same name. What can you say about their histories?

Script:

    Each commit names the commit it was made on top of. Its parent. (Screen: two commits; an arrow from the new one to the old one.)

    The arrows point backward. From child to parent. A commit does not know what comes after it. (Screen: a chain of four, every arrow pointing back.)

    The parent's name is part of the child's content. So the child's name covers its parent too. And the parent's parent. All the way down. (Screen: the parent's name written inside the child.)

    One name stands for a whole history. Same name, same history, byte for byte. (Screen: one commit; the chain behind it lights up.)

    A merge has two parents. The chain becomes a graph. Still, every arrow points back. (Screen: a commit with two arrows back.)

Unit 6: A branch is a note on a commit


    Idea. A branch is a 41-byte file holding one commit name; it moves when you commit on it; making or deleting it does nothing to the commits.

    Why it matters. Cheap branches are the reason Git workflows look the way they do, and "deleting a branch deletes work" is false.

    Context assumed. Unit 5.

    Metaphor. A sticky note with a name on it. Break, spoken: a note only moves when Git moves it.

    Misconception. A branch is a copy of the project. Addressed at beat 1.

    Visual language. Note, commits, the branch file.

    Target length. 55 to 70 seconds.

    Check question. You delete a branch. What happens to its commits?

Script:

    People picture a branch as a copy of the project. It is not. (Screen: a copied folder, crossed out.)

    A branch is a note with a name. It points at one commit. On disk it is a file holding that commit's name. Forty one bytes. (Screen: a note named main points at one commit; its file.)

    Commit again, and the note moves to the new commit. The commits stay where they are. (Screen: a new commit; the note slides onto it.)

    Making a branch writes one small file. Deleting one removes the note. The commits it pointed at are untouched. (Screen: a second note appears, then is removed; commits unchanged.)

    So a branch is cheap. Make as many as you like. The history is the commits. The notes just mark places, and only move when Git moves them. (Screen: three notes on one graph.)

Unit 7: HEAD says where you are


    Idea. HEAD points at the branch you are on; a commit's parent is the commit under HEAD and only that branch moves; switching moves HEAD and rewrites the files; HEAD itself is a one-line file naming the branch.

    Why it matters. It explains which branch grows when you commit, and what checkout and switch actually do.

    Context assumed. Unit 6.

    Metaphor. A "you are here" marker.

    Misconception. Commits go to "the repository" rather than to one branch. Addressed at beat 3.

    Visual language. HEAD label, notes, desk of files, the HEAD file.

    Target length. 50 to 60 seconds.

    Check question. You have branches main and fix. You commit. Which branch moves, and how does Git know?

Script:

    Several notes, one project. Which one are you on? HEAD answers. (Screen: three notes; a HEAD marker on main.)

    HEAD is a marker that points at another note. Usually a branch. (Screen: HEAD points at main; main points at a commit.)

    When you commit, the parent is the commit under HEAD. And the branch under HEAD moves. Not the others. (Screen: a new commit; main moves, the other note stays.)

    Switching branches moves HEAD to a different note. Then Git rewrites your files to match that commit. (Screen: HEAD jumps to another note; the files on the desk change.)

    HEAD is itself a small file. Inside is one line: the name of the branch note. (Screen: the HEAD file: one line, the name of the note.)

Unit 8: Three places: your files, the tray, the last commit


    Idea. Git moves content between the working tree, the index and HEAD: add copies a file into the index (staging it), commit photographs the index and moves the branch.

    Why it matters. The index is the thing most people never form a picture of, and without it add, commit, diff and reset all look arbitrary.

    Context assumed. Unit 7.

    Metaphor. A tray where you lay out the next photo.

    Misconception. Commit saves your working files. It saves the tray. Addressed at beat 5.

    Visual language. Three columns, file cards.

    Target length. 55 to 70 seconds.

    Check question. You edit a file after adding it, then commit. Which version is in the commit?

Script:

    Git works with three places. Your files on disk. The index. And the last commit, the one under HEAD. (Screen: three columns: your files, the index, HEAD.)

    The index is the proposed next commit. Git also calls it the staging area. A tray where you lay out exactly what the next photo will hold. Putting a file there is staging it. (Screen: the index highlighted; the words next commit.)

    You edit a file. Only your copy changes. The tray still holds the old version. (Screen: a file changes in the first column only.)

    git add copies the file into the tray. Now the tray and your copy agree. The last commit does not. (Screen: the file is copied into the tray.)

    git commit takes the photo of the tray, not of your disk. Then it moves the branch to it. Now all three agree. (Screen: the tray becomes a new commit; all three columns match.)

Unit 9: Every diff compares two of the three places


    Idea. git diff compares the working tree with the index, git diff --staged compares the index with HEAD, and git status reports both gaps.

    Why it matters. "My change disappeared from git diff" is the most common index confusion.

    Context assumed. Unit 8.

    Metaphor. Two gaps between three columns.

    Misconception. git diff shows all uncommitted changes. Addressed at beat 4.

    Visual language. Three columns, two gap arrows, status lists.

    Target length. 50 to 60 seconds.

    Check question. You added a file and git diff shows nothing. Where is the change?

Script:

    Three places. A diff is always a comparison between two of them. (Screen: three columns with two gaps between them.)

    git diff compares your files with the tray. It shows what you have not added yet. (Screen: an arrow between your files and the tray.)

    git diff, staged, compares the tray with the last commit. It shows what the next commit will contain. (Screen: an arrow between the tray and the last commit.)

    Add a file, and git diff goes quiet about it. The change did not vanish. It moved to the other gap. (Screen: a change moves from the first gap to the second.)

    git status reports both gaps at once. Changes not staged. Changes to be committed. (Screen: status with two lists.)

Unit 10: HEAD can point at a commit with no note


    Idea. HEAD can point straight at a commit; commits made there belong to no branch and will be collected unless a branch or tag is placed on them.

    Why it matters. The detached HEAD warning scares people into losing work or avoiding useful checkouts.

    Context assumed. Unit 7.

    Metaphor. The marker standing on a commit with no note under it.

    Misconception. Detached HEAD is an error state. Addressed at beat 3.

    Visual language. HEAD label on a commit, dimmed commit, new note.

    Target length. 50 to 60 seconds.

    Check question. You committed in detached HEAD and want to keep it. What do you do before switching away?

Script:

    HEAD usually points at a branch. It can also point straight at a commit. (Screen: HEAD points straight at a commit; no note.)

    Check out an old commit, and that is what happens. Git calls it a detached HEAD. (Screen: HEAD on an old commit; the word detached.)

    Looking around is fine. Build it, run it, read it. (Screen: the desk shows that commit's files.)

    Commit here, and the new commit has no branch. Only HEAD points at it. Move HEAD away, and no note does. (Screen: a new commit off the chain; HEAD leaves; it dims.)

    To keep that work, make a branch before you leave. A note on the commit keeps it. (Screen: a note placed on the commit; it brightens.)

Unit 11: Commits never change


    Idea. A commit cannot be edited because its name is its content; amend and every other rewrite make new commits and move the note, leaving the old commits with no note on them until cleanup.

    Why it matters. It makes rewriting history understandable and recovery possible.

    Context assumed. Units 5 and 6.

    Metaphor. The note moving to a sibling commit.

    Misconception. Amend edits the commit in place. Addressed at beat 2.

    Visual language. Commit, sibling commit, note, dimmed commits, clock.

    Target length. 55 to 65 seconds.

    Check question. After amend, where is the original commit?

Script:

    You cannot edit a commit. Its name is its content. Change the content, and you have a different commit. (Screen: a commit; an edit; a different name appears.)

    So what does amend do? Amend is the command for fixing your last commit. It makes a new commit with the same parent and your new content. Then it moves the branch note. (Screen: a new commit beside the old one; the note moves to it.)

    The old commit is still there. No note points at it any more. It is just not on the branch. (Screen: the old commit dimmed, no note.)

    Every command that rewrites history works like this. New commits. Moved notes. The old ones stay behind. (Screen: a row of old commits dimmed under a new row.)

    Only much later does Git clean up commits nothing points at. Until then, nothing is lost. (Screen: dimmed commits with a clock.)

Unit 12: The reflog remembers where the notes have been


    Idea. Git logs every move of HEAD and of each branch locally; entries for commits no note reaches last about thirty days; a "lost" commit is recovered by pointing a branch at the name in the log.

    Why it matters. It is the safety net under every rewrite and reset.

    Context assumed. Unit 11.

    Metaphor. A diary of where the marker has been.

    Misconception. A commit with no branch is gone. Addressed at beat 3.

    Visual language. Diary, entries, dimmed commit, note.

    Target length. 50 to 60 seconds.

    Check question. Does the reflog travel with a clone of your repository?

Script:

    Every time HEAD or a branch moves, Git writes a line in a diary. The reflog. (Screen: a diary with entries.)

    Each entry says where the note was, and why it moved. Commit. Checkout. Reset. (Screen: three entries: commit, checkout, reset.)

    You amended, and want the old commit back? It is in the reflog. Point a branch at it. (Screen: an entry leads to a dimmed commit; a note is placed.)

    The diary is local. Yours alone. It stays with your folder. It never travels to another repository. (Screen: the diary inside your folder; it never travels.)

    Entries for commits no note reaches expire after about thirty days. Only after that are those commits removed. Before then, everything is recoverable. (Screen: a calendar: thirty days.)

Unit 13: Reset moves the note; the flags say what follows


    Idea. Reset moves the current branch to a commit, then optionally makes the index match (mixed, the default) and the working tree match (hard); only uncommitted work can be lost.

    Why it matters. Reset is the command people fear most and it is three steps.

    Context assumed. Units 8 and 12.

    Metaphor. The note moves back and the tray and desk follow, one at a time.

    Misconception. Reset deletes commits. Addressed at beat 5.

    Visual language. Three columns, note, dimmed commits.

    Target length. 55 to 65 seconds.

    Check question. Which flag can lose work that was never committed?

Script:

    git reset moves the branch under HEAD to a commit you name. That is the first step. Always. (Screen: the note moves back two commits.)

    With soft, it stops there. The tray and your files keep what they had. (Screen: note moved; the tray and your files unchanged.)

    With no flag, the tray is made to match the commit too. Your files keep their changes. (Screen: the tray now matches the commit; your files unchanged.)

    With hard, your files are made to match as well. Changes that were never committed are gone. (Screen: all three match; an edited file disappears.)

    The commits you moved away from are not deleted. The reflog has them. Uncommitted work is the only thing a hard reset can lose. (Screen: old commits dimmed; a lost file crossed.)

Unit 14: A merge starts from the common ancestor


    Idea. Git finds the last commit both branches share, measures each tip's changes from it, applies both, and records a commit with two parents.

    Why it matters. Knowing there is an ancestor explains why merges are usually clean and where conflicts come from.

    Context assumed. Units 5 and 6.

    Metaphor. Two people editing copies of the same page; compare each copy to the original.

    Misconception. Merge compares the two tips to each other. Addressed at beat 3.

    Visual language. Fork, lit ancestor, two copies of a page, two change sets, merge commit.

    Target length. 50 to 60 seconds.

    Check question. How many commits does a three-way merge read?

Script:

    Two branches, each with new commits. You want one result. (Screen: a fork: two branches, two new commits each.)

    Git finds the last commit both branches share. The common ancestor. (Screen: the fork point lights up.)

    Like two people who each copied one page and edited it. To combine them, compare each copy to the original. Not to each other. (Screen: two copies of one page, each edited; the original between them.)

    Then it compares each tip to that ancestor. Two sets of changes. It applies both. (Screen: two sets of changes, each measured from the ancestor.)

    The result is a new commit with two parents. The merge commit. (Screen: a merge commit with two arrows back.)

    Three photos go in. The ancestor, yours, theirs. That is why it is called a three way merge. (Screen: three photos go in, one comes out.)

Unit 15: Fast-forward: nothing to merge


    Idea. When the other tip already contains your tip in its history, a merge just moves your note; no commit is made unless you ask for one.

    Why it matters. It explains why some merges leave no merge commit and what "non-fast-forward" means later.

    Context assumed. Unit 14.

    Metaphor. The note sliding forward along a line.

    Misconception. Every merge creates a merge commit. Addressed at beat 3.

    Visual language. One line of commits, two notes.

    Target length. 45 to 55 seconds.

    Check question. A merge produced no new commit. What was true of the two branches?

Script:

    Sometimes there is nothing to combine. Your branch has no new commits. The other one is simply ahead. (Screen: main on a commit; feature two commits ahead on the same line.)

    The other tip already has your tip in its history. (Screen: the path from the other tip back through yours lights up.)

    So Git just moves your note forward to that tip. No new commit. That is a fast forward. (Screen: the main note slides forward.)

    Nothing was merged, because there was nothing on your side to merge. (Screen: both notes on the same commit.)

    You can ask Git for a merge commit anyway. Some teams do, to keep a record that the branch existed. (Screen: an optional merge commit with two parents.)

Unit 16: A conflict is two changes to the same lines


    Idea. When both sides changed the same lines Git stops, writes both versions between markers, and waits; you edit, add to mark resolved, and commit to finish the merge.

    Why it matters. Conflicts are routine and mechanical once you know Git is asking a question, not reporting a failure.

    Context assumed. Unit 14.

    Metaphor. None; the file is shown as itself.

    Misconception. A conflict means something broke. Addressed at beat 5.

    Visual language. File card with two edits, markers, tray, merge commit.

    Target length. 50 to 60 seconds.

    Check question. What does git add do during a conflicted merge?

Script:

    A merge applies two sets of changes. Usually they touch different lines. Git applies both. (Screen: a file with two edits in different places; check.)

    Sometimes both sides changed the same lines. Git has no rule for picking one. (Screen: the same lines edited on both sides.)

    So it stops. It writes both versions into the file, between markers. And it waits. (Screen: the file with both versions between markers.)

    You edit the file until it says what you want. Then git add. That marks it resolved. (Screen: the file cleaned up and added to the tray.)

    Then git commit finishes the merge. A conflict is not an error. It is a question only you can answer. (Screen: the merge commit appears.)

Unit 17: Cherry-pick copies a change, not a commit


    Idea. Cherry-pick takes the difference a commit made against its parent, applies it on HEAD, and records a new commit with a new name; the original is untouched and unlinked.

    Why it matters. It is the building block of rebase and the reason "the same commit" can exist twice.

    Context assumed. Unit 11.

    Metaphor. A copy, not a move.

    Misconception. Cherry-pick moves the commit over. Addressed at beat 4.

    Visual language. Two branches, highlighted commit, difference, new commit.

    Target length. 50 to 60 seconds.

    Check question. After a cherry-pick, how many commits carry that change?

Script:

    A commit on another branch has a fix you want. You could merge the whole branch. Or copy just that one change. (Screen: a graph; one commit on the other branch highlighted.)

    Cherry pick takes the difference that commit made, compared to its parent. (Screen: that commit compared with its parent; a difference.)

    It applies that difference on top of your current commit. And records a new commit. (Screen: the difference lands on your branch; a new commit.)

    New parent, new content, new name. Same message, same author. It is a copy, not a move. (Screen: the two commits side by side, different names.)

    The original stays on its branch. Git does not know the two are related. You do. (Screen: both commits, no link between them.)

Unit 18: Rebase replays your commits on a new base


    Idea. Rebase cherry-picks each of your commits onto the new tip and moves your note; the old commits remain unreferenced; the files match a merge but the history is a line.

    Why it matters. It demystifies the most feared command by reducing it to two ideas already learned.

    Context assumed. Units 14 and 17.

    Metaphor. Copying commits one by one onto a new base.

    Misconception. Rebase moves commits. It copies them. Addressed at beat 4.

    Visual language. Fork, copied commits, dimmed chain, two histories.

    Target length. 50 to 60 seconds.

    Check question. After a rebase, are the commit names on your branch the same as before?

Script:

    Your branch started from an old commit on main. Main has moved on. (Screen: a fork; main has moved ahead.)

    Rebase moves your work to start from the new tip. It cherry picks your commits, one by one, onto it. (Screen: your commits copied one by one onto main's tip.)

    Then it moves your branch note to the last copy. (Screen: your note moves to the last copy.)

    The copies have new names. The originals are still there, with no note. Same rule as always. (Screen: the old chain dimmed, no note.)

    Merge and rebase end with the same files. The difference is the shape of the history. Rebase makes it a straight line. (Screen: two histories: one with a merge, one straight line.)

Unit 19: A clone is the whole repository


    Idea. Everything Git knows is in .git; clone copies every object, so a clone works offline and is a full repository; origin is only a remembered name for where it came from.

    Why it matters. It is the difference between Git and a checkout from a central server, and it frames every remote command.

    Context assumed. Units 6 and 12.

    Metaphor. Two equal boxes.

    Misconception. A clone is a working copy of the latest files. Addressed at beat 2.

    Visual language. .git box, second box, origin line.

    Target length. 50 to 60 seconds.

    Check question. What does a clone contain that a downloaded zip of the files does not?

Script:

    Everything Git knows lives in one folder. Dot git. Every commit, every photo, every note. (Screen: a box labelled .git: commits, photos, notes.)

    Clone copies every object. Every commit, every photo, from the first one. Not just the latest files. (Screen: a second box filled with the same objects.)

    So you can read the history, make commits and branches, all without a network. (Screen: the clone with no connection; commits added.)

    The place you cloned from is remembered under a name. Origin, by default. It is a remote. A repository somewhere else. (Screen: a line from the clone to the first box, labelled origin.)

    Both sides are full repositories. Neither is the master copy, except by agreement. (Screen: two equal boxes.)

Unit 20: origin/main is your memory of their note


    Idea. A remote-tracking branch is a read-only bookmark of where the remote's branch was at last contact; Git moves it on fetch and push, and it goes stale in between.

    Why it matters. "origin/main" appears in every status line and most people cannot say what it is.

    Context assumed. Unit 20.

    Metaphor. A bookmark versus a live view.

    Misconception. origin/main is the remote's branch. It is your memory of it. Addressed at beat 2.

    Visual language. Two boxes, notes, a bookmark, a lock.

    Target length. 50 to 60 seconds.

    Check question. Someone pushes to origin. Does your origin/main move?

Script:

    Your clone has your branches. It also has notes like origin slash main. (Screen: your repository with notes main and origin/main.)

    Origin slash main is where origin's main was, the last time you looked. A bookmark, not a live view. (Screen: origin's main further ahead; your origin/main behind.)

    You cannot commit on it. Git moves it for you, when you fetch or push. (Screen: origin/main with a lock.)

    Someone pushes to origin. Your bookmark does not move. It is stale until you ask. (Screen: origin's main moves; your bookmark stays.)

    So two notes for one branch. Main is yours. Origin slash main is your memory of theirs. (Screen: two notes labelled yours and theirs.)

Unit 21: Fetch downloads. Pull also merges


    Idea. Fetch downloads missing objects and moves the bookmarks only; pull is fetch followed by a merge or rebase of the bookmark into your branch.

    Why it matters. Fetch is always safe and pull is not, and the difference is one step.

    Context assumed. Units 15 and 21.

    Metaphor. Bookmarks versus your note.

    Misconception. Fetch changes your files. Addressed at beat 3.

    Visual language. Two boxes, flowing objects, bookmark, merge commit.

    Target length. 50 to 60 seconds.

    Check question. After git fetch, has your branch moved?

Script:

    git fetch talks to the remote. It downloads every commit you do not have yet. (Screen: objects flow from origin into your repository.)

    Then it moves the bookmarks. Origin slash main now matches their main. (Screen: the origin/main bookmark slides forward.)

    Your own branches do not move. Your files do not change. Fetch is safe to run any time. (Screen: your main and your files unchanged; check.)

    git pull is fetch, then merge origin slash main into your branch. Or rebase onto it, if you set that. (Screen: fetch, then a merge commit on your main.)

    So pull changes your branch and your files. Fetch only changes what you know. (Screen: side by side: fetch moves a bookmark; pull also moves your branch.)

Unit 22: Push asks the remote to move its note


    Idea. Push sends your commits and asks the remote to fast-forward its branch; it refuses if the remote's tip is not in your history; force skips the check and strands the skipped commits.

    Why it matters. "Rejected, non-fast-forward" is the most common push error and this is the whole explanation.

    Context assumed. Units 15 and 22.

    Metaphor. A request to move the other box's note.

    Misconception. Push uploads files. It moves a pointer after sending commits. Addressed at beat 1.

    Visual language. Two boxes, flowing objects, note, cross, dimmed commit.

    Target length. 55 to 65 seconds.

    Check question. Why does the remote refuse a push?

Script:

    git push sends your new commits to the remote. Then it asks: move your main to this commit. (Screen: objects flow out; a request to move their note.)

    Git says yes only if their main is in the history of your commit. A fast forward. (Screen: their main is an ancestor of yours; the note moves.)

    If someone pushed first, their commit is not in your history. The push is refused. (Screen: their main is off your line; the push is refused.)

    Fetch, then merge or rebase their work in, then push again. Now their commit is behind yours. (Screen: their work merged in; the push accepted.)

    A force push skips the check and moves the note anyway. The commits it skipped over lose their note. Use it only on branches that are yours alone. (Screen: the note yanked; a skipped commit dims.)

Unit 23: Do not rewrite commits others have


    Idea. Rewriting replaces commits others may have built on; their merge brings the abandoned commits back; rewrite only commits nobody else has built on.

    Why it matters. It is the one rule that keeps rewriting safe for a team.

    Context assumed. Units 18, 21 and 22.

    Metaphor. Two boxes whose chains disagree.

    Misconception. Rebase is dangerous in general. It is dangerous only on shared commits. Addressed at beat 1 and 5.

    Visual language. Two repositories, similar chains, tangled merge.

    Target length. 50 to 60 seconds.

    Check question. You amended a commit that others have already pulled. What is the safe alternative?

Script:

    Rebase and amend make new commits and abandon the old ones. On your own machine, that is fine. (Screen: old commits dimmed inside your repository.)

    But if someone pulled the old commits, their work is built on top of them. (Screen: a second repository with the old commits and new work on top.)

    You push the rewritten ones. Now their history and yours disagree about commits that look the same. (Screen: two repositories, two chains of similar commits.)

    They have to merge the two, and the abandoned commits come back. Twice the history. Easy to get wrong. (Screen: a tangled merge.)

    The rule: rewrite only commits nobody else has built on. Once others have them, add a new commit instead. (Screen: your repository: rewrite; shared: a new commit on top.)

Unit 24: A tag is a note that never moves


    Idea. A tag is a note pinned to one commit; lightweight is only the pointer, annotated is a fourth kind of object with message, date, tagger and optional signature.

    Why it matters. Releases need a name that cannot drift.

    Context assumed. Units 3 and 6.

    Metaphor. A pinned note.

    Misconception. A tag is a kind of branch. Addressed at beat 2.

    Visual language. Moving note, pinned tag, tag file, tag object. Post only: tags are pushed on purpose (git push --tags or by name).

    Target length. 50 to 60 seconds.

    Check question. What does an annotated tag have that a lightweight tag does not?

Script:

    A branch note moves every time you commit. Sometimes you want a name that stays put. (Screen: a branch note moving along; a tag staying put.)

    A tag is a note pinned to one commit, forever. Version one point zero means this exact photo. (Screen: a tag v1.0 pinned on one commit.)

    A lightweight tag is only the pointer. A file with a name, holding a commit name. (Screen: a lightweight tag: a file with a name and a commit name.)

    An annotated tag is a fourth kind of object. It carries a message, a date, and a tagger, and can be signed. (Screen: an annotated tag object: message, date, tagger.)

    Pin one on every release. Months later, the branch has moved on. Version one point zero still means that one photo. (Screen: the pinned tag; the branch note far ahead.)

Review notes

Phase 1d text review, 2026-10-20, by an independent reviewer with only the guide, the curriculum, the Pro Git book, the Git manual and a throwaway repository on git 2.54. Full report: Git Curriculum Review. What changed:

    Three wrong claims. "Git checks the name every time it reads" became a detectability claim: Git can prove a mismatch, it does not check on every read (unit 2). The reflog window for commits no note reaches is about thirty days, not ninety (unit 12). Clone copies every object, not the reflog or settings; the "everything in .git" list now names commits, photos and notes (unit 19).

    Order. The rule against rewriting shared commits moved from 19 to 23, after clone, bookmarks, fetch and push, which it depends on. Its rule now matches the source: rewrite only commits nobody else has built on.

    A missing definition. Unit 8 now says the index is also called the staging area and that putting a file there is staging it, so unit 9's "staged" has a referent.

    "Nothing points at it" became "no note points at it" in units 10 and 11, because the reflog does.

    Metaphors. The merge unit gained a beat that speaks its page-copies metaphor; the tag unit now says "pinned"; the chain unit's fingerprint stays implicit by choice.

    Second ideas removed. Unit 7's checkout-refusal beat was replaced by the HEAD file itself; unit 24's push-tags beat was replaced by the pinned note over time, and "tags are pushed on purpose" moved to the card as post-only.

    Terms. "three main kinds" and "a fourth kind of object"; "forty characters" not "hex"; "amend" defined in its sentence; "or a tag" dropped from unit 10; the branch shape is now called a label so Git tags are unambiguous.

    Seven verified claims recorded as sources: the checkout refusal, --staged, the reflog staying local, --no-ff, cherry-pick keeping author and message, pull --rebase, push updating the bookmark and leaving tags behind.

    Screens cut to four things in units 3, 12, 13, 19 and 24. Push refusal is now said as "the push is refused", since the fast-forward check runs on your side.

Kept against the reviewer's suggestion. Unit 5 keeps "the parent's name" rather than "fingerprint"; the word name is the one every later unit uses.

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime

Comments