Learning path · Level 6 · Tutorial 6

Track and Restore Local Changes with Git

Record understandable checkpoints for a local project, inspect exactly what changed, and recover earlier file contents without relying on a remote service.

  • Level: Beginner
  • Duration: 25 min
  • 10 steps
Start tutorial Back to the path
Track and Restore Local Changes with Git

What you will go through

  1. Prepare a Safe Local Repository Create an isolated local Git practice repository, verify Git, and configure the identity recorded in future commits. 3 min
  2. Choose What Belongs in History Exclude installed dependencies while retaining the files needed to understand and recreate the project. 2 min
  3. Record the First Checkpoint Stage, inspect, and record the first reviewed checkpoint in a local Git repository. 4 min
  4. See Exactly What Changed Inspect saved edits, then use status and two diff views to distinguish unstaged work from content selected for the next commit. 3 min
  5. Unstage Without Losing Edits Refine an over-broad staging selection, preserve unrelated working-tree edits, and record only the intended heading change. 3 min
  6. Inspect Earlier Snapshots Find a local checkpoint and inspect its recorded patch or a file's stored contents without altering current work. 2 min
  7. Discard Only an Unwanted Edit Review an unwanted unstaged stylesheet change, discard only that file after inspection, and distinguish discarding from unstaging. 2 min
  8. Recover a File and Keep the History Restore index.html from the baseline snapshot, review the result, and record the recovery without removing earlier local commits. 3 min
  9. Know What Local Commits Protect Determine what existing local commits preserve, what they leave out, and why a separate backup is still necessary. 1 min
  10. Complete a Local Recovery Challenge Apply the complete local Git workflow to record a change, recover an earlier stylesheet, and verify the retained history. 3 min

What you will learn

  • Initialize a local Git repository, configure its commit identity, and exclude installed dependencies with .gitignore.
  • Use status and diffs to distinguish working-tree changes, staged changes, and committed content.
  • Stage selected files, inspect the staged diff, and create a focused commit.
  • Unstage a file without discarding its edits and inspect earlier snapshots through local history.
  • Review changes before discarding them, then restore selected file contents from an earlier commit and record the recovery in a new commit.
  • Identify which work local commits protect and why a local repository does not replace an external backup.

Before you start

  • Prepare a Local Project with Node.js and npm
  • Manage npm Dependencies and Lockfiles
  • Run a Local Development Server with Vite

Step 1 of 10

Prepare a Safe Local Repository

Create an isolated local Git practice repository, verify Git, and configure the identity recorded in future commits.

Check Git before creating the project

Local history, no service required

Git can record a project’s history on your own computer. This tutorial uses only a local repository: no account, hosting service, remote repository, or sign-in is required.

First, open a terminal and run this command from any location to confirm that Git is available.

Terminal

Check the installed Git version.

shell
git --version
Expected output
git version 2.45.1

Your version number will differ. Continue if it is 2.23 or later; later steps use `git restore`.

Git records history locally

A project folder and a history database shown together on one laptop, with no cloud connection.

A local Git repository stores project history on the computer where the project lives.

Tip

Version requirement

If Git is missing or older than 2.23, install a current supported release using trusted Git installation instructions for your operating system. Then run git --version again. Do not substitute another command: later steps use git restore.

Build the small local project

Create a fresh practice folder

Choose a location outside any existing repository, then create a fresh folder named git-practice. Open that folder in your editor and terminal.

Create the following files exactly. Do not create .gitignore yet; you will add it in the next step. The linked stylesheet and baseline heading give later Git changes something clear to compare.

index.html

Create index.html.

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Local Change Lab</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <main>
      <h1>Local Change Lab</h1>
      <p>A small project for practicing local Git history.</p>
    </main>
  </body>
</html>

styles.css

Create styles.css.

css
:root {
  font-family: system-ui, sans-serif;
  color: #1e293b;
  background: #f8fafc;
}

body {
  display: grid;
  min-height: 100vh;
  margin: 0;
  place-items: center;
}

main {
  padding: 2rem;
}

h1 {
  color: #334155;
}

Generate the project lockfile

package.json

Create package.json with this dependency-free package configuration.

json
{
  "name": "git-practice",
  "version": "1.0.0",
  "private": true
}

Generate the lockfile

From the git-practice folder, run npm’s install command. It generates package-lock.json; do not hand-author or manually edit that lockfile. This package has no dependencies, so do not rely on a node_modules folder being created.

Terminal

Generate the lockfile from the saved package.json.

shell
npm install
Expected output
up to date, audited 1 package in 300ms

found 0 vulnerabilities

Timing and audit wording vary by npm version. Confirm that `package-lock.json` now exists.

Initialize Git and identify future commits

Initialize the repository

Still in the git-practice folder, initialize Git. This creates a hidden .git directory for repository metadata and local history. Do not edit .git manually; use Git commands to work with the repository.

Initialization creates repository structure, but it does not record a project checkpoint.

Terminal

Run this command from git-practice.

shell
git init
Expected output
Initialized empty Git repository in /path/to/git-practice/.git/

The path and any reported default branch name vary by computer. This tutorial does not depend on a branch name.

What initialization adds

A project folder containing ordinary files and a separate hidden metadata area represented by gears and a timeline.

