Chapter 1.6☕ 14 min read

git add -p — Partial Staging

Yeh Git ki sabse underrated command hai — ek baar seekho, phir kabhi git add . use nahi karoge.

01Hunks — Git Thinks in Chunks, Not Files

A hunk is a contiguous block of changes in a file — a section of added or removed lines surrounded by unchanged context lines.

Git does not think in files for staging — it thinks in hunks. This is the key insight that separates beginners from pros.

git add -p (or --patch) enters interactive mode where Git shows you one hunk at a time and asks: stage this?

This means ONE file can have its changes split across MULTIPLE commits. Bug fix and feature in the same file? Separate commits.

Without -p, you must stage the ENTIRE file. With -p, you stage only the specific changes you want.

If a hunk is too big, press s to split it into smaller hunks. If still too big, press e to manually edit the hunk in your editor.

# A file with 3 separate changes (3 hunks)
cat app.js
# line 1: const express = require("express");
# line 2: const app = express();
# line 3: console.log("DEBUG: starting");   ← DEBUG (skip this)
# line 4: app.listen(3000);
# line 5: // BUG FIX: handle null response   ← BUG FIX (commit this)
# line 6: if (user !== null) { authenticate(user); }
# line 7: // FEATURE: add analytics          ← FEATURE (separate commit)
# line 8: trackPageView();

# Without -p: all changes go in one commit
git add app.js   # stages DEBUG + BUG FIX + FEATURE together

# With -p: you choose which hunks to stage
git add -p app.js
# Git shows hunk 1 (DEBUG):    press n (skip)
# Git shows hunk 2 (BUG FIX):  press y (stage this)
# Git shows hunk 3 (FEATURE):  press n (skip)
# Now only the bug fix is staged!
Git thinks in hunks, not files. When you run git add -p, Git computes the diff between your working directory and the staging area, then breaks it into hunks — contiguous blocks of changes separated by unchanged context lines. Each hunk is presented to you one at a time. This is why one file can produce multiple commits — each hunk can go into a different commit.
02Interactive Commands — y/n/s/e/a/d/q

git add -p shows each hunk and waits for your command. Here are all the options:

  • y — yes, stage this hunk
  • n — no, skip this hunk
  • s — split the hunk into smaller pieces (if possible)
  • e — open editor to manually choose which lines to stage (most control)
  • q — quit; do not stage this hunk or any remaining hunks
  • a — stage this hunk AND all remaining hunks in this file (dangerous!)
  • d — skip this hunk AND all remaining hunks in this file
  • ? — show help

git add -p <filename> — patch a specific file. git add -p — patch all changed files.

The -p flag works with other commands too: git reset -p, git stash -p, git checkout -p.

# Start interactive patch mode
git add -p app.js

# Git shows:
# @@ -2,6 +2,8 @@
#  const express = require("express");
#  const app = express();
# +console.log("DEBUG: starting");    ← added line (green)
#  app.listen(3000);
# Stage this hunk [y,n,q,a,d,s,e,?]?

# Press y → stage it
# Press n → skip it
# Press s → split into smaller hunks
# Press e → open editor, manually delete lines you don't want

# After staging selected hunks:
git diff --staged   # shows only the staged hunks
git diff            # shows the remaining unstaged hunks

# Commit the carefully selected changes
git commit -m "fix: handle null user response"

# Stage the remaining feature hunk
git add -p app.js   # press y for the analytics hunk
git commit -m "feat: add page view analytics"
💡 Pro Tip: Most of the time you only need y, n, and s. The e option is for surgical precision when changes are mixed together on adjacent lines. Avoid a — it stages everything remaining, defeating the purpose of using -p in the first place.
03Real Use Cases for Partial Staging

Use case 1: Bug fix + debug code in the same file. Stage the fix, skip the console.logs.

Use case 2: Two features started in the same file. Stage one, commit, then stage the other. Separate commits for separate features.

Use case 3: Refactoring mixed with style changes. Stage the refactor (logic change) separately from formatting. Reviewers will thank you.

Use case 4: Accidental changes. IDE auto-format, trailing whitespace — skip the accidental changes, stage only the intentional ones.

Use case 5: WIP code mixed with a critical hotfix. Stage only the hotfix, leave WIP unstaged. Ship the fix now, finish the feature later.

Partial staging is how professionals maintain clean, logical commits despite messy working directories.

# Real scenario: mixed changes in auth.js
git diff auth.js
# +  console.log("DEBUG: checking auth");   ← debug, skip
# +  if (token && !isExpired(token)) {      ← bug fix, stage
# +    return validateSession(token);        ← bug fix, stage
# +  }                                       ← bug fix, stage
# +  sessionStorage.clear();                 ← refactor, maybe stage
# +  trackLogout();                          ← new feature, skip

