skipnothing/Git

Git

Branching, merging, rebasing, workflows, see what git actually does under the hood.

You can use a terminal and have written code in any language.

Loading…
01

How Git Thinks

The object model, what git actually stores

3/3
02

Everyday Git

Staging, tracking, history, and setting aside work

4/4
#4

The Staging Area

Track one file across the working tree, `.git/index`, and your last commit, decode the two columns of `git status`, stage a single hunk with `git add -p`, and know what `.gitignore` can and cannot untrack.

Edit `config.json`, run `git add`, then change one line again, and your next commit keeps the earlier version, not what sits on disk. Three copies of one file exist at once, and one command chose between them.

12 min
#5

Reading History

Reconstruct every `git log`, `git diff`, `git blame`, and `git grep` result by hand as a walk over the commit snapshots, and see why re-reading history never adds a byte to `.git/`.

You scroll `git log` and picture git reading a stored list of what happened, but nothing is stored. Each line was recomputed a breath ago by walking your commits, and recomputed again the next time you look.

10 min
#6

Tags & Releases

Pin a release to one commit with a tag that never moves, choose lightweight or annotated by the metadata it stores, read what each writes to `.git/refs/tags/` and `.git/objects/`, decode the `git describe` string, and number releases with semantic versioning.

You shipped `app.py` at the commit everyone now runs, then kept committing on top. Weeks later you need that exact snapshot back, and one small file, written once and never rewritten, still points straight at it.

10 min
#7

Stash & Worktrees

Stash edits into the two-parent commit git writes under `.git/refs/stash`, restore them with apply (keeps the entry) or pop (erases it), and open a second `git worktree` that shares one object store while keeping its own HEAD and index.

You're mid-edit in `app.py` when a teammate pings: their fix needs the working tree clean right now. You don't want a half-baked commit, and you don't want to lose the last hour of work.

10 min
03

Branching & Merging

Parallel work and bringing it together

3/3
04

Rewriting & Undoing

Amend, rebase, reset, bisect, and recovery

5/5
#11

Amend & Fixup

Correct the tip of your branch with `git commit --amend`, which writes a new commit and moves the ref while the original waits in the reflog, then queue a fix for a buried commit by writing a `fixup!` marker to fold in later.

You just committed `Add config.json`, then spot a typo in the message and reach to fix it in place. Git has no such button: change one byte and `git cat-file -p` prints a different object with a different name.

10 min
#12

Rebase

Rebuild your branch's commits onto a new base, watching each become a new object with the same diff but a fresh parent and hash, fold a queued `fixup!` marker into its target with `--autosquash`, and see why `ours` and `theirs` swap when a replay hits a conflict.

Your feature branch holds three commits, and `main` has moved ahead since you branched off it. You want your three sitting on top of today's `main`, carrying the same file changes on fresh footing.

15 min
#13

Reset, Revert & Clean

Rewind a branch with `git reset` and pick with `--soft`, `--mixed`, or `--hard` how far the staging area and working tree follow; append a push-safe inverse commit with `git revert` (choosing a mainline with `-m` on a merge); and wipe untracked files with `git clean -fd`, the only one of the three the reflog cannot undo.

You ran `git reset` once and lost an afternoon of edits, then ran almost the same command another day and nothing bad happened at all. Undo in git is really three separate tools wearing one word.

12 min
#14

Cherry-pick

Copy the change from any commit onto your current branch as a new object with its own hash while the original stays put, select a merge's mainline with `-m`, and run a range through the sequencer that halts on a conflict with four ways out.

A one-line fix lands on `main` as commit `a1b2c3d`, but the same bug is still live on `release/v2.5`. Merging the whole branch drags along ten unrelated commits; you want that single change and nothing else.

12 min
#15

Bisect

Pinpoint the commit that broke a test by halving a 1024-commit range in about ten classifications, read the `.git/BISECT_*` state the search parks on disk without moving your branch, and automate the whole loop with `git bisect run` (exit 0 good, 125 skip, non-zero bad).

A test passed at tag `v1.0` and fails on the newest commit, 1024 commits later. Testing them one at a time means 1024 runs; there is a way to name the culprit in ten.

12 min
05

Collaboration

Remotes, pull requests, hooks, and team workflows

4/4
#16

Remotes

Watch `git remote add` write two lines to `.git/config` with no network call, see `git fetch` fill `.git/objects/` and `refs/remotes/origin/` while your branches stay put, and read a `non-fast-forward` push rejection as the remote refusing to drop a teammate's commit.

You clone a coworker's repo, add their URL, and expect a live wire to their machine. Open `.git/config` instead: two text lines got written, and no connection was ever opened.

14 min
#17

Pull Requests

Search the server's `.git/` after opening a PR and find no new object, push more commits to see the diff re-resolve off the live tip with no update step, then run merge, squash, and rebase to land `refs/heads/main` at three different hashes.

You've clicked the green Merge button and watched your branch fold into `main`. Now grep the whole `.git/` folder for that button, the object store, the refs, the config, every command git ships, and it isn't there.

12 min
#18

Git Hooks

Place a file named `pre-commit` in `.git/hooks/`, `chmod +x` it, and watch git fork it on the next commit and abort on a non-zero exit, then clone the repo to find the hook gone and see why `--no-verify` skips your copy but never the server's `pre-receive`.

You run `git commit` and it just works, every time. Then one day it stops, refuses, and prints a line you wrote yourself, because a plain script sitting in `.git/hooks/` returned a number git did not like.

10 min
#19

Workflows

Read a team's model off its `git branch -a`, route one feature through trunk-based, GitFlow, and forking so identical code lands on `main` three ways, then pick the shape by release cadence and contributor trust.

Two teams, two printouts of `git branch -a`: one is a single line, the other a dozen. Same git binary, the same objects underneath, so the difference is a shape each team chose, not a feature git turned on.

12 min
View full 19-topic curriculum