βͺ Lesson 3: History & Undo
Your commits are a time machine. Learn to see exactly what changed, visit any old version of your site, and undo mistakes safely, without losing a thing.
π― Learning Objectives
By the end of this lesson, you will be able to:
- See exactly what you changed with
git diffandgit diff --staged - Inspect any past commit with
git showand a single file's history withgit log --oneline -- <file> - Look at an old version of a file without changing anything (
git show <hash>:<file>or VS Code's Timeline) - Pick the right step on the undo ladder:
git restore,git restore --staged,git commit --amend, andgit revert - Recognize which commands are dangerous, and why we avoid them today
Estimated Time: 40 minutes
Project: Break your own website on purpose, then undo it three different ways
In This Lesson
π°οΈ Introduction
In the last lesson you made your first commits. Each one is a save point for your whole website. Saving is only half the story, though. The reason save points exist is so you can go back: to check what you changed, to find when a bug crept in, or to undo something you regret.
This lesson is about exactly that. First you'll learn to look (what changed, and when). Then you'll learn to undo, choosing the gentlest tool that fixes the problem. Every command here is safe: nothing you learn today throws away a commit.
Here's the map from Lesson 1 again, now with the "look" and "undo" commands added. Each area has its own way of seeing and undoing changes:
π± Mistakes Are How You Learn Git
Every developer, including ones with twenty years of experience, commits a typo, stages the wrong file, or breaks a page. The difference isn't that they never make mistakes. They just know which undo to reach for. By the end of this lesson, so will you. So feel free to break things today. That's the assignment!
π Seeing Changes with git diff
git status tells you which files changed. git diff tells you which lines changed. It's the command to run just before you stage, so you know exactly what's about to go into your next commit.
Unstaged changes: git diff
Open css/style.css in VS Code, change your h1 color, and save. Then, in the integrated terminal:
git diff
You'll see something like this:
diff --git a/css/style.css b/css/style.css
index 136cefd..bbe85b5 100644
--- a/css/style.css
+++ b/css/style.css
@@ -4,5 +4,5 @@ body {
}
h1 {
- color: #1e3a8a;
+ color: #b91c1c;
}
How to read a diff
--- a/and+++ b/name the file:ais the old version,bis the new one.@@ -4,5 +4,5 @@says where in the file this is (around line 4). You can mostly ignore it.- Lines starting with
-(usually red) were removed. - Lines starting with
+(usually green) were added. - Lines with no sign are unchanged context, shown so you can tell where you are.
Notice that Git doesn't have a "changed" line. A changed line is shown as the old line removed and the new line added.
Staged changes: git diff --staged
Now stage the file and run git diff again:
git add css/style.css
git diff
Nothing prints! That surprises everybody the first time. Plain git diff only compares your working folder with the staging area, and those now match. To see what's staged (what your next commit will contain), add --staged:
git diff --staged
Now the same red/green diff appears again.
| Command | Shows the difference between⦠| Use it when⦠|
|---|---|---|
git diff |
Working folder β staging area | "What have I changed that I haven't staged yet?" |
git diff --staged |
Staging area β last commit | "What exactly am I about to commit?" |
π‘ Press q to Get Out
When a diff (or a log) is longer than your terminal window, Git shows it one screen at a time in a pager. Use the arrow keys or Space to scroll, and press q to quit back to your prompt. If your terminal ever looks "stuck" with a : or (END) at the bottom, it's just the pager. Press q.
π Exploring Your History
You already know git log --oneline from Lesson 2. It lists your commits, newest first, each with a short hash (its ID) and its message. Here's Ada's history from Lesson 2, with two more small commits on top:
git log --oneline
0d2abf0 (HEAD -> main) Add a note about weekly photos
4c2960c Add photography to about page
3cfc1b8 Add hobbies section to About page
9cc816c Add site images
e56cc25 Add site stylesheet
a9a2faf Add home, about, and contact pages
9b951eb Add .gitignore for system files
Your hashes will be different. Every commit in the world gets its own. You never have to type the full 40-character hash; the short 7-character version works fine. You can also copy and paste it from the terminal instead of typing it.
What did that commit change? git show
Give git show a hash and it prints who made the commit, when, the message, and the diff:
git show 4c2960c
commit 4c2960c697f1acdd6b917765a52c6a03dce574d1
Author: Ada Lovelace <ada@example.com>
Date: Sat Sep 26 12:42:34 2026 -0700
Add photography to about page
diff --git a/about.html b/about.html
index c79a249..7fa5da4 100644
--- a/about.html
+++ b/about.html
@@ -5,6 +5,6 @@
</head>
<body>
<h1>About Me</h1>
- <p>I love hiking and baking bread.</p>
+ <p>I love hiking, baking bread, and photography.</p>
</body>
</html>
Run git show with no hash at all and you get the most recent commit.
Just one file's history: git log --oneline -- <file>
When you want to know "when did my About page change?", put the file name after --:
git log --oneline -- about.html
4c2960c Add photography to about page
3cfc1b8 Add hobbies section to About page
a9a2faf Add home, about, and contact pages
Commits that didn't touch about.html (like the stylesheet, the images, and the note on the home page) are left out. The -- means "everything after this is a file name," which avoids confusion if a file is ever named like a branch.
π‘ This Is Why Good Messages Matter
Look at that history again. Because the messages say what changed ("Add photography to about page"), you can find the right commit in seconds. A history full of "stuff" and "fix" and "asdf" is a time machine with no labels on the dials. Future-you will thank present-you for every clear message.
π Visiting an Old Version
Sometimes you just want to read an old version of a page: "What did my About page say this morning?" You can do that without changing any files at all.
In the terminal: git show <hash>:<file>
Put a colon between the hash and the file's path:
git show a9a2faf:about.html
Git prints the whole file exactly as it was in that commit. Your working folder is untouched. For a file in a subfolder, include the folder, using forward slashes on every operating system:
git show e56cc25:css/style.css
In VS Code: the Timeline view
- Open the file in the editor (for example,
about.html). - In the Explorer sidebar, look near the bottom for a collapsed section called Timeline and click to expand it.
- You'll see a list of that file's commits, with their messages. (It may also show local saves; those are VS Code's own file history, not Git commits.)
- Click any commit to open a side-by-side comparison: the old version on the left, the version after that commit on the right.
Both methods are read-only. Look all you like; nothing changes until you decide to change it.
πͺ The Undo Ladder
There isn't one "undo" button in Git. There are several, and the right one depends on how far your mistake has traveled: is it just an edit in a file, is it staged, or is it already committed? Start at the bottom of the ladder and climb only as high as you need.
Good news: you don't have to memorize this. git status prints the right undo command as a hint, right under each heading. Read what it tells you!
Rung 1: Throw away an unstaged edit: git restore <file>
You edited a file, saved it, and hate the result. You haven't staged it. Run git status:
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: css/style.css
no changes added to commit (use "git add" and/or "git commit -a")
See the second hint? That's your undo:
git restore css/style.css
The file snaps back to how it was at your last commit. If VS Code has it open, the editor updates on its own.
β οΈ git restore Really Throws the Edit Away
Uncommitted edits were never saved in Git, so once you restore, they're gone. There's no undo for this undo. Run git diff first if you're not sure what you'd be losing.
Rung 2: Unstage a file: git restore --staged <file>
You ran git add . and staged something you didn't mean to commit yet. git status shows:
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: css/style.css
Take it back out of the staging area:
git restore --staged css/style.css
This is completely safe. Your edit is still in the file; it's just no longer staged. Run git status and you'll see the file back under "Changes not staged for commit." (And if you now want to throw the edit away too, that's Rung 1.)
Rung 3: Fix the last commit: git commit --amend
You just committed and immediately spotted a problem. Two classic cases:
A typo or unclear commit message. Replace the message on your most recent commit:
git commit --amend -m "Add a note about weekly photos"
[main 0d2abf0] Add a note about weekly photos
Date: Sat Sep 26 12:42:41 2026 -0700
1 file changed, 1 insertion(+)
You forgot a file (or a last-second fix). Stage it, then amend with --no-edit to keep the same message:
git add index.html
git commit --amend --no-edit
The missing change is folded into the last commit, as if you'd included it all along.
β οΈ Only Amend What You Haven't Shared
Amending doesn't edit the old commit; it replaces it with a new one (notice the hash changes). That's fine while the commit lives only on your computer. Once you've pushed it to GitHub (Lesson 5), don't amend it. Use git revert or simply make a new commit instead. Today, nothing is pushed yet, so amend freely.
Rung 4: Undo an older commit safely: git revert <hash>
Say you rewrote your About page, committed it, and now you want the old text back. Find the commit:
git log --oneline
e3f2c9b (HEAD -> main) Rewrite about page
0d2abf0 Add a note about weekly photos
4c2960c Add photography to about page
3cfc1b8 Add hobbies section to About page
...
Then revert it:
git revert e3f2c9b
Because you set VS Code as Git's editor in Lesson 1, a tab opens with a ready-made message: Revert "Rewrite about page", followed by This reverts commit e3f2c9bβ¦. That message is fine as-is. Close the tab (save first if you edited it) and Git finishes the job. Now look at the log:
60efe82 (HEAD -> main) Revert "Rewrite about page"
e3f2c9b Rewrite about page
0d2abf0 Add a note about weekly photos
4c2960c Add photography to about page
3cfc1b8 Add hobbies section to About page
...
git revert doesn't erase anything. It adds a new commit that does the exact opposite of the old one. History stays honest ("I tried a rewrite, then undid it"), and it's always safe, even after you've pushed and shared your work. That's why it's the go-to undo for anything already committed.
π‘ Terminal Waiting for You?
If your terminal seems to hang after git revert (or later, git merge), look for a VS Code tab named COMMIT_EDITMSG or MERGE_MSG. Git is waiting for you to close it. If you'd rather skip the editor entirely, add --no-edit: git revert --no-edit e3f2c9b. And if Git says unable to start editor (the code command isn't set up yet; see Lesson 1), the revert is already staged: run git commit --no-edit to finish it.
The ladder at a glance
| The situation | The command | Is anything lost? |
|---|---|---|
| Edited a file, want the last committed version back | git restore <file> |
Yes, the uncommitted edit |
| Staged something by mistake | git restore --staged <file> |
No, the edit stays in the file |
| Last commit has a bad message or is missing a file (not pushed) | git commit --amend |
No, the commit is replaced by a better one |
| An earlier commit was a mistake | git revert <hash> |
No, a new "undo" commit is added |
π±οΈ Undo in VS Code
The first two rungs have buttons in VS Code's Source Control panel (the branching icon in the Activity Bar, or Ctrl+Shift+G / Cmd+Shift+G). Hover over a file to reveal its small icons:
- Under "Changes", the curved-arrow icon is Discard Changes. That's
git restore <file>. VS Code asks you to confirm, because the edit will be gone. - Under "Staged Changes", the β (minus) icon is Unstage Changes. That's
git restore --staged <file>. - Clicking a changed file opens a side-by-side diff, the visual version of
git diff.
For amend, the β¦ (More Actions) menu at the top of the panel has Commit β Commit (Amend). The menu layout moves around between VS Code versions, so if you can't find it, the terminal command always works.
Use whichever you like. The terminal and the buttons do exactly the same thing to the same repository, so you can mix them freely.
π« The Command We Won't Use Today
β git reset --hard: Powerful, and It Destroys Work
While searching online for "undo git commit," you will find answers that say git reset --hard. It moves your branch back in time and wipes out every uncommitted change in every file, with no confirmation and no undo button. Experienced developers use it carefully; beginners lose an afternoon's work to it.
You don't need it. Everything it's usually recommended for, you can do today with restore, amend, and revert. If a tutorial tells you to run it, stop and ask your instructor first.
β Common Questions
I ran git restore by accident. Can I get my edit back?
Not from Git, because the edit was never committed. Try Ctrl+Z / Cmd+Z in the VS Code tab if it's still open, or check that file's Timeline, which also lists VS Code's local saves. This is the best argument for small, frequent commits: anything committed can always be recovered.
Why doesn't git revert just delete the bad commit?
Deleting commits rewrites history, and that causes real trouble once your work is shared (anyone who already has the old commit ends up out of sync). Adding an "opposite" commit is always safe, and your log still tells the true story.
Can I revert a revert?
Yes! If you change your mind again, git revert the revert commit's hash and the change comes back, as yet another new commit.
What if I type the wrong hash?
If it doesn't exist, Git just prints an error and does nothing. If you revert the wrong (real) commit, revert that revert. Nothing you've committed is ever lost with the commands in this lesson.
π οΈ Hands-on Exercise
ποΈ Exercise: Break It, Then Undo It Three Ways
Objective: Practice three rungs of the undo ladder on your own my-website project. Start with a clean slate: git status should say nothing to commit, working tree clean. If it doesn't, commit your work first.
Part A: Undo an unstaged edit (Rung 1)
- In VS Code, open
index.htmland delete your whole<h1>line. Save. Check Live Server: the heading is gone. - Run
git statusandgit diff. Find the red-line. - Undo it with
git restore index.html. Confirm the heading is back in the browser andgit statusis clean.
Part B: Unstage, then discard (Rungs 2 and 1)
- In
css/style.css, change thebodybackground to something awful (trylime). Save. - Stage it with
git add ., then look at it withgit diff --staged. - Unstage it with
git restore --staged css/style.css. Checkgit status: it's back under "not staged." - This time use VS Code: in the Source Control panel, hover over
style.cssand click Discard Changes. Confirm. The lime is gone.
Part C: Commit a mistake, then revert it (Rung 4)
- In
about.html, change a paragraph to say something silly. Save, then commit it:git commit -am "Rewrite about page intro". (-astages already-tracked files for you; see Lesson 2.) - Run
git log --onelineand copy that commit's hash. - Revert it with
git revert <hash>. Close the message tab in VS Code to finish. - Check the browser: your original About text is back. Run
git log --oneline: you should see both the mistake and theRevert "β¦"commit. - Finally, use
git show <hash>:about.htmlwith the silly commit's hash to prove the silly version is still safely in history.
Deliverable: a clean git status, your site looking exactly as it did at the start, and a git log --oneline that shows your mistake and its revert.
π‘ Hint
Stuck? Run git status. It tells you which area your change is in and prints the command to undo it. If the terminal seems frozen after git revert, look for the COMMIT_EDITMSG tab in VS Code and close it. If you see : at the bottom of the terminal, press q.
β Solution
# Part A
git status
git diff
git restore index.html
git status
# Part B
git add .
git diff --staged
git restore --staged css/style.css
git status
# then: Source Control panel β hover style.css β Discard Changes
# Part C
git commit -am "Rewrite about page intro"
git log --oneline
git revert a1b2c3d # use YOUR hash of the silly commit
git log --oneline
git show a1b2c3d:about.html # the silly version, still in history
Your final log should end with something like this (your hashes will differ):
f9e8d7c (HEAD -> main) Revert "Rewrite about page intro"
a1b2c3d Rewrite about page intro
...
π Want to Go Further?
Try Rung 3: make a small commit with a deliberately bad message like "stuff", then fix it with git commit --amend -m "Add footer text to home page". Run git log --oneline before and after, and notice that the hash changed. Why do you think that is?
Extra credit: git restore --source=<hash> about.html copies an old version of one file back into your working folder (as an ordinary unstaged edit you can commit or discard). Try it with an early commit, look at the result in Live Server, then decide whether to keep it.
π― Quick Quiz
Question 1: You edited style.css and ran git add style.css. Now plain git diff prints nothing. Why?
Question 2: You accidentally staged contact.html but want to keep your edits in it. Which command do you run?
Question 3: Three commits ago you changed your site's fonts and now you want the old fonts back, keeping everything you've done since. What's the safest command?
Question 4: What does git show 4c2960c:about.html do?
Question 5: You just committed with the message "updaet homepage" and haven't pushed. How do you fix the typo?
π Learning Journal
Take five minutes to add to your learning journal. Write down:
- Key concepts you learned
- What clicked β the idea or technique that made sense
- Questions or confusion, so you know what to revisit
- Ideas to try on your own pages
- How you feel about your progress
βοΈ This lesson's prompt: Think back to a time before today when you lost work or broke a page and couldn't get it back. Which rung of the undo ladder would have saved you? Now that you've broken your site on purpose and fixed it, how does it feel to experiment knowing you can always go back? Which undo command do you still need to look up?
Summary
π Key Takeaways
git diffshows unstaged line changes;git diff --stagedshows what your next commit will containgit show <hash>shows one commit;git log --oneline -- <file>shows one file's historygit show <hash>:<file>and VS Code's Timeline let you read old versions without changing anything- The undo ladder:
restore(discard an edit) βrestore --staged(unstage) βcommit --amend(fix the last, unpushed commit) βrevert(safely undo any commit) git statusprints the undo command you need. Read its hints!- Avoid
git reset --hard: it destroys uncommitted work
π Additional Resources
- Pro Git β Undoing Things
- Pro Git β Viewing the Commit History
- git-restore documentation
- git-revert documentation
- Git Quick Reference (this site)
π What's Next?
That wraps up Module 1: you can save, look back, and undo. After lunch, you'll learn Git's favorite feature: branches. A branch is a safe copy of your timeline where you can try a bold new color scheme without touching the working site, then merge it in when you like it. You'll even cause a merge conflict on purpose and fix it.