git init adds Git’s hidden metadata directory; it does not automatically record the project files.

Tip

Commit identity is not authentication

Set an identity for commits in this repository only. The name and email are authorship information recorded with future commits. They are example values to replace with your preferred commit identity—not account credentials and not a sign-in to any service.

Set the local identity

Use your own name and email if you prefer. Keep --local so these settings apply only inside this repository.

shell
git config --local user.name "Alex Morgan"
git config --local user.email "alex@example.com"

Verify the essential setup

Practice: initialize and identify commits

In your git-practice terminal, complete the commands. The displayed values are example commit identity values, not service login details.

Complete the setup commands

Complete the missing command parts.

shell
git 
git config  user.name "Alex Morgan"
git config  user.email "alex@example.com"

Step 2 of 10

Choose What Belongs in History

Exclude installed dependencies while retaining the files needed to understand and recreate the project.

See the untracked project

Inspect the new project

Before the first commit, use long-form status to see the files Git recognizes in the new git-practice repository. They are in your working tree, but Git has not recorded them yet.

This dependency-free practice package may not create a node_modules/ directory at all. Do not expect that directory to appear here; you will add its ignore rule proactively for any installed dependencies the project may have later.

Check untracked files

Run this from git-practice.

shell
git status
Expected output
On branch <your initial branch>

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	index.html
	package-lock.json
	package.json
	styles.css

nothing added to commit but untracked files present (use "git add" to track)

Your initial branch name and the ordering of files can vary. With this dependency-free package, `node_modules/` may not exist and is not expected in this output.

Project records and installed copies

A git-practice folder contains four project files, while a separate dashed node_modules folder represents optional locally installed dependency contents.

The project files are untracked candidates for history. The dashed dependency folder may not exist in this dependency-free practice package, but it should be ignored whenever installed dependencies create it.

Add the dependency exclusion

Exclude installed copies, not project records

Create a file named .gitignore in the git-practice folder with your editor. Its rule tells Git to ignore the installed dependency directory whenever that directory exists.

Keep .gitignore itself in project history: the project needs the same exclusion rule wherever it is used. Because this rule is added before the first commit, it applies while dependency contents are still untracked. After saving it, run git status again.

.gitignore

Contents of .gitignore

gitignore
node_modules/

Verify the candidates for history

Check the remaining project-file candidates after saving .gitignore.

shell
git status
Expected output
On branch <your initial branch>

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	.gitignore
	index.html
	package-lock.json
	package.json
	styles.css

nothing added to commit but untracked files present (use "git add" to track)

The branch name and file ordering can vary. `node_modules/` is absent because it does not exist in this practice project; if it exists later, this rule keeps it out of ordinary untracked-file reporting.

Decide what belongs in history

Files that explain or recreate the project belong in history. Installed copies can be recreated from the manifest and lockfile, so they do not.

Use this distinction before the initial commit.
Project itemDecisionReason
index.html and styles.cssTrackAuthored page and styles
package.jsonTrackProject package configuration
package-lock.jsonTrackGenerated resolved dependency record
.gitignoreTrackShared exclusion rule
node_modules/IgnoreLocal installed dependency contents

Tip

Important limit

An ignore rule affects untracked paths. Adding node_modules/ later would not automatically stop Git from tracking a dependency folder that had already been recorded. That is why this practice adds the rule now, before its first commit.

Practice the decision

Classify the project contents

Match each item with its appropriate handling before the initial commit.

Tap an item and then its matching pair.

Apply the exclusion rule

Apply the full history decision

Complete the handling decision for each category, then complete the one-line .gitignore entry that applies the dependency decision.

gitignore
# Authored source (index.html and styles.css): 
# Project configuration (package.json): 
# Dependency record (package-lock.json): 
# Installed dependencies (node_modules/): 

Step 3 of 10

Record the First Checkpoint

Stage, inspect, and record the first reviewed checkpoint in a local Git repository.

Separate editing from recording

Three states, three actions

Git keeps three local states separate:

  • Working tree: the editable files saved in git-practice.
  • Staging area: the exact file contents selected for the next commit.
  • Commit: a recorded snapshot in this repository’s local history.

Saving a file changes the working tree. Staging selects its current contents. Committing records the staged selection. These are distinct actions.

How a local checkpoint is recorded

A three-part diagram showing editable files in the working tree moving to the staging area and then becoming a commit snapshot.

Saving affects the working tree; staging selects contents; committing records the selected snapshot.

Tip

Key distinction

After the first commit, HEAD refers to the currently checked-out commit. Throughout this tutorial, HEAD remains the latest commit. A commit records what is in the staging area at that moment—not every possible edit on disk.

Stage and review the checkpoint

Select the baseline files

From the git-practice folder, stage the five baseline files with explicit paths. The -- separator makes clear that the remaining values are paths.

Stage the baseline

Run this from git-practice. Git normally produces no output when the files are staged successfully.

shell
git add -- .gitignore index.html styles.css package.json package-lock.json

Review source files, part 1

Review the staged .gitignore and HTML contents. In this initial diff, + marks lines being added to the first snapshot.

shell
git diff --staged -- .gitignore index.html
Expected output
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..<hash>
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..<hash>
--- /dev/null
+++ b/index.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Local Change Lab</title>
+    <link rel="stylesheet" href="styles.css" />
+  </head>
+  <body>
+    <main>
+      <h1>Local Change Lab</h1>
+      <p>A small project for practicing local Git history.</p>
+    </main>
+  </body>
+</html>

