What are staging areas?

When you run git status after modifying some files, you’ll see something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   file1.txt
	modified:   file8.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   file2.txt
	modified:   file4.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	file5.txt
	sacred-texts.txt

Notice there are three categories of files here: to be committed (also called staged), not staged for commit, and untracked files.

These are the different staging areas.

  • To be committed/staged means that these files will be included in the next commit made.
  • Not staged for commit means that git noticed changes in those files, but they will not be included by default next time git commit is run.
  • Untracked means that git is not watching those files.

Moving files between staging areas

There are two git subcommands we need to understand for this: git add and git resore.

git add

We introduced git add in the last tutorial. It moves a file to the staged area so that it will be included in the next commit. Here’s an example (the lines starting with $ are the commands run:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ git status

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   file1.txt
	modified:   file8.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   file2.txt
	modified:   file4.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	file5.txt
	sacred-texts.txt

$ git add file2.txt file5.txt

$ git status

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   file1.txt
	modified:   file2.txt
	modified:   file5.txt
	modified:   file8.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   file4.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	sacred-texts.txt

As you can see, running git add file{2,5}.txt moved them to the staged area. This is also referred to as “staging” a file.

A file can also be partially staged, where some part(s) of it are included in the next commit, but not the whole thing. This usually happens when you stage a file and then edit it. Running git add <partially staged file> will stage the entire thing.

git restore

This command is slightly more complicated than the other ones we’ve used so far. git restore overwrites a file, using either the latest commit or the staged version as reference. That might be quite confusing at first, and that’s okay. You can always come back to a tutorial, man page, or documentation later.

git restore can be very dangerous since it won’t warn you before overwriting files. Be careful!

There are some options that control how the file is overwritten.

default (–worktree, -W)

By default if no options are specified, or with the --worktree, -W option, git restore will discard any unstaged changes. This means that if you have a partially staged file, the staged changes will be kept, while the unstaged ones will be discarded.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
$ git status

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   file2.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified: file2.txt

$ git restore file2.txt

$ git status

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   file2.txt

Running git restore file2.txt discarded the unstaged changes in file2.txt while keeping the staged ones.

–staged, -S

Running git restore with the --staged, -S option will essentially unstage any currently staged changes, but does not discard them.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ git status

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   file1.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified: file2.txt

$ git restore --staged file1.txt

$ git status

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified: file1.txt
	modified: file2.txt

Note that this command is also listed in the output of git status, so it’s easy to remember.

–worktree, -W and –staged, -S

Using both the --worktree, -W and --staged, -S options will completely overwrite the file to its last committed state. It discards both staged and unstaged changes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ git status

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   file1.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   file1.txt
	modified:   file2.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	file5.txt

$ git restore --worktree --staged file1.txt

$ git status

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   file2.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	file5.txt

Running git restore --worktree --staged file1.txt discarded all changes in file1.txt.

Tip: using short options can make the commands much simpler. git restore -WS <file> is equivalent to the above command.

Tip: almost all git commands can handle directories, too. Since git doesn’t track directories, it just applies the command recursively to all files in the directory. So git add . will stage all files in the current directory, and git restore --staged . will unstage them all.