Chapter 04Lesson 04~90 minutes

Repositories, Working Tree, Index, HEAD, and the File Lifecycle: Diagnostics, Failure Modes, Security, and Performance

Diagnose file-lifecycle failures without destructive guesses: wrong repository, overly broad staging, restore misconceptions, ignored files, case/file-mode surprises, path ambiguity, and detached HEAD.

DiagnosticsDetached HEADIgnore debuggingSafety

Learning objectives

  • Apply an evidence-first sequence to repository, index, pathspec, ignore, and HEAD problems.
  • Recover from unintended broad staging without discarding working-tree content.
  • Explain what git restore can and cannot recover by default.
  • Diagnose ignored files and case/file-mode surprises with narrow read-only commands.
  • Recognize detached HEAD as valid state and preserve useful unnamed commits by creating a ref.

1. Diagnostic sequence — identify the layer before changing it

  1. Preserve evidence: current directory, exact command, status output, diff output.
  2. Locate the repository: git rev-parse --show-toplevel and git rev-parse --git-dir.
  3. Inspect HEAD/refs/history: status --branch, symbolic-ref, log.
  4. Inspect index/working tree: ordinary and staged diff, ls-files.
  5. Inspect config/ignore sources only when the symptom points there.
  6. Choose the least destructive correction, then repeat the inspection.

2. Failure mode — “nothing to commit” in the wrong repository

Imagine editing service-a/config.yml while your terminal is in a different checkout. Git may truthfully report a clean repository.

pwd
git rev-parse --show-toplevel
git status --short --branch
git ls-files -- config.yml

The fix is navigation/repository selection, not git add -A or reset. In automation, prefer explicit repository paths (for example git -C /path/to/repo status) rather than relying on an inherited working directory.

3. Failure mode — a broad pathspec staged too much

git add . stages matching changes beneath the current directory. git add -A can stage additions/modifications/deletions across the repository according to its pathspec scope. After any broad add:

git status --short
git diff --staged --stat
git diff --staged

If one path should not be staged, remove only that path from the index proposal:

git restore --staged -- path/to/unwanted.txt
git status --short
git diff --staged

The working-tree copy remains. This is safer than discarding files or resetting the whole repository.

4. Failure mode — treating git restore as a time machine

By default, git restore -- path copies from the index into the working tree. It does not automatically search old commits for a lost version. If you explicitly provide --source=<tree>, then you are selecting a historical source.

Risk boundary: restoring a working-tree path overwrites uncommitted content for that path. Always inspect git diff -- path first.
git diff -- config.yml
git diff --staged -- config.yml
git restore -- config.yml

Recovery from committed/reflog history is Chapter 10. Do not teach “restore” as generic recovery from any past state.

5. Failure mode — “Git cannot see my file” because it is ignored

git status --short
git check-ignore -v -- path/to/file
git status --ignored --short
git config --show-origin --get core.excludesFile

The verbose ignore command identifies the matching rule and source. If the file is already tracked, ordinary ignore rules do not hide it from tracking; diagnose with git ls-files -- path.

6. Failure mode — case-only rename or file-mode noise

On case-insensitive filesystems, Readme.md → README.md can be ambiguous to the OS/Git interaction. Use an intermediate rename when needed and inspect the staged summary. For executable-bit noise, inspect configuration and mode-only diffs instead of disabling file-mode tracking globally.

git config --show-origin --get core.ignoreCase
git config --show-origin --get core.fileMode
git diff --summary

7. Failure mode — detached HEAD after checking out an object directly

Modern Git makes this explicit:

git status --short --branch
git switch --detach HEAD~1
git status --short --branch
git symbolic-ref -q HEAD
git rev-parse HEAD

In detached state, symbolic-ref exits non-zero because HEAD is no longer attached to a local branch. Inspection is safe. If you create useful commits, attach a branch before leaving:

git switch -c keep-this-work

If you made no commits and only inspected an old commit, return to the previous branch with git switch -.

8. Intentionally broken example — a path/revision ambiguity

In a disposable repository, create both a branch and a file named release. A command such as:

git diff release

can be interpreted as a revision argument rather than “diff only the path named release.” The error or unexpected output is evidence of ambiguous grammar, not corrupted state. Repair it by declaring the boundary:

git diff -- release
git diff HEAD -- release

Line by line, the first form compares working tree/index only for the path; the second names HEAD as the revision baseline and then release as the path.

9. Security failures relevant to this layer

  • Broad pathspecs can stage local credentials, environment files, or build outputs. Review staged content before commit.
  • Ignore rules are prevention; they are not secret revocation or history erasure.
  • Shell expansion can make a pathspec touch more files than the runbook author intended. Quote Git patterns and prefer dry-run/inspection where supported.
  • Detached-HEAD builds are normal in CI, but a pipeline must capture the exact commit OID rather than infer a branch name that may not exist locally.

10. Performance issues that actually belong here

Large working trees with many untracked files can make git status slower because Git must discover filesystem state. Do not solve that by hiding meaningful source files. Use correct ignore rules for generated/cache directories and later large-repository features where appropriate. Machine-readable automation should prefer git status --porcelain rather than parsing localized/human-oriented long status output.

11. Red-zone commands that do not belong in first-response diagnostics

Do not reach for git reset --hard, git clean -fdx, force pushes, reflog expiry, object pruning, or history-rewrite tools to fix a staging/path problem. They can destroy uncommitted or recoverable data. The failures in this lesson are repaired with navigation, path-specific unstaging/restoring, ignore/pathspec diagnosis, or creating/switching refs.

12. Symptom → first evidence

Symptom First evidence Likely layer
“Nothing to commit” rev-parse --show-toplevel + status Repository/path
Too many staged files diff --staged --stat Index/pathspec
File missing from status check-ignore -v, ls-files Ignore/index
Case/mode-only diff diff --summary + config Filesystem/config
“Not on any branch” status --branch, symbolic-ref HEAD/ref

13. Knowledge check

Question 1. Git says “nothing to commit,” but your editor shows unsaved-looking changes. What do you verify before staging anything?

Question 2. You staged one secret file accidentally with a broad pathspec. What is the narrow first correction before any commit?

Question 3. Does detached HEAD mean the repository is damaged?

Question 4. Why can git diff release be misleading when both a branch and file are named release?

14. Summary

File-lifecycle failures are usually location, pathspec, index, ignore, filesystem, or HEAD/ref problems—not reasons to run destructive recovery commands. Preserve evidence, identify the affected layer, make the narrowest correction, and verify.

Next

Checkpoint the complete path state machine

Lesson 5 moves several files through untracked, ignored, staged, staged-plus-modified, committed, renamed, and deleted states while predicting status/diff output before every transition.

Authoritative references

 git-status
 git-restore
 git-switch
 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.