Skip to main content

🎯 Git Practice Projects

One day of Git is a great start. A few more hours of practice is what makes it stick. These projects re-use exactly what you learned in class, without step-by-step notes beside you, plus a couple of stretch projects for when you're curious.

πŸ“– How these projects work

  • Unless a project says otherwise, use a practice folder (not your real site), so you can break things freely.
  • Create and edit files in VS Code, then run Git commands in VS Code's terminal. Every command works the same in PowerShell, Git Bash, and the macOS Terminal.
  • Try each step yourself first. The πŸ’‘ Hint and βœ… Solution boxes are there when you need them, and needing them is fine.
  • Run git status constantly. It's the fastest way to understand what just happened.
Beginner uses only class material Intermediate combines skills in new ways Stretch introduces one new command
Projects

🧺 Project 1: Recipe Box from Scratch

Beginner ⏱️ 30–40 minutes

  • git init
  • git add
  • git commit
  • .gitignore
  • README.md
  • git push -u

Scenario: You want a tiny recipe site, tracked by Git from the very first file and backed up on GitHub. You've done every step before, just not all in a row without notes.

  1. Make a new folder called recipe-box somewhere sensible (your projects folder, not inside my-website). Open it in VS Code with File β†’ Open Folder.
  2. Turn it into a repository and confirm with git status.
  3. In VS Code, create index.html with a heading and a list of three recipe names. Commit it.
  4. Create pancakes.html with an ingredients list. Commit it separately.
  5. Create css/style.css, link it from both pages, and commit.
  6. Create a .gitignore containing .DS_Store and Thumbs.db. Commit it.
  7. Create README.md with a heading, one sentence about the project, and a bulleted list of pages. Commit it.
  8. On GitHub, create an empty repository called recipe-box (no README, .gitignore, or license). Connect it and push.
  9. Check that git log --oneline shows five commits and that GitHub shows the same five.
πŸ’‘ Hint

The order is always: edit and save in VS Code β†’ git add β†’ git commit -m. For the GitHub part, the empty repo page shows a "…or push an existing repository from the command line" box. Your commands are the same as Lesson 5.

βœ… Solution
git init
git status

git add index.html
git commit -m "Add home page with recipe list"

git add pancakes.html
git commit -m "Add pancakes recipe page"

git add css/style.css index.html pancakes.html
git commit -m "Add stylesheet and link it from both pages"

git add .gitignore
git commit -m "Ignore OS clutter files"

git add README.md
git commit -m "Add README"

git remote add origin https://github.com/YOUR-USERNAME/recipe-box.git
git push -u origin main
git log --oneline

βœ… Checklist

🌟 Want to go further?

Connect recipe-box to Netlify exactly as you did in Lesson 6, so every push to main updates a live recipe site.

βš”οΈ Project 2: Conflict Dojo

Beginner ⏱️ 25 minutes

  • git switch -c
  • git merge
  • conflict markers
  • git merge --abort

Scenario: Conflicts feel scary exactly until you've resolved a few on purpose. This dojo has you cause three and settle each one differently.

gitGraph commit id: "Recipe list" branch cozy-title commit id: "Cozy heading" checkout main branch bold-title commit id: "Bold heading" checkout main merge cozy-title merge bold-title
  1. In recipe-box, from main, create a branch cozy-title. Change the <h1> in index.html to "Grandma's Kitchen". Commit.
  2. Switch back to main. Create a branch bold-title. Change the same <h1> to "THE RECIPE BOX". Commit.
  3. Switch to main and merge cozy-title. Notice the word Fast-forward: no conflict, because main hadn't moved.
  4. Now merge bold-title. You should see:
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
  1. Round 1: escape. Run git merge --abort and check that git status is clean. Then run the merge again.
  2. Round 2: choose one. Click Accept Incoming Change, save, stage, and commit.
  3. Round 3: combine. Make two more branches that both change the <title>, merge them, and this time use Accept Both Changes, then edit the result by hand into a single sensible title before committing.
  4. Look at the result with git log --oneline --graph --all and delete the merged branches with git branch -d.
πŸ’‘ Hint

A merge always brings another branch into the one you're on, so git switch main comes first. After fixing a conflict, git status tells you exactly what's left: "fix conflicts and run git commit".

βœ… Solution (rounds 1–2)
git switch -c cozy-title
# edit the h1 in VS Code, save
git commit -am "Change heading to Grandma's Kitchen"

