Everyday Git
Topic 06

Staging and Committing

Core

Recording work in Git is a two-step loop: git add selects changes into the index, and git commit writes them as a permanent snapshot with a message. The split feels like a chore at first, but the staging step is exactly what lets you turn a messy working tree into a series of clean, reviewable commits.

The commit is the unit everything downstream depends on — git log, code review, git revert, and git bisect all operate on commits. A commit that bundles three unrelated changes cannot be reverted surgically or reviewed cleanly, so the discipline you apply at this step is what makes the history worth reading later.

The Add-Then-Commit Loop

git add <paths> copies the current content of those paths into the index; git commit then writes whatever is in the index as a new commit and advances the branch. The two steps are separate because the index is a real layer you build up deliberately — you can stage some changes, leave others alone, and commit only the coherent subset, instead of being forced to commit the whole working tree at once.

Partial Staging

git add -p walks you through each changed hunk and asks whether to stage it. This is the lever that turns one chaotic afternoon of edits into separate commits: stage the hunks belonging to the bug fix, commit, then stage the refactor hunks and commit those separately. The result is a history where each commit is one logical change, which is what makes review and a later git revert precise rather than all-or-nothing.

Writing Commit Messages

A good message is a summary line under about 50 characters, a blank line, then a body that explains why the change exists — the diff already shows what changed. Future-you reading git log or git blame needs the reasoning, not a restatement of the patch. Conventions like Conventional Commits (fix:, feat:) add machine-readable structure on top, useful for generating changelogs, but the body explaining intent is the part that pays off.

Amending the Last Commit

git commit --amend replaces the most recent commit — to fix a typo in the message or add a file you forgot to stage. It does not edit the commit in place; it creates a new commit with a new hash and moves the branch to it. That is why it is safe only before pushing: once others have pulled the original commit, amending rewrites history they already have, and their next pull diverges.

Shortcuts and Their Traps

git commit -a auto-stages modified tracked files and commits in one step. The trap is in the word "tracked": it does nothing for new, untracked files, so a brand-new file is silently left out of the commit. It also skips the staging review the index gives you, so you lose the chance to confirm exactly what is going in. Convenient for a quick edit to known files, dangerous as a reflex.

Common Mistakes
  • Reaching for git commit -am reflexively, which skips staging review and never includes new untracked files, so a just-created file is left out and the build breaks on the remote.
  • Writing one-word messages like "fix" or "wip", which makes git log useless for ever finding when and why a change happened.
  • Running git commit --amend on a commit already pushed to a shared branch, rewriting history others have pulled and forcing them into divergence conflicts.
  • Bundling unrelated changes into one large commit, so git revert cannot undo just one of them and review has to untangle them by hand.
  • Forgetting to git add a new file and committing only the tracked edits, leaving the remote build broken because a referenced file is missing.
Best Practices
  • Stage deliberately with git add -p and confirm with git status so each commit is one coherent change.
  • Write a summary under 50 characters in imperative mood, plus a body explaining why rather than what.
  • Use git commit --amend only to fix the most recent commit before it has been pushed.
  • Commit small and often, since a series of focused commits reverts and reviews far better than one large one.
  • Run git diff --staged immediately before committing to see exactly what will be recorded.
Comparable toolsMercurial hg commit commits the working copy directly; hg commit --amend matches GitSubversion svn commit sends the working copy with no stagingPerforce submits a changelist of grouped filesFossil fossil commit records the checkout

Knowledge Check

You created a new file, edited an existing tracked file, then ran git commit -am "update". What gets committed?

  • Only the tracked file's edit — -a stages modified tracked files but ignores new untracked ones
  • Both files, since the -a flag automatically stages everything currently present in the whole working tree
  • Only the brand-new file, because untracked files take priority during a commit
  • Nothing at all — Git refuses -a outright when any untracked file is present

Why is git commit --amend safe locally but a problem after pushing to a shared branch?

  • Amend creates a new commit with a new hash; once others have the original, replacing it makes their history diverge
  • Amend deletes the entire remote branch on the server and recreates it from scratch, silently dropping everyone's unpushed work
  • Amend only edits the commit message text, which the server rejects outright after a push
  • It is equally safe in both of these cases; the warning about it is purely cosmetic

What does the separate staging step buy you that committing the whole working tree at once does not?

  • The ability to select exactly which changes — even individual hunks via git add -p — go into each commit
  • Noticeably faster commits overall, because the staged index is held cached entirely in memory for quick writes
  • Automatic conflict resolution against the remote branch as you stage each file
  • A durable backup of the working tree that survives even a git reset --hard

Why does commit granularity matter for git revert and review months later?

  • A focused commit can be reverted on its own and reviewed in isolation; a commit bundling unrelated changes cannot be undone surgically
  • Smaller, single-purpose commits compress noticeably better than large ones, which steadily reduces the overall repository size on disk over time
  • Git refuses to revert any commit larger than a configured maximum number of changed lines
  • Granularity only affects how fast git log renders its output, not any actual behavior

You got correct