Output excerpt. The object hash and file-mode details can vary; the added file contents should match your saved files.

Review source files, part 2

Review the selected stylesheet contents as part of the same initial checkpoint.

shell
git diff --staged -- styles.css
Expected output
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..<hash>
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,20 @@
+:root {
+  font-family: system-ui, sans-serif;
+  color: #1e293b;
+  background: #f8fafc;
+}
+
+body {
+  display: grid;
+  min-height: 100vh;
+  margin: 0;
+  place-items: center;
+}
+
+main {
+  padding: 2rem;
+}
+
+h1 {
+  color: #334155;
+}

Output excerpt. The object hash can vary; the added CSS lines should match your saved stylesheet.

Review configuration and lockfile

Review the project configuration and the lockfile generated by npm install. Do not manually edit the lockfile.

shell
git diff --staged -- package.json package-lock.json
Expected output
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..<hash>
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+  "name": "git-practice",
+  "version": "1.0.0",
+  "private": true
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..<hash>
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,12 @@
+{
+  "name": "git-practice",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "git-practice",
+      "version": "1.0.0"
+    }
+  }
+}

Output excerpt. The lockfile structure shown is typical of current npm versions; its lockfile version, hash, or formatting can vary. Verify that your generated lockfile is staged along with `package.json`.

Tip

If the diff fills the terminal

Git may open a pager when a diff is long. Read the output, then press q to return to the terminal.

Record and verify

Record the baseline

The reviewed staging area is ready to become the first local checkpoint. Create the commit, then use long-form status to verify the result.

Create the commit

Create the first local snapshot with the required message.

shell
git commit -m "Create local practice baseline"
Expected output
[<initial-branch> (root-commit) <commit-hash>] Create local practice baseline
 5 files changed, 53 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 index.html
 create mode 100644 package-lock.json
 create mode 100644 package.json
 create mode 100644 styles.css

Your initial branch name and commit hash will differ. The insertion count can differ if npm generated a different lockfile format.

Verify the working tree

Check the repository after the commit.

shell
git status
Expected output
On branch <initial-branch>
nothing to commit, working tree clean

The initial branch name varies by Git installation and configuration.

Tip

Read the confirmation carefully

“Working tree clean” means there are no pending tracked changes. Ignored files may still exist on your computer; Git simply does not report them as ordinary untracked files.

Practice the sequence

Checkpoint sequence

Put the actions in the only order that creates a reviewed local checkpoint.

  1. Stage the intended file contents
  2. Review the staged diff
  3. Create the commit
  4. Save the project files

Apply the baseline workflow

Complete the baseline commands

Complete the commands that record the supplied baseline files after they have been saved.

shell
git  -- .gitignore index.html styles.css package.json package-lock.json
git  --staged
git  -m ""

Step 4 of 10

See Exactly What Changed

Inspect saved edits, then use status and two diff views to distinguish unstaged work from content selected for the next commit.

Edit and locate the changes

Make two working-tree edits

In your existing git-practice folder, make and save these two edits:

  1. In index.html, change the heading from Local Change Lab to My Local Change Lab.
  2. In styles.css, change the h1 color from #334155 to #2563eb.

Both files are already tracked by the baseline commit. Saving these edits changes the working tree only. The staging area and HEAD—the currently checked-out, latest commit—still contain the baseline contents.

Where the edits are now

A three-part diagram shows modified HTML and CSS files in the working tree while the staging area and latest commit still contain their baseline versions.

After saving both edits, the working tree differs from the staging area and from HEAD. Nothing has been selected for the next commit yet.

Inspect the working tree

Run this from the git-practice folder to locate the saved edits.

shell
git status
Expected output
On branch <your-current-branch>
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:   index.html
	modified:   styles.css

no changes added to commit (use "git add" and/or "git commit -a")

Your branch name and Git's instructional hints can vary. The important section is “Changes not staged for commit,” which should list both files.

Inspect an unstaged change

Read a focused working-tree diff

git diff compares the working tree with the staging area. Before staging, the staging area still has the baseline heading, so a file-scoped diff shows the saved HTML edit.

The diff --git, index, ---, and +++ lines are comparison metadata, not source edits. In the source lines, - labels a removal from the earlier version and + labels an addition in the newer version.

Compare one file

Use an explicit path to inspect only the HTML change.

shell
git diff -- index.html
Expected output
diff --git a/index.html b/index.html
index 9ac3b51..df51f84 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@
   </head>
   <body>
     <main>
-      <h1>Local Change Lab</h1>
+      <h1>My Local Change Lab</h1>
       <p>A small project for practicing local Git history.</p>
     </main>
   </body>

The index IDs and hunk line numbers can vary. The unchanged paragraph is context, while the labeled `-` and `+` source lines are the actual heading change.

Separate selected and unselected work

Stage one file and compare both views

Now select only the HTML contents for the next commit. Staging captures the current index.html contents in the staging area; the stylesheet color edit remains only in the working tree.

Afterward, git diff compares the working tree with the staging area, so it shows the unselected stylesheet edit. git diff --staged compares the staging area with HEAD, so it shows the selected heading edit. Ordinary git diff does not display the contents of a brand-new untracked file.