git switch main
git switch -c bold-title
# edit the same h1, save
git commit -am "Change heading to THE RECIPE BOX"

git switch main
git merge cozy-title        # Fast-forward
git merge bold-title        # CONFLICT
git merge --abort           # round 1: back out
git merge bold-title        # conflict again
# click "Accept Incoming Change", save
git add index.html
git commit                  # VS Code opens with a merge message; save and close the tab

git branch -d cozy-title bold-title

git commit -am stages files Git already tracks and commits in one step; it's a shortcut for git add + git commit -m when you haven't created any new files.

βœ… Checklist

↩️ Project 3: Undo Gym

Beginner ⏱️ 20 minutes

  • git restore
  • git restore --staged
  • git commit --amend
  • git revert
  • git show

Scenario: Five quick "oops" drills. For each one: make the mistake on purpose, fix it with the right rung of the undo ladder, and prove it's fixed with git status or git log --oneline.

#Make this mistakeFix it with
1Delete half of pancakes.html and savegit restore pancakes.html
2Stage style.css when you didn't mean togit restore --staged css/style.css
3Commit with the message fxi typogit commit --amend -m "Fix typo in pancakes recipe"
4Commit a change but forget to include a second filegit add <forgotten file> then git commit --amend --no-edit
5Commit (and push) a change that makes all the text bright pinkgit revert <hash>, then push

Bonus drill: without changing anything, look at what index.html looked like in your very first commit: git show <first-hash>:index.html. Then find the same thing in VS Code's Timeline view.

⚠️ Amend is for unpushed commits

Amending replaces a commit with a new one. If you've already pushed it, GitHub still has the old one and your next push will be rejected. For anything already pushed, use git revert (drill 5), which adds a new commit instead of changing old ones.

βœ… How to check each drill
  • Drills 1–2: git status shows the file is no longer modified (1) or no longer staged (2).
  • Drills 3–4: git log --oneline shows one commit with the right message, not two. git show --stat HEAD lists both files for drill 4.
  • Drill 5: the log shows your pink commit and a Revert "…" commit after it. The page is back to normal and history is intact.

πŸ”€ Project 4: Pull Request Rehearsal

Beginner ⏱️ 30 minutes · uses your real, Netlify-connected site

  • GitHub Flow
  • git push -u origin <branch>
  • Deploy Previews
  • git branch -d

Scenario: Lesson 6 walked you through one pull request. Do three more on your own site until the rhythm feels automatic, including two situations the lesson didn't cover.

  1. PR A: the normal one. Branch, fix something small (a typo, a better photo caption), push the branch, open a PR, open the Deploy Preview, merge, delete the branch on GitHub, then tidy up locally.
  2. PR B: update a PR after opening it. Open a PR, then notice something else to fix. Make another commit on the same branch and git push. Watch the PR update itself and Netlify build a fresh Deploy Preview. Then merge.
  3. PR C: change your mind. Open a PR for an experiment you end up not liking (say, a neon color scheme). Instead of merging, click Close pull request. Delete the branch on GitHub, and locally with git branch -D (capital D, because it was never merged).
βœ… Solution (the loop for PR A)
git switch main
git pull
git switch -c fix-caption
# edit, save
git add .
git commit -m "Fix caption on team photo"
git push -u origin fix-caption
# GitHub: Compare & pull request β†’ Create pull request
# check the Deploy Preview link β†’ Merge pull request β†’ Confirm merge β†’ Delete branch
git switch main
git pull
git branch -d fix-caption

πŸ’‘ Why bother with PRs when you work alone?

The Deploy Preview lets you see a change on a real URL before it reaches your live site, and each PR leaves a written record of why you changed something. It's also exactly the workflow every team uses, so practising it solo means you'll already know it when you join one.

πŸ‘― Project 5: Two-Computer Simulation

Intermediate ⏱️ 40 minutes

  • git clone
  • git pull
  • rejected push
  • conflict after pull

Scenario: You (or you and a teammate) work on the same repository from two places. You'll fake the second computer with a second clone in a different folder, then create the most common real-world problem on purpose: a rejected push.

