+developed. If you blow the directory cache away entirely, you generally
+haven't lost any information as long as you have the name of the tree
+that it described.
+
+At the same time, the directory index is at the same time also the
+staging area for creating new trees, and creating a new tree always
+involves a controlled modification of the index file. In particular,
+the index file can have the representation of an intermediate tree that
+has not yet been instantiated. So the index can be thought of as a
+write-back cache, which can contain dirty information that has not yet
+been written back to the backing store.
+
+
+
+ The Workflow
+
+
+Generally, all "git" operations work on the index file. Some operations
+work _purely_ on the index file (showing the current state of the
+index), but most operations move data to and from the index file. Either
+from the database or from the working directory. Thus there are four
+main combinations:
+
+ 1) working directory -> index
+
+ You update the index with information from the working directory
+ with the "update-cache" command. You generally update the index
+ information by just specifying the filename you want to update,
+ like so:
+
+ update-cache filename
+
+ but to avoid common mistakes with filename globbing etc, the
+ command will not normally add totally new entries or remove old
+ entries, ie it will normally just update existing cache entryes.
+
+ To tell git that yes, you really do realize that certain files
+ no longer exist in the archive, or that new files should be
+ added, you should use the "--remove" and "--add" flags
+ respectively.
+
+ NOTE! A "--remove" flag does _not_ mean that subsequent
+ filenames will necessarily be removed: if the files still exist
+ in your directory structure, the index will be updated with
+ their new status, not removed. The only thing "--remove" means
+ is that update-cache will be considering a removed file to be a
+ valid thing, and if the file really does not exist any more, it
+ will update the index accordingly.
+
+ As a special case, you can also do "update-cache --refresh",
+ which will refresh the "stat" information of each index to match
+ the current stat information. It will _not_ update the object
+ status itself, and it wil only update the fields that are used
+ to quickly test whether an object still matches its old backing
+ store object.
+
+ 2) index -> object database
+
+ You write your current index file to a "tree" object with the
+ program
+
+ write-tree
+
+ that doesn't come with any options - it will just write out the
+ current index into the set of tree objects that describe that
+ state, and it will return the name of the resulting top-level
+ tree. You can use that tree to re-generate the index at any time
+ by going in the other direction:
+
+ 3) object database -> index
+
+ You read a "tree" file from the object database, and use that to
+ populate (and overwrite - don't do this if your index contains
+ any unsaved state that you might want to restore later!) your
+ current index. Normal operation is just
+
+ read-tree <sha1 of tree>
+
+ and your index file will now be equivalent to the tree that you
+ saved earlier. However, that is only your _index_ file: your
+ working directory contents have not been modified.
+
+ 4) index -> working directory
+
+ You update your working directory from the index by "checking
+ out" files. This is not a very common operation, since normally
+ you'd just keep your files updated, and rather than write to
+ your working directory, you'd tell the index files about the
+ changes in your working directory (ie "update-cache").
+
+ However, if you decide to jump to a new version, or check out
+ somebody elses version, or just restore a previous tree, you'd
+ populate your index file with read-tree, and then you need to
+ check out the result with
+
+ checkout-cache filename
+
+ or, if you want to check out all of the index, use "-a".
+
+ NOTE! checkout-cache normally refuses to overwrite old files, so
+ if you have an old version of the tree already checked out, you
+ will need to use the "-f" flag (_before_ the "-a" flag or the
+ filename) to _force_ the checkout.
+
+
+Finally, there are a few odds and ends which are not purely moving from
+one representation to the other:
+
+ 5) Tying it all together
+
+ To commit a tree you have instantiated with "write-tree", you'd
+ create a "commit" object that refers to that tree and the
+ history behind it - most notably the "parent" commits that
+ preceded it in history.
+
+ Normally a "commit" has one parent: the previous state of the
+ tree before a certain change was made. However, sometimes it can
+ have two or more parent commits, in which case we call it a
+ "merge", due to the fact that such a commit brings together
+ ("merges") two or more previous states represented by other
+ commits.
+
+ In other words, while a "tree" represents a particular directory
+ state of a working directory, a "commit" represents that state
+ in "time", and explains how we got there.
+
+ You create a commit object by giving it the tree that describes
+ the state at the time of the commit, and a list of parents:
+
+ commit-tree <tree> -p <parent> [-p <parent2> ..]
+
+ and then giving the reason for the commit on stdin (either
+ through redirection from a pipe or file, or by just typing it at
+ the tty).
+
+ commit-tree will return the name of the object that represents
+ that commit, and you should save it away for later use.
+ Normally, you'd commit a new "HEAD" state, and while git doesn't
+ care where you save the note about that state, in practice we
+ tend to just write the result to the file ".git/HEAD", so that
+ we can always see what the last committed state was.
+
+ 6) Examining the data
+
+ You can examine the data represented in the object database and
+ the index with various helper tools. For every object, you can
+ use "cat-file" to examine details about the object:
+
+ cat-file -t <objectname>
+
+ shows the type of the object, and once you have the type (which
+ is usually implicit in where you find the object), you can use
+
+ cat-file blob|tree|commit <objectname>
+
+ to show its contents. NOTE! Trees have binary content, and as a
+ result there is a special helper for showing that content,
+ called "ls-tree", which turns the binary content into a more
+ easily readable form.
+
+ It's especially instructive to look at "commit" objects, since
+ those tend to be small and fairly self-explanatory. In
+ particular, if you follow the convention of having the top
+ commit name in ".git/HEAD", you can do
+
+ cat-file commit $(cat .git/HEAD)
+
+ to see what the top commit was.
+
+ 7) Merging multiple trees
+
+ Git helps you do a three-way merge, which you can expand to
+ n-way by repeating the merge procedure arbitrary times until you
+ finally "commit" the state. The normal situation is that you'd
+ only do one three-way merge (two parents), and commit it, but if
+ you like to, you can do multiple parents in one go.
+
+ To do a three-way merge, you need the two sets of "commit"
+ objects that you want to merge, use those to find the closest
+ common parent (a third "commit" object), and then use those
+ commit objects to find the state of the directory ("tree"
+ object) at these points.
+
+ To get the "base" for the merge, you first look up the common
+ parent of two commits with
+
+ merge-base <commit1> <commit2>
+
+ which will return you the commit they are both based on. You
+ should now look up the "tree" objects of those commits, which
+ you can easily do with (for example)
+
+ cat-file commit <commitname> | head -1
+
+ since the tree object information is always the first line in a
+ commit object.
+
+ Once you know the three trees you are going to merge (the one
+ "original" tree, aka the common case, and the two "result" trees,
+ aka the branches you want to merge), you do a "merge" read into
+ the index. This will throw away your old index contents, so you
+ should make sure that you've committed those - in fact you would
+ normally always do a merge against your last commit (which
+ should thus match what you have in your current index anyway).
+ To do the merge, do
+
+ read-tree -m <origtree> <target1tree> <target2tree>
+
+ which will do all trivial merge operations for you directly in
+ the index file, and you can just write the result out with
+ "write-tree".
+
+ NOTE! Because the merge is done in the index file, and not in
+ your working directory, your working directory will no longer
+ match your index. You can use "checkout-cache -f -a" to make the
+ effect of the merge be seen in your working directory.
+
+ NOTE2! Sadly, many merges aren't trivial. If there are files
+ that have been added.moved or removed, or if both branches have
+ modified the same file, you will be left with an index tree that
+ contains "merge entries" in it. Such an index tree can _NOT_ be
+ written out to a tree object, and you will have to resolve any
+ such merge clashes using other tools before you can write out
+ the result.
+
+ [ fixme: talk about resolving merges here ]
+