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
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-checkout' [-f] [-b <new_branch>] [<branch>]
|
'git-checkout' [-f] [-b <new_branch>] [<branch>] [<paths>...]
|
||||||
|
|
||||||
DESCRIPTION
|
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
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
@ -29,6 +41,30 @@ OPTIONS
|
||||||
Branch to checkout; may be any object ID that resolves to a
|
Branch to checkout; may be any object ID that resolves to a
|
||||||
commit. Defaults to HEAD.
|
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
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
|
|
@ -23,32 +23,81 @@ while [ "$#" != "0" ]; do
|
||||||
"-f")
|
"-f")
|
||||||
force=1
|
force=1
|
||||||
;;
|
;;
|
||||||
|
--)
|
||||||
|
break
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) ||
|
if rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null)
|
||||||
die "I don't know any '$arg'."
|
then
|
||||||
if [ -z "$rev" ]; then
|
if [ -z "$rev" ]; then
|
||||||
echo "unknown flag $arg"
|
echo "unknown flag $arg"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ "$new" ]; then
|
new="$rev"
|
||||||
echo "Multiple revisions?"
|
if [ -f "$GIT_DIR/refs/heads/$arg" ]; then
|
||||||
exit 1
|
branch="$arg"
|
||||||
fi
|
fi
|
||||||
new="$rev"
|
elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
|
||||||
if [ -f "$GIT_DIR/refs/heads/$arg" ]; then
|
then
|
||||||
branch="$arg"
|
# checking out selected paths from a tree-ish.
|
||||||
|
new="$rev"
|
||||||
|
branch=
|
||||||
|
else
|
||||||
|
new=
|
||||||
|
branch=
|
||||||
|
set x "$arg" "$@"
|
||||||
|
shift
|
||||||
fi
|
fi
|
||||||
|
break
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
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
|
[ -z "$new" ] && new=$old
|
||||||
|
|
||||||
#
|
|
||||||
# If we don't have an old branch that we're switching to,
|
# 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
|
# and we don't have a new branch name for the target we
|
||||||
# are switching to, then we'd better just be checking out
|
# are switching to, then we'd better just be checking out
|
||||||
# what we already had
|
# what we already had
|
||||||
#
|
|
||||||
[ -z "$branch$newbranch" ] &&
|
[ -z "$branch$newbranch" ] &&
|
||||||
[ "$new" != "$old" ] &&
|
[ "$new" != "$old" ] &&
|
||||||
die "git checkout: you need to specify a new branch name"
|
die "git checkout: you need to specify a new branch name"
|
||||||
|
|
Loading…
Reference in New Issue