Image of Git Add | Adding Changes to Git’s Staging Area

ADVERTISEMENT

Table of Contents

What Does git add Do?

Git is a feature rich version control system used by programmers for tracking changes made to code files.

One unique feature of Git that sets it apart from other version control systems is the staging area. The staging area is a temporary holding location for adding changes before actually committing them to the repository, and eventually pushing them to a central repository.

Staging is used to track new files in Git and update existing files. All file changes must be staged before they can be committed, and git add is the tool we use to add file contents into Git's staging area. The git add command can be used to stage one file, multiple files, or stage changes in an entire directory.

Older version control systems like SVN (Subversion) required an internet connection to add and commit changes back to the central repository. However, one of the advantages of distributed systems like Git is that all of this can be done locally with no internet.

Before digging into the details of git add, let's take a look at a basic example of staging some changes in a mock Git repo. We'll use this working tree in examples throughout the article:

git-add-ex/
|   file1.ext
|   file2.ext
|
|   dir1/
|       dir1file1.ext

After initializing this repo with git init, we can then stage all working tree files and make our initial commit using the following commands:

git add .
git commit -m 'Initial commit'

[master (root-commit) 720edf7] Initial commit
 3 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 dir1/dir1file1.ext
 create mode 100644 file1.ext
 create mode 100644 file2.ext

Notice the output - git add doesn't actually give us any output unless an error is thrown. The git commit command will output basic info about which files were committed from the staging area into the Git repo.

It's a wise choice to use git add and git commit often. We can break up a large collection of changes into multiple smaller stages and commits. It's good practice to stage and commit in small chunks as you code. This gives developers more flexibility and control over the history of your codebase.

The Staging Area

As we've mentioned already, the staging area - also known as the staging index - is where Git puts our changes prior to committing them to the repo. But what's the point? Why doesn't Git allow us to simply commit all changes to our repo in one fell swoop?

There are many instances where the staging area comes in handy, and in some ways it may even be helpful to think of it as a rough draft for your commits. Here's a few examples of when and why the staging area can be helpful:

  1. Sometimes, we lose track of progress in the midst of coding and end up with a large amount of code changes that need to be committed. To stage and commit everything at once is contrary to our goal of leaving an easy to read history of our project's evolution. The --patch option git add -p allows us to interactively choose which chunks of code to stage for a commit, allowing us to break our commits up into more reasonable sizes. In this way we can commit the bits of changes within a file that we need, instead of all the changes in the file at once.

  2. You may be in the process of making multiple changes to a repo, and receive an unrelated request to fix a small bug. A typical approach is to make a new branch for this fix. However, the staging area allows us to make this small change in our current branch, and only stage and commit the small fix while leaving our other changes untouched for a separate stage.

  3. Prior to making commits to a repo, it's common to review the changes first. The staging area allows you to focus in on each individual change prior to making the decision to commit or not. You can run a diff command like git diff --staged to see the differences between your staged changes and the last commit, to see if it makes sense before you commit.

How Do I Use git add?

Using git add is straightforward in most cases. The basic syntax is as follows:

  • git add <path> : Use git add to stage a specific file or directory.
  • git add . : Stage all files and directories in the working tree unless specified otherwise in .gitignore
  • git add -p : Use an interactive mode to choose which hunks of changes to stage.

Using git add often comes after creating a new branch and checking it out, then making changes to one or more files. Let's give that a try with our previous example working tree version:

$ git branch updatefile
$ git checkout updatefile
Switched to branch 'updatefile'

Now, let's write and save some text inside file2.ext, and stage those changes. We can git add a folder or specific file by simply specifying the path after git add. We'll also use git status for a quick review of the staging area.

$ git add file2.ext
$ git status
On branch updatefile
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   file2.ext

A glance at the output tells us we have a change staged in our updatefile branch awaiting a commit or restore. But before we do any of that, let's make some changes to both file1.ext and dir1/dir1file1.ext and stage those changes as well:

$ git add .
$ git status
On branch updatefile
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   dir1/dir1file1.ext
        modified:   file1.ext
        modified:   file2.ext

Here we used git add . to stage our two changes at once, and as you can see from the output, all three of our changes are waiting patiently in the staging area of our updatefile branch. Now, we could commit all these changes in one chunk, but what if we belatedly realized these changes should be in three separate commits?

Yes, we can undo these staged changes and then use our interactive mode to break up our changes into multiple stages and commits.

Files ignored by Git in the .gitignore file will not be able to be tracked using Git add. Update the .gitignore to tell Git not to ignore specific files that you need to track.

Git Add README

One of the first tasks you'll do in a new project is to add a readme file. This is usually called README.MD. If you use GitHub, you can create the readme automatically in the online interface. You can also update the readme content and commit it as well. Just make sure to pull down your readme changes locally once done.

Alternatively, you can create and add an empty readme file locally like this:

$ touch README.md
$ git add README.md
$ git commit -m "Create readme"

How to Undo git add?

As seen from the previous example output, git restore can be used to undo git add (or change git add) and restore files to the working tree from the staging area. The syntax is as follows:

git restore --staged <file>...

It's worth noting that git restore isn't the only command we can use to undo git add, and is in fact a relatively new addition to the git toolbox.

The git reset command has been around since Git's inception, and is the legacy option for undoing git add. However, git reset defaults to updating your branch and moving the tip. The git reset command is a more robust tool, but to simply undo a git add command without updating your branch, git restore is the way to go.

All that being said, let's get back to our example repo and undo those staged changes:

$ git reset
Unstaged changes after reset:
M       dir1/dir1file1.ext
M       file1.ext
M       file2.ext

Now that we've resolved our problem of having staged our unwieldy chunk of changes, let's take a look at using the git add -p command to interactively choose which changes to stage.

Choosing What to Stage With git add -p

The -p option stands for --patch. You can think of a patch as simply a set of changes in Git. You can use Git add patch to interactively add changes from one or more files into the staging area. The best part is that you can choose to include some, but not all the changes in a given file.

A "hunk" is a series of lines of code that are next to each other in a code file. These are also called contiguous lines of code.

The Git add patch command lets you pick the hunks that you want to include and exclude from the staging area. You can include hunks from one or more files in the staging area.

You can run git add -p for Git to prompt you for each changed hunk in the working directory across all files that have changes. Or you can run git add <filename> -p to have Git only prompt you to add hunks from a specific file.

For each hunk (set of changes) that Git identifies, it will prompt you with something like: (1/1) Stage this hunk [y,n,q,a,d,e,?]?. You can type y to add that hunk to the staging area or n to disregard it. You can use q to quit the interactive staging. There are several other hunk-handling options you can check out if desired.

Here is an example of running the interactive Git add patch command:

$ git add -p
diff --git a/dir1/dir1file1.ext b/dir1/dir1file1.ext
index e69de29..c8f7ee1 100644
--- a/dir1/dir1file1.ext
+++ b/dir1/dir1file1.ext
@@ -0,0 +1 @@
+Changed dir1file1 also!
\ No newline at end of file
(1/1) Stage this hunk [y,n,q,a,d,e,?]? y

diff --git a/file1.ext b/file1.ext
index e69de29..cc5a71d 100644
--- a/file1.ext
+++ b/file1.ext
@@ -0,0 +1 @@
+Changed file1!
\ No newline at end of file
(1/1) Stage this hunk [y,n,q,a,d,e,?]? n

diff --git a/file2.ext b/file2.ext
index fb94200..11476f3 100644
--- a/file2.ext
+++ b/file2.ext
@@ -1 +1,3 @@
-Made a change
\ No newline at end of file
+Made a change
+
+// Added important comment.
\ No newline at end of file
(1/1) Stage this hunk [y,n,q,a,d,e,?]? n

$ git commit -m 'Commit a smaller hunk!'
[updatefile2 0183d87] Commit a smaller hunk!
 1 file changed, 1 insertion(+)

Note that for each hunk that Git identified above, it prompted us as to whether we wanted to add it to the staging area.

In this example output, git add -p has allowed us to stage and commit only one out of the three changes we made in our branch, a very helpful feature to say the least.

git add Options

The git add command comes with a quite a few options. Let's take a look at some that you're likely to come across:

  • git add * : This options tells git to stage all files in the current directory (that don't begin with a dot - i.e. no hidden files). And to stage all files in subdirectories whether they begin with a dot or not.
  • git add -A : Will stage all files, including new, modified, and deleted files, as well as files in the current directory and sub-directories that belong to the same git repo.
  • git add -u : Will only stage modified tracked files, but not untracked files.

For a comprehensive look at all git add options, head over the the git add docs and take a look.

Do I Have to git add Every Time?

Technically, no. There is a Git shortcut that you can use to add and commit with a single command. You can use the git commit command with the -a flag like: git commit -a -m <commit-message>

The -a flag tells Git to automatically stage all tracked file changes (including modifications and deletions but not untracked files), and commit them in one fell swoop.

This is a handy shortcut that can save you some time when you have a few small changes to stage and commit. However, for larger more complex commits, you should probably use git add every time.

Summary

The git add command is used for staging changes in Git prior to committing them to the current branch. It is helpful for reviewing changes prior to commits, breaking up changes into multiple smaller commits, or even making small changes unrelated to the current branch.

The result of git add isn't permanent, and can be reversed using git restore or git reset, which will keep any of the staged changes from reflecting in the commit history. For this reason, the staging area can be thought of as a rough draft for your commits.

Overall, git add and the staging area are an excellent feature that sets Git apart from other version control systems. To use it wisely, use it often.

Next Steps

If you're interested in learning more about how Git works under the hood, check out our Baby Git Guidebook for Developers, which dives into Git's code in an accessible way. We wrote it for curious developers to learn how Git works at the code level. To do this we documented the first version of Git's code and discuss it in detail.

We hope you enjoyed this post! Feel free to shoot me an email at jacob@initialcommit.io with any questions or comments.

Final Notes