Chapter 04Lesson 02~105 minutes

Repositories, Working Tree, Index, HEAD, and the File Lifecycle: Guided Hands-On Workflow and Core Operations

Move paths deliberately through Git's file lifecycle with status, add, partial staging, diff, restore, rm, mv, ls-files, and ignore diagnostics inside a disposable repository.

git add -pgit restoregit mv/rmState inspection

Learning objectives

  • Compare working tree, index, and HEAD before and after each state-changing command.
  • Stage whole files and selected hunks while preserving unstaged work.
  • Unstage with modern git restore syntax and understand the legacy reset compatibility form.
  • Track deletion and rename operations while distinguishing explicit file movement from inferred rename reporting.
  • Inspect ignored and indexed paths with check-ignore and ls-files.

1. Create a disposable lifecycle lab

Git Bash, Bash, or zsh

mkdir git-lifecycle-lab
cd git-lifecycle-lab
git init -b trunk
git config user.name "Lifecycle Lab"
git config user.email "lifecycle@example.invalid"
printf "alpha\nbeta\ngamma\ndelta\n" > app.txt
printf "temporary.log\n" > .gitignore
git status --short
git add app.txt .gitignore
git diff --staged
git commit -m "Create lifecycle baseline"
git status --short --branch

PowerShell file-creation alternative

New-Item -ItemType Directory git-lifecycle-lab | Out-Null
Set-Location git-lifecycle-lab
git init -b trunk
git config user.name "Lifecycle Lab"
git config user.email "lifecycle@example.invalid"
@('alpha','beta','gamma','delta') | Set-Content app.txt
Set-Content .gitignore 'temporary.log'
git status --short
git add app.txt .gitignore
git diff --staged
git commit -m "Create lifecycle baseline"
git status --short --branch

2. Prove all three views agree at baseline

git status --short
git diff
git diff --staged
git ls-files --stage
git show HEAD:app.txt

Both diffs should be empty. The index and HEAD contain the same snapshot, and the working-tree copy matches the index.

3. Stage a whole-file change

Change one line, inspect first, then copy that working-tree version into the index.

Git Bash / Bash / zsh

printf "alpha\nbeta changed\ngamma\ndelta\n" > app.txt
git status --short
git diff -- app.txt
git add -- app.txt
git status --short
git diff -- app.txt
git diff --staged -- app.txt

After git add, ordinary git diff for the path becomes empty because working tree and index agree; git diff --staged shows the proposed next snapshot relative to HEAD.

4. Modify after staging — one path, three versions

Git Bash / Bash / zsh

printf "alpha\nbeta changed\ngamma\ndelta working-only\n" > app.txt
git status --short
git diff -- app.txt
git diff --staged -- app.txt
git show HEAD:app.txt

Short status should show changes in both columns for app.txt. HEAD still has the original file; the index has the staged beta change; the working tree has that plus the new delta change.

5. Unstage safely with modern restore syntax

git status --short
git restore --staged -- app.txt
git status --short
git diff -- app.txt
git diff --staged -- app.txt

With --staged and no explicit source, Git restores the index entry from HEAD. It leaves the working-tree file alone. You should now see only a working-tree modification.

Compatibility context: older tutorials often use git reset HEAD -- app.txt to unstage. That form still exists, but this course uses git restore --staged because it names the destination layer explicitly. Chapter 10 studies reset/recovery semantics in depth.

6. Restore a working-tree path from the index

This discards uncommitted working-tree changes for the selected path. Inspect the diff first and use it only in this disposable lab.
git diff -- app.txt
git restore -- app.txt
git status --short
git diff -- app.txt

Because the index currently matches HEAD, restoring the working tree from the index returns app.txt to the committed baseline. This does not search old history for “whatever version you meant”; the default source is the index.

7. Partial staging with git add -p

Create two separated edits so Git offers separate hunks. Use a real text editor or the platform-specific example below, then inspect:

Git Bash / Bash / zsh

python - <<'PY'
from pathlib import Path
p = Path('app.txt')
text = p.read_text()
text = text.replace('alpha', 'alpha staged-candidate')
text = text.replace('delta', 'delta working-candidate')
p.write_text(text)
PY
git diff -- app.txt
git add -p -- app.txt

At the interactive prompt, choose y for the first hunk and n for the second. If Git combines the edits into one hunk, use s (split) when available or make the edits farther apart. Then:

git status --short
git diff --staged -- app.txt
git diff -- app.txt

The staged diff should contain only the hunk you accepted. The ordinary diff should contain the working-tree hunk you declined.

8. Commit only the staged hunk

git diff --staged --check
git commit -m "Stage selected app change"
git status --short
git diff -- app.txt

The commit records exactly the index, not every working-tree change. The declined hunk remains as an uncommitted working-tree modification.

9. Discard only the remaining intended local edit

Prediction: git restore -- app.txt will replace the working-tree copy with the index version, which now matches the new HEAD after the commit.
git diff -- app.txt
git restore -- app.txt
git status --short

10. Rename with git mv and inspect what changed

git status --short
git mv app.txt service.txt
git status --short
git diff --staged --summary
git ls-files
git commit -m "Rename app to service"

git mv moves the working-tree path and updates the index. The eventual commit still stores snapshots; rename reporting is inferred when comparing old and new trees.

11. Remove a tracked path with git rm

printf "remove me\n" > obsolete.txt
git add obsolete.txt
git commit -m "Add obsolete file"

git status --short
git rm -- obsolete.txt
git status --short
git diff --staged -- obsolete.txt
git commit -m "Remove obsolete file"

git rm removes the working-tree file and stages its deletion. If you need to stop tracking but keep the working-tree file, git rm --cached is a different policy choice—use it deliberately rather than as a generic cleanup command.

12. Inspect ignored files instead of guessing

printf "local runtime output\n" > temporary.log
git status --short
git check-ignore -v -- temporary.log
git ls-files --others --ignored --exclude-standard

check-ignore -v shows which exclude source and pattern matched. The file is absent from ordinary status because it is intentionally ignored.

13. Challenge — choose the destination layer

For each requirement, choose a command before looking back:

  1. Keep a working-tree edit but remove it from the proposed next commit.
  2. Discard a working-tree edit and restore the index version.
  3. Stage only one hunk from a two-hunk file.
  4. Show every path currently in the index.
  5. Find which ignore rule hides temporary.log.

14. Cleanup

Git Bash / Bash / zsh

git status --short --branch
cd ..
pwd
rm -rf git-lifecycle-lab

PowerShell

git status --short --branch
Set-Location ..
Get-Location
Remove-Item -Recurse -Force git-lifecycle-lab

15. Knowledge check

Question 1. After staging a file and editing it again, what does git commit record by default?

Question 2. What exactly did git restore --staged -- app.txt change in this lab?

Question 3. Does git mv create a permanent rename object?

Question 4. Why did temporary.log disappear from ordinary git status?

16. Summary

You moved content among working tree, index, and commit history; staged only selected hunks; unstaged without discarding work; restored only the working-tree layer; and tracked rename/deletion/ignore behavior with inspection commands before and after every mutation.

Next

Turn file-state mechanics into repository policy

Lesson 3 decides what should be ignored, tracked, partially staged, or left machine-specific, and separates Git pathspec matching from shell expansion across Windows, Linux, and macOS.

Authoritative references

 git-add
 git-restore
 git-mv
 git-rm
 git-check-ignore

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.