# Use -p to separate concerns
git add -p auth.js
# Hunk 1 (DEBUG): press n
# Hunk 2 (bug fix): press y
# Hunk 3 (clear + feature): press e to edit
#   In editor: keep the sessionStorage.clear() line
#   Delete the trackLogout() line

git diff --staged
# Only shows the bug fix + sessionStorage.clear()

git commit -m "fix: validate token before auth and clear stale session"

# Stage the feature separately later
git add -p auth.js   # the trackLogout() is still there
git commit -m "feat: add logout tracking"
04Manual Editing — The e Command

Sometimes Git's automatic hunk boundaries are too coarse — two logical changes are grouped into one hunk.

Press s to split: Git breaks the hunk into smaller pieces at natural boundaries (unchanged lines between changes).

If s still isn't fine enough, press e to open your editor with the hunk displayed.

In the editor: lines starting with + will be staged. Lines starting with - will be removed from staging.

To NOT stage an added line: change the + to a space (keep the line but don't stage it), or delete the line entirely.

To NOT stage a removed line: change the - to a space (keep the line in the file, don't stage the removal).

Manual editing is the surgical tool — precise control over exactly which lines are staged.

# Git shows a hunk with mixed changes
# Stage this hunk [y,n,q,a,d,s,e,?]? s
# Sorry, cannot split this hunk further

# Time for manual editing
# Stage this hunk [y,n,q,a,d,s,e,?]? e

# Editor opens with:
# @@ -2,6 +2,8 @@
#  const app = express();
# +console.log("DEBUG");      ← want to SKIP this
# -// old auth check          ← want to KEEP this removal
# +if (token) {               ← want to STAGE this addition
# +  validate(token);         ← want to STAGE this addition
# +}

# To skip the console.log line:
# Option 1: Delete the line entirely
# Option 2: Replace + with a space
#  console.log("DEBUG");

# Save and close editor → only the selected lines are staged
💡 Common Mistake: When using e (manual edit), the most common error is leaving the + or - sign when you meant to remove it. Remember: + means "stage this addition", - means "stage this removal", space means "leave as is, don't stage". If you mess up, just close the editor without saving — Git will abort the patch for that hunk.
05The -p Family — add, reset, stash, checkout

-p isn't just for git add. It works with other commands too!

git reset -p: interactively UNSTAGE hunks. Made a mistake staging? Selectively unstage without resetting everything.

git stash -p: interactively choose which hunks to stash. Stash only the WIP code, keep the bug fix staged.

git checkout -p: interactively discard hunks from working directory. DANGEROUS but precise.

The interface is identical: y/n/s/e/a/d/q for all of them.

git reset -p is the "undo" of git add -p. Together they give you full control over the staging area.

# Oops, staged too much — selectively unstage
git reset -p app.js
# Git shows each staged hunk
# "Unstage this hunk [y,n,q,a,d,s,e,?]?"
# Press y to unstage, n to keep staged

# Stash only specific changes — leave the rest
git stash -p
# Git shows each hunk
# "Stash this hunk [y,n,q,a,d,s,e,?]?"
# Press y for WIP code, n for ready-to-commit code
# Only the selected hunks go into the stash

# Precisely discard unwanted changes
git checkout -p app.js
# "Discard this hunk from worktree [y,n,q,a,d,s,e,?]?"
# Press y for accidental changes (like IDE formatting)
# Press n for intentional changes
# WARNING: discarding is PERMANENT, no undo

# The -p flag family:
git add -p      # stage selectively
git reset -p    # unstage selectively
git stash -p    # stash selectively
git checkout -p # discard selectively
The -p flag is a family of commands. Once you learn the interface for git add -p, you already know how to use git reset -p, git stash -p, and git checkout -p. The y/n/s/e/a/d/q options are identical across all commands. Learn once, apply everywhere. This is why mastering -p is such a high-leverage investment.

Lo kar liya — Key Points:

  • ✅ A hunk is a contiguous block of changes — Git's unit of change for staging, not the entire file
  • ✅ git add -p enters interactive mode: Git shows each hunk and asks whether to stage it (y/n/s/e/a/d/q)
  • ✅ y = stage, n = skip, s = split into smaller hunks, e = manually edit which lines to stage
  • ✅ Partial staging lets you create clean, logical commits from messy working directories
  • ✅ git reset -p selectively unstages, git stash -p selectively stashes — same interface
  • ✅ Use case: separate bug fixes from debug code, features from refactoring, intentional from accidental changes
  • ✅ The e option gives surgical control — edit the hunk in your editor to stage exactly the lines you want
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase