Путеводитель по Руководству Linux

  User  |  Syst  |  Libr  |  Device  |  Files  |  Other  |  Admin  |  Head  |



   gitcore-tutorial    ( 7 )

основное руководство Git для разработчиков (A Git core tutorial for developers)

MAKING A CHANGE

Remember how we did the git update-index on file hello and then we changed hello afterward, and could compare the new state of hello with the state we saved in the index file?

Further, remember how I said that git write-tree writes the contents of the index file to the tree, and thus what we just committed was in fact the original contents of the file hello, not the new ones. We did that on purpose, to show the difference between the index state, and the state in the working tree, and how they don't have to match, even when we commit things.

As before, if we do git diff-files -p in our git-tutorial project, we'll still see the same difference we saw last time: the index file hasn't changed by the act of committing anything. However, now that we have committed something, we can also learn to use a new command: git diff-index.

Unlike git diff-files, which showed the difference between the index file and the working tree, git diff-index shows the differences between a committed tree and either the index file or the working tree. In other words, git diff-index wants a tree to be diffed against, and before we did the commit, we couldn't do that, because we didn't have anything to diff against.

But now we can do

$ git diff-index -p HEAD

(where -p has the same meaning as it did in git diff-files), and it will show us the same difference, but for a totally different reason. Now we're comparing the working tree not against the index file, but against the tree we just wrote. It just so happens that those two are obviously the same, so we get the same result.

Again, because this is a common operation, you can also just shorthand it with

$ git diff HEAD

which ends up doing the above for you.

In other words, git diff-index normally compares a tree against the working tree, but when given the --cached flag, it is told to instead compare against just the index cache contents, and ignore the current working tree state entirely. Since we just wrote the index file to HEAD, doing git diff-index --cached -p HEAD should thus return an empty set of differences, and that's exactly what it does.

Note git diff-index really always uses the index for its comparisons, and saying that it compares a tree against the working tree is thus not strictly accurate. In particular, the list of files to compare (the "meta-data") always comes from the index file, regardless of whether the --cached flag is used or not. The --cached flag really only determines whether the file contents to be compared come from the working tree or not.

This is not hard to understand, as soon as you realize that Git simply never knows (or cares) about files that it is not told about explicitly. Git will never go looking for files to compare, it expects you to tell it what the files are, and that's what the index is there for.

However, our next step is to commit the change we did, and again, to understand what's going on, keep in mind the difference between "working tree contents", "index file" and "committed tree". We have changes in the working tree that we want to commit, and we always have to work through the index file, so the first thing we need to do is to update the index cache:

$ git update-index hello

(note how we didn't need the --add flag this time, since Git knew about the file already).

Note what happens to the different git diff-* versions here. After we've updated hello in the index, git diff-files -p now shows no differences, but git diff-index -p HEAD still does show that the current state is different from the state we committed. In fact, now git diff-index shows the same difference whether we use the --cached flag or not, since now the index is coherent with the working tree.

Now, since we've updated hello in the index, we can commit the new version. We could do it by writing the tree by hand again, and committing the tree (this time we'd have to use the -p HEAD flag to tell commit that the HEAD was the parent of the new commit, and that this wasn't an initial commit any more), but you've done that once already, so let's just use the helpful script this time:

$ git commit

which starts an editor for you to write the commit message and tells you a bit about what you have done.

Write whatever message you want, and all the lines that start with # will be pruned out, and the rest will be used as the commit message for the change. If you decide you don't want to commit anything after all at this point (you can continue to edit things and update the index), you can just leave an empty message. Otherwise git commit will commit the change for you.

You've now made your first real Git commit. And if you're interested in looking at what git commit really does, feel free to investigate: it's a few very simple shell scripts to generate the helpful (?) commit message headers, and a few one-liners that actually do the commit itself (git commit).