9

The git book defines the git index:

The Git index is used as a staging area between your working directory and your repository. You can use the index to build up a set of changes that you want to commit together. When you create a commit, what is committed is what is currently in the index, not what is in your working directory.

But I am still having a difficult time understanding it, especially the highlighted statement that "what's committed is not what's in my working directory".

So far, in my limited working with git, everything in the working directory is always committed, if I do:

git add <all new files in the working directory>
git commit -a -m "git will refuse to commit without this comment" 

git then commits all modified files as well as all new files.

So, in effect, my working directory is the staging area?

I am not sure then what the git index is and how it is interpreted as the staging area.

Could you please explain?

Nicolas Kaiser
  • 1,628
  • 2
  • 14
  • 26
WinWin
  • 7,493
  • 10
  • 44
  • 53

4 Answers4

7

The trick is:

when you add (git add) to the index, you don't have to commit right away

So if you add some super complex function, and then proceed to change and... finally break it completely, you still can commit, because what is in your index (what you have added 10 minutes ago before break it with further failed modifications) is not what is currently in your working tree (which is hopelessly broken right now).

So it can help adding from time to time to the index a current development effort, knowing that you can commit at any time the last "stable" state you have indexed.


The other way what is committed is not what is in your working tree is when you git add --patch:

Interactively choose hunks of patch between the index and the work tree and add them to the index.
This gives the user a chance to review the difference before adding modified contents to the index.

You can add portion of your current file to the index (like one of the three functions you are writing), and then commit only that.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • So do I understand correctly that the difference between the working directory and the git index is `git add`? – WinWin Jul 09 '11 at 14:57
  • @WinWin: Yes: in other CVCS (SVN, ClearCase, ...), you just commit. But Git introduces the index as an intermediate state in order to commit *exactly* what you need and not a all file. That is why Git is a *content* manager, not a *file* versionning system. – VonC Jul 09 '11 at 15:00
  • 1
    @WinWin: See http://www.ericsink.com/entries/git_index.html on the `git add -p` option. See this old 2007 debate on the rationale for the index: http://thread.gmane.org/gmane.comp.version-control.git/46341. And finally, embrace the index ;) http://www.jdl.com/papers/Embrace_The_Git_Index.pdf – VonC Jul 09 '11 at 15:02
5

The index is a copy of the directory tree managed by git. Initially, it is a copy of what is in the HEAD commit. git add copies files from the working directory to the index. git commit creates a new commit from what is in the index.

The index is like a buffer-- it is not stored in the git history but access to it is controlled by git (unlike your working directory, which can be accessed in any number of ways). git commits from the index so what is committed is something that git controls.

antlersoft
  • 14,636
  • 4
  • 35
  • 55
  • Your statement "`git add` copies files from the working directory to the index." is exactly what was missing from my understanding. Thanks +1. – WinWin Jul 09 '11 at 15:01
4

The answer in your particular case is that you are understanding the documentation correctly, but using the "shortcut" command to commit your entire working directory.

If you run git commit -a -m "Message" then your working directory is treated like it is the staging area. This is convenient sometimes, but you lose the ability to use the index as designed. Try the following command:

git commit -m "Message"

If you do this instead, you can use the staging area to commit only part of the changes you have made to your working directory.

Clueless
  • 3,984
  • 1
  • 20
  • 27
  • This is a great refinement to my understanding that the difference between the working directory and the git index is `git add`. Should I correct that phrasing to "the difference between the working directory and the git index is `git add -a`? – WinWin Jul 09 '11 at 15:09
  • 3
    Nope, you were right initially. The difference between the working directory and the index is whether you have run `git add` on files with changes in them. The problem is that running `git commit -a` is kind of like running `git add --update` and then `git commit`. – Clueless Jul 09 '11 at 15:13
  • You are far from being clueless... :) Thanks +1. – WinWin Jul 09 '11 at 15:15
  • Oops... by `git add -a` I meant "`git add` **plus** `commit -a`". I hope that doesn't change your answer. – WinWin Jul 09 '11 at 15:18
  • 1
    I think it still makes sense. In your original question you said that `what is committed is what is currently in the index, not what is in your working directory` was confusing. I think this is because you were using `git commit -a` where that statement doesn't apply. – Clueless Jul 09 '11 at 15:27
3

The index/staging area is NOT your working directory. You can do a simple test to see this. Create a file in your working directory called, say, foo. Add some text to the file. Then do git add foo. Now edit foo again and add (or remove) some more text.

If you run git diff --cached (which shows what's in the index), you'll only see foo as it was after the first round of edits and subsequent git add. If you do git diff (which shows what's changed in your working directory), you will see all of the additional modifications you have made since the git add.

siride
  • 200,666
  • 4
  • 41
  • 62
  • 1
    This is incorrect, because `git commit -a` doesn't commit changes to new files. OP should have to use `git add` for new files as described. – Clueless Jul 09 '11 at 15:02
  • @Clueless: that's a small part of my answer and mostly irrelevant to the question at hand. Please don't downvote because of that. I've edited my answer. – siride Jul 09 '11 at 15:04
  • @siride I have an entire subdirectory in the working directory that keeps changing and yet is never committed, despite using `commit -a`, because I never added it. @Clueless Thanks +1 for pointing this out as @siride's statement really confused me. – WinWin Jul 09 '11 at 15:06
  • @WinWin: I did't pay attention to the part where you said you were adding new files. I've gotten rid of that entirely now since you were correct there. Sorry for the confusion! – siride Jul 09 '11 at 16:09