Staging and Committing

It is important to understand that Git doesn’t save the changes to every file in the directory when you create a commit - it only saves those files you have staged to be committed. This extra step often confuses new Git users, but it exists to give you full control over what gets committed into your repository.

Staging Diagram

It may help to understand how Git thinks about files. Files in your repository directory fall into one of five categories - untracked, unstaged, staged, committed, and ignored.

Untracked files are those that have never been added to the repository. As far as the repository is concerned, they don’t exist. If you were to delete one, you cannot restore it, as the repository has no saved version of it. Mostly these are files that have recently been created.

Unstaged files are those that are tracked, but have at least some changes that have not been committed. These are either new files that have just been added to the repository’s index with a git add command, or files that have been altered since the last commit.

Staged files are those that will be included in the next commit. They are added to the list of staged files with the git add command, and will be committed with the git commit command.

Committed files are those whose current state has been saved as a commit. In other words, they are “safe” as they can be restored from that commit with a git checkout command.

Ignored files are those whose path matches the pattern in the .gitignore file. We’ll come back to this idea shortly.

You can check for the status of your files in the repository at any time with the git status command:

$ git status 

This will print the status of all uncommitted files:

The output of git status

There are four files in the ff directory: example0.txt, example1.txt, example2.txt, and example3.txt. In the output above, we see:

  • example0.txt was committed at some point, but now has changes. Git helpfully lets us know we can undo those changes and restore the committed version with the command $ git checkout -- example0.txt, or add this file to those staged with $ git add example0.txt.
  • example1.txt does not appear in the status message, as it is already committed and has no changes.
  • example2.txt is a new file (it has never been committed), and is staged to be committed.
  • example3.txt is also a new file, but is not staged to be committed.

Interestingly, you can still change a staged file. If you do so, Git keeps track of the staged but not committed changes, and the new, unstaged modifications. For example, if we change example2.txt and run git status again, we’ll see:

The output of git status

Notice example2.txt now has two statuses - corresponding to the staged and unstaged changes!

Committing Changes

With this understanding in mind, the standard way of committing changes is to combine a git add command and a git commit command:

$ git add .
$ git commit -a -m "<a message about the commit>"

The git add . adds all untracked and unstaged files (making them staged), and git commit -a commits all staged or unstaged files. If you only want to add some files, you can add them individually as we did above, by specifying the path (i.e. git commit path/to/a/file.txt) and omit the -a in the commit command so only those staged will be committed.