📄 readme
字号:
cache, and the normal operation is to re-generate it completely from aknown tree object, or update/compare it with a live tree that is beingdeveloped. If you blow the directory cache away entirely, you generallyhaven't lost any information as long as you have the name of the treethat it described. At the same time, the directory index is at the same time also thestaging area for creating new trees, and creating a new tree alwaysinvolves a controlled modification of the index file. In particular,the index file can have the representation of an intermediate tree thathas not yet been instantiated. So the index can be thought of as awrite-back cache, which can contain dirty information that has not yetbeen written back to the backing store. The WorkflowGenerally, all "git" operations work on the index file. Some operationswork _purely_ on the index file (showing the current state of theindex), but most operations move data to and from the index file. Eitherfrom the database or from the working directory. Thus there are fourmain 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 fromone 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 ]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -