From d4a1cab541be0c276b38285c8b33050ea411eacf Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Tue, 21 Feb 2006 15:04:51 -0800 Subject: [PATCH 1/2] Add new git-rm command with documentation This adds a git-rm command which provides convenience similar to git-add, (and a bit more since it takes care of the rm as well if given -f). Like git-add, git-rm expands the given path names through git-ls-files. This means it only acts on files listed in the index. And it does act recursively on directories by default, (no -r needed as in the case of rm itself). When it recurses, it does not remove empty directories that are left behind. Signed-off-by: Junio C Hamano --- .gitignore | 1 + Documentation/git-rm.txt | 89 ++++++++++++++++++++++++++++++++++++++++ Makefile | 2 +- git-rm.sh | 67 ++++++++++++++++++++++++++++++ t/t3600-rm.sh | 42 +++++++++++++++++++ 5 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 Documentation/git-rm.txt create mode 100755 git-rm.sh create mode 100755 t/t3600-rm.sh diff --git a/.gitignore b/.gitignore index d7e8d2ac0d..94f66d5a1e 100644 --- a/.gitignore +++ b/.gitignore @@ -84,6 +84,7 @@ git-resolve git-rev-list git-rev-parse git-revert +git-rm git-send-email git-send-pack git-sh-setup diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt new file mode 100644 index 0000000000..401bfb2d9c --- /dev/null +++ b/Documentation/git-rm.txt @@ -0,0 +1,89 @@ +git-rm(1) +========= + +NAME +---- +git-rm - Remove files from the working tree and from the index. + +SYNOPSIS +-------- +'git-rm' [-f] [-n] [-v] [--] ... + +DESCRIPTION +----------- +A convenience wrapper for git-update-index --remove. For those coming +from cvs, git-rm provides an operation similar to "cvs rm" or "cvs +remove". + + +OPTIONS +------- +...:: + Files to remove from the index and optionally, from the + working tree as well. + +-f:: + Remove files from the working tree as well as from the index. + +-n:: + Don't actually remove the file(s), just show if they exist in + the index. + +-v:: + Be verbose. + +--:: + This option can be used to separate command-line options from + the list of files, (useful when filenames might be mistaken + for command-line options). + + +DISCUSSION +---------- + +The list of given to the command is fed to `git-ls-files` +command to list files that are registered in the index and +are not ignored/excluded by `$GIT_DIR/info/exclude` file or +`.gitignore` file in each directory. This means two things: + +. You can put the name of a directory on the command line, and the + command will remove all files in it and its subdirectories (the + directories themselves are never removed from the working tree); + +. Giving the name of a file that is not in the index does not + remove that file. + + +EXAMPLES +-------- +git-rm Documentation/\\*.txt:: + + Removes all `\*.txt` files from the index that are under the + `Documentation` directory and any of its subdirectories. The + files are not removed from the working tree. ++ +Note that the asterisk `\*` is quoted from the shell in this +example; this lets the command include the files from +subdirectories of `Documentation/` directory. + +git-rm -f git-*.sh:: + + Remove all git-*.sh scripts that are in the index. The files + are removed from the index, and (because of the -f option), + from the working tree as well. Because this example lets the + shell expand the asterisk (i.e. you are listing the files + explicitly), it does not remove `subdir/git-foo.sh`. + + +Author +------ +Written by Linus Torvalds + +Documentation +-------------- +Documentation by Junio C Hamano and the git-list . + +GIT +--- +Part of the gitlink:git[7] suite + diff --git a/Makefile b/Makefile index 0c04882646..5d2ec1f111 100644 --- a/Makefile +++ b/Makefile @@ -120,7 +120,7 @@ SCRIPT_SH = \ git-merge-one-file.sh git-parse-remote.sh \ git-prune.sh git-pull.sh git-push.sh git-rebase.sh \ git-repack.sh git-request-pull.sh git-reset.sh \ - git-resolve.sh git-revert.sh git-sh-setup.sh \ + git-resolve.sh git-revert.sh git-rm.sh git-sh-setup.sh \ git-tag.sh git-verify-tag.sh git-whatchanged.sh \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ diff --git a/git-rm.sh b/git-rm.sh new file mode 100755 index 0000000000..0a3f546683 --- /dev/null +++ b/git-rm.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +USAGE='[-f] [-n] [-v] [--] ...' +SUBDIRECTORY_OK='Yes' +. git-sh-setup + +index_remove_option=--force-remove +remove_files= +show_only= +verbose= +while : ; do + case "$1" in + -f) + remove_files=true + index_remote_option=--force + ;; + -n) + show_only=true + ;; + -v) + verbose=--verbose + ;; + --) + shift; break + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +# This is typo-proofing. If some paths match and some do not, we want +# to do nothing. +case "$#" in +0) ;; +*) + git-ls-files --error-unmatch -- "$@" >/dev/null || { + echo >&2 "Maybe you misspelled it?" + exit 1 + } + ;; +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 \ + --exclude-per-directory=.gitignore -- "$@" + fi | sort | uniq +) + +case "$show_only" in +true) + echo $files + ;; +*) + [[ "$remove_files" = "true" ]] && rm -- $files + git-update-index $index_remove_option $verbose $files + ;; +esac diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh new file mode 100755 index 0000000000..841573210a --- /dev/null +++ b/t/t3600-rm.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# +# Copyright (c) 2006 Carl D. Worth +# + +test_description='Test of the various options to git-rm.' + +. ./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" + +test_expect_success \ + 'Pre-check that foo is in index before git-rm foo' \ + 'git-ls-files --error-unmatch foo' + +test_expect_success \ + 'Test that git-rm foo succeeds' \ + 'git-rm foo' + +test_expect_failure \ + 'Post-check that foo is not in index after git-rm foo' \ + 'git-ls-files --error-unmatch foo' + +test_expect_success \ + 'Test that "git-rm -f bar" works' \ + 'git-rm -f bar' + +test_expect_failure \ + 'Post-check that bar no longer exists' \ + '[ -f bar ]' + +test_expect_success \ + 'Test that "git-rm -- -q" works to delete a file named -q' \ + 'git-rm -- -q' + +test_done From 3844cdc8f19dcd848003586d6b98c9f2bd36a7d0 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Wed, 22 Feb 2006 16:37:27 -0800 Subject: [PATCH 2/2] git-rm: Fix to properly handle files with spaces, tabs, newlines, etc. New tests are added to the git-rm test case to cover this as well. Signed-off-by: Carl Worth Signed-off-by: Junio C Hamano --- git-rm.sh | 37 +++++++++++++++++++----------------- t/t3600-rm.sh | 52 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/git-rm.sh b/git-rm.sh index 0a3f546683..fda4541c76 100755 --- a/git-rm.sh +++ b/git-rm.sh @@ -4,7 +4,6 @@ USAGE='[-f] [-n] [-v] [--] ...' 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 841573210a..cabfadd56d 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -7,36 +7,54 @@ test_description='Test of the various options to git-rm.' . ./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' \ - 'git-ls-files --error-unmatch foo' + 'Pre-check that foo exists and is in index before git-rm foo' \ + '[ -f foo ] && git-ls-files --error-unmatch foo' test_expect_success \ 'Test that git-rm foo succeeds' \ 'git-rm foo' -test_expect_failure \ - 'Post-check that foo is not in index after git-rm foo' \ - 'git-ls-files --error-unmatch foo' +test_expect_success \ + 'Post-check that foo exists but is not in index after git-rm foo' \ + '[ -f foo ] && ! git-ls-files --error-unmatch foo' test_expect_success \ - 'Test that "git-rm -f bar" works' \ + 'Pre-check that bar exists and is in index before "git-rm -f bar"' \ + '[ -f bar ] && git-ls-files --error-unmatch bar' + +test_expect_success \ + 'Test that "git-rm -f bar" succeeds' \ 'git-rm -f bar' -test_expect_failure \ - 'Post-check that bar no longer exists' \ - '[ -f bar ]' +test_expect_success \ + 'Post-check that bar does not exist and is not in index after "git-rm -f bar"' \ + '! [ -f bar ] && ! git-ls-files --error-unmatch bar' test_expect_success \ - 'Test that "git-rm -- -q" works to delete a file named -q' \ + 'Test that "git-rm -- -q" succeeds (remove a file that looks like an option)' \ 'git-rm -- -q' +test_expect_success \ + "Test that \"git-rm -f\" succeeds with embedded space, tab, or newline characters." \ + "git-rm -f '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