sequenceDiagram participant D as recipe-box (desktop) participant G as GitHub participant L as recipe-box-laptop L->>G: git push (laptop's change) D->>G: git push (desktop's change) G-->>D: rejected: fetch first D->>G: git pull (merge, maybe a conflict) D->>G: git push βœ“
  1. In a terminal, go to the folder above recipe-box and clone it again under a new name: git clone https://github.com/YOUR-USERNAME/recipe-box.git recipe-box-laptop. Open that folder in a second VS Code window.
  2. Easy round. In the laptop window, add a recipe to the list, commit, and push. In the desktop window, git pull. The new recipe appears.
  3. Rejected round. In the laptop window, change the page footer and push. In the desktop window, without pulling, change the same footer differently, commit, and push. Git refuses:
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'https://github.com/YOUR-USERNAME/recipe-box.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
  1. Do what the hint says: git pull. Because both sides changed the same line, you get a conflict. Resolve it, git add, git commit, and git push. Now it works.
  2. Finally, git pull in the laptop window so both copies match. Compare git log --oneline --graph in both windows.

⚠️ "Need to specify how to reconcile divergent branches"

If git pull stops with this message instead of merging, your Git hasn't been told whether to merge or rebase. For this class, merge: run git pull --no-rebase now, and git config --global pull.rebase false so plain git pull merges from now on. (Git for Windows usually sets this for you during install.)

🚫 Never "fix" a rejected push by forcing it

You'll see advice online to use git push --force. That would overwrite the laptop's commit on GitHub, deleting someone's work. The rejection is Git protecting you. Pull, merge, push.

βœ… Checklist

🌍 Project 6: A First Open-Source Contribution

Intermediate ⏱️ 45–60 minutes

  • fork
  • git clone
  • branch + PR to someone else's repo
  • Sync fork

Scenario: On your own repo you could push to main directly. On someone else's project you can't, so you make a fork (your own copy on GitHub), push your branch there, and send a pull request back to the original. The First Contributions project exists exactly for practising this.

  1. Read that repository's README. It's the real instructions, and projects are allowed to change their process.
  2. Click Fork (top right) β†’ Create fork. You now have YOUR-USERNAME/first-contributions.
  3. Clone your fork (not the original), open it in VS Code, and create a branch:
git clone https://github.com/YOUR-USERNAME/first-contributions.git
cd first-contributions
git switch -c add-your-name
  1. In VS Code, open Contributors.md and add your name where the README tells you to. Save, then commit and push the branch:
git add Contributors.md
git commit -m "Add YOUR NAME to Contributors list"
git push -u origin add-your-name
  1. On GitHub, click Compare & pull request. Check that the PR goes from your fork's branch to the original repository's main, then create it.
  2. Wait. Real projects are run by volunteers. When your PR is merged, you're officially an open-source contributor.
πŸ’‘ Keeping your fork up to date later

Your fork doesn't update itself. The easy way: on your fork's GitHub page click Sync fork β†’ Update branch, then git pull locally. The command-line way uses a second remote, conventionally called upstream:

git remote add upstream https://github.com/firstcontributions/first-contributions.git
git switch main
git fetch upstream
git merge upstream/main
git push

πŸ’‘ Before contributing to any real project

Look for a CONTRIBUTING.md file and read it. Search GitHub for issues labelled good first issue, and start with documentation or typo fixes. Maintainers love those, and they teach you a project's workflow before you touch its code.

πŸ› Stretch Project 7: Bug Hunt with git bisect

Stretch ⏱️ 30–40 minutes Β· new command: git bisect

  • git bisect start
  • git bisect good / bad
  • git bisect reset

Scenario: "The headings used to be dark blue. Now they're red. Which of the last ten commits did that?" git bisect finds out by checking out commits halfway between "good" and "bad" and letting you test each one. It narrows ten commits down in about four checks. bisect only looks at old commits; it doesn't change history.

  1. In recipe-box, make sure h1 is dark blue in style.css and commit. Note that commit's hash from git log --oneline. That's your known-good commit.
  2. Make ten small commits (add recipes, tweak spacing, fix wording). Somewhere in the middle, sneak in a commit that changes the h1 color to red with an innocent message like "Tidy up CSS". Try to forget which one it was!
  3. Start the hunt:
