Session 5 · Adding and staging files#

The big idea#

Git does not save everything you changed automatically. You pick what goes into the next snapshot by staging it with git add, then git commit saves exactly what is staged. The staging area lets you build a clean, focused commit even when you have touched many files.

Everyday example: packing a courier box. Your desk has many things on it (the working folder). You choose only the items for this order, put them in the box (staging), check the box, and then seal and label it (commit). Everything else stays on the desk for another box.

Working folder, staging area, repository You edit files in the working folder, choose what goes into the next snapshot with git add, and git commit stores it in the repository. Working folder files you edit Staging area the next snapshot, being prepared Repository saved history (.git) git add git commit git restore --staged git status shows the difference between each pair of areas
You edit files in the working folder, choose what goes into the next snapshot with git add, and git commit stores it in the repository.

Staging in practice#

git config --global user.name "Dev User"
git config --global user.email "dev@example.com"
git config --global init.defaultBranch main
git init -q site
cd site
touch app.js style.css README.md

echo '--- 1. stage one file only'
git add style.css
git status -s

echo '--- 2. stage everything except README.md'
git add -- ':!README.md'
git status -s

echo '--- 3. stage only part of a file (git add -p)'
git commit -q -m "Start the site"
seq -f 'line %g' 1 20 > style.css
git add style.css && git commit -q -m "Add styles"
sed -i -e '1s/.*/line 1 (edited)/' -e '20s/.*/line 20 (edited)/' style.css
printf 'y\nn\n' | git add -p style.css | grep '^[-+@]\|Stage'
git status -s
echo '--- staged part versus the rest'
git diff --staged --stat
git diff --stat

echo '--- take a file back out of the staging area'
git restore --staged style.css
git status -s
--- 1. stage one file only
A  style.css
?? README.md
?? app.js
--- 2. stage everything except README.md
A  app.js
A  style.css
?? README.md
--- 3. stage only part of a file (git add -p)
--- a/style.css
+++ b/style.css
@@ -1,4 +1,4 @@
-line 1
+line 1 (edited)
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? @@ -17,4 +17,4 @@ line 16
-line 20
+line 20 (edited)
(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? 
MM style.css
?? README.md
--- staged part versus the rest
 style.css | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 style.css | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
--- take a file back out of the staging area
 M style.css
?? README.md

Reading git status -s (short status): the left column is the staging area, the right column is the working folder.

Code

Meaning

??

New file Git has never seen (untracked)

A

New file staged for the next commit

M

Modified and staged

M

Modified but not staged

MM

Staged, and then modified again

What the demo did:

  1. git add style.css staged one file; app.js and README.md stayed ??.

  2. git add -- ':!README.md' staged everything except README.md. The :! is a pathspec exclude. Now only README.md is ??.

  3. git add -p showed the edited file one hunk (a block of changes) at a time. We changed line 1 and line 20, which are far apart, so Git asked twice: y for the first, n for the second. The result MM means part of the file is staged and part is not.

  4. git restore --staged style.css took the file back out of the staging area. Its edits are kept in the working folder ( M).

Useful variations#

Command

Stages

git add FILE

One file

git add .

Everything in this folder and below

git add -u

Only files Git already tracks (changes and deletions)

git add '*.css'

Files matching a pattern (quote it)

git add -p

Chosen hunks, with a prompt for each

git restore --staged FILE

Un-stage (keeps the edits)

Common mistakes#

  • git add . without looking first. It will happily stage logs, passwords and build output. Run git status before and after.

  • Thinking git add saves the file. It only stages it. Nothing is stored in history until git commit.

  • Editing after staging. Git stages the file as it was when you added it. Edit it again and it shows MM; add it again to include the new edits.

  • Misreading the two status columns. Left is staged, right is not staged.

  • Using git checkout . or git restore . to “un-stage”. Those throw away your edits. To un-stage use git restore --staged.

Hands-on exercises#

Exercise 1. Create app.js, style.css and README.md. Stage only style.css and show the short status.

Solution
touch app.js style.css README.md
git add style.css
git status -s

Output: A  style.css, then ?? README.md and ?? app.js.

Exercise 2. Stage every file except README.md using a pathspec.

Solution
git add -- ':!README.md'
git status -s

app.js and style.css show A , and README.md stays ??.

Exercise 3. Edit a committed file in two places far apart and stage only the first change with git add -p.

Solution
seq -f 'line %g' 1 20 > style.css && git add style.css && git commit -m "Add styles"
sed -i -e '1s/.*/line 1 (edited)/' -e '20s/.*/line 20 (edited)/' style.css
git add -p style.css      # answer y for the first hunk, n for the second
git status -s             # MM style.css

git diff --staged then shows only the line 1 change, and plain git diff shows the line 20 change.

Practice#

Take the Session 5 quiz. The original Q2 Adding and Staging Files page is in the reference section.