← Back to list

The Complete Guide to git add: From Staging Your First File to Mastering Patch Mode (The…

Everything you need to know about the command that prepares your changes for a commit, explained in plain English with real-world…

Eloquent Coder · 2026-05-23 10:36 · 0 claps · 32.9 min read
#git #github #git-commands #version-control #version-control-system
Open on Medium ↗
Wiki topics: 🔓 · Open Source 🥊 · Combat Sports

The Complete Guide to git add: From Staging Your First File to Mastering Patch Mode (The human-readable manual: git add)

Everything you need to know about the command that prepares your changes for a commit, explained in plain English with real-world scenarios, visual diagrams, and honest talk about the mistakes everyone makes.

A deep-dive tutorial covering Beginner, Intermediate, and Advanced usage, all options from the official Git manual

**inter-git.com** is an interactive Git tutorial where each command is shown visually so you can see exactly how it works in real time. It runs entirely in your browser, so there is nothing to install.

Table of Contents

  1. Introduction: Why git add Is the Heart of Every Commit
  2. Level 1: Beginner 2.1 The staging area: Git’s secret middle layer 2.2 The three zones every Git user must understand 2.3 git add <file>: staging a specific file 2.4 git add .: stage everything in the current directory 2.5 How to check what you have staged 2.6 Your first complete workflow with git add 2.7 Staging multiple files at once 2.8 Beginner pitfalls
  3. Level 2: Intermediate 3.1 git add -A: stage all changes across the entire repo 3.2 git add -u: stage only tracked file changes 3.3 git add -n: dry run before you stage 3.4 git add <dir>/: staging a whole directory 3.5 Glob patterns: staging by file type 3.6 git add -f: staging ignored files 3.7 git add -N: intent to add 3.8 Comparing -A, dot, and -u side by side 3.9 Intermediate pitfalls
  4. Level 3: Advanced 4.1 git add -p: the patch mode that changes everything 4.2 Every patch mode key explained 4.3 Splitting and editing hunks manually 4.4 git add -i: the full interactive mode 4.5 git add -e: editing a patch directly 4.6 git add — chmod: setting the executable bit 4.7 git add — renormalize: fixing line ending disasters 4.8 git add — pathspec-from-file: staging from a list 4.9 git add — sparse: working with sparse checkouts 4.10 — ignore-errors, — refresh, — ignore-missing 4.11 — unified and — inter-hunk-context 4.12 Configuration: add.ignoreErrors and interactive.singleKey 4.13 Real-world advanced workflows 4.14 Advanced pitfalls
  5. Quick Reference Card
  6. Conclusion

Introduction: Why git add Is the Heart of Every Commit

You have probably typed git add . a hundred times without thinking too hard about what it actually does. Most developers learn it as a ritual, the thing you type before git commit. But git add is far more than a formality. It is the command that gives you something no other version control system offered when Git was invented: the ability to decide, with surgical precision, exactly what goes into your next snapshot of the code.

Think about this for a moment. You have been working for three hours. You fixed a bug in the payment module, added a new feature to the user profile page, and also tweaked some whitespace in a completely unrelated file. With older version control systems, you would commit everything together or nothing at all. With Git’s staging area, you can choose to commit only the bug fix right now, give it a clear and specific commit message, and deal with the feature later. That discipline is what makes a project’s history readable six months down the road.

This guide covers every single option in the official git add manual, organized into three levels so that whether you are brand new to Git or an experienced developer who wants to understand patch mode properly, you will find exactly what you need. Each option is explained the way a senior developer would explain it to a junior colleague: plain English, real examples, and honest warnings about what trips people up.

Level 1 Beginner: Understanding git add From the Ground Up

The Staging Area: Git’s Secret Middle Layer

Before you can understand git add, you need to understand the concept it operates on. Git has a layer that most developers either do not know about or do not fully appreciate: the staging area, also called the index.

Here is a simple analogy. Imagine you are packing a suitcase for a trip. Your bedroom floor (the working directory) has clothes scattered everywhere. You want to pack some of them, but not everything you own. So you pick up certain items, inspect them, and set them on your bed (the staging area). Once you are happy with the selection on the bed, you zip everything up and the suitcase is ready (you make a commit). The suitcase represents a permanent snapshot: a commit in your repository’s history.

The staging area is that pile on the bed. It is a draft of your next commit. You can add things to it, remove things from it, and inspect it. Nothing becomes permanent until you actually run git commit.

Figure 1: Git’s three zones. Changes travel from Working Directory to Staging Area with git add, and from Staging Area to permanent history with git commit. Only staged changes go into a commit.

Figure 1: Git’s three zones. Changes travel from Working Directory to Staging Area with git add, and from Staging Area to permanent history with git commit. Only staged changes go into a commit.

The Three Zones Every Git User Must Understand

Zone 1: The Working Directory. This is the folder on your computer where your project lives. Every file you open in your editor, every file you create or delete, exists in the working directory. Git knows about this zone but does not automatically record changes here. It just watches.

Zone 2: The Staging Area (the Index). This is Git’s draft area. When you run git add, you are copying the current state of a file from your working directory into the staging area. The staging area holds a precise snapshot of what you want to include in your next commit. You can add files, add just part of a file, or remove things from the staging area, all without touching your actual files on disk.

Zone 3: The Repository. This is the .git folder inside your project. It stores every commit you have ever made, every branch, every tag. When you run git commit, Git takes everything in the staging area and wraps it up as a permanent, immutable object in the repository. This commit will exist forever unless you deliberately rewrite history.

The key insight is this: git add does not save your work permanently. It only promotes changes to the staging area. Nothing is permanent until git commit runs. This means you can think of staging as a way to compose and review your commit before it is set in stone.

Why does the staging area exist? Linus Torvalds designed the staging area deliberately. He wanted developers to craft commits that tell a coherent story, not just “everything I changed today.” A well-crafted commit history is like a well-written series of journal entries: each one focused, clear, and meaningful. The staging area is the tool that makes that possible.

git add <file>: Staging a Specific File

git add <file>

Takes the current state of one specific file in your working directory and copies it into the staging area. The file is now “staged” and will be included in the next commit. If you modify the file again after running git add, those new modifications are NOT automatically staged: you need to run git add again to update the staged version.

# Stage a single file
git add app.js

# Stage a file in a subdirectory
git add src/components/Button.js

# Stage a file with spaces in its name
git add "my file with spaces.txt"

After you run git add app.js, Git reads the file from your working directory and takes a snapshot of it, storing that snapshot in the staging area. The file in your working directory is untouched. You can continue editing it. But the version in the staging area is frozen at the moment you ran git add.

Common Beginner Trap: Editing After Staging You stage a file with git add app.js. Then you keep coding and make more changes to app.js. When you run git commit, only the version you staged earlier will be committed, not the latest version. Your newer edits are still only in the working directory. Run git add app.js again to update the staging area with your latest changes before committing.

git status

# Changes to be committed:
#         modified:   src/auth/login.js    <-- the version you staged

# Changes not staged for commit:
#         modified:   src/auth/login.js    <-- newer edits on disk

The same file appearing twice is not a bug. It means the version in the staging area is older than the version on disk. Run git add src/auth/login.js again to update the staged version.

git add .: Stage Everything in the Current Directory

git add .

The dot (.) is a special pathspec meaning “the current directory and everything inside it recursively.” This stages all new files, all modifications to tracked files, and all deletions in the current directory and every subdirectory under it. It does NOT stage files in parent directories above where you currently are.

# Stage everything in and under the current directory
git add .

# If you navigate into a subdirectory first, only that subtree is staged
cd src/components
git add .
# Only stages changes inside src/components/ and below

Dot Is Location-Aware The behaviour of git add . depends entirely on where your terminal is. If you are in the project root, it stages the whole project. If you have navigated into a subfolder, it only stages changes in that subfolder. This location-awareness is a feature, not a bug: it lets you stage a focused subset of changes without naming each file.

How to Check What You Have Staged

Develop the habit of running git status before and after every git add. It shows a clear picture of which zone each file is in.

# Check the current state of all your files
git status

# Changes to be committed:           <-- STAGING AREA
#   new file:   feature.js
#   modified:   app.js

# Changes not staged for commit:     <-- WORKING DIRECTORY (tracked)
#   modified:   config.json

# Untracked files:                   <-- WORKING DIRECTORY (new)
#   notes.txt

For a more compact view, use the short form:

git status -s

# M  app.js        <-- green M in left column = staged modification
#  M config.json   <-- red M in right column = unstaged modification
# A  feature.js    <-- A = new file, staged
# ?? notes.txt     <-- ?? = untracked file

Figure 2: A file cycles through four states as you work. Untracked files become Staged after git add. Staged changes become Committed after git commit. Editing a committed file puts it in Modified. Running git add again on a modified file brings it back to Staged.

Figure 2: A file cycles through four states as you work. Untracked files become Staged after git add. Staged changes become Committed after git commit. Editing a committed file puts it in Modified. Running git add again on a modified file brings it back to Staged.

Your First Complete Workflow with git add

Let us walk through a complete real-world example. You have been asked to fix a typo in the homepage text of a web project. Here is the whole process from start to finish:

# Step 1: Check what has changed
git status
# Changes not staged for commit:
#         modified:   index.html

# Step 2: Review the actual changes before staging
git diff index.html
# -  <h1>Wellcome to our site</h1>
# +  <h1>Welcome to our site</h1>

# Step 3: Stage the file
git add index.html

# Step 4: Confirm it is staged correctly
git status
# Changes to be committed:
#         modified:   index.html

# Step 5: Make the permanent commit
git commit -m "fix: correct typo in homepage heading"

# Done. The log now shows your focused commit
git log --oneline -1
# a4c23f1 fix: correct typo in homepage heading

That is the heartbeat of all Git work. Edit, add, commit. Edit, add, commit. Every professional Git workflow, no matter how complex, is built on top of this three-step cycle.

Figure 3: The three-step development loop. Edit files, stage the changes you want to include, commit the staged snapshot. Repeat indefinitely.

Figure 3: The three-step development loop. Edit files, stage the changes you want to include, commit the staged snapshot. Repeat indefinitely.

Staging Multiple Files at Once

You can pass as many filenames to git add as you like, separated by spaces:

# Stage two specific files
git add login.js logout.js

# Stage three files across different directories
git add src/auth.js src/user.js tests/auth.test.js

# Stage all HTML files in the current directory (shell expands unquoted glob)
git add *.html

# Stage all JS files recursively through the whole repo (Git expands quoted glob)
git add "*.js"

Quoting the glob pattern tells the shell not to expand it, letting Git do the glob matching itself across the entire repo. Without quotes, your shell expands the glob first, which only covers the current directory.

Real-World Scenario Your team’s convention is to commit related changes together. You have refactored the authentication system touching three files, plus edited the README separately. Stage only the auth-related files first:

git add src/auth/login.js src/auth/logout.js tests/auth.test.js
git commit -m "refactor: modernize authentication module"

git add README.md
git commit -m "docs: update auth setup instructions"

Two focused commits tell a much clearer story than one big “misc changes” commit. When someone runs git blame six months later to understand a line of code, they will find a meaningful explanation waiting in the commit message.

Beginner Pitfalls

Pitfall 1: Forgetting to Stage Before Committing You make changes to several files, then run git commit -m "my changes" without running git add first. Git will either complain "nothing to commit" or commit only what was previously staged. Always run git status before committing to confirm you are staging exactly what you intend.

Pitfall 2: Staging Files You Did Not Mean to Stage You run git add . in a hurry and accidentally stage a config file, a large binary, or some debugging code. To unstage a file, run git restore --staged <file> (Git 2.23+) or git reset HEAD <file>. The file stays in your working directory, it is just removed from the staging area.

Pitfall 3: Accidentally Staging Secrets One of the most common real-world mistakes: a developer runs git add . and stages a .env file full of API keys. If you catch it before committing and run git restore --staged .env, you are safe. But once you commit and push it, the secret is in the repository history and must be treated as compromised. Always set up a .gitignore file early in every project to exclude .env, *.key, and similar files.

Pitfall 4: Assuming git add . Stages the Entire Repository If your terminal is inside a subdirectory like src/components/, running git add . only stages changes inside that subdirectory. Changes in sibling directories or the project root will not be staged. To stage everything from anywhere in the repo, use git add -A instead.

Visualize what you just learned: **inter-git.com** teaches Git fundamentals visually: each command is shown in a live diagram so you can see exactly what happens to the staging area and the commit graph in real time. It runs entirely in your browser, so there is nothing to install.

Level 2 Intermediate: Taking Control of What You Stage

Once you are comfortable with the basics, you will quickly run into situations where git add <file> and git add . are not quite the right tools. Maybe you want to stage every changed file across the entire repository, not just from your current subdirectory. Maybe you want to stage only files you have already modified, leaving new untracked files out. Maybe you want to preview what would be staged without actually staging anything. This level covers all of that.

git add -A: Stage All Changes Across the Entire Repository

git add -A (also: git add --all, git add --no-ignore-removal)

Stages ALL changes in the entire working tree, no matter which directory your terminal is currently in. This includes new files that were never tracked, modifications to existing tracked files, and deletions of tracked files. It is the most comprehensive staging command available and is location-independent.

# Stage everything in the entire repository (works from any subdirectory)
git add -A

# Same thing with the long flag name
git add --all

The critical difference between git add -A and git add . is location independence. If you are inside src/components/ and run git add ., it only stages files in that directory tree. Files you modified at the project root are missed. Run git add -A from the same location and it stages everything across the whole repo.

git add -u: Stage Only Tracked File Changes

git add -u (also: git add --update)

Updates the index to match what tracked files look like in your working directory. It stages modifications and deletions for files that Git already knows about, but does NOT add new untracked files. If Git has never seen a file before, -u completely ignores it.

# Stage only modifications and deletions for tracked files
git add -u

# Limited to a specific path
git add -u src/

Real-World Scenario You are refactoring a module. You have modified auth.js, deleted the obsolete auth-old.js, and also created a debug-temp.js that you used for testing but definitely do not want committed. Running git add -u stages the modification and the deletion but leaves debug-temp.js completely untouched. Perfect staging with zero risk of committing work-in-progress files.

git add -n: Dry Run Before You Stage

git add -n (also: git add --dry-run)

Shows you what WOULD be staged if you ran the command for real, but does not actually stage anything. This is a safe way to preview the effect of any git add command before committing to it. Combine it with any other flag: -An, -n ., -n “*.js” all work.

# Preview what git add . would do, without actually doing it
git add -n .
# add 'src/app.js'
# add 'styles/main.css'
# add 'tests/app.test.js'

# Preview what adding all JS files would stage
git add -n "*.js"

# Preview git add -A for the entire repo
git add -An

Run with -n first when you are unsure what a glob or directory command will match. Read the output, confirm it looks right, then remove the -n and run the real command. This one habit prevents an enormous category of accidental staging mistakes.

git add <dir>/: Staging a Whole Directory

git add <dir>/

Stages all changes within a specific directory and all its subdirectories, regardless of where your terminal currently is. More explicit and predictable than navigating into the directory and running git add .

# Stage all changes under the src/ directory (run from project root)
git add src/

# Stage all changes under the tests/ directory
git add tests/

# Stage a nested subdirectory
git add src/components/forms/

This form is particularly useful when your project has a clear directory structure and you want to stage “everything in the backend” or “everything in the frontend” as separate commits. You can run these commands from the project root without needing to cd anywhere.

Glob Patterns: Staging by File Type

# Stage all JavaScript files anywhere in the repo (Git handles the expansion)
git add "*.js"

# Stage all test files
git add "*.test.js"

# Stage all Markdown files
git add "*.md"

Shell Glob Expansion Varies by Shell Bash, Zsh, and Fish all handle unquoted globs differently. Zsh is particularly aggressive: it will throw an error if no matches are found, rather than passing the literal pattern to Git. Always quote glob patterns in git add to get consistent behaviour across systems and between team members.

git add -f: Staging Ignored Files

git add -f <file> (also: git add --force <file>)

Forces Git to add a file that would normally be ignored by .gitignore rules. By default, git add silently skips ignored files or shows an error if you name one explicitly. The — force flag overrides that protection.

# Force-add a normally-ignored file
git add -f build/vendor.min.js

# What normally happens without -f
git add build/vendor.min.js
# The following paths are ignored by one of your .gitignore files:
# build/vendor.min.js
# hint: Use -f if you really want to add them.

Do Not Force-Add Sensitive Files Your .gitignore is a safety net that exists to protect you from committing secrets, binaries, and machine-specific config. Using -f should be a rare, deliberate decision. Never use it to add .env files, *.key files, or any file containing passwords or tokens.

git add -N: Intent to Add

git add -N <file> (also: git add --intent-to-add <file>)

Records that you plan to add this file later but does not yet stage any content. It creates an empty placeholder entry in the index. The main practical effect: the file now shows up in git diff (new untracked files normally do not appear in git diff), and git add -p can process the file hunk by hunk.

# Register intent to add a new file without staging its content yet
git add -N src/newfeature.js

# Now git diff shows the new file's content as additions
git diff src/newfeature.js

# And now git add -p can process the new file
git add -p src/newfeature.js

The -N flag solves a specific problem: patch mode (git add -p) silently skips completely new untracked files. By registering intent first, you can use patch mode to carefully choose which parts of a new file to stage, leaving the rest as work in progress.

Comparing -A, dot, and -u Side by Side

Here is a concrete scenario. You are in the project root. Since your last commit you have modified src/app.js, deleted src/old-utils.js, and created src/new-module.js.

Figure 4: Side-by-side comparison. The only command that never stages new untracked files is -u. The difference between -A and dot only appears when run from inside a subdirectory.

Figure 4: Side-by-side comparison. The only command that never stages new untracked files is -u. The difference between -A and dot only appears when run from inside a subdirectory.

attribute: Stages modifications git add -A: Yes git add .: Yes (current dir) git add -u: Yes (tracked files)

attribute: Stages deletions git add -A: Yes git add .: Yes (current dir) git add -u: Yes

attribute: Stages new files git add -A: Yes git add .: Yes (current dir) git add -u: No, never

attribute: Scope git add -A: Entire repo always git add .: Current directory tree git add -u: Entire repo, tracked only

attribute: Best for git add -A: Stage everything regardless of location git add .: Stage changes in current dir tree git add -u: Stage without picking up scratch files

Intermediate Pitfalls

Pitfall 5: Using git add -A and Staging Generated Files Running git add -A will cheerfully stage everything not in your .gitignore, including node_modules/ if you forgot to add it to .gitignore, compiled dist/ files, OS metadata like .DS_Store, and editor configs. Before using -A in a new project, make sure your .gitignore is thorough. Run git add -An first to inspect what would be staged.

Pitfall 6: Confusing -u Behaviour in Old Git Versions In Git older than 2.0, running git add -u without a path argument only updated files in the current directory, not the whole repo. In modern Git (2.x), it updates the whole working tree. If you write scripts that must run on older Git versions, always pass an explicit path: git add -u .

Pitfall 7: Staging a Directory When You Meant One File If you mistype a filename and accidentally pass a directory name, you might stage hundreds of files you did not intend to. Running git add src stages everything under src/. Always double-check with git status after staging a directory, and use git add -n when unsure.

Level 3 Advanced: Surgical Precision and the Full Power of git add

This is where git add reveals its full depth. The features in this level are what separate developers who have a clean, readable commit history from those who have commits full of unrelated changes and debugging artifacts. The centrepiece is patch mode (-p), which lets you stage individual lines within a file. But there are many other powerful options here too: editing patches directly, handling line ending problems, setting executable bits, and automating staging from file lists.

git add -p: The Patch Mode That Changes Everything

git add -p (also: git add --patch)

Enters an interactive mode where Git shows you each “hunk” of changes in your modified files, one at a time, and asks whether you want to stage it. A hunk is a contiguous block of changes. You can stage some hunks and skip others, giving you line-level control over what goes into the staging area.

Imagine you have been working on a file for two hours. During that time you fixed a real bug on lines 34–40, but you also added some console.log debugging statements on lines 15-18 and 67-70 that you absolutely do not want committed. With git add auth.js, you have to take all of it or none of it. With git add -p auth.js, you choose exactly which blocks to stage.

# Enter patch mode for a specific file
git add -p auth.js

# Enter patch mode for all modified tracked files
git add -p

# Enter patch mode for files in a specific directory
git add -p src/

When you run git add -p, Git shows you something like this:

diff --git a/src/auth.js b/src/auth.js
--- a/src/auth.js
+++ b/src/auth.js
@@ -12,6 +12,8 @@ function checkPermissions(user) {
   if (!user) return false;
+  console.log('DEBUG: checking user', user.id);
   const permissions = loadPermissions(user.role);
+  console.log('DEBUG: result', result);
 }

(1/3) Stage this hunk [y,n,q,a,d,s,e,p,?]?

This hunk contains debug logs you do not want. Type n and press Enter. Git shows the next hunk. Maybe that is your real bug fix. Type y. Git stages just that block. The number (1/3) tells you which hunk out of the total found in this file you are currently reviewing.

Figure 5: How git add -p works. A single file has four hunks. You stage hunks 2 and 4 (real changes) and skip hunks 1 and 3 (debug logs). Only the staged hunks appear in the next commit, while all changes remain in the working directory file.

Figure 5: How git add -p works. A single file has four hunks. You stage hunks 2 and 4 (real changes) and skip hunks 1 and 3 (debug logs). Only the staged hunks appear in the next commit, while all changes remain in the working directory file.

Every Patch Mode Key Explained

key: y what it does: Stage this hunk when to use it: You want this block of changes in your commit

key: n what it does: Do not stage this hunk when to use it: Skip this block, it stays in your working directory

key: q what it does: Quit patch mode now when to use it: Done deciding, exit without processing remaining hunks

key: a what it does: Stage this and all remaining hunks in this file when to use it: You have reviewed enough, accept the rest of this file

key: d what it does: Skip this and all remaining hunks in this file when to use it: None of the remaining changes in this file should be staged

key: g what it does: Go to a specific hunk by number when to use it: Jump directly to a hunk instead of stepping through all of them

key: / what it does: Search for a hunk matching a regular expression when to use it: Looking for a specific function name or variable in a large diff

key: j what it does: Next undecided hunk (wraps around) when to use it: Navigate forward, skipping already-decided hunks

key: J what it does: Next hunk regardless of decision status when to use it: Move forward and revisit decided hunks too

key: k what it does: Previous undecided hunk when to use it: Navigate backward through undecided hunks

key: K what it does: Previous hunk regardless of decision status when to use it: Move backward through all hunks

key: s what it does: Split this hunk into smaller hunks when to use it: The hunk contains two separate changes you want to decide independently

key: e what it does: Manually edit the hunk in your text editor when to use it: You need to stage only specific lines within a hunk that cannot be auto-split

key: p what it does: Print the current hunk again when to use it: Redisplay the diff after the screen has scrolled

key: P what it does: Print the current hunk using the pager when to use it: Very large hunks that do not fit on screen

key: ? what it does: Show help with all options when to use it: When you forget any of the above

Splitting and Editing Hunks Manually

Splitting with s: Git groups changes that are close together into one hunk. Sometimes you want to stage one of those changes but not the other. Press s and Git tries to split the hunk into smaller ones. If the changes are on immediately adjacent lines, splitting may not be possible automatically, in which case you need e.

# Press s when you want to split a hunk
(1/2) Stage this hunk [y,n,q,a,d,s,e,p,?]? s
Split into 2 hunks.
@@ -24,4 +24,4 @@
 function login(user) {
-  return oldLoginMethod(user);
+  return newLoginMethod(user);
(1/3) Stage this hunk [y,n,q,a,d,s,e,p,?]?

Editing with e: This opens the raw patch text in your configured editor. You can manually delete lines to exclude them from staging. Here is what you see:

# Manual hunk edit mode -- see bottom for a quick guide.
@@ -34,8 +34,12 @@ function checkPermissions(user) {
 const permissions = loadPermissions(user.role);
+console.log('DEBUG user:', user.id);    <-- delete this line
-const result = checkLegacy(user);
+const result = checkModern(user);
 return result;
+console.log('DEBUG done');              <-- delete this line
# To remove '+' lines, delete them.
# To remove '-' lines, change them to context (add a space).

Delete the +console.log lines, save, and close. Git applies only the surviving changes to the index. This is the most surgical staging technique available in Git.

Set Your Editor for Patch Editing The editor that opens when you press e is determined by GIT_EDITOR, EDITOR, or core.editor in Git config. To use VS Code: git config --global core.editor "code --wait". To use Nano: git config --global core.editor "nano". The --wait flag is required for VS Code so Git waits until you close the file.

git add -i: The Full Interactive Mode

git add -i (also: git add --interactive)

Opens a full interactive menu-driven interface for staging. Unlike -p which jumps straight into patch selection, -i shows a main menu with subcommands: status, update (stage files), revert (unstage files), add untracked, patch (same as -p), and diff. Think of it as a text-mode dashboard for the staging area.

# Enter the full interactive mode
git add -i

           staged     unstaged path
  1:    unchanged        +5/-2 src/auth.js
  2:    unchanged        +1/-0 src/user.js

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

1: status shows staged and unstaged line counts for each modified file. A quick overview before deciding what to do.

2: update lets you select files to stage. Type numbers, ranges like 2-4, or * for all. Press Enter on an empty line to confirm.

3: revert unstages changes that were previously staged. Same selection interface as update but removes from the staging area instead of adding.

4: add untracked shows new files and lets you select which ones to start tracking.

5: patch is identical to git add -p but reached through the menu. Pick a file and go through hunk by hunk.

6: diff shows the diff between HEAD and the currently staged content. This is your preview of what the commit will contain if you commit right now.

When to Use -i vs -p Use git add -p when you know you want hunk selection and want to get there immediately. Use git add -i when you want a full overview first: see what is staged and unstaged across all files, unstage some things, add new files, and then do hunk selection. The interactive mode is an all-in-one dashboard for the staging area.

git add -e: Editing a Patch Directly

git add -e (also: git add --edit)

Opens the complete diff between the index and your working tree directly in your configured text editor. You can manually edit the patch file to choose exactly which lines get staged. After you save and close, Git applies the modified patch to the index. The most surgical staging option available.

# Open the full diff in your editor
git add -e

# Edit only the diff for one file
git add -e src/auth.js

Rules for editing: delete + lines to exclude added content from staging. Convert - to a space to keep a line (not stage its removal). Never touch context lines (starting with space) or hunk headers (starting with @@).

Broken Patches Cause Errors Deleting context lines or modifying hunk headers causes Git to fail with “patch does not apply.” The safest rule: only delete + lines and convert - to spaces. Do not touch anything else. If something goes wrong, run git add -e again or reset the file with git checkout -- <file>.

git add --chmod: Setting the Executable Bit

git add - chmod=(+|-)x <file>

Overrides the executable bit of files being staged. — chmod=+x marks files as executable in the index. — chmod=-x marks them as non-executable. This only changes the bit in the index (the commit), not the actual file on disk. Essential for cross-platform teams because Windows filesystems do not store Unix-style executable bits.

# Stage a shell script and mark it as executable
git add --chmod=+x scripts/deploy.sh

# Remove the executable bit from a file that was accidentally marked executable
git add --chmod=-x src/config.json

Real-World Scenario: Cross-Platform Teams A Windows developer adds scripts/deploy.sh to the repository. On their machine, chmod does not exist. They use git add --chmod=+x scripts/deploy.sh and commit. When a Linux developer pulls the change, the script is correctly executable. The Windows developer solved a Linux problem without leaving Windows.

— chmod Only Changes the Index, Not the Disk

Running git add --chmod=+x deploy.sh does NOT make deploy.sh executable in your current terminal session. To run it locally you still need chmod +x deploy.sh. The git add --chmod change only matters when someone else clones or checks out the file.

git add --renormalize: Fixing Line Ending Disasters

git add --renormalize

Re-applies the “clean” filter process to all tracked files and forces them to be re-added to the index. Used specifically to fix line ending problems after changing core.autocrlf or the text attribute in .gitattributes. Implies -u, so it only works on already-tracked files.

Line ending problems are one of the most frustrating cross-platform issues. Windows uses CRLF (\r\n) and Unix or macOS uses LF (\n). When files with the wrong endings are committed, every line of every affected file looks changed in git diff, flooding code review with meaningless noise.

# Add or update .gitattributes to enforce LF for all text files
echo "* text=auto eol=lf" > .gitattributes

# Force all tracked files to be re-processed with the new rules
git add --renormalize .

# Review what changed (should only be line ending normalization)
git diff --staged

# Commit the normalization
git commit -m "chore: normalize line endings across the codebase"

Prevent Problems From the Start Add a .gitattributes file with * text=auto at the very beginning of a project. This tells Git to normalize line endings automatically. Done once at project creation, you will never need --renormalize reactively.

git add --pathspec-from-file: Staging From a List

git add --pathspec-from-file=<file>

Instead of listing files on the command line, reads the list of paths from a file. Each path on its own line. Use a hyphen (-) as the filename to read from standard input. Avoids the command-line length limit when staging thousands of files. Requires Git 2.25 or later.

# Stage everything in a list file
cat files_to_stage.txt
# src/app.js
# src/user.js

git add --pathspec-from-file=files_to_stage.txt

# Read from standard input using a pipe
find src -name "*.js" -newer last_deploy.txt | git add --pathspec-from-file=-

# With NUL separators for filenames that contain spaces
find . -name "*.js" -print0 | git add --pathspec-from-file=- --pathspec-file-nul

This flag is primarily useful in CI/CD pipelines where you compute a list of files to stage programmatically. It also avoids the shell argument length limit that you can hit when trying to pass thousands of filenames as arguments to a single command.

git add --sparse: Working With Sparse Checkouts

git add --sparse

In a repository using sparse checkout, git add normally refuses to update index entries for paths outside the sparse checkout cone, because those files might be removed from disk without warning. The — sparse flag overrides this safety restriction and allows updating out-of-cone entries.

# In a sparse checkout, allow adding a file outside the active cone
git add --sparse path/outside/sparse/cone/file.js

Sparse checkout is used in large monorepos where checking out the entire working tree is impractical. Most developers will never encounter this flag unless they work in very large monorepo environments with millions of files.

--ignore-errors, --refresh, and --ignore-missing

git add --ignore-errors

When staging multiple files and some fail due to permission errors or locking conflicts, normally git add aborts. With — ignore-errors, Git logs the error and continues processing the remaining files. The command still exits with a non-zero status to signal something went wrong.

# Stage everything possible even if some files have errors
git add --ignore-errors .

# Make this the default via config
git config add.ignoreErrors true
git add --refresh

Does not stage any content. Instead, it refreshes the stat() metadata (file size, modification time) for tracked files in the index without changing recorded content. Useful to clear “false dirty” states that cause git status to show files as modified when their content has not actually changed.

# Refresh stat metadata for all tracked files (no content staged)
git add --refresh

You rarely need --refresh in normal development. It becomes relevant when git status shows files as modified even though their content is identical to what is in the index. This can happen after certain filesystem operations that change file metadata without changing file content.

git add --ignore-missing

Only meaningful with — dry-run (-n). Lets you check whether given paths would be ignored by .gitignore rules, even for files that do not currently exist on disk. Useful for writing scripts that verify .gitignore configuration.

# Check if a file would be ignored even if it does not exist yet
git add -n --ignore-missing hypothetical-secret.env
git add --no-warn-embedded-repo

By default, if you try to add a directory that itself contains a .git folder, git add warns you to use git submodule add instead. This flag suppresses that warning. Use it only when you deliberately want to manage a nested repository without the submodule system.

If you see the embedded repo warning, stop and think carefully before suppressing it. The right answer is almost always to set up a proper Git submodule instead, which tracks the exact commit of the nested repository explicitly and reproducibly.

--unified and --inter-hunk-context

git add -U<n> (also: git add --unified=<n>)

Controls how many lines of context Git shows around each change in patch mode. Default is 3. Increasing this gives you more context to understand what changed. Decreasing it produces smaller, more numerous hunks for finer-grained staging control.

# Show 5 lines of context around each change
git add -U5 -p src/auth.js

# Show only 1 line of context (compact hunks)
git add -U1 -p src/auth.js

# Show zero context lines (maximum granularity)
git add -U0 -p src/auth.js
git add --inter-hunk-context=<n>

Shows up to n lines of context between diff hunks, potentially fusing nearby hunks into one. Default is 0. If two changes are within n lines of each other, they become one combined hunk. Requires Git 2.38 or later when used specifically with git add.

Configuration: add.ignoreErrors and interactive.singleKey

add.ignoreErrors is the persistent equivalent of always passing --ignore-errors. When set to true, errors indexing individual files do not abort the entire staging operation.

# Set globally for all repositories
git config --global add.ignoreErrors true

interactive.singleKey makes patch mode significantly more comfortable. By default, after pressing a key like y or n, you have to press Enter to confirm. With singleKey set to true, each key press takes effect immediately.

# Enable single-key responses in all interactive modes
git config --global interactive.singleKey true

Set interactive.singleKey Immediately If you use git add -p regularly, set interactive.singleKey = true right now. When you are reviewing 20 or 30 hunks in a large file, not having to press Enter after every key is dramatically faster and more natural. This is one of those settings that, once enabled, you will not want to turn off.

Real-World Advanced Workflows

Workflow 1: The Clean Commit From Messy Work

You have been coding for four hours. Your modified files contain the actual feature, some refactoring, and temporary debugging statements. You want two separate focused commits and no debug logs.

# Use patch mode to stage only feature-related hunks
git add -p src/feature.js
# (stage feature hunks, press n for debug logs)

# git add tests/feature.test.js
# (stage the whole test file)

# Verify exactly what is staged
git diff --staged

git commit -m "feat: add user preference caching"

# Now stage the refactoring hunks
git add -p src/utils.js
git commit -m "refactor: extract validation logic to utils"

Workflow 2: Stage Everything With Targeted Exceptions

# Stage everything first
git add -A

# Unstage the two files you are not ready for
git restore --staged src/wip-feature.js
git restore --staged config/experimental.json

git commit -m "feat: complete authentication module"

Workflow 3: Using Intent-to-Add With Patch Mode on a New File

# New file that git add -p would normally skip entirely
git add -N src/new-payment-module.js

# Now patch mode can see it
git add -p src/new-payment-module.js
# (stage the complete tested sections, skip WIP parts)

git commit -m "feat: add payment validation core"

Workflow 4: Automating Staging in CI/CD

# Find changed generated files and stage them
find dist/ -name "*.min.js" -newer src/index.js -print0 | \
  git add --pathspec-from-file=- --pathspec-file-nul

# Stage all tracked changes
git add -u

# Only commit if there is something to commit
git diff --staged --quiet || git commit -m "chore: update generated assets [skip ci]"

Workflow 5: Fixing Line Endings for a Cross-Platform Team

# Create or update .gitattributes
echo "* text=auto eol=lf" > .gitattributes
echo "*.sh text eol=lf" >> .gitattributes

# Re-normalize all tracked files
git add --renormalize .

# Commit the normalization standalone
git commit -m "chore: normalize line endings, add .gitattributes"

Advanced Pitfalls

Pitfall 8: Breaking a Patch With git add -e Accidentally deleting a context line or a hunk header (@@ line) causes Git to refuse the patch with "patch does not apply." To recover, run git add -e again, or reset the file with git checkout -- <file>. Always follow the rule: only delete + lines and convert - lines to spaces. Never touch context lines or headers.

Pitfall 9: git add -p Silently Skips New Untracked Files If a file is completely new, it does not appear in git add -p because there is nothing in the index to compare it against. You will simply not see the new file in the patch session and may assume it was staged when it was not. Always run git add -N <file> first on new files if you want to use patch mode on them.

Pitfall 10: Staging Half a Feature With -p If you stage only some hunks of a feature and commit, you can end up with a commit that is syntactically valid but logically incomplete. For example, staging the function definition but not the export statement means the feature cannot be used. Always review your complete staged diff with git diff --staged before committing to confirm the staged changes form a coherent, working unit on their own.

Pitfall 11: — renormalize Corrupting Binary Files Running git add --renormalize applies the clean filter to ALL tracked files. If your .gitattributes does not explicitly exclude binary files, the normalization might corrupt images or compiled binaries by treating their bytes as text. Before running --renormalize, ensure your .gitattributes marks binary files correctly: *.png binary, *.jpg binary, and so on.

Pitfall 12: Confusing — refresh With Staging Content Running git add --refresh before a commit will NOT include any of your code changes in the commit. It only refreshes metadata (timestamps, file sizes) without staging actual content changes. You still need a regular git add with a path to stage content.

Figure 6: Decision tree for choosing the right git add command. Follow the branch that matches your situation. When uncertain, always run with -n first for a safe preview.

Figure 6: Decision tree for choosing the right git add command. Follow the branch that matches your situation. When uncertain, always run with -n first for a safe preview.

Quick Reference Card

# git add: Complete Command Reference

git add <file>                          # Stage a specific file
git add .                               # Stage all changes in current directory tree
git add -A                              # Stage all changes in entire repo (any location)
git add -u                              # Stage only tracked file changes (no new files)
git add -n .                            # Dry run: show what would be staged
git add src/                            # Stage all changes inside a directory
git add "*.js"                          # Stage all JS files (Git handles the glob)
git add -p                              # Hunk-by-hunk patch mode
git add -p src/auth.js                  # Patch mode for one specific file
git add -i                              # Full interactive staging menu
git add -e                              # Edit the diff directly in your editor
git add -f <file>                       # Force-add an otherwise-ignored file
git add -N <file>                       # Intent to add (empty placeholder in index)
git add --chmod=+x scripts/run.sh       # Stage and mark as executable
git add --chmod=-x src/config.js        # Stage and remove executable bit
git add --renormalize .                 # Fix line endings after .gitattributes change
git add --pathspec-from-file=list.txt   # Stage files listed in a file

find src -name "*.js" | git add --pathspec-from-file=-
                                        # Stage from stdin

git add --refresh                       # Refresh stat metadata only
git add --ignore-errors .               # Continue staging even if some files fail
git add -U5 -p                          # Patch mode with 5 lines of context
git add -U0 -p                          # Patch mode: zero context, max granularity
git add --sparse <path>                 # Add outside sparse checkout cone
git add -An                             # Dry run for the entire repo
git add -v .                            # Verbose: print each file as it is staged
-v                                   # Print each file name as it is staged
--verbose                            # Print each file name as it is staged

-n                                   # Show what would be staged, do nothing
--dry-run                            # Show what would be staged, do nothing

-f                                   # Force-add files that are normally ignored
--force                              # Force-add files that are normally ignored

--sparse                             # Allow staging outside the sparse-checkout cone

-i                                   # Open the full interactive staging menu
--interactive                        # Open the full interactive staging menu

-p                                   # Stage hunks interactively, one by one
--patch                              # Stage hunks interactively, one by one

-U<n>                                # Set number of context lines shown in patch mode
--unified=<n>                        # Set number of context lines shown in patch mode

--inter-hunk-context=<n>             # Fuse hunks that are within n lines of each other

-e                                   # Edit the raw diff in your text editor before staging
--edit                               # Edit the raw diff in your text editor before staging

-u                                   # Stage only modifications and deletions for tracked files
--update                             # Stage only modifications and deletions for tracked files

-A                                   # Stage all changes in the entire repo
--all                                # Stage all changes in the entire repo
--no-ignore-removal                  # Stage all changes in the entire repo

--no-all                             # Stage new and modified files, ignore deletions
--ignore-removal                     # Stage new and modified files, ignore deletions

-N                                   # Register an empty placeholder entry for a new file
--intent-to-add                      # Register an empty placeholder entry for a new file

--refresh                            # Refresh stat info in index only, no content staged

--ignore-errors                      # Continue staging even if some files fail to index

--ignore-missing                     # With -n: check ignore rules for files that do not exist

--no-warn-embedded-repo              # Suppress the nested repository warning

--renormalize                        # Re-apply line ending rules to all tracked files

--chmod=(+|-)x                       # Set or clear the executable bit in the index

--pathspec-from-file=<file>          # Read paths to stage from a text file

--pathspec-file-nul                  # Use NUL as separator in pathspec file

--                                   # Explicit separator between options and file list

Conclusion: git add Is Not Just a Stepping Stone to git commit

Most developers treat git add as a chore, the necessary button to press before the "real" command. Hopefully this guide has changed that perception completely.

git add is where your commit story is written. The choices you make in the staging area: which files to include, which hunks to take, which lines matter, determine whether your project history will be a readable and searchable record of meaningful changes or a chaotic archive of "stuff I did." The former is a gift to your future self and your colleagues. The latter is technical debt that compounds every time someone tries to understand what changed and why.

At the beginner level, you built the foundational mental model: the three zones (working directory, staging area, repository), the four file states (untracked, staged, committed, modified), the fundamental edit-stage-commit loop, and the habit of using git status before and after every staging operation.

At the intermediate level, you gained the vocabulary to handle any real-world staging scenario: -A for the whole repo regardless of your location, -u for tracked-only changes when you want to leave new scratch files untouched, -n for safe previewing before any complex operation, glob patterns for staging by file type, -f for the rare ignored-file case, and -N for the underappreciated intent-to-add pattern that unlocks patch mode on new files.

At the advanced level, you unlocked the tools that separate a good Git user from a great one: -p for hunk-by-hunk selection with every navigation and editing key, -e for line-level surgical staging that goes beyond hunk splitting, --chmod for solving cross-platform executable bit problems, --renormalize for cleaning up line ending disasters, --pathspec-from-file for automation and scripting, and the configuration settings that make your daily interactive staging workflow fast and comfortable.

The next time you are about to reflexively type git add . before a commit, pause for a moment. Ask: does every change in this directory belong in this commit? Are there debug logs mixed in with the real fix? Is there a refactoring bundled with a feature? If the answer to any of these is yes, you now have the tools to separate them cleanly. Your commit history will be better for it, your code reviews will be easier to understand, and the next developer who needs to trace why a particular line changed will find a clear and honest explanation waiting in the commit message.

That is the real purpose of git add: not just to prepare a commit, but to tell the truth about what changed and why, one well-crafted snapshot at a time.

This tutorial covers Git 2.x and later. The --pathspec-from-file option requires Git 2.25 or later. The --renormalize option requires Git 2.16 or later. The --no-warn-embedded-repo option requires Git 2.25 or later. The --inter-hunk-context option with git add requires Git 2.38 or later. Run git --version to check your installed version.

**inter-git.com** is an interactive Git tutorial where each command is shown visually so you can see exactly how it works in real time. It runs entirely in your browser, so there is nothing to install.


메타데이터
post_id
bdb28a2aaf44
slug
the-complete-guide-to-git-add-from-staging-your-first-file-to-mastering-patch-mode-the-bdb28a2aaf44
url
https://medium.com/@eloquentcoder/the-complete-guide-to-git-add-from-staging-your-first-file-to-mastering-patch-mode-the-bdb28a2aaf44
canonical_url
https://medium.com/@eloquentcoder/the-complete-guide-to-git-add-from-staging-your-first-file-to-mastering-patch-mode-the-bdb28a2aaf44
author_url
https://medium.com/@eloquentcoder
status
ok
fetched_at
2026-06-09 15:37:30