git bisect start
git bisect bad                 # the current commit has the bug
git bisect good <good-hash>    # this old one didn't
Bisecting: 5 revisions left to test after this (roughly 3 steps)
[3f1c2ab9d0e84c6f15a2b7e3c9d41f08a6b5e21c] Add waffles recipe
  1. Git has checked out a middle commit. Look at the page in Live Server (refresh it). Red heading? git bisect bad. Dark blue? git bisect good. Repeat.
  2. After a few rounds Git announces <hash> is the first bad commit and shows it. That's your culprit.
  3. Always finish with git bisect reset to return to main. Then fix the bug the safe way: git revert <culprit-hash>.

⚠️ Don't edit files mid-hunt

During a bisect you're in "detached HEAD" state, looking at old commits. Just look and answer good/bad. If you get confused, git bisect reset always takes you back to where you started. Answered wrong by mistake? git bisect reset and start over; it's quick.

πŸ›Ÿ Stretch Project 8: Rescue Drills with git reflog

Stretch ⏱️ 30 minutes · new command: git reflog

  • git reflog
  • git branch <name> <hash>
  • git switch --detach
  • git restore --source

Scenario: Git keeps a private diary, the reflog, of every commit your HEAD has pointed to recently (about the last 90 days by default). That means a commit you "lost" is almost always still findable. Practise in recipe-box so the real thing never panics you.

Drill A: the deleted branch

  1. Create a branch experiment, make a commit on it, switch back to main.
  2. Try git branch -d experiment. Git refuses: "The branch 'experiment' is not fully merged." That's a safety check. Override it with git branch -D experiment. Gone?
  3. Run git reflog. You'll see something like this:
f996ad6 (HEAD -> main) HEAD@{0}: checkout: moving from experiment to main
c0ea865 HEAD@{1}: commit: Try a new layout
f996ad6 (HEAD -> main) HEAD@{2}: checkout: moving from main to experiment
  1. The commit c0ea865 is still there. Bring the branch back: git branch experiment c0ea865 (use your hash). Check with git log --oneline experiment.

Drill B: detached HEAD

  1. Pick an old hash from git log --oneline and run git switch --detach <hash>. Read the message: you're looking at the past, not on any branch.
  2. Just looking? git switch main and you're home.
  3. Do it again, but this time make a commit while detached. To keep it, create a branch before leaving: git switch -c rescued-idea.

Drill C: the file deleted three commits ago

  1. Delete pancakes.html in VS Code and commit that. Make two more unrelated commits.
  2. Find the last commit where the file still existed: git log --oneline -- pancakes.html shows the commit that deleted it. You want the one before that, written <hash>~1.
  3. Bring the file back and commit it:
git restore --source=<deleting-hash>~1 pancakes.html
git add pancakes.html
git commit -m "Restore pancakes page"

🌱 The big lesson

Committed work is very hard to lose. Deleted branches, detached HEADs, and "wrong" merges all leave a trail in the reflog. Uncommitted work, on the other hand, has no safety net, which is one more reason to commit small and often.

⚑ Mini-Challenges (10–15 minutes each)

✍️ Commit Message Makeover

Find five of your own commits with vague messages (update, fix, stuff). For each, write the message you should have written, in imperative mood, saying what changed. Don't rewrite history; this is writing practice for next time.

πŸ“ README Glow-Up

Give your site's README.md a heading, a live-site link, a screenshot (![alt text](images/screenshot.png)), a bulleted page list, and a "Built with" section. Commit, push, and admire it on GitHub.

πŸ™ˆ .gitignore Test

Create notes.tmp in VS Code. Watch it appear as U. Add *.tmp to .gitignore and save. Watch it vanish from git status. Commit the .gitignore change.

🏷️ Version Tags

Mark today's site as a release: git tag -a v1.0 -m "Site after Git class", then git push origin v1.0. Find it under Tags on GitHub. List tags with git tag.

πŸ“¦ Stash Juggling

Start an edit, then "get interrupted": git stash push -m "half-done footer". Switch branches, fix something else, commit, come back, and git stash pop. Try it with two stashes and git stash list.

⌨️ Your First Alias

Make a shortcut for the graph view: git config --global alias.lg "log --oneline --graph --all". Now git lg does the same thing. Invent one more alias you'd actually use.

πŸŽ‰ Where this leaves you

If you've worked through even half of these, you've used Git more than most people do in their first month. When something unexpected happens, and it will, you now have the habits that matter: read git status, reach for the gentlest undo, and remember that committed work is almost never truly lost. Next up: Team Workflows, for when other people join your repository.