If you edit a file again after staging it, its later working-tree version can differ from its earlier staged version. That file can then appear in both status sections.

Select the heading change

Stage only the HTML file, then check which status section contains each file.

shell
git add -- index.html
git status
Expected output
On branch <your-current-branch>
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   index.html

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:   styles.css

`git add` normally produces no output. Your branch name and Git's hints can vary.

Inspect the unstaged stylesheet edit

This view now shows the tracked change that remains outside the staging area.

shell
git diff
Expected output
diff --git a/styles.css b/styles.css
index a631d92..b78ad15 100644
--- a/styles.css
+++ b/styles.css
@@ -16,5 +16,5 @@ main {
 }
 
 h1 {
-  color: #334155;
+  color: #2563eb;
 }

The index IDs and hunk line numbers can vary. The `-` and `+` labels identify the removed and added CSS source lines.

Inspect the staged heading edit

This view previews the tracked content currently selected for the next commit.

shell
git diff --staged
Expected output
diff --git a/index.html b/index.html
index 9ac3b51..df51f84 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@
   </head>
   <body>
     <main>
-      <h1>Local Change Lab</h1>
+      <h1>My Local Change Lab</h1>
       <p>A small project for practicing local Git history.</p>
     </main>
   </body>

The index IDs and hunk line numbers can vary. This command compares the staging area with HEAD.

Check your interpretation

Confirm what the next commit includes

Match each command or file to its comparison or current state.

Tap an item and then its matching pair.

Step 5 of 10

Unstage Without Losing Edits

Refine an over-broad staging selection, preserve unrelated working-tree edits, and record only the intended heading change.

Select, then refine

Make the selection too broad

A focused commit tells one understandable story. index.html already has the staged heading change, while styles.css has an unrelated unstaged color change.

Deliberately stage the stylesheet now. This makes the next commit too broad, so you can correct its selection without deleting the edit.

What unstaging changes

A before-and-after diagram shows a stylesheet edit being removed from the staging area while remaining in the working tree. The heading edit remains staged.

Unstaging changes the next commit's selection only. It leaves the saved stylesheet edit in the working tree.

Stage the stylesheet

Run this from the git-practice folder. It temporarily adds the stylesheet edit to the staging area.

shell
git add -- styles.css

Inspect the over-broad selection

Both files should now appear under Changes to be committed. The current branch name differs between repositories.

shell
git status
Expected output
On branch <your-current-branch>
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   index.html
        modified:   styles.css

The branch name varies. Git normally shows both modified files in the staged section.

Verify both locations

Unstage without discarding

HEAD is the currently checked-out commit; throughout this tutorial, it remains the latest commit. Because the baseline commit exists, Git can replace the staging-area entry for styles.css with the version from HEAD.

This does not overwrite the edited file in the working tree. The result is a focused selection: the heading stays staged, while the blue stylesheet edit stays saved but unselected.

Remove the unrelated file from the selection

Remove only styles.css from the staging area. Git normally produces no output for a successful unstage.

shell
git restore --staged -- styles.css

Confirm that the stylesheet edit survives

Check the working-tree version of the stylesheet. The surrounding lines match the complete baseline file; - marks the earlier color and + marks the saved edit that survived.

shell
git diff -- styles.css
Expected output
diff --git a/styles.css b/styles.css
--- a/styles.css
+++ b/styles.css
@@ -16,5 +16,5 @@
 }
 
 h1 {
-  color: #334155;
+  color: #2563eb;
 }

This focused diff shows the relevant hunk. The object-ID metadata line, if shown by Git, is omitted here because it is not source content.

Confirm the focused staged diff

Now inspect exactly what the next commit would contain. Only the staged heading change appears; the unchanged paragraph provides context from the complete HTML page.

shell
git diff --staged
Expected output
diff --git a/index.html b/index.html
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@
   </head>
   <body>
     <main>
-      <h1>Local Change Lab</h1>
+      <h1>My Local Change Lab</h1>
       <p>A small project for practicing local Git history.</p>
     </main>
   </body>

This focused diff shows the relevant hunk. The object-ID metadata line, if shown by Git, is omitted here because it is not source content.

Record a focused checkpoint

Commit only the heading

The staged diff now contains one coherent change. Record it with the required message. A commit records the staging area, not every edit currently present in the working tree.

Record the heading change

Create the focused checkpoint.

shell
git commit -m "Clarify page heading"
Expected output
[<your-current-branch> <abbreviated-hash>] Clarify page heading
 1 file changed, 1 insertion(+), 1 deletion(-)

The branch name and abbreviated commit hash vary on each computer.

Inspect the remaining work

The heading is now committed. The stylesheet edit remains uncommitted in the working tree, ready for a later decision.

shell
git status
Expected output
On branch <your-current-branch>
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:   styles.css

no changes added to commit (use "git add" and/or "git commit -a")

The branch name varies. The important result is that only styles.css remains under unstaged changes.

Check your understanding

Apply the focused-commit workflow

Complete the file-scoped unstage command and predict where the stylesheet edit remains after the heading commit.

shell
git  --staged -- styles.css
git commit -m "Clarify page heading"

# After the commit, the stylesheet edit remains in the  and is excluded from it.

