git-checkout: revert specific paths to either index or a given tree-ish.
When extra paths arguments are given, git-checkout reverts only those paths to either the version recorded in the index or the version recorded in the given tree-ish. This has been on the TODO list for quite a while. Signed-off-by: Junio C Hamano <junkio@cox.net>maint
parent
4bfe1199ea
commit
4aaa702794
|
@ -7,12 +7,24 @@ git-checkout - Checkout and switch to a branch.
|
|||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-checkout' [-f] [-b <new_branch>] [<branch>]
|
||||
'git-checkout' [-f] [-b <new_branch>] [<branch>] [<paths>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Updates the index and working tree to reflect the specified branch,
|
||||
<branch>. Updates HEAD to be <branch> or, if specified, <new_branch>.
|
||||
|
||||
When <paths> are not given, this command switches branches, by
|
||||
updating the index and working tree to reflect the specified
|
||||
branch, <branch>, and updating HEAD to be <branch> or, if
|
||||
specified, <new_branch>.
|
||||
|
||||
When <paths> are given, this command does *not* switch
|
||||
branches. It updates the named paths in the working tree from
|
||||
the index file (i.e. it runs `git-checkout-index -f -u`). In
|
||||
this case, `-f` and `-b` options are meaningless and giving
|
||||
either of them results in an error. <branch> argument can be
|
||||
used to specify a specific tree-ish to update the index for the
|
||||
given paths before updating the working tree.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
@ -29,6 +41,30 @@ OPTIONS
|
|||
Branch to checkout; may be any object ID that resolves to a
|
||||
commit. Defaults to HEAD.
|
||||
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
|
||||
The following sequence checks out the `master` branch, reverts
|
||||
the `Makefile` to two revisions back, deletes hello.c by
|
||||
mistake, and gets it back from the index.
|
||||
|
||||
------------
|
||||
$ git checkout master
|
||||
$ git checkout master~2 Makefile
|
||||
$ rm -f hello.c
|
||||
$ git checkout hello.c
|
||||
------------
|
||||
|
||||
If you have an unfortunate branch that is named `hello.c`, the
|
||||
last step above would be confused as an instruction to switch to
|
||||
that branch. You should instead write:
|
||||
|
||||
------------
|
||||
$ git checkout -- hello.c
|
||||
------------
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
|
|
@ -23,32 +23,81 @@ while [ "$#" != "0" ]; do
|
|||
"-f")
|
||||
force=1
|
||||
;;
|
||||
--)
|
||||
break
|
||||
;;
|
||||
*)
|
||||
rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) ||
|
||||
die "I don't know any '$arg'."
|
||||
if [ -z "$rev" ]; then
|
||||
echo "unknown flag $arg"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$new" ]; then
|
||||
echo "Multiple revisions?"
|
||||
exit 1
|
||||
fi
|
||||
new="$rev"
|
||||
if [ -f "$GIT_DIR/refs/heads/$arg" ]; then
|
||||
branch="$arg"
|
||||
if rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null)
|
||||
then
|
||||
if [ -z "$rev" ]; then
|
||||
echo "unknown flag $arg"
|
||||
exit 1
|
||||
fi
|
||||
new="$rev"
|
||||
if [ -f "$GIT_DIR/refs/heads/$arg" ]; then
|
||||
branch="$arg"
|
||||
fi
|
||||
elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
|
||||
then
|
||||
# checking out selected paths from a tree-ish.
|
||||
new="$rev"
|
||||
branch=
|
||||
else
|
||||
new=
|
||||
branch=
|
||||
set x "$arg" "$@"
|
||||
shift
|
||||
fi
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# The behaviour of the command with and without explicit path
|
||||
# parameters is quite different.
|
||||
#
|
||||
# Without paths, we are checking out everything in the work tree,
|
||||
# possibly switching branches. This is the traditional behaviour.
|
||||
#
|
||||
# With paths, we are _never_ switching branch, but checking out
|
||||
# the named paths from either index (when no rev is given),
|
||||
# or the named tree-ish (when rev is given).
|
||||
|
||||
if test "$#" -ge 1
|
||||
then
|
||||
if test '' != "$newbranch$force"
|
||||
then
|
||||
die "updating paths and switching branches or forcing are incompatible."
|
||||
fi
|
||||
if test '' != "$new"
|
||||
then
|
||||
# from a specific tree-ish; note that this is for
|
||||
# rescuing paths and is never meant to remove what
|
||||
# is not in the named tree-ish.
|
||||
git-ls-tree -r "$new" "$@" |
|
||||
sed -ne 's/^\([0-7]*\) blob \(.*\)$/\1 \2/p' |
|
||||
git-update-index --index-info || exit $?
|
||||
fi
|
||||
git-checkout-index -f -u -- "$@"
|
||||
exit $?
|
||||
else
|
||||
# Make sure we did not fall back on $arg^{tree} codepath
|
||||
# since we are not checking out from an arbitrary tree-ish,
|
||||
# but switching branches.
|
||||
if test '' != "$new"
|
||||
then
|
||||
git-rev-parse --verify "$new^{commit}" >/dev/null 2>&1 ||
|
||||
die "Cannot switch branch to a non-commit."
|
||||
fi
|
||||
fi
|
||||
|
||||
[ -z "$new" ] && new=$old
|
||||
|
||||
#
|
||||
# If we don't have an old branch that we're switching to,
|
||||
# and we don't have a new branch name for the target we
|
||||
# are switching to, then we'd better just be checking out
|
||||
# what we already had
|
||||
#
|
||||
|
||||
[ -z "$branch$newbranch" ] &&
|
||||
[ "$new" != "$old" ] &&
|
||||
die "git checkout: you need to specify a new branch name"
|
||||
|
|
Loading…
Reference in New Issue