10 · Project — Clone, Fork & Ship a Repo¶
This capstone pulls together every Level 1 module: local commits, a branch
merged in, remotes, a real GitHub repository, .gitignore, and forking/
cloning someone else's project. Work through it top to bottom in order —
each part builds on the last.
Part 1 — Fork and clone an existing repository¶
- On GitHub, find a small, beginner-friendly public repository. GitHub's
own
github/gitignoreworks well, or useoctocat/Spoon-Knife(a repo GitHub maintains specifically for practicing forks). - Click Fork (top-right of the repo page) — this creates a full copy
under your account (
github.com/yourname/Spoon-Knife). - Clone your fork (not the original) to your machine:
origin https://github.com/yourname/Spoon-Knife.git (fetch)
origin https://github.com/yourname/Spoon-Knife.git (push)
- Add the original repository as a second remote, conventionally named
upstream— this lets you pull in future updates from the original project without affecting yourorigin:
origin https://github.com/yourname/Spoon-Knife.git (fetch)
origin https://github.com/yourname/Spoon-Knife.git (push)
upstream https://github.com/octocat/Spoon-Knife.git (fetch)
upstream https://github.com/octocat/Spoon-Knife.git (push)
This fork → clone → add-upstream pattern is exactly how you'd start contributing to any real open-source project.
Part 2 — Build your own project from scratch¶
Now start an original project that you'll fully own, applying everything from this level.
Add a .gitignore before anything else, so you never accidentally track
files you don't want to:
Create a starting file and commit it:
cat > README.md <<'EOF'
# Task Tracker
A tiny plain-text task tracker, built while learning Git.
EOF
git add README.md
git commit -m "Add README"
echo "Buy groceries" > tasks.txt
git add tasks.txt
git commit -m "Add first task"
Part 3 — Branch, work, and merge¶
Edit tasks.txt to add priority markers:
cat > tasks.txt <<'EOF'
[high] Buy groceries
[low] Reorganize bookshelf
EOF
git add tasks.txt
git commit -m "Add priority tags to tasks"
Meanwhile, simulate other work happening on main directly (this ensures
your merge is a true three-way merge, not a fast-forward):
git switch main
echo "See tasks.txt for the current list." >> README.md
git add README.md
git commit -m "Mention tasks.txt in README"
git merge feature/add-priority-tags -m "Merge priority tags feature"
Confirm the shape of your history:
You should see a merge commit with two parent lines coming together.
Part 4 — Push to a real GitHub repository¶
- On GitHub, create a new empty repository (no README) named
task-tracker. - Connect and push:
- Refresh the repo page on GitHub and confirm: the README,
.gitignore, andtasks.txtare all present, and the commit history (visible via the "commits" link near the top of the file list) shows every commit including the merge.
Part 5 — One more round-trip¶
Prove the remote workflow end to end by making one more change and syncing it:
Then, simulating "another machine," clone your own repo into a second folder and confirm everything — including the merge commit — is there:
cd ..
git clone https://github.com/yourname/task-tracker.git task-tracker-clone
cd task-tracker-clone
git log --oneline --graph
cat tasks.txt
How It Actually Works¶
This project touches every mechanism from the level, all at once — worth tying together explicitly:
- Fork + clone +
upstreamis entirely built from remotes, and nothing more: your fork is a server-side copy of the original repo's object database (see module 7), your clone is a local copy of that copy's objects,originpoints at your fork, and addingupstreampointing at the original just gives you a second remote tofetchfrom.git fetch upstream && git merge upstream/mainpulls in commits Git recognizes as new purely by SHA comparison — if the original project and your fork share ancestry (they do, since a fork copies rather than reinvents history), the fetched commits slot straight into your existing DAG. - Two clones of the same repo staying in sync works because clone URLs
are just a network address for the same underlying object store — cloning
twice gives you two independent
.git/objects/directories that happen to contain identical content, addressed by identical SHAs, because SHAs are computed from content alone, not from where the object lives. A commit made in one clone and pushed becomes byte-identical, hash- identical, in the other clone after a pull. - A merge commit with two parents surviving a push and re-clone proves
the commit DAG travels intact: pushing sends the merge commit object
(with both
parentlines) and every ancestor it needs; cloning reconstructs the exact same graph by walking those parent pointers from the tip down, which is whygit log --graphon the fresh clone shows the identical branch/merge shape as the original. - Deleting a merged branch has zero effect on history — the branch
pointer (a single-line file, module 4) is removed, but every commit it
ever pointed to remains reachable through
main's own parent chain (a merge commit's second parent is the tip of the branch you merged), so nothing in the object database becomes unreachable or gets garbage- collected.
Capstone checklist¶
By the end of this project you should have, verifiable via git log
--graph --all and your GitHub repo page:
- [ ] A local repo with a
.gitignorecommitted from the very first commit - [ ] At least four commits on
main - [ ] A feature branch that was merged with a genuine merge commit (two parents, not a fast-forward)
- [ ] The branch deleted after merging
- [ ] The repository pushed to a real GitHub repo under your account
- [ ] A second local clone of that same GitHub repo, containing identical history
- [ ] A forked copy of someone else's repository, with both
origin(your fork) andupstream(the original) configured as remotes
If every box is checked, you're ready for Level 2, where the focus shifts from "working solo" to "working with other people through GitHub": resolving real merge conflicts, rebase vs. merge tradeoffs, and running pull requests end to end.