Step 6 of 10

Inspect Earlier Snapshots

Find a local checkpoint and inspect its recorded patch or a file's stored contents without altering current work.

Locate a checkpoint

Find the baseline commit

Your repository now has two commits. Run git log --oneline from git-practice to view them newest first. Each line starts with an abbreviated commit hash followed by its message.

HEAD is still the currently checked-out, latest commit: Clarify page heading. Locate Create local practice baseline and copy the hash beside that message. Hashes are created locally, so yours will not match an example from another computer.

The stylesheet color edit is still only in the working tree. Because it has not been committed, it is not an entry in this history.

List local commits

Run this command inside the git-practice folder.

shell
git log --oneline
Expected output
8fa31c7 Clarify page heading
42bd9e1 Create local practice baseline

Representative output only: abbreviated hashes differ in every repository. Copy the hash beside `Create local practice baseline` in your own output.

History is read newest first

A two-snapshot local history timeline with an older snapshot examined by a magnifying glass and a newer snapshot shown as current.

Find the baseline by its commit message, then use the hash from your own local timeline.

Compare a change with stored contents

Inspect a patch or a complete file

After copying the baseline hash, replace COMMIT_HASH in the commands below with that actual value. COMMIT_HASH is a replacement token in this tutorial, not text to enter literally.

git show COMMIT_HASH displays commit details and its patch: lines the commit added or removed compared with its parent. The baseline has no earlier project snapshot, so its patch records newly added files.

git show COMMIT_HASH:index.html instead prints the complete index.html stored in that snapshot. Both commands only inspect history: they do not change the working tree, staging area, existing commits, or the uncommitted stylesheet edit.

Inspect the baseline commit patch

Use the actual baseline hash that you copied. This command shows the commit and its recorded patch.

shell
git show COMMIT_HASH
Expected output
commit 42bd9e1a4c8d7f3b9e0a1c2d3e4f5a6b7c8d9e0f
Author: Alex Morgan <alex@example.com>
Date:   Tue Jan 14 10:30:00 2025 +0000

    Create local practice baseline

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5c27f26
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..c2a0b18
--- /dev/null
+++ b/index.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Local Change Lab</title>
+    <link rel="stylesheet" href="styles.css" />
+  </head>
+  <body>
+    <main>
+      <h1>Local Change Lab</h1>
+      <p>A small project for practicing local Git history.</p>
+    </main>
+  </body>
+</html>

Representative excerpt. The hash and date vary. The full output continues with patches for the other files in the baseline, including the npm-generated package-lock.json.

Inspect the stored HTML file

Use the same actual baseline hash. The output is the full file stored in that commit, not a patch.

shell
git show COMMIT_HASH:index.html
Expected output
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Local Change Lab</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <main>
      <h1>Local Change Lab</h1>
      <p>A small project for practicing local Git history.</p>
    </main>
  </body>
</html>

This is the complete baseline `index.html` content. Your terminal prints the same file contents after you replace `COMMIT_HASH` with your copied baseline hash.

Patch or complete file?

A patch answers “What did this commit change?” A historical file view answers “What did this file contain at that checkpoint?”

Both commands inspect history without modifying local Git states.
CommandDisplaysDoes not do
git show COMMIT_HASHCommit details and its recorded patchEdit a file or move HEAD
git show COMMIT_HASH:index.htmlComplete stored index.html contentsStage, restore, or overwrite anything

Practice: choose and inspect

Choose the baseline file view

This is a newest-first local history:

91ab3c0 Clarify page heading
4e82a19 Create local practice baseline

Choose the completed command that displays the baseline commit’s stored index.html contents without restoring or changing anything.

Step 7 of 10

Discard Only an Unwanted Edit

Review an unwanted unstaged stylesheet change, discard only that file after inspection, and distinguish discarding from unstaging.

Review before you overwrite

Inspect the possible loss

The heading change is already committed. The only pending edit should be in styles.css: the h1 color changed from #334155 to #2563eb.

Before overwriting a file, inspect both its location and its exact difference. git status should show styles.css only under Changes not staged for commit. Then use a file-scoped diff to see precisely what would be lost.

Locate the unwanted edit

A diagram showing the blue stylesheet edit only in the working tree, while the staging area and HEAD keep the slate color.

The blue edit exists only in the working tree; the staging area still matches HEAD.

Check status and the stylesheet diff

Run these commands from the git-practice folder. Read the - removed line and + added line in the diff before deciding whether to discard the edit.

shell
git status
git diff -- styles.css
Expected output
On branch <your-current-branch>
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:   styles.css

no changes added to commit (use "git add" and/or "git commit -a")
diff --git a/styles.css b/styles.css
index 8cf9c32..e7a486d 100644
--- a/styles.css
+++ b/styles.css
@@ -16,5 +16,5 @@ main {
 }
 
 h1 {
-  color: #334155;
+  color: #2563eb;
 }

Your branch name and blob hashes can differ. The important evidence is that `styles.css` appears only as an unstaged change and that the complete CSS context shows the color changing from `#334155` to `#2563eb`.

Restore one reviewed file

Discard the reviewed edit

You have reviewed the diff and decided the blue color is unwanted. In this exercise, styles.css has no staged change, so its staging-area version still has the baseline color and matches HEAD, the currently checked-out commit.

git restore -- styles.css copies that staging-area version into the working tree. It overwrites this file’s unstaged edit; it does not create a commit and does not alter existing history.

Warning

Overwrite only one selected file

Run the file-scoped command only after reviewing the stylesheet diff and deciding that its edit is unwanted. The command overwrites the current working-tree contents of styles.css. If you might want an uncommitted edit, preserve it instead of assuming Git can recover it later.

Discard and check

Run the restore, then verify that no stylesheet difference remains and that the repository is clean.

shell
git restore -- styles.css
git diff -- styles.css
git status
Expected output
On branch <your-current-branch>
nothing to commit, working tree clean

`git restore -- styles.css` and a clean `git diff -- styles.css` produce no output. The displayed lines are the expected output from the final `git status`; your branch name can differ.

Do not confuse restore with unstage

Both commands begin with git restore, but they affect different local states. An unstaged edit that you overwrite was never recorded in a commit, so do not assume it can be recovered later.

Here, the staging-area version of `styles.css` matches HEAD.
CommandWhat it changesWhat happens to the working-tree edit
git restore --staged -- styles.cssThe staging-area selection is restored from HEAD.It stays in the working tree.
git restore -- styles.cssThe working-tree file is restored from the staging area.It is overwritten.

Practice the safe sequence

Order the discard workflow

Put the safe workflow in its only sensible order.

  1. Run `git status` and confirm that `styles.css` is only unstaged.
  2. Run `git status` and confirm the working tree is clean.
  3. Run `git restore -- styles.css`.
  4. Run `git diff -- styles.css` and inspect the color change.
  5. Decide that the reviewed stylesheet edit is unwanted.

Choose the correct effect

Apply the safe discard decision

Complete the safe sequence: inspect before discarding styles.css, then identify the state changed by the alternative unstaging form.

shell
# Review first:
git 
git  -- styles.css

# After deciding the edit is unwanted:
git  -- styles.css

# The form with --staged changes the  and preserves working-tree edits.

Step 8 of 10

Recover a File and Keep the History

Restore index.html from the baseline snapshot, review the result, and record the recovery without removing earlier local commits.

Locate the restoration source

Choose the baseline snapshot

Your local history contains two commits. List it newest first, then find the commit whose message is Create local practice baseline. Copy the abbreviated hash beside that message.

COMMIT_HASH below is a replacement token: replace it with the actual hash from your own history, never type the token literally. Inspecting history does not change the working tree, staging area, or existing commits.

List local commits

Find the baseline commit by its message.

shell
git log --oneline
Expected output
c7d91a4 Clarify page heading
a4e8b2f Create local practice baseline

This is an example only; your hashes will differ. The newest commit appears first.

Inspect the stored HTML file

Use the baseline hash you copied to inspect the complete index.html stored in that snapshot.

shell
git show COMMIT_HASH:index.html
Expected output
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Local Change Lab</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <main>
      <h1>Local Change Lab</h1>
      <p>A small project for practicing local Git history.</p>
    </main>
  </body>
</html>

Replace COMMIT_HASH with your copied baseline hash. This output is the complete baseline file; confirm its original heading before using it as a restoration source.

Restore only the selected file

Protect current work before restoring

Before overwriting a file, check that it has no wanted edits. At this point, index.html should have no staged or unstaged changes. If git status lists that file in either change section, stop and preserve, commit, or deliberately discard that work first.

git restore --source=COMMIT_HASH -- index.html takes file contents from the named historical commit instead of the default staging-area source. Because this form has no --staged, it changes only the working tree. It does not change the staging area, HEAD, or existing history.

What an explicit historical source changes

Diagram showing an earlier commit copying index.html into the working tree while the staging area and current commit remain unchanged.

With an explicit source and no --staged flag, Git changes the selected working-tree file only.

Warning

Pause before overwriting

This command overwrites the current working-tree contents of the selected file. Run it only after reviewing the historical source and confirming that overwriting index.html is safe.

Restore and review index.html

First confirm the repository is clean. Then restore index.html from the copied baseline hash and review the resulting working-tree diff.

shell
git status
git restore --source=COMMIT_HASH -- index.html
git diff -- index.html
Expected output
On branch <your branch name>
nothing to commit, working tree clean

diff --git a/index.html b/index.html
index 2e9ad88..7bfc967 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@
   </head>
   <body>
     <main>
-      <h1>My Local Change Lab</h1>
+      <h1>Local Change Lab</h1>
       <p>A small project for practicing local Git history.</p>
     </main>
   </body>

`git restore` itself produces no output. The blob IDs can differ, but the diff should change only the h1 line and retain the original paragraph.

Create a recovery checkpoint

Review and record the recovery

The diff shows recovered content only in the working tree. Stage just index.html, then inspect the staged diff before committing.

The new commit records this recovery as a new checkpoint. It does not move the repository back in time or remove either earlier commit. After committing, HEAD becomes the new recovery commit.

A recovery adds to history

Before-and-after history diagram showing a new recovery commit added above two retained earlier commits.

Restoring one file creates a change to commit. The new Restore original heading commit is added while the baseline and heading-revision commits remain available.

Stage the recovered contents

Stage only the recovered file and inspect exactly what the next commit would contain.

