The Three States: Working, Staging, and Committed
Introduction
Understanding Git's three-state workflow is fundamental to mastering version control. Unlike simpler systems where you just "save" your work, Git gives you precise control over what gets saved and when. This might seem complicated at first, but it's actually one of Git's most powerful features.
This lesson will help you understand how files move through Git's workflow and why this multi-stage approach makes you a more effective developer.
The Three States Explained
Every file in your Git repository can exist in one of three states:
Modified (Working Directory) - You've changed the file, but haven't told Git you want to save those changes yet. The file exists in your working directory with unsaved modifications.
Staged (Staging Area/Index) - You've marked the modified file to be included in your next commit. Think of this as adding items to a shopping cart before checkout.
Committed (Repository) - The changes are safely stored in your Git repository's database. This is like completing the purchase—the transaction is final and recorded.
Visualizing the Workflow
Imagine you're a photographer managing photos:
Working Directory = Your camera's memory card with new photos Staging Area = A selection table where you choose which photos to publish Repository = Your published photo album
You take many photos (modify files), select the best ones for your album (stage files), then publish that curated collection (commit). You wouldn't publish every single photo you take—you carefully choose what goes into each album. Git works the same way.
The Working Directory
The working directory is simply your project folder—the files and folders you see and edit normally. When you modify a file here, Git notices but doesn't automatically do anything with that change.
Example Scenario:
You're building a website. You edit index.html to add a new navigation menu. At this point, the file is modified in your working directory. Git sees the change but hasn't captured it in history yet.
Check what's modified:
git status
Output might show:
On branch main
Changes not staged for commit:
modified: index.html
The file is modified but not staged. If your computer crashes right now, you'd lose those changes because they're only in your working directory—not yet protected by Git.
The Staging Area
The staging area (also called the "index") is Git's unique feature. It's a holding area where you prepare your next commit. This intermediate step gives you control over exactly what goes into each commit.
Why Have a Staging Area?
Imagine you're working on two different features: fixing a bug and adding a new feature. You've modified five files, but three relate to the bug fix and two to the new feature. The staging area lets you commit these separately, keeping your project history clean and logical.
Without staging, you'd have to commit everything at once, creating messy commits that mix unrelated changes.
Using git add
The git add command moves changes from the working directory to the staging area.
Stage a Single File:
git add index.html
Stage Multiple Specific Files:
git add index.html styles.css
Stage All Changed Files:
git add .
The dot (.) means "everything in the current directory and subdirectories."
Stage All Files of a Certain Type:
git add *.js
This stages all JavaScript files.
Stage Files Interactively:
git add -p
This shows you each change and asks if you want to stage it, giving you fine-grained control.
After staging, check status again:
git status
Output shows:
On branch main
Changes to be committed:
modified: index.html
The file is now staged and ready to commit. It's in your shopping cart, waiting for checkout.
The Repository (Committed State)
When you commit, Git takes everything in the staging area and creates a permanent snapshot in the repository. This snapshot gets a unique ID and becomes part of your project's history forever.
Using git commit
Basic Commit:
git commit -m "Add navigation menu to homepage"
The -m flag lets you include a message directly in the command. The message should briefly describe what changed and why.
Commit with Detailed Message:
If you need to write a longer message, omit the -m flag:
git commit
Git opens your configured text editor where you can write:
Add navigation menu to homepage
- Created responsive navigation bar
- Added links to all main sections
- Implemented mobile hamburger menu
- Fixed header positioning issues
The first line is the summary (50 characters or less), followed by a blank line, then detailed explanation if needed.
Staging and Committing in One Step:
For files already tracked by Git, you can skip staging:
git commit -am "Update contact page"
The -a flag automatically stages all modified tracked files before committing. Be careful with this—it's easy to accidentally commit changes you didn't intend to.
Note: This shortcut only works for files Git is already tracking. New files must be explicitly added with git add.
Complete Workflow Example
Let's walk through a complete example building a simple website:
Step 1: Check Status
git status
Output shows you're on the main branch with a clean working directory—no changes.
Step 2: Create New Files
echo "Welcome to my site" > index.html
echo "body { margin: 0; }" > styles.css
You've created two files in your working directory.
Step 3: Check Status Again
git status
Output shows:
Untracked files:
index.html
styles.css
These files exist but Git isn't watching them yet. They're in the working directory but not staged or committed.
Step 4: Stage the HTML File
git add index.html
Step 5: Check Status
git status
Output shows:
Changes to be committed:
new file: index.html
Untracked files:
styles.css
Only index.html is staged. The CSS file is still untracked.
Step 6: Commit the HTML
git commit -m "Add homepage structure"
Git creates a commit containing only index.html. This commit is now permanently in your repository's history.
Step 7: Stage and Commit the CSS
git add styles.css
git commit -m "Add basic CSS styling"
Now you have two separate commits, each focused on one aspect of the work. This makes your history clear and meaningful.
Understanding File States
At any moment, your files can be in various states. Let's clarify each:
Untracked - Git doesn't know about the file. It exists in your working directory but has never been staged or committed. New files start as untracked.
Unmodified - The file is tracked by Git and hasn't changed since the last commit. Git has no work to do with this file.
Modified - The file has changed since the last commit but hasn't been staged. Changes exist only in your working directory.
Staged - The file's changes are marked for inclusion in the next commit. The file is in the staging area.
The Lifecycle
Here's how files typically move through states:
- Create a new file → Untracked
- Run
git add→ Staged (new file) - Run
git commit→ Unmodified (committed) - Edit the file → Modified
- Run
git add→ Staged - Run
git commit→ Unmodified (committed)
This cycle repeats throughout your project's development.
Unstaging Files
What if you stage something by mistake? You can unstage it without losing your changes.
Unstage a Specific File:
git restore --staged index.html
This moves the file back to the working directory (modified but not staged). Your changes remain intact.
Unstage Everything:
git restore --staged .
Older Git Versions:
If you have an older Git version, the command might be:
git reset HEAD index.html
Git's status message usually tells you which command to use for your version.
Discarding Changes
Be careful with this section—these operations can permanently delete your work.
Discard Changes in Working Directory:
git restore index.html
This reverts the file to how it looked in the last commit. Your modifications are permanently lost.
Discard All Changes:
git restore .
This reverts all modified files to their last committed state. Again, this is permanent—you cannot recover discarded changes.
Always double-check before discarding changes. When in doubt, commit or stash your work first.
Viewing Changes
Before staging or committing, it's wise to review what changed.
View Unstaged Changes:
git diff
This shows line-by-line differences between your working directory and the last commit. Red lines were removed, green lines were added.
View Staged Changes:
git diff --staged
This shows what's in the staging area—changes that will go into the next commit.
View Specific File:
git diff index.html
These commands help you understand exactly what you're about to commit.
Why This Workflow Matters
The three-state workflow provides critical benefits:
Selective Commits
You can work on multiple features simultaneously but commit them separately, keeping your history clean and logical.
Review Before Committing
Staging forces you to review changes before committing. You might catch mistakes or realize you want to split changes into multiple commits.
Flexibility
You can stage some changes, continue working, then commit what you staged without committing your newer work. This flexibility is invaluable for complex projects.
Safety Net
Uncommitted changes are vulnerable. The staging and committing process ensures your work is protected in Git's database.
Common Patterns
Pattern 1: Feature Development
# Make changes to multiple files
git add feature-related-file1.js
git add feature-related-file2.js
git commit -m "Implement user authentication"
# Continue working on other changes without committing them yet
Pattern 2: Bug Fix
# Fix a bug
git add buggy-file.js
git commit -m "Fix null pointer exception in login"
# Other modified files remain uncommitted
Pattern 3: Checkpoint Commits
# After finishing a logical chunk of work
git add .
git commit -m "Complete navigation component"
# Creates a safe restore point
Best Practices
Commit Often
Small, frequent commits are better than large, infrequent ones. Each commit should represent one logical change.
Review Before Staging
Use git diff to review your changes before running git add. Catch errors early.
Stage Selectively
Don't just run git add . blindly. Think about what belongs together in a commit.
Write Good Commit Messages
Your future self will thank you. Describe what changed and why, not how (the code shows how).
Don't Commit Half-Broken Code
Each commit should leave the project in a working state when possible. This makes debugging with git bisect easier later.
Use .gitignore
Don't stage files that shouldn't be tracked (build artifacts, dependencies, environment files). Use .gitignore to automatically exclude them.
Troubleshooting Common Issues
Accidentally Staged the Wrong File
Use git restore --staged filename to unstage it.
Made a Commit Too Early
You can amend the last commit:
git commit --amend -m "Updated commit message"
Or add forgotten changes:
git add forgotten-file.js
git commit --amend --no-edit
Want to See What's Staged
Use git diff --staged to review staged changes before committing.
Confused About File States
Run git status frequently. It's your dashboard showing where everything is.
Visualizing with git status
The git status command is your best friend. It clearly shows which state each file is in:
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: index.html
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes)
modified: styles.css
Untracked files:
(use "git add <file>..." to include in what will be committed)
script.js
This output tells you:
index.htmlis staged (ready to commit)styles.cssis modified but not stagedscript.jsis untracked (new file)
Git even suggests the commands to use next. Always read the status output carefully.
Summary
The three-state workflow—working directory, staging area, and repository—gives you precise control over your project's history. While it adds an extra step compared to simple "save" operations, this staging area is what makes Git powerful and flexible.
Understanding these states transforms you from someone who just uses Git to someone who leverages it effectively. You can now craft meaningful commits, separate concerns, and maintain a clean project history that tells the story of your development journey.
In the next lesson, we'll explore viewing your commit history, navigating through past snapshots, and understanding the timeline of your project's evolution. The commits you create using this three-state workflow become the foundation of that history.