Before this lesson
First understand initialization, add and commit.
Use Git 2.35+ and a Bash-compatible terminal, such as Git Bash on Windows. Each complete example creates an independent temporary directory. Run it only in that practice repository. Configuration is repository-local and uses a practice identity. Temporary directories are not automatically removed; clean them up after finishing.
What you will be able to do
Explain differences between three states and avoid omitting the latest edit.
Understand the mechanism
The working tree contains files you edit. The index records content intended for the next commit. HEAD normally points at the current branch tip. add stages the current version rather than automatically including future edits.
git diff compares the worktree to the index; git diff --staged compares the index to HEAD. A file edited again after staging can have both staged and unstaged changes. The two short-status columns describe index and worktree changes.
Prefer one explainable, verifiable change per commit. Reviewing diffs and staging specific files reduces unrelated or temporary content. Interactive git add -p provides finer hunk-level selection.
Runnable example
lab=$(mktemp -d)
cd "$lab"
git init -b main .
git config user.name "Honeysuck Learner"
git config user.email 'learner'@'example.invalid'
git config commit.gpgsign false
git config core.autocrlf false
printf 'Start learning\n' > notes.txt
git add notes.txt
git commit -m "Start learning notes"
printf 'Read Git basics\n' >> notes.txt
git add notes.txt
printf 'Try branching\n' >> notes.txt
git status --short
git diff -- notes.txt
git diff --staged -- notes.txt
git commit -m "Record Git reading"
git show HEAD:notes.txt
git diff -- notes.txt
Trace and verify
The commit includes Start learning and Read Git basics, while Try branching remains an unstaged diff. commit does not automatically absorb edits made after staging.
Common mistakes and boundaries
git commit -a handles modifications and deletions of tracked files, not new untracked files. A successful commit does not mean every local file is recorded.
Practice challenge
Record the remaining third line in a separate commit.
Reference solution and reasoning
Review git diff, stage notes.txt and commit. HEAD:notes.txt should contain three lines and short status should be empty.
Lab: a commit reads the index, not your latest edit
This lab deliberately gives one path three versions: one in HEAD, two in the index and three in the worktree. Predict which version each command reads. Use Git 2.35+ and Bash. The script creates an isolated temporary repository, changes only local configuration and prints its path for later cleanup.
lab=$(mktemp -d)
cd "$lab"
git init -q -b main
git config user.name "Honeysuck Learner"
git config user.email 'learner'@'example.invalid'
git config commit.gpgsign false
git config core.autocrlf false
printf 'one\n' > notes.txt
git add notes.txt
git commit -q -m "Seed"
printf 'two\n' > notes.txt
git add notes.txt
printf 'three\n' > notes.txt
git show HEAD:notes.txt
git show :notes.txt
cat notes.txt
git status --short
git commit -q -m "Record staged version"
git show HEAD:notes.txt
cat notes.txt
printf 'Practice directory: %s\n' "$lab"
Expected observations
The first reads are one, two and three. Short status is MM notes.txt. After the commit, HEAD contains two while the worktree still contains three.
Why this happens and where it stops applying
The first M compares the index with HEAD; the second compares the worktree with the index. git add records content at that moment rather than subscribing to future edits. Inspect both git diff and git diff --staged before committing: each answers a different question. To record three, stage it again, then choose a new commit or an appropriate unpublished-history amendment.
Extension challenge
Before committing, would git restore --staged notes.txt remove three from the worktree?
Reasoned solution
No. With the default HEAD source, --staged restores only the index to one; the worktree remains three. A subsequent plain git restore notes.txt copies from the index into the worktree and discards those uncommitted edits. Keep this experiment inside the disposable repository.