[PATCH] git-rm: Fix to properly handle files with spaces, tabs, newlines, etc.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



New tests are added to the git-rm test case to cover this as well.

Signed-off-by: Carl Worth <cworth@xxxxxxxxxx>

---

On Wed, 22 Feb 2006 00:19:46 -0800, Junio C Hamano wrote:
>
> Note you are not using -z, which means we will c-quote the funny
> characters in the output...

Oh, I didn't expect C-language-style quoting. That's definitely not
going to work.

> > +*)
> > +	[[ "$remove_files" = "true" ]] && rm -- $files
> 
> Same here. What happens to filenames with IFS letters in them?
> "git-add" does not use -z and xargs -0 without a good reason.

Yeah, this is just me unleashing my shell-programming incompetence on
the world.

The attached patch addresses that problem with a rather blunt
hammer. Let me know if anyone has a more elegant approach than what I
did here.

One thing I've lost is that the previous version had a sort|uniq on
the output of git-ls-files which is useful in the case of failed
merges and other ways in which git-ls-files reports the same file
multiple times. What might be nice is a --unique flag to git-ls-files
that git-rm could use, (but on first glance it doesn't look trivial to
implement as git-ls-files doesn't ever store or sort its entire list).

> Even if rm -- $files were quoted correctly, and tried to remove
> the right files, if some of the files failed to disappear for
> whatever reason, what happens?

My intent with the previous patch was that, when git-rm is given -f,
and the rm fails to remove a file, that the file is then not removed
from the index. Of course, this was hopelessly broken due to two major
typos in the same line:

	index_remote_option=--force
instead of:
	index_remove_option=--remove

which my tests were insufficient to catch.

This behavior should now work in the current patch as well as the
proper handling of files with funny characters, (tests are included
for both).

The desired behavior when rm fails is debatable, so I'm open to
opinions. One reason I liked this was that in the previous patch, rm
would prompt the user before deleting a read-only file, and if the
user said no, then git-rm would also not remove it from the index.

This did cause another minor problem in that there would then be no
way to get git-rm to use "rm -f" when desired.

In the current patch, with my blunt hammer, there's another sub-shell
before the rm which apparently steals its tty and causes it to not
prompt at all. So that aspect may be moot.

-Carl

PS. What's the syntax/tool support for just replying to an existing
message, and at the end inserting a patch with its own subject and
commit message? Here I've manually whacked the subject and put the
commit message above my reply (in the style of git-format-patch) but
that seem seems inelegant.

 git-rm.sh     |   37 ++++++++++++++++++++-----------------
 t/t3600-rm.sh |   30 ++++++++++++++++++++++--------
 2 files changed, 42 insertions(+), 25 deletions(-)

3d52c6d60047390d434f8737368adea77fa26310
diff --git a/git-rm.sh b/git-rm.sh
index 0a3f546..fa361bd 100755
--- a/git-rm.sh
+++ b/git-rm.sh
@@ -4,7 +4,6 @@ USAGE='[-f] [-n] [-v] [--] <file>...'
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
-index_remove_option=--force-remove
 remove_files=
 show_only=
 verbose=
@@ -12,7 +11,6 @@ while : ; do
   case "$1" in
     -f)
 	remove_files=true
-	index_remote_option=--force
 	;;
     -n)
 	show_only=true
@@ -45,23 +43,28 @@ case "$#" in
 	;;
 esac
 
-files=$(
-    if test -f "$GIT_DIR/info/exclude" ; then
-	git-ls-files \
-	    --exclude-from="$GIT_DIR/info/exclude" \
-	    --exclude-per-directory=.gitignore -- "$@"
-    else
-	git-ls-files \
+if test -f "$GIT_DIR/info/exclude"
+then
+	git-ls-files -z \
+	--exclude-from="$GIT_DIR/info/exclude" \
 	--exclude-per-directory=.gitignore -- "$@"
-    fi | sort | uniq
-)
-
-case "$show_only" in
-true)
-	echo $files
+else
+	git-ls-files -z \
+	--exclude-per-directory=.gitignore -- "$@"
+fi |
+case "$show_only,remove_files" in
+true,*)
+	xargs -0 echo
+	;;
+*,true)
+	xargs -0 sh -c "
+		while [ \$# -gt 0 ]; do
+			file=\$1; shift
+			rm -- \"\$file\" && git-update-index --remove $verbose \"\$file\"
+		done
+	" inline
 	;;
 *)
-	[[ "$remove_files" = "true" ]] && rm -- $files
-	git-update-index $index_remove_option $verbose $files
+	git-update-index --force-remove $verbose -z --stdin
 	;;
 esac
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 8415732..b87beb0 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -7,13 +7,12 @@ test_description='Test of the various op
 
 . ./test-lib.sh
 
-# Setup some files to be removed
-touch foo bar
-git-add foo bar
-# Need one to test --
-touch -- -q
-git update-index --add -- -q
-git-commit -m "add foo, bar, and -q"
+# Setup some files to be removed, some with funny characters
+touch -- foo bar baz 'space embedded' 'tab	embedded' 'newline
+embedded' -q
+git-add -- foo bar baz 'space embedded' 'tab	embedded' 'newline
+embedded' -q
+git-commit -m "add files"
 
 test_expect_success \
     'Pre-check that foo is in index before git-rm foo' \
@@ -36,7 +35,22 @@ test_expect_failure \
     '[ -f bar ]'
 
 test_expect_success \
-    'Test that "git-rm -- -q" works to delete a file named -q' \
+    'Test that "git-rm -- -q" works to delete a file that looks like an option' \
     'git-rm -- -q'
 
+test_expect_success \
+    "Test that \"git-rm -f\" can remove files with embedded space, tab, or newline characters." \
+    "git-rm 'space embedded' 'tab	embedded' 'newline
+embedded"
+
+chmod u-w .
+test_expect_failure \
+    'Test that "git-rm -f" fails if its rm fails' \
+    'git-rm -f baz'
+chmod u+w .
+
+test_expect_success \
+    'When the rm in "git-rm -f" fails, it should not remove the file from the index' \
+    'git-ls-files --error-unmatch baz'
+
 test_done
-- 
1.2.2.g01a2-dirty


Attachment: pgpJgn2rC15ta.pgp
Description: PGP signature


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]