Step 1 of 5 · Reading · ~4 min
Read
Branching, Diff & Merge
Putting It All Together
Every piece you wrote so far is one idea from the same design, and this lesson chains them into a working repository. After it your program accepts WRITE, ADD, COMMIT, LOG, STATUS, BRANCH, CHECKOUT and MERGE and produces the same commit hashes, the same log and the same status as real git. It is a few hundred lines because the design is small.
The layers, in the order a command uses them
| Layer | What you built | Used by |
|---|---|---|
| Hashing | hash-object: blob <size> NUL bytes, SHA-1 | add |
| Storage | the object format and the zlib wrapper | everything that stores or reads an object |
| Trees | sorted entries, raw hashes, 40000 for directories | commit |
| Commits | tree, parent, author, committer, message | commit |
| Walks | the date-ordered walk over parents | log, merge |
| Refs | HEAD as a symbolic ref, branches as names for hashes | commit, branch, checkout |
| Index | the draft of the next tree | add, commit, status |
| Status | HEAD vs index vs working tree | status |
| Checkout | a plan from one flat tree to another, with a safety rule | checkout, merge |
Porcelain commands are conveniences over this plumbing: git add is "hash the file, write the blob, update the index entry", and git commit is "write trees from the index, write a commit, move the branch HEAD names".
How the commands compose
ADD path: if the file exists, store its blob and point the index entry at it. If the file is gone but the index still lists it, drop the entry (git stages the deletion).COMMIT message: write one tree object per directory from the index, bottom-up. If the root tree equals the tree of the current commit (or the index is empty and there is no commit yet), there is nothing to commit and nothing is written. Otherwise write a commit whose parent is the branch's current tip, move the branch to it and print its hash. HEAD itself never changes.STATUS: the two-letter short format. The first letter compares HEAD with the index, the second compares the index with the working tree, usingA,M,Dand a space. Untracked files come last as??.BRANCH name: a new name for the current commit. It fails before the first commit, because there is nothing to name.CHECKOUT name: flatten the current commit and the target commit, plan the file operations, refuse if the safety rule blocks, apply the plan to the working tree, set the index to the target tree and point HEAD at the branch.MERGE name(fast-forward only): if the other tip is already an ancestor of ours there is nothing to do. If ours is an ancestor of theirs, a merge is just checkout of their commit with the branch moved to it. If the histories have diverged a real merge would have to combine content, which this tool does not do.
What this tiny git leaves out
Packfiles and the network protocol (fetching and pushing are exchanging objects), hooks, the stash (commits on a special ref), bisect (a binary search over this same graph), worktrees, submodules and the reflog, which records every position HEAD has held and is why git reset --hard is recoverable. All of them sit on the same few primitives: blobs, trees, commits, refs and SHA-1.
Common mistakes
- Hashing a nested directory's tree with the wrong sort order, which changes every commit hash above it.
- Writing a commit when the tree did not change, or committing an empty index.
- Moving HEAD instead of the branch it names.
- Switching branches without applying the plan to the index, which shows every file as changed afterwards.
- Letting a file edited but not staged slip past the safety rule, or blocking a file that is identical in both snapshots.
Your exercise
The starter provides the repository, the command loop, flattening and the ancestor test. You supply four pieces, each a function you have already written once: the blob hash, the tree writer for nested directories, the commit builder and the checkout plan. The expected output of every test was produced by running the same script against real git, so a single wrong byte anywhere changes a hash.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…