- 3ede4ed7e895432c0a247f09d71a76db53bd0fa4
-
-which is another incomprehensible object name. Again, if you want to,
-you can use "git-cat-file -t 3ede4.." to see that this time the object
-is not a "blob" object, but a "tree" object (you can also use
-git-cat-file to actually output the raw object contents, but you'll see
-mainly a binary mess, so that's less interesting).
-
-However - normally you'd never use "git-write-tree" on its own, because
-normally you always commit a tree into a commit object using the
-"git-commit-tree" command. In fact, it's easier to not actually use
-git-write-tree on its own at all, but to just pass its result in as an
-argument to "git-commit-tree".
-
-"git-commit-tree" normally takes several arguments - it wants to know
-what the _parent_ of a commit was, but since this is the first commit
-ever in this new archive, and it has no parents, we only need to pass in
-the tree ID. However, git-commit-tree also wants to get a commit message
-on its standard input, and it will write out the resulting ID for the
-commit to its standard output.
-
-And this is where we start using the .git/HEAD file. The HEAD file is
-supposed to contain the reference to the top-of-tree, and since that's
-exactly what git-commit-tree spits out, we can do this all with a simple
-shell pipeline:
-
- echo "Initial commit" | git-commit-tree $(git-write-tree) > .git/HEAD
-
-which will say:
-
- Committing initial tree 3ede4ed7e895432c0a247f09d71a76db53bd0fa4
-
-just to warn you about the fact that it created a totally new commit
-that is not related to anything else. Normally you do this only _once_
-for a project ever, and all later commits will be parented on top of an
-earlier commit, and you'll never see this "Committing initial tree"
-message ever again.
-
-
- Making a change
- ---------------
-
-Remember how we did the "git-update-cache" on file "a" and then we
-changed "a" afterward, and could compare the new state of "a" 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 "a", not the new ones. We did
-that on purpose, to show the difference between the index state, and the
-state in the working directory, 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-cache".
-
-Unlike "git-diff-files", which showed the difference between the index
-file and the working directory, "git-diff-cache" shows the differences
-between a committed _tree_ and either the the index file or the working
-directory. In other words, git-diff-cache 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-cache -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 directory 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.
-
-In other words, "git-diff-cache" normally compares a tree against the
-working directory, but when given the "--cached" flag, it is told to
-instead compare against just the index cache contents, and ignore the
-current working directory state entirely. Since we just wrote the index
-file to HEAD, doing "git-diff-cache --cached -p HEAD" should thus return
-an empty set of differences, and that's exactly what it does.
-
-[ Digression: "git-diff-cache" really always uses the index for its
- comparisons, and saying that it compares a tree against the working
- directory 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 directory 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
-directory contents", "index file" and "committed tree". We have changes
-in the working directory 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-cache a
-
-(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-xxx versions here. After
-we've updated "a" in the index, "git-diff-files -p" now shows no
-differences, but "git-diff-cache -p HEAD" still _does_ show that the
-current state is different from the state we committed. In fact, now
-"git-diff-cache" shows the same difference whether we use the "--cached"
-flag or not, since now the index is coherent with the working directory.
-
-Now, since we've updated "a" in the index, we can commit the new
-version. We could do it by writing the tree by hand, 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 the fact is, git has a simple helper
-script for doing all of the non-initial commits that does all of this
-for you, and starts up an editor to let you write your commit message
-yourself, so let's just use that:
-
- git commit
-
-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 cache), you
-can just leave an empty message. Otherwise git-commit-script will commit
-the change for you.
-
-(Btw, current versions of git will consider the change in question to be
-so big that it's considered a whole new file, since the diff is actually
-bigger than the file. So the helpful comments that git-commit-script
-tells you for this example will say that you deleted and re-created the
-file "a". For a less contrived example, these things are usually more
-obvious).
-
-You've now made your first real git commit. And if you're interested in
-looking at what git-commit-script 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.
-
-
- Checking it out
- ---------------
-
-While creating changes is useful, it's even more useful if you can tell
-later what changed. The most useful command for this is another of the
-"diff" family, namely "git-diff-tree".
-
-git-diff-tree can be given two arbitrary trees, and it will tell you the
-differences between them. Perhaps even more commonly, though, you can
-give it just a single commit object, and it will figure out the parent
-of that commit itself, and show the difference directly. Thus, to get
-the same diff that we've already seen several times, we can now do
-
- git-diff-tree -p HEAD
-
-(again, "-p" means to show the difference as a human-readable patch),
-and it will show what the last commit (in HEAD) actually changed.
-
-More interestingly, you can also give git-diff-tree the "-v" flag, which
-tells it to also show the commit message and author and date of the
-commit, and you can tell it to show a whole series of diffs.
-Alternatively, you can tell it to be "silent", and not show the diffs at
-all, but just show the actual commit message.
-
-In fact, together with the "git-rev-list" program (which generates a
-list of revisions), git-diff-tree ends up being a veritable fount of
-changes. A trivial (but very useful) script called "git-whatchanged" is
-included with git which does exactly this, and shows a log of recent
-activity.
-
-To see the whole history of our pitiful little git-tutorial project, you
-can do
-
- git log
-
-which shows just the log messages, or if we want to see the log together
-with the associated patches use the more complex (and much more
-powerful)
-
- git-whatchanged -p --root
-
-and you will see exactly what has changed in the repository over its
-short history.