Git - Adding & Staging

Beginner

The staging area (also called the "index") is Git's unique feature that lets you carefully choose which changes to include in your next commit. Mastering git add and staging gives you precise control over your project history.

Understanding the Staging Area

Think of the staging area as a "loading dock" where you prepare changes before committing them:

Working Directory → Staging Area → Repository
    (modified)         (staged)      (committed)
        ↓                 ↓             ↓
    [file.txt]     [file.txt ready]  [file.txt saved]
                   [for commit]       [permanently]

This three-step process lets you:

  • Review changes before committing
  • Commit only related changes together
  • Skip temporary or experimental changes
  • Create clean, logical commits

Basic git add Commands

Adding Specific Files

# Add single file
git add README.md

# Add multiple files
git add file1.txt file2.txt file3.txt

# Add files with wildcards
git add *.js          # All JavaScript files
git add src/*.py      # All Python files in src/
git add docs/**/*.md  # All Markdown files in docs/ and subdirectories

Adding Directories

# Add entire directory
git add src/

# Add multiple directories
git add src/ tests/ docs/

Adding All Changes

# Add all changes in current directory and subdirectories
git add .

# Add all changes in entire repository (from any location)
git add -A
# or
git add --all

# Add only tracked files (skip new files)
git add -u
# or
git add --update

Practical Staging Examples

Let's work through realistic scenarios:

Scenario 1: Web Development Project

Create example files:
mkdir web-project && cd web-project
git init

# Create files
echo "# My Website" > README.md
echo "Home

Welcome

" > index.html echo "body { font-family: Arial; }" > style.css echo "console.log('Hello World!');" > script.js echo "Temporary notes..." > temp.txt
Check status:
git status
Expected Output:
On branch main

No commits yet

Untracked files:
  (use "git add ..." to include in what will be committed)
	README.md
	index.html
	script.js
	style.css
	temp.txt

nothing added to commit but untracked files present (use "git add" to track)
Stage only web files (skip temp.txt):
git add README.md index.html style.css script.js
Check what's staged:
git status
Expected Output:
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached ..." to unstage)
	new file:   README.md
	new file:   index.html
	new file:   script.js
	new file:   style.css

Untracked files:
  (use "git add ..." to include in what will be committed)
	temp.txt

Scenario 2: Selective Changes

Make multiple types of changes:
# Modify existing file
echo "

New paragraph

" >> index.html # Create new feature file echo "function newFeature() { return 'awesome'; }" > feature.js # Create configuration file echo "DEBUG=true" > config.env # Modify CSS echo "h1 { color: blue; }" >> style.css
Check status:
git status
Expected Output:
On branch main
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git restore ..." to discard changes to working directory)
	modified:   index.html
	modified:   style.css

Untracked files:
  (use "git add ..." to include in what will be committed)
	config.env
	feature.js
	temp.txt

no changes added to commit (use "git add" or "git commit -a")
Stage only the feature-related changes:
git add feature.js index.html

Now you can commit the feature separately from the CSS styling changes.

Advanced Staging Techniques

Interactive Staging

For even more control, use interactive mode:

git add -i
Interactive menu:
           staged     unstaged path
  1:        +4/-0      nothing index.html
  2:    unchanged        +1/-0 style.css

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now>

Patch Mode (Partial File Staging)

Stage only parts of a file:

git add -p filename
Example: File with multiple changes
echo "function oldFunction() { return 'old'; }" > functions.js
echo "function newFunction() { return 'new'; }" >> functions.js
echo "function buggyFunction() { return 'bugs'; }" >> functions.js
git add functions.js
git commit -m "Add function definitions"

# Now modify the file
sed -i '' 's/old/updated/' functions.js
sed -i '' 's/bugs/fixed/' functions.js
Stage changes selectively:
git add -p functions.js
Interactive prompt:
@@ -1,3 +1,3 @@
-function oldFunction() { return 'old'; }
+function oldFunction() { return 'updated'; }
 function newFunction() { return 'new'; }
 function buggyFunction() { return 'bugs'; }
(1/1) Stage this hunk [y,n,q,a,d,e,?]?

