From: Junio C Hamano Date: Mon, 26 Nov 2007 03:10:01 +0000 (-0800) Subject: Merge branch 'maint' X-Git-Tag: v1.5.4-rc0~145 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/1ab58e8d6f728cdde0057f7ee88daab3a1c2d06f?ds=inline;hp=-c Merge branch 'maint' * maint: user-manual: recovering from corruption user-manual: clarify language about "modifying" old commits user-manual: failed push to public repository user-manual: define "branch" and "working tree" at start git-checkout: describe detached head correctly --- 1ab58e8d6f728cdde0057f7ee88daab3a1c2d06f diff --combined Documentation/user-manual.txt index 3661879f1a,b0a873bd7f..0aaed10c76 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@@ -56,11 -56,12 +56,12 @@@ $ git clone git://git.kernel.org/pub/sc 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 <>, 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 +72,13 @@@ of files. It stores the history as a c interrelated snapshots of the project's contents. In git each such version is called a <>. - A single git repository may contain multiple branches. It keeps track - of them by keeping a list of <> 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 >, which may + merge and diverge. + + A single git repository can track development on multiple branches. It + does this by keeping a list of <> 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 +481,7 @@@ Bisecting: 3537 revisions left to test 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: ------------------------------------------------- @@@ -933,7 -939,7 +939,7 @@@ file such that it contained the given c commit. You can find out with this: ------------------------------------------------- -$ git log --raw --abbrev=40 --pretty=oneline -- filename | +$ git log --raw --abbrev=40 --pretty=oneline | grep -B 1 `git hash-object filename` ------------------------------------------------- @@@ -1374,7 -1380,7 +1380,7 @@@ If you make a commit that you later wis 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 @@@ -1410,8 -1416,8 +1416,8 @@@ with the changes to be reverted, then y conflicts manually, just as in the case of <>. - [[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 @@@ -1434,7 -1440,7 +1440,7 @@@ Again, you should never do this to a co 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 <>. @@@ -1502,7 -1508,7 +1508,7 @@@ Ensuring good performanc ------------------------- On large repositories, git depends on compression to keep the history -information from taking up to much space on disk or in memory. +information from taking up too much space on disk or in memory. This compression is not performed automatically. Therefore you should occasionally run gitlink:git-gc[1]: @@@ -1543,7 -1549,7 +1549,7 @@@ dangling tree b24c2473f1fd3d91352a62479 Dangling objects are not a problem. At worst they may take up a little extra disk space. They can sometimes provide a last-resort method for recovering lost work--see <> for details. However, if -you wish, you can remove them with gitlink:git-prune[1] or the --prune +you wish, you can remove them with gitlink:git-prune[1] or the `--prune` option to gitlink:git-gc[1]: ------------------------------------------------- @@@ -1554,6 -1560,11 +1560,11 @@@ This may be time-consuming. Unlike mos 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 + <> for a detailed discussion. + [[recovering-lost-changes]] Recovering lost changes ~~~~~~~~~~~~~~~~~~~~~~~ @@@ -1562,7 -1573,7 +1573,7 @@@ Reflogs ^^^^^^^ -Say you modify a branch with gitlink:git-reset[1] --hard, and then +Say you modify a branch with `gitlink:git-reset[1] --hard`, and then realize that the branch was the only reference you had to that point in history. @@@ -1574,9 -1585,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, @@@ -1691,7 -1702,7 +1702,7 @@@ $ git pul More generally, a branch that is created from a remote branch will pull by default from that branch. See the descriptions of the branch..remote and branch..merge options in -gitlink:git-config[1], and the discussion of the --track option in +gitlink:git-config[1], and the discussion of the `--track` option in gitlink:git-checkout[1], to learn how to control these defaults. In addition to saving you keystrokes, "git pull" also helps you by @@@ -1789,7 -1800,7 +1800,7 @@@ $ git clone /path/to/repositor $ git pull /path/to/other/repository ------------------------------------------------- -or an ssh url: +or an ssh URL: ------------------------------------------------- $ git clone ssh://yourhost/~you/repository @@@ -1850,7 -1861,7 +1861,7 @@@ Exporting a git repository via the git This is the preferred method. If someone else administers the server, they should tell you what -directory to put the repository in, and what git:// url it will appear +directory to put the repository in, and what git:// URL it will appear at. You can then skip to the section "<>", below. @@@ -1887,8 -1898,8 +1898,8 @@@ $ chmod a+x hooks/post-updat gitlink:git-update-server-info[1], and the documentation link:hooks.html[Hooks used by git].) -Advertise the url of proj.git. Anybody else should then be able to -clone or pull from that url, for example with a command line like: +Advertise the URL of proj.git. Anybody else should then be able to +clone or pull from that URL, for example with a command line like: ------------------------------------------------- $ git clone http://yourserver.com/~you/proj.git @@@ -1923,15 -1934,9 +1934,9 @@@ or jus $ git push ssh://yourserver.com/~you/proj.git master ------------------------------------------------- - As with git-fetch, git-push will complain if this does not result in - a <>. 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 + <>; see the following section for details on + handling this case. Note that the target of a "push" is normally a <> repository. You can also push to a @@@ -1959,6 -1964,52 +1964,52 @@@ See the explanations of the remote..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 <> 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 <>), or + - use `git rebase` to rebase any already-published commits (as + in <>). + + 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 <>.) + + 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 + <> and + link:cvs-migration.html[git for CVS users] for more. + [[setting-up-a-shared-repository]] Setting up a shared repository ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@@ -2047,7 -2098,7 +2098,7 @@@ $ git branch --track test origin/maste $ git branch --track release origin/master ------------------------------------------------- -These can be easily kept up to date using gitlink:git-pull[1] +These can be easily kept up to date using gitlink:git-pull[1]. ------------------------------------------------- $ git checkout test && git pull @@@ -2139,7 -2190,7 +2190,7 @@@ changes are in a specific branch, use $ git log linux..branchname | git-shortlog ------------------------------------------------- -To see whether it has already been merged into the test or release branches +To see whether it has already been merged into the test or release branches, use: ------------------------------------------------- @@@ -2152,12 -2203,12 +2203,12 @@@ o $ git log release..branchname ------------------------------------------------- -(If this branch has not yet been merged you will see some log entries. +(If this branch has not yet been merged, you will see some log entries. If it has been merged, then there will be no output.) Once a patch completes the great cycle (moving from test to release, then pulled by Linus, and finally coming back into your local -"origin/master" branch) the branch for this change is no longer needed. +"origin/master" branch), the branch for this change is no longer needed. You detect this when the output from: ------------------------------------------------- @@@ -2419,18 -2470,18 +2470,18 @@@ $ git rebase --continu and git will continue applying the rest of the patches. -At any point you may use the --abort option to abort this process and +At any point you may use the `--abort` option to abort this process and 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 <> that you can replace the + We saw in <> that you can replace the most recent commit using ------------------------------------------------- @@@ -2440,8 -2491,10 +2491,10 @@@ $ git commit --amen 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 @@@ -2486,9 -2539,9 +2539,9 @@@ $ git checkout -b mywork-new origi $ gitk origin..mywork & ------------------------------------------------- -And browse through the list of patches in the mywork branch using gitk, +and browse through the list of patches in the mywork branch using gitk, applying them (possibly in a different order) to mywork-new using -cherry-pick, and possibly modifying them as you go using commit --amend. +cherry-pick, and possibly modifying them as you go using `commit --amend`. The gitlink:git-gui[1] command may also help as it allows you to individually select diff hunks for inclusion in the index (by right-clicking on the diff hunk and choosing "Stage Hunk for Commit"). @@@ -2812,7 -2865,7 +2865,7 @@@ others - Git can quickly determine whether two objects are identical or not, just by comparing names. -- Since object names are computed the same way in ever repository, the +- Since object names are computed the same way in every repository, the same content stored in two repositories will always be stored under the same name. - Git can detect errors when it reads an object, by checking that the @@@ -2829,7 -2882,7 +2882,7 @@@ There are four different types of objec "blob" objects into a directory structure. In addition, a tree object can refer to other tree objects, thus creating a directory hierarchy. - A <> ties such directory hierarchies - together into a <> of revisions - each + together into a <> of revisions--each commit contains the object name of exactly one tree designating the directory hierarchy at the time of the commit. In addition, a commit refers to "parent" commit objects that describe the history of how we @@@ -3102,7 -3155,7 +3155,7 @@@ There are also other situations that ca example, a "dangling blob" may arise because you did a "git add" of a file, but then, before you actually committed it and made it part of the bigger picture, you changed something else in that file and committed -that *updated* thing - the old state that you added originally ends up +that *updated* thing--the old state that you added originally ends up not being pointed to by any commit or tree, so it's now a dangling blob object. @@@ -3117,7 -3170,7 +3170,7 @@@ up pointing to them, so they end up "da Generally, dangling objects aren't anything to worry about. They can even be very useful: if you screw something up, the dangling objects can be how you recover your old tree (say, you did a rebase, and realized -that you really didn't want to - you can look at what dangling objects +that you really didn't want to--you can look at what dangling objects you have, and decide to reset your head to some old dangling state). For commits, you can just use: @@@ -3161,10 -3214,10 +3214,10 @@@ $ git prun ------------------------------------------------ and they'll be gone. But you should only run "git prune" on a quiescent -repository - it's kind of like doing a filesystem fsck recovery: you +repository--it's kind of like doing a filesystem fsck recovery: you don't want to do that while the filesystem is mounted. -(The same is true of "git-fsck" itself, btw - but since +(The same is true of "git-fsck" itself, btw, but since git-fsck never actually *changes* the repository, it just reports on what it found, git-fsck itself is never "dangerous" to run. Running it while somebody is actually changing the repository can cause @@@ -3172,6 -3225,127 +3225,127 @@@ confusing and scary messages, but it wo 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 + ------------------------------------------------ + + and your repository is good again! + -(Btw, you could have ignored the fsck, and started with doing a ++(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 ++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 ----------- @@@ -3498,10 -3672,9 +3672,10 @@@ The Workflo ------------ High-level operations such as gitlink:git-commit[1], -gitlink:git-checkout[1] and git-reset[1] work by moving data between the -working tree, the index, and the object database. Git provides -low-level operations which perform each of these steps individually. +gitlink:git-checkout[1] and gitlink:git-reset[1] work by moving data +between the working tree, the index, and the object database. Git +provides low-level operations which perform each of these steps +individually. Generally, all "git" operations work on the index file. Some operations work *purely* on the index file (showing the current state of the @@@ -3556,7 -3729,7 +3730,7 @@@ You write your current index file to a $ git write-tree ------------------------------------------------- -that doesn't come with any options - it will just write out the +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 @@@ -3567,7 -3740,7 +3741,7 @@@ object database -> inde ~~~~~~~~~~~~~~~~~~~~~~~~ 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 +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 @@@ -3615,7 -3788,7 +3789,7 @@@ Tying it all togethe To commit a tree you have instantiated with "git-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 +behind it--most notably the "parent" commits that preceded it in history. Normally a "commit" has one parent: the previous state of the tree @@@ -3758,7 -3931,7 +3932,7 @@@ Once you know the three trees you are g tree, aka the common tree, and the two "result" trees, aka the branches you want to merge), you do a "merge" read into the index. This will complain if it has to throw away your old index contents, so you should -make sure that you've committed those - in fact you would normally +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). @@@ -3778,7 -3951,7 +3952,7 @@@ Merging multiple trees, continue --------------------------------- Sadly, many merges aren't trivial. If there are files that have -been added.moved or removed, or if both branches have modified the +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 @@@ -4030,7 -4203,7 +4204,7 @@@ Two things are interesting here - `get_sha1()` returns 0 on _success_. This might surprise some new Git hackers, but there is a long tradition in UNIX to return different - negative numbers in case of different errors -- and 0 on success. + negative numbers in case of different errors--and 0 on success. - the variable `sha1` in the function signature of `get_sha1()` is `unsigned char \*`, but is actually expected to be a pointer to `unsigned @@@ -4135,7 -4308,7 +4309,7 @@@ $ git branch new # create branch "n $ git branch -d new # delete branch "new" ----------------------------------------------- -Instead of basing new branch on current HEAD (the default), use: +Instead of basing a new branch on current HEAD (the default), use: ----------------------------------------------- $ git branch new test # branch named "test" @@@ -4382,4 -4555,7 +4556,7 @@@ Write a chapter on using plumbing and w 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 diff --combined git-checkout.sh index aa724ac1a3,5ca71242e7..f80939da5a --- a/git-checkout.sh +++ b/git-checkout.sh @@@ -1,16 -1,6 +1,16 @@@ #!/bin/sh -USAGE='[-q] [-f] [-b ] [-m] [] [...]' +OPTIONS_KEEPDASHDASH=t +OPTIONS_SPEC="\ +git-branch [options] [] [...] +-- +b= create a new branch started at +l create the new branchs reflog +track tells if the new branch should track the remote branch +f proceed even if the index or working tree is not HEAD +m performa three-way merge on local modifications if needed +q,quiet be quiet +" SUBDIRECTORY_OK=Sometimes . git-sh-setup require_work_tree @@@ -30,12 -20,13 +30,12 @@@ quiet v=-v LF=' ' -while [ "$#" != "0" ]; do - arg="$1" - shift - case "$arg" in - "-b") - newbranch="$1" + +while test $# != 0; do + case "$1" in + -b) shift + newbranch="$1" [ -z "$newbranch" ] && die "git checkout: -b needs a branch name" git show-ref --verify --quiet -- "refs/heads/$newbranch" && @@@ -43,54 -34,64 +43,54 @@@ git check-ref-format "heads/$newbranch" || die "git checkout: we do not like '$newbranch' as a branch name." ;; - "-l") + -l) newbranch_log=-l ;; - "--track"|"--no-track") - track="$arg" + --track|--no-track) + track="$1" ;; - "-f") + -f) force=1 ;; -m) merge=1 ;; - "-q") + -q|--quiet) quiet=1 v= ;; --) + shift break ;; - -*) - usage - ;; *) - if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null) - then - if [ -z "$rev" ]; then - echo "unknown flag $arg" - exit 1 - fi - new_name="$arg" - if git show-ref --verify --quiet -- "refs/heads/$arg" - then - rev=$(git rev-parse --verify "refs/heads/$arg^0") - branch="$arg" - fi - new="$rev" - elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null) - then - # checking out selected paths from a tree-ish. - new="$rev" - new_name="$arg^{tree}" - branch= - else - new= - new_name= - branch= - set x "$arg" "$@" - shift - fi - case "$1" in - --) - shift ;; - esac - break + usage ;; - esac + esac + shift done +arg="$1" +if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null) +then + [ -z "$rev" ] && die "unknown flag $arg" + new_name="$arg" + if git show-ref --verify --quiet -- "refs/heads/$arg" + then + rev=$(git rev-parse --verify "refs/heads/$arg^0") + branch="$arg" + fi + new="$rev" + shift +elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null) +then + # checking out selected paths from a tree-ish. + new="$rev" + new_name="$arg^{tree}" + shift +fi +[ "$1" = "--" ] && shift + case "$newbranch,$track" in ,--*) die "git checkout: --track and --no-track require -b" @@@ -133,16 -134,9 +133,16 @@@ Did you intend to checkout '$@' which c fi # Make sure the request is about existing paths. - git ls-files --error-unmatch -- "$@" >/dev/null || exit - git ls-files -- "$@" | - git checkout-index -f -u --stdin + git ls-files --full-name --error-unmatch -- "$@" >/dev/null || exit + git ls-files --full-name -- "$@" | + (cd_to_toplevel && git checkout-index -f -u --stdin) + + # Run a post-checkout hook -- the HEAD does not change so the + # current HEAD is passed in for both args + if test -x "$GIT_DIR"/hooks/post-checkout; then + "$GIT_DIR"/hooks/post-checkout $old $old 0 + fi + exit $? else # Make sure we did not fall back on $arg^{tree} codepath @@@ -175,7 -169,7 +175,7 @@@ detach_warn describe_detached_head () { test -n "$quiet" || { printf >&2 "$1 " - GIT_PAGER= git log >&2 -1 --pretty=oneline --abbrev-commit "$2" + GIT_PAGER= git log >&2 -1 --pretty=oneline --abbrev-commit "$2" -- } } @@@ -290,8 -284,3 +290,8 @@@ if [ "$?" -eq 0 ]; the else exit 1 fi + +# Run a post-checkout hook +if test -x "$GIT_DIR"/hooks/post-checkout; then + "$GIT_DIR"/hooks/post-checkout $old $new 1 +fi