shell
git add -- index.html
git diff --staged -- index.html
Expected output
diff --git a/index.html b/index.html
index 2e9ad88..7bfc967 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@
   </head>
   <body>
     <main>
-      <h1>My Local Change Lab</h1>
+      <h1>Local Change Lab</h1>
       <p>A small project for practicing local Git history.</p>
     </main>
   </body>

The staged patch should show only the heading returning to its original text. Metadata IDs can vary by repository.

Commit and verify

Create the recovery checkpoint. Then verify the clean working tree and inspect the newest-first history.

shell
git commit -m "Restore original heading"
git status
git log --oneline
Expected output
[<your branch name> f3a81c9] Restore original heading
 1 file changed, 1 insertion(+), 1 deletion(-)
On branch <your branch name>
nothing to commit, working tree clean
f3a81c9 Restore original heading
c7d91a4 Clarify page heading
a4e8b2f Create local practice baseline

Your branch name and hashes will differ. The important results are a clean working tree and all three commit messages remaining in the log.

Apply the complete recovery workflow

Verify recovery without losing history

After completing the workflow in your terminal, report all of the following:

  1. Immediately after the historical restore and before git add, which Git area changed?
  2. Which areas remained unchanged at that moment?
  3. After staging and committing, what did long-form git status report?
  4. List the three commit messages visible in newest-first history, and state why the two earlier commits are still available.

Write at least 220 characters (0/220).

Step 9 of 10

Know What Local Commits Protect

Determine what existing local commits preserve, what they leave out, and why a separate backup is still necessary.

Separate snapshots from current files

A commit is a recorded checkpoint

A commit preserves the exact file contents that were staged and recorded at that moment. It does not automatically include edits saved later in the working tree, even if those edits were staged but no new commit was created.

In this practice repository, commits are useful local checkpoints: while the git-practice folder remains available, you can inspect and restore the contents they recorded.

One snapshot, not every file state

Diagram showing a local commit protecting its recorded snapshot while later working-tree edits, staged-only content, and ignored dependencies remain outside that snapshot.

A local commit captures selected content only after it is recorded.

What existing commits protect

Use this table to decide what an existing local commit can preserve.

Protection applies only to contents that were actually recorded in a commit.
SituationWhat existing commits preserveImportant limit
A source-file version recorded in a commitThat exact recorded versionA later edit needs another commit
A saved working-tree edit after the commitNothing from that later editSaving is not a checkpoint
A staged change with no new commitNothing from that staged-only versionStaging selects; committing records
Ignored `node_modules/` contentsNothing from the ignored folderOrdinary commits do not include ignored contents
Loss of the whole project folder or diskNo separate copyWorking files and `.git` can disappear together

Protect against a different kind of loss

Warning

Local history is not an external backup

Local history is valuable, but it normally lives in the same git-practice folder and on the same computer as your working files. If that folder is deleted or the device storage fails, both the project files and the .git history may be lost together.

Keep a separate, verified backup for loss of the computer or project folder. Setting up backup tools or remote services is outside this tutorial.

One location versus a separate copy

Comparison showing a project folder and its local Git history together on one laptop, contrasted with a separate verified backup copy.

A local repository helps recover recorded versions only while that local project and its history still exist.

Saving and staging are not enough

Check the boundary

True or false: Once a file is staged, its current version is already protected by local commit history.

Apply the protection rule

Classify local protection

Match each situation to what existing local commit history protects or does not protect.

Tap an item and then its matching pair.

Step 10 of 10

Complete a Local Recovery Challenge

Apply the complete local Git workflow to record a change, recover an earlier stylesheet, and verify the retained history.

Record the green change

Part 1: Record the green change

In git-practice, open styles.css and change only the h1 color from #334155 to #16a34a. Save the file.

Then inspect the working-tree change, stage only styles.css, review the staged version, and record it. This adds a focused checkpoint; it does not alter earlier commits.

From saved edit to checkpoint

A stylesheet color changes from slate to green, then the stylesheet moves from editable files through a selected staging area into a new local commit.

Inspect the saved file first, then stage and review only styles.css before committing it.

Inspect, stage, review, and commit

Run these commands after saving the color change. The output shows the complete stylesheet diff before and after staging; your branch name and hashes will differ.

shell
git status
git diff -- styles.css
git add -- styles.css
git diff --staged -- styles.css
git commit -m "Set heading color to green"
Expected output
On branch BRANCH_NAME
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:   styles.css

no changes added to commit (use "git add" and/or "git commit -a")
diff --git a/styles.css b/styles.css
index BASELINE_BLOB_HASH..GREEN_BLOB_HASH 100644
--- a/styles.css
+++ b/styles.css
@@ -16,5 +16,5 @@ main {
 }
 
 h1 {
-  color: #334155;
+  color: #16a34a;
 }
diff --git a/styles.css b/styles.css
index BASELINE_BLOB_HASH..GREEN_BLOB_HASH 100644
--- a/styles.css
+++ b/styles.css
@@ -16,5 +16,5 @@ main {
 }
 
 h1 {
-  color: #334155;
+  color: #16a34a;
 }
[BRANCH_NAME GREEN_COMMIT_HASH] Set heading color to green
 1 file changed, 1 insertion(+), 1 deletion(-)

