diff options
Diffstat (limited to 'Documentation/user-manual.txt')
-rw-r--r-- | Documentation/user-manual.txt | 318 |
1 files changed, 284 insertions, 34 deletions
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index d99adc6f72..93a47b439b 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -56,11 +56,12 @@ $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git The initial clone may be time-consuming for a large project, but you will only need to clone once. -The clone command creates a new directory named after the project -("git" or "linux-2.6" in the examples above). After you cd into this +The clone command creates a new directory named after the project ("git" +or "linux-2.6" in the examples above). After you cd into this directory, you will see that it contains a copy of the project files, -together with a special top-level directory named ".git", which -contains all the information about the history of the project. +called the <<def_working_tree,working tree>>, together with a special +top-level directory named ".git", which contains all the information +about the history of the project. [[how-to-check-out]] How to check out a different version of a project @@ -71,8 +72,13 @@ of files. It stores the history as a compressed collection of interrelated snapshots of the project's contents. In git each such version is called a <<def_commit,commit>>. -A single git repository may contain multiple branches. It keeps track -of them by keeping a list of <<def_head,heads>> which reference the +Those snapshots aren't necessarily all arranged in a single line from +oldest to newest; instead, work may simultaneously proceed along +parallel lines of development, called <def_branch,branches>>, which may +merge and diverge. + +A single git repository can track development on multiple branches. It +does this by keeping a list of <<def_head,heads>> which reference the latest commit on each branch; the gitlink:git-branch[1] command shows you the list of branch heads: @@ -475,7 +481,7 @@ Bisecting: 3537 revisions left to test after this If you run "git branch" at this point, you'll see that git has temporarily moved you to a new branch named "bisect". This branch points to a commit (with commit id 65934...) that is reachable from -v2.6.19 but not from v2.6.18. Compile and test it, and see whether +"master" but not from v2.6.18. Compile and test it, and see whether it crashes. Assume it does crash. Then: ------------------------------------------------- @@ -658,16 +664,23 @@ gitlink:git-diff[1]: $ git diff master..test ------------------------------------------------- -Sometimes what you want instead is a set of patches: +That will produce the diff between the tips of the two branches. If +you'd prefer to find the diff from their common ancestor to test, you +can use three dots instead of two: + +------------------------------------------------- +$ git diff master...test +------------------------------------------------- + +Sometimes what you want instead is a set of patches; for this you can +use gitlink:git-format-patch[1]: ------------------------------------------------- $ git format-patch master..test ------------------------------------------------- will generate a file with a patch for each commit reachable from test -but not from master. Note that if master also has commits which are -not reachable from test, then the combined result of these patches -will not be the same as the diff produced by the git-diff example. +but not from master. [[viewing-old-file-versions]] Viewing old file versions @@ -1367,7 +1380,7 @@ If you make a commit that you later wish you hadn't, there are two fundamentally different ways to fix the problem: 1. You can create a new commit that undoes whatever was done - by the previous commit. This is the correct thing if your + by the old commit. This is the correct thing if your mistake has already been made public. 2. You can go back and modify the old commit. You should @@ -1403,8 +1416,8 @@ with the changes to be reverted, then you will be asked to fix conflicts manually, just as in the case of <<resolving-a-merge, resolving a merge>>. -[[fixing-a-mistake-by-editing-history]] -Fixing a mistake by editing history +[[fixing-a-mistake-by-rewriting-history]] +Fixing a mistake by rewriting history ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If the problematic commit is the most recent commit, and you have not @@ -1427,7 +1440,7 @@ Again, you should never do this to a commit that may already have been merged into another branch; use gitlink:git-revert[1] instead in that case. -It is also possible to edit commits further back in the history, but +It is also possible to replace commits further back in the history, but this is an advanced topic to be left for <<cleaning-up-history,another chapter>>. @@ -1547,6 +1560,11 @@ This may be time-consuming. Unlike most other git operations (including git-gc when run without any options), it is not safe to prune while other git operations are in progress in the same repository. +If gitlink:git-fsck[1] complains about sha1 mismatches or missing +objects, you may have a much more serious problem; your best option is +probably restoring from backups. See +<<recovering-from-repository-corruption>> for a detailed discussion. + [[recovering-lost-changes]] Recovering lost changes ~~~~~~~~~~~~~~~~~~~~~~~ @@ -1567,9 +1585,9 @@ old history using, for example, $ git log master@{1} ------------------------------------------------- -This lists the commits reachable from the previous version of the head. -This syntax can be used to with any git command that accepts a commit, -not just with git log. Some other examples: +This lists the commits reachable from the previous version of the +"master" branch head. This syntax can be used with any git command +that accepts a commit, not just with git log. Some other examples: ------------------------------------------------- $ git show master@{2} # See where the branch pointed 2, @@ -1916,15 +1934,9 @@ or just $ git push ssh://yourserver.com/~you/proj.git master ------------------------------------------------- -As with git-fetch, git-push will complain if this does not result in -a <<fast-forwards,fast forward>>. Normally this is a sign of -something wrong. However, if you are sure you know what you're -doing, you may force git-push to perform the update anyway by -preceding the branch name by a plus sign: - -------------------------------------------------- -$ git push ssh://yourserver.com/~you/proj.git +master -------------------------------------------------- +As with git-fetch, git-push will complain if this does not result in a +<<fast-forwards,fast forward>>; see the following section for details on +handling this case. Note that the target of a "push" is normally a <<def_bare_repository,bare>> repository. You can also push to a @@ -1952,6 +1964,52 @@ See the explanations of the remote.<name>.url, branch.<name>.remote, and remote.<name>.push options in gitlink:git-config[1] for details. +[[forcing-push]] +What to do when a push fails +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a push would not result in a <<fast-forwards,fast forward>> of the +remote branch, then it will fail with an error like: + +------------------------------------------------- +error: remote 'refs/heads/master' is not an ancestor of + local 'refs/heads/master'. + Maybe you are not up-to-date and need to pull first? +error: failed to push to 'ssh://yourserver.com/~you/proj.git' +------------------------------------------------- + +This can happen, for example, if you: + + - use `git reset --hard` to remove already-published commits, or + - use `git commit --amend` to replace already-published commits + (as in <<fixing-a-mistake-by-rewriting-history>>), or + - use `git rebase` to rebase any already-published commits (as + in <<using-git-rebase>>). + +You may force git-push to perform the update anyway by preceding the +branch name with a plus sign: + +------------------------------------------------- +$ git push ssh://yourserver.com/~you/proj.git +master +------------------------------------------------- + +Normally whenever a branch head in a public repository is modified, it +is modified to point to a descendent of the commit that it pointed to +before. By forcing a push in this situation, you break that convention. +(See <<problems-with-rewriting-history>>.) + +Nevertheless, this is a common practice for people that need a simple +way to publish a work-in-progress patch series, and it is an acceptable +compromise as long as you warn other developers that this is how you +intend to manage the branch. + +It's also possible for a push to fail in this way when other people have +the right to push to the same repository. In that case, the correct +solution is to retry the push after first updating your work by either a +pull or a fetch followed by a rebase; see the +<<setting-up-a-shared-repository,next section>> and +link:cvs-migration.html[git for CVS users] for more. + [[setting-up-a-shared-repository]] Setting up a shared repository ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2419,11 +2477,11 @@ return mywork to the state it had before you started the rebase: $ git rebase --abort ------------------------------------------------- -[[modifying-one-commit]] -Modifying a single commit +[[rewriting-one-commit]] +Rewriting a single commit ------------------------- -We saw in <<fixing-a-mistake-by-editing-history>> that you can replace the +We saw in <<fixing-a-mistake-by-rewriting-history>> that you can replace the most recent commit using ------------------------------------------------- @@ -2433,8 +2491,10 @@ $ git commit --amend which will replace the old commit by a new commit incorporating your changes, giving you a chance to edit the old commit message first. -You can also use a combination of this and gitlink:git-rebase[1] to edit -commits further back in your history. First, tag the problematic commit with +You can also use a combination of this and gitlink:git-rebase[1] to +replace a commit further back in your history and recreate the +intervening changes on top of it. First, tag the problematic commit +with ------------------------------------------------- $ git tag bad mywork~5 @@ -2554,6 +2614,72 @@ branches into their own work. For true distributed development that supports proper merging, published branches should never be rewritten. +[[bisect-merges]] +Why bisecting merge commits can be harder than bisecting linear history +----------------------------------------------------------------------- + +The gitlink:git-bisect[1] command correctly handles history that +includes merge commits. However, when the commit that it finds is a +merge commit, the user may need to work harder than usual to figure out +why that commit introduced a problem. + +Imagine this history: + +................................................ + ---Z---o---X---...---o---A---C---D + \ / + o---o---Y---...---o---B +................................................ + +Suppose that on the upper line of development, the meaning of one +of the functions that exists at Z is changed at commit X. The +commits from Z leading to A change both the function's +implementation and all calling sites that exist at Z, as well +as new calling sites they add, to be consistent. There is no +bug at A. + +Suppose that in the meantime on the lower line of development somebody +adds a new calling site for that function at commit Y. The +commits from Z leading to B all assume the old semantics of that +function and the callers and the callee are consistent with each +other. There is no bug at B, either. + +Suppose further that the two development lines merge cleanly at C, +so no conflict resolution is required. + +Nevertheless, the code at C is broken, because the callers added +on the lower line of development have not been converted to the new +semantics introduced on the upper line of development. So if all +you know is that D is bad, that Z is good, and that +gitlink:git-bisect[1] identifies C as the culprit, how will you +figure out that the problem is due to this change in semantics? + +When the result of a git-bisect is a non-merge commit, you should +normally be able to discover the problem by examining just that commit. +Developers can make this easy by breaking their changes into small +self-contained commits. That won't help in the case above, however, +because the problem isn't obvious from examination of any single +commit; instead, a global view of the development is required. To +make matters worse, the change in semantics in the problematic +function may be just one small part of the changes in the upper +line of development. + +On the other hand, if instead of merging at C you had rebased the +history between Z to B on top of A, you would have gotten this +linear history: + +................................................................ + ---Z---o---X--...---o---A---o---o---Y*--...---o---B*--D* +................................................................ + +Bisecting between Z and D* would hit a single culprit commit Y*, +and understanding why Y* was broken would probably be easier. + +Partly for this reason, many experienced git users, even when +working on an otherwise merge-heavy project, keep the history +linear by rebasing against the latest upstream version before +publishing. + [[advanced-branch-management]] Advanced branch management ========================== @@ -3099,6 +3225,127 @@ confusing and scary messages, but it won't actually do anything bad. In contrast, running "git prune" while somebody is actively changing the repository is a *BAD* idea). +[[recovering-from-repository-corruption]] +Recovering from repository corruption +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By design, git treats data trusted to it with caution. However, even in +the absence of bugs in git itself, it is still possible that hardware or +operating system errors could corrupt data. + +The first defense against such problems is backups. You can back up a +git directory using clone, or just using cp, tar, or any other backup +mechanism. + +As a last resort, you can search for the corrupted objects and attempt +to replace them by hand. Back up your repository before attempting this +in case you corrupt things even more in the process. + +We'll assume that the problem is a single missing or corrupted blob, +which is sometimes a solveable problem. (Recovering missing trees and +especially commits is *much* harder). + +Before starting, verify that there is corruption, and figure out where +it is with gitlink:git-fsck[1]; this may be time-consuming. + +Assume the output looks like this: + +------------------------------------------------ +$ git-fsck --full +broken link from tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8 + to blob 4b9458b3786228369c63936db65827de3cc06200 +missing blob 4b9458b3786228369c63936db65827de3cc06200 +------------------------------------------------ + +(Typically there will be some "dangling object" messages too, but they +aren't interesting.) + +Now you know that blob 4b9458b3 is missing, and that the tree 2d9263c6 +points to it. If you could find just one copy of that missing blob +object, possibly in some other repository, you could move it into +.git/objects/4b/9458b3... and be done. Suppose you can't. You can +still examine the tree that pointed to it with gitlink:git-ls-tree[1], +which might output something like: + +------------------------------------------------ +$ git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8 +100644 blob 8d14531846b95bfa3564b58ccfb7913a034323b8 .gitignore +100644 blob ebf9bf84da0aab5ed944264a5db2a65fe3a3e883 .mailmap +100644 blob ca442d313d86dc67e0a2e5d584b465bd382cbf5c COPYING +... +100644 blob 4b9458b3786228369c63936db65827de3cc06200 myfile +... +------------------------------------------------ + +So now you know that the missing blob was the data for a file named +"myfile". And chances are you can also identify the directory--let's +say it's in "somedirectory". If you're lucky the missing copy might be +the same as the copy you have checked out in your working tree at +"somedirectory/myfile"; you can test whether that's right with +gitlink:git-hash-object[1]: + +------------------------------------------------ +$ git hash-object -w somedirectory/myfile +------------------------------------------------ + +which will create and store a blob object with the contents of +somedirectory/myfile, and output the sha1 of that object. if you're +extremely lucky it might be 4b9458b3786228369c63936db65827de3cc06200, in +which case you've guessed right, and the corruption is fixed! + +Otherwise, you need more information. How do you tell which version of +the file has been lost? + +The easiest way to do this is with: + +------------------------------------------------ +$ git log --raw --all --full-history -- somedirectory/myfile +------------------------------------------------ + +Because you're asking for raw output, you'll now get something like + +------------------------------------------------ +commit abc +Author: +Date: +... +:100644 100644 4b9458b... newsha... M somedirectory/myfile + + +commit xyz +Author: +Date: + +... +:100644 100644 oldsha... 4b9458b... M somedirectory/myfile +------------------------------------------------ + +This tells you that the immediately preceding version of the file was +"newsha", and that the immediately following version was "oldsha". +You also know the commit messages that went with the change from oldsha +to 4b9458b and with the change from 4b9458b to newsha. + +If you've been committing small enough changes, you may now have a good +shot at reconstructing the contents of the in-between state 4b9458b. + +If you can do that, you can now recreate the missing object with + +------------------------------------------------ +$ git hash-object -w <recreated-file> +------------------------------------------------ + +and your repository is good again! + +(Btw, you could have ignored the fsck, and started with doing a + +------------------------------------------------ +$ git log --raw --all +------------------------------------------------ + +and just looked for the sha of the missing object (4b9458b..) in that +whole thing. It's up to you - git does *have* a lot of information, it is +just missing one particular blob version. + [[the-index]] The index ----------- @@ -3460,7 +3707,7 @@ 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 +removed. The only thing `--remove` means is that update-index 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. @@ -4309,4 +4556,7 @@ Write a chapter on using plumbing and writing scripts. Alternates, clone -reference, etc. -git unpack-objects -r for recovery +More on recovery from repository corruption. See: + http://marc.theaimsgroup.com/?l=git&m=117263864820799&w=2 + http://marc.theaimsgroup.com/?l=git&m=117147855503798&w=2 + http://marc.theaimsgroup.com/?l=git&m=117147855503798&w=2 |