Course outline

Git and GitHub / Basic: the local Git model / Lesson 2

Working tree, index, and deliberate commits

Control exactly which content enters the next snapshot and inspect both staged and unstaged changes.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain the working tree, index, and HEAD snapshot.
  • Stage, inspect, and unstage without discarding working changes.

Keep three views of a tracked file

The working tree contains the files you edit. The index, often called the staging area, holds content selected for the next commit. HEAD normally identifies the current commit through the current branch. These views can differ simultaneously. Staging records the file content at that moment; it does not establish a live subscription to future edits. A later edit remains unstaged until added again. This is why reviewing only the visible editor buffer cannot tell you exactly what the next commit will contain. Inspect the index explicitly before committing.

Observe staging as a snapshot

In a lab that already contains the initial notes.txt commit, replace the file, stage it, and edit it again. The index preserves the middle version while the working tree contains the latest version. git show with the colon path syntax reads the indexed content. This makes the distinction concrete without relying on color conventions from a particular terminal. The example changes only a synthetic lab file. On an actual project, inspect the current status and protect unrelated work before any operation that updates the index or working tree.

bash Read the content selected for the next commit
printf 'draft one\n' > notes.txt
git add -- notes.txt
printf 'draft two\n' > notes.txt
git show :notes.txt
Expected output
draft one

After the stated lab setup, the indexed content is draft one even though the working file says draft two. A commit at this point would include draft one for this file. The output is content, not a prediction of generated commit metadata.

Choose the comparison you intend

git diff compares working-tree content with the index by default. git diff --cached compares the index with HEAD. git diff HEAD compares current working content with the current commit for tracked paths. These answer different questions. Use -- before a path to separate path arguments from revisions and options. Empty unstaged diff output does not prove the whole repository is clean because staged changes and untracked files can remain. Combine status with both relevant comparisons. For a coherent commit, review the complete staged patch, including deletions, generated files, and accidental private content.

Unstage without erasing the edit

For a tracked path with an existing HEAD commit, git restore --staged moves the indexed version back to the chosen source, which defaults to HEAD for this mode. It leaves the working file intact. This differs from restoring the working-tree file, which can discard local edits and requires a separate decision. The example returns notes.txt to an unstaged-only modification. Avoid treating every restore or reset form as interchangeable undo. Read the selected destination and source, and distinguish index changes from working-tree changes before executing a command.

bash Remove a tracked lab file from staging
git restore --staged -- notes.txt
git diff --cached --name-only
git diff --name-only

Following the previous example, the cached name list is empty and the unstaged list contains notes.txt. The working file still contains draft two. This command is not used for a repository with no first commit, where HEAD is absent.

Build a commit as an explanation

A useful commit groups one understandable change with a message explaining intent and relevant constraints. It need not match an arbitrary number of files. Partial staging can separate independent changes, but the staged snapshot must remain coherent and testable; tests run against the working tree can include unstaged fixes that are missing from the commit. Verify the selected snapshot through an isolated checkout or a suitable workflow when that risk matters. Ignore rules prevent ordinary discovery of matching untracked paths, but they do not remove already tracked files or cleanse history.

Common errors and fixes

A commit omits the latest edit

Why it happens
The file was edited after staging.
How to fix it
Review the unstaged diff and stage the intended final content.
Prevent it next time
Inspect git diff --cached immediately before committing.

A blank diff is mistaken for a clean repository

Why it happens
Only working-tree versus index was compared.
How to fix it
Inspect status, staged changes, and untracked files.
Prevent it next time
Name the two states being compared.

An ignore rule does not stop tracking a file

Why it happens
The file is already present in the index.
How to fix it
Plan an explicit tracking change and review data exposure separately.
Prevent it next time
Add appropriate ignore rules before first staging.

Check your understanding

1. A file is staged, edited again, and committed. Which version enters the commit?

Show worked solution

The indexed version enters unless another option or staging operation changes that selection. The later working-tree edit remains outside the ordinary commit. Compare both diffs to verify rather than assuming commit captures every editor buffer.

2. Tests pass with an unstaged fix, but the staged change is incomplete. How should review improve?

Show worked solution

Review and test the actual selected snapshot in an isolated lab checkout or equivalent process. Stage the required fix if it belongs to the same change, or separate the changes coherently. Working-tree success alone does not establish the commit is complete.

Key takeaways

  • Staging records content at a specific moment.
  • Status and explicit diff pairs reveal different kinds of work.
  • Unstaging and discarding edits are separate operations.

Official references