The Git Lifecycle
Every file in a Git project moves through a small number of states. Knowing those states — and the commands that move files between them — is the day-to-day mental model. There are only four states and maybe a dozen commands; everything else builds on top.
The four states
Lifecycle of a file
┌─────────────┐ git add ┌─────────────┐ edit ┌─────────────────┐
│ Untracked │ ────────▶ │ Staged │ ─────▶ │ Staged & also │
│ │ │ │ │ modified again │
└─────────────┘ └─────────────┘ └─────────────────┘
│ git commit
▼
┌──────────────┐
│ Unmodified │ ◀── you just committed,
│ (tracked) │ or just ran git pull
└──────────────┘
│ edit
▼
┌──────────────┐ git add ┌──────────────┐
│ Modified │ ────────▶ │ Staged │
└──────────────┘ └──────────────┘
The four states explained
Untracked — the file exists in your working directory but Git has never been told to track it. New files start here.
Unmodified — tracked by Git, identical to the last committed version. The boring, default state of most files most of the time.
Modified — tracked by Git, but you have changed it since the last commit. Not yet staged.
Staged — you have run
git addon the modified version. Git will include it in the next commit.
The everyday loop
The five commands you'll use every day
# 1. See where things stand git status # 2. Look at exactly what changed git diff # unstaged changes git diff --staged # staged changes # 3. Stage selected changes git add path/to/file git add . # stage everything # 4. Commit the staged snapshot git commit -m "Short description of the change" # 5. (Optional) share with the team git push
A more visual walkthrough
From new file to pushed commit
# Start: clean working tree git status # nothing to commit, working tree clean # Add a new file echo "<h1>Hello</h1>" > index.html git status # Untracked files: # index.html # Stage it git add index.html git status # Changes to be committed: # new file: index.html # Now also modify the file BEFORE committing echo "<p>World</p>" >> index.html git status # Changes to be committed: ← from the original 'git add' # new file: index.html # Changes not staged for commit: ← the extra edit # modified: index.html # Stage the new edits, then commit git add index.html git commit -m "Add hello world page" git status # nothing to commit, working tree clean # Share with team git push
How status reports each state
Status output decoded
On branch main Your branch is ahead of 'origin/main' by 1 commit. ← local has unpushed commits Changes to be committed: ← STAGED modified: src/app.js new file: src/utils.js Changes not staged for commit: ← MODIFIED modified: src/app.js (same file appears in both!) Untracked files: ← UNTRACKED notes.md
The same file (src/app.js) appears twice because part of it is staged and part is not. That is the “staged and modified” state.
Branching and the lifecycle
Branches live on top of the lifecycle. When you git switch -c feature-x, you create a new branch pointer — but the working tree, index, and file states do not change. You can keep editing as before; the next commit just lands on feature-x instead of main.
The bigger team loop
Daily team rhythm
git pull ← bring others' work down
│
▼
create or switch to a branch
│
▼
edit → git add → git commit (repeat as needed)
│
▼
git push ← share your branch
│
▼
open a Pull Request, get review
│
▼
merge into main
│
▼
git pull ← everyone syncs
Where common mistakes happen
Forgetting to
git addbeforegit commit— Git commits only what is staged. New edits since the lastgit addare not in the commit.Committing too much at once — small, focused commits are easier to review and undo. Use
git add -pto stage parts of a file.Editing on the wrong branch —
git statusalways tells you the current branch on its first line. Glance at it before you start.Forgetting to push — your commits are local until you push. They are invisible to teammates and not backed up off your machine.
git status after every single action for the first week. It teaches you which state every file is in, and you stop guessing.