Subject: [RFC/PATCH] reset: accept "git reset <removed file>"

From: Jonathan Nieder <[email-masked]>
Date: Mon, 18 Oct 2010 17:48:40 -0500

Suppose I try to use "git reset" to un-add an new, unwanted file:

	echo hello >foo.c
	git add foo.c
	rm foo.c; # bad file! bad!
	git reset foo.c

The file foo.c does not exist on disk, so "git reset" rejects the
request with

	fatal: ambiguous argument 'foo.c': unknown revision or path not in the working tree.
	Use '--' to separate paths from revisions

Git can do better: since foo.c is not a revision and has an entry in
the index, it is clear the request refers to a path and not a rev.

Signed-off-by: Jonathan Nieder <[email-masked]>
---
Jonathan Nieder wrote:

> Ah, this is a kind of obnoxious thing!  For a newly added file,
>
> 	git reset -- <path>
>
> ought to un-add it, but it doesn't.

Err, yes it does.  Probably I was thinking of

	rm <path>
	git reset <path>

producing an "ambiguous argument" message.

 builtin/reset.c  |    8 +++++++-
 t/t7102-reset.sh |   34 ++++++++++++++++++++++++++++++++--
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/builtin/reset.c b/builtin/reset.c
index 0037be4..7d23d75 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -295,7 +295,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 			rev = argv[i++];
 		} else {
 			/* Otherwise we treat this as a filename */
-			verify_filename(prefix, argv[i]);
+			const char *name = argv[i];
+			if (prefix)
+				name = prefix_filename(prefix, strlen(prefix), name);
+			if (read_cache() < 0)
+				die("Could not read index");
+			if (cache_name_pos(name, strlen(name)) < 0)
+				verify_filename(prefix, argv[i]);
 		}
 	}
 
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index b8cf260..69d125e 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -5,7 +5,7 @@
 
 test_description='git reset
 
-Documented tests for git reset'
+Miscellaneous tests for git reset'
 
 . ./test-lib.sh
 
@@ -441,6 +441,15 @@ test_expect_success 'disambiguation (1)' '
 
 '
 
+test_expect_success "disambiguation (1')" '
+
+	git reset --hard &&
+	git reset secondfile &&
+	git diff --exit-code &&
+	git diff --cached --exit-code
+
+'
+
 test_expect_success 'disambiguation (2)' '
 
 	git reset --hard &&
@@ -448,11 +457,18 @@ test_expect_success 'disambiguation (2)' '
 	git add secondfile &&
 	rm -f secondfile &&
 	test_must_fail git reset secondfile &&
-	test -n "$(git diff --cached --name-only -- secondfile)" &&
+	test -z "$(git diff --cached --name-only)" &&
 	test ! -f secondfile
 
 '
 
+test_expect_success "disambiguation (2')" '
+
+	git reset --hard &&
+	test_must_fail git reset doesnotexist
+
+'
+
 test_expect_success 'disambiguation (3)' '
 
 	git reset --hard &&
@@ -465,6 +481,13 @@ test_expect_success 'disambiguation (3)' '
 
 '
 
+test_expect_success "disambiguation (3')" '
+
+	git reset --hard &&
+	git reset HEAD doesnotexist
+
+'
+
 test_expect_success 'disambiguation (4)' '
 
 	git reset --hard &&
@@ -476,4 +499,11 @@ test_expect_success 'disambiguation (4)' '
 	test ! -f secondfile
 '
 
+test_expect_success "disambiguation (4')" '
+
+	git reset --hard &&
+	git reset -- doesnotexist
+
+'
+
 test_done
-- 
1.7.2.3