Patch mode commands:

  • y - Yes, stage this hunk
  • n - No, don't stage this hunk
  • q - Quit, don't stage this or remaining hunks
  • a - Stage this and all remaining hunks
  • d - Don't stage this or remaining hunks
  • s - Split this hunk into smaller ones
  • e - Edit the hunk manually

Working with .gitignore

Some files should never be tracked. Use .gitignore to exclude them:

Create .gitignore file:
# Operating system files
.DS_Store
Thumbs.db

# IDE and editor files
.vscode/
.idea/
*.swp
*.swo

# Language-specific
node_modules/
*.pyc
__pycache__/
target/
*.class

# Build outputs
dist/
build/
*.o
*.exe

# Logs and databases
*.log
*.db
*.sqlite

# Environment and secrets
.env
.env.local
config/secrets.json
*.key
Test .gitignore:
# Create ignored files
touch .DS_Store
mkdir node_modules
touch debug.log

# Check status - these files won't show up
git status

Global .gitignore

Set up patterns for all your repositories:

# Create global gitignore
echo ".DS_Store" > ~/.gitignore_global
echo "*.swp" >> ~/.gitignore_global

# Configure Git to use it
git config --global core.excludesfile ~/.gitignore_global

Forcing Ignored Files

Sometimes you need to track normally-ignored files:

# Force add ignored file
git add -f debug.log

# Check what's ignored
git check-ignore -v debug.log

Unstaging Files

Made a mistake? Remove files from staging area:

Unstage specific file:
git restore --staged filename
Unstage all files (Git 2.23+):
git restore --staged .
Older Git versions:
# Unstage specific file
git reset HEAD filename

# Unstage all files
git reset HEAD

Viewing Staged Changes

See What's Staged

# Show staged changes
git diff --staged
# or
git diff --cached

See What's Not Staged

# Show unstaged changes
git diff

Compare Working, Staged, and Committed

# Working vs staged
git diff

# Staged vs last commit
git diff --staged

# Working vs last commit (skip staging)
git diff HEAD

Staging Strategies

Feature-Based Staging

# Work on multiple features
# Feature A: User login
git add auth.js login.html
git commit -m "Add user login feature"

# Feature B: Dashboard
git add dashboard.js dashboard.html dashboard.css
git commit -m "Add user dashboard"

File-Type Staging

# Stage by file type
git add *.html          # HTML first
git commit -m "Update HTML structure"

git add *.css           # Then CSS
git commit -m "Improve styling"

git add *.js            # Finally JavaScript
git commit -m "Add interactive features"

Common Staging Patterns

The "Add Everything" Anti-Pattern

❌ Don't do this:
git add .
git commit -m "stuff"
This creates messy commits with unrelated changes.
✅ Better approach:
git add src/user-auth.js tests/auth.test.js
git commit -m "Add user authentication with tests"

git add src/styles.css
git commit -m "Update button styling for accessibility"

Review Before Staging

Good workflow:
# 1. See what changed
git status
git diff

# 2. Stage thoughtfully
git add specific-files

# 3. Review staged changes
git diff --staged

# 4. Commit with good message
git commit -m "Descriptive message"

Troubleshooting Staging

File Not Staging

Check if file is ignored:
git check-ignore -v filename

Unexpected Files in Status

See ignored files:
git status --ignored

Staging Area Corruption

Reset staging area:
git reset

Performance Tips

Large Repositories

# Use pathspecs for large repos
git add src/components/    # Instead of git add .

# Skip expensive operations
git add --ignore-removal .  # Don't check for deleted files

Summary

You now understand Git staging:

  • ✅ The staging area acts as a preparation zone for commits
  • git add has many variations for different needs
  • ✅ Interactive staging with -p allows partial file commits
  • .gitignore prevents unwanted files from being tracked
  • git restore --staged unstages files
  • ✅ Always review staged changes before committing
  • ✅ Strategic staging creates cleaner project history

Next Steps

Now that you can stage changes precisely, let's learn about creating great commits:

Git - Committing

Practice Tip: Create a practice repository and experiment with different staging patterns. Try interactive staging on files with multiple changes.