`BRANCH_NAME` and the values ending in `_HASH` stand for values generated in your local repository. The two displayed diffs are expected to show the same one-line color change: first as an unstaged change, then as a staged change.

Select the restoration command

Choose a historical restoration source

Complete the option that copies styles.css from a selected earlier commit into the working tree. COMMIT_HASH is a replacement token for a hash copied from git log; do not enter that word literally.

shell
git restore  -- styles.css

Distinguish the three choices

Make the right recovery decision

Match each goal to the Git command that fits it.

Tap an item and then its matching pair.

Recover the earlier file contents

Part 2: Recover the original stylesheet

Use newest-first history to find Create local practice baseline, then copy the actual hash beside that message. Inspect that commit’s stored styles.css and confirm that it contains the original stylesheet.

Before restoring, confirm that styles.css has no wanted staged or unstaged work. Replace COMMIT_HASH with the baseline hash you copied. Review the recovered change, stage only that file, review it again, and commit the recovery.

This keeps the green-color commit in local history while making the current stylesheet match the selected earlier snapshot.

Inspect, restore, review, and commit

Use your actual baseline hash in place of COMMIT_HASH. The output below shows the expected checkpoints and complete stylesheet contents.

shell
git status
git log --oneline
git show COMMIT_HASH:styles.css
git restore --source=COMMIT_HASH -- styles.css
git diff -- styles.css
git add -- styles.css
git diff --staged -- styles.css
git commit -m "Restore original heading color"
Expected output
On branch BRANCH_NAME
nothing to commit, working tree clean
GREEN_COMMIT_HASH Set heading color to green
RESTORE_HEADING_HASH Restore original heading
CLARIFY_HASH Clarify page heading
BASELINE_HASH Create local practice baseline
:root {
  font-family: system-ui, sans-serif;
  color: #1e293b;
  background: #f8fafc;
}

body {
  display: grid;
  min-height: 100vh;
  margin: 0;
  place-items: center;
}

main {
  padding: 2rem;
}

h1 {
  color: #334155;
}
diff --git a/styles.css b/styles.css
index GREEN_BLOB_HASH..BASELINE_BLOB_HASH 100644
--- a/styles.css
+++ b/styles.css
@@ -16,5 +16,5 @@ main {
 }
 
 h1 {
-  color: #16a34a;
+  color: #334155;
 }
diff --git a/styles.css b/styles.css
index GREEN_BLOB_HASH..BASELINE_BLOB_HASH 100644
--- a/styles.css
+++ b/styles.css
@@ -16,5 +16,5 @@ main {
 }
 
 h1 {
-  color: #16a34a;
+  color: #334155;
 }
[BRANCH_NAME RESTORE_COLOR_HASH] Restore original heading color
 1 file changed, 1 insertion(+), 1 deletion(-)

`BRANCH_NAME` and values ending in `_HASH` vary by repository. In the log, identify the baseline by its message, not by an example hash. The initial clean status assumes you completed Part 1 and have made no additional edits.

Review the final state

Verify your local result

Run these final checks from git-practice. They confirm the clean working tree, the current stylesheet stored at HEAD, and the retained newest-first history.

shell
git status
git show HEAD:styles.css
git log --oneline
Expected output
On branch BRANCH_NAME
nothing to commit, working tree clean
:root {
  font-family: system-ui, sans-serif;
  color: #1e293b;
  background: #f8fafc;
}

body {
  display: grid;
  min-height: 100vh;
  margin: 0;
  place-items: center;
}

main {
  padding: 2rem;
}

h1 {
  color: #334155;
}
RESTORE_COLOR_HASH Restore original heading color
GREEN_COMMIT_HASH Set heading color to green
RESTORE_HEADING_HASH Restore original heading
CLARIFY_HASH Clarify page heading
BASELINE_HASH Create local practice baseline

`BRANCH_NAME` and values ending in `_HASH` vary by repository. The five commit messages and their newest-first order should match this output.

Summary

Repeatable local workflow

  • Inspect before changing, discarding, or recovering file contents.
  • Select only the files intended for the next commit, then review the staged diff.
  • Use git restore --staged to change a commit selection without deleting working-tree edits.
  • Use git restore -- only to discard a reviewed working-tree edit; use --source=COMMIT_HASH to recover historical contents.
  • Local commits protect recorded contents, but a separate verified backup is still needed for device or folder loss.

Report and finish

Final local verification

Using results from your own computer, report all of the following:

  1. The final h1 color you observed.
  2. The exact long-form git status result after the two challenge commits.
  3. The two retained challenge commit messages, newest first.
  4. Why the earlier green-color commit remains useful even though the current stylesheet has the original color.

Write at least 100 characters (0/100).

Tutorial complete

Congratulations! You completed: Track and Restore Local Changes with Git

You recorded a focused change, restored earlier file contents in a new commit, and verified the result through local history.

Download the App now to have access to + 5000 free courses, exercises, certificates and lots of content without paying anything!

  • 100% free online courses from start to finish

    Thousands of online courses in video, ebooks and audiobooks.

  • More than 60 thousand free exercises

    To test your knowledge during online courses

  • Valid free Digital Certificate with QR Code

    Generated directly from your cell phone's photo gallery and sent to your email

Cursa app on the ebook screen, the video course screen and the course exercises screen, plus the course completion certificate