git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Junio C Hamano <junkio@cox.net>
To: git@vger.kernel.org
Cc: Linus Torvalds <torvalds@osdl.org>
Subject: [PATCH] git-checkout: revert specific paths to either index or a given tree-ish.
Date: Tue, 18 Oct 2005 01:34:58 -0700	[thread overview]
Message-ID: <7vu0ffrznx.fsf_-_@assigned-by-dhcp.cox.net> (raw)
In-Reply-To: <7vmzl7tv89.fsf@assigned-by-dhcp.cox.net> (Junio C. Hamano's message of "Mon, 17 Oct 2005 19:27:50 -0700")

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>

---

    Junio C Hamano <junkio@cox.net> writes:

    > Linus Torvalds <torvalds@osdl.org> writes:
    >
    >> Btw, I'd really like a "git checkout" that can do the per-file thing, 
    >> instead of always using the equivalent of git-checkout-index with "-a".
    >>
    >> and I suspect that a lot of people would prefer that
    >>
    >> 	git checkout filename
    >>
    >> would just do that. Instead, we error out ("no such branch"). Which 
    >> isn't even what I want, and almost certainly not what most CVS users want 
    >> (they're used to checking out individual files).

    I've redone this a bit differently since last night's "in
    the meantime..." patch, so that we can pull selected paths
    out of arbitrary tree-ish.

 git-checkout.sh                |   79 ++++++++++++++++++++++++++++++++--------
 Documentation/git-checkout.txt |   42 ++++++++++++++++++++-
 2 files changed, 103 insertions(+), 18 deletions(-)

applies-to: f7e1a8387657c4da9991861ae44347813b67bc46
4aaa702794447d9b281dd22fe532fd61e02434e1
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index f753c14..b7bb1b4 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -7,12 +7,24 @@ git-checkout - Checkout and switch to a 
 
 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>
diff --git a/git-checkout.sh b/git-checkout.sh
index 2c053a3..73652fa 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -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
-[ -z "$new" ] && new=$old
 
+# 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"
---
0.99.8.GIT

      parent reply	other threads:[~2005-10-18  8:35 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-10-16 19:14 git-checkout-index, flag ordering and --prefix kludgy handling Blaisorblade
2005-10-17 22:58 ` Junio C Hamano
2005-10-17 22:58 ` Linus Torvalds
2005-10-18  0:33   ` Junio C Hamano
2005-10-18  1:28     ` Linus Torvalds
2005-10-18  2:27       ` Junio C Hamano
2005-10-18  2:48         ` Linus Torvalds
2005-10-18  5:49           ` Teach "git diff" to handle filenames startign with '-' Linus Torvalds
2005-10-18  5:57             ` Handle "-" at beginning of filenames, part 3 Linus Torvalds
2005-10-18  8:34         ` Junio C Hamano [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7vu0ffrznx.fsf_-_@assigned-by-dhcp.cox.net \
    --to=junkio@cox.net \
    --cc=git@vger.kernel.org \
    --cc=torvalds@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).