git-diff-index in default mode has an annoying behaviour wrt filenames containing non-ascii chars. As suggested by Pasky, we can use -z mode, which gives us a much better way of handling all other special chars. With associated testcases ensuring it works with simple and double quotes, backslashes, and spaces as well. This is an improved version of the previous patch, which fixes other commands like cg-switch which use tree_timewarp. A couple of other commands using git-diff-index still need to be fixed in a similar manner. Signed-off-by: Yann Dirson <ydirson@xxxxxxxxxx> --- cg-Xlib | 7 ++---- cg-commit | 10 ++++---- t/t9900-specialchars.sh | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/cg-Xlib b/cg-Xlib index 38172a0..e594986 100755 --- a/cg-Xlib +++ b/cg-Xlib @@ -555,10 +555,9 @@ tree_timewarp() [ "$no_head_update" ] || git-update-ref HEAD "$branch" || : # Kill gone files - git-diff-tree -r "$base" "$branch" | - # match ":100755 000000 14d43b1abf... 000000000... D" - sed -ne 's/^:[^\t]* D\t//p' | - xargs rm -f -- + git-diff-tree -z --name-status -r "$base" "$branch" | + perl -n0e 'chomp; if (defined $meta) { print "$_\0" if $meta eq 'D'; $meta=undef } else { $meta = $_ }' | + xargs --null rm -f -- git-checkout-index -u -f -a # FIXME: Can produce bogus "contains only garbage" messages. diff --git a/cg-commit b/cg-commit index 8dac57c..1d8de92 100755 --- a/cg-commit +++ b/cg-commit @@ -274,8 +274,8 @@ if [ "$ARGS" -o "$_git_relpath" ]; then echo "${_git_relpath}$file" >>"$filter" done - eval "commitfiles=($(cat "$filter" | path_xargs git-diff-index -r -m HEAD -- | \ - sed -e 's/"\|\\/\\&/g' -e 's/^\([^ ]*\)\(.\) \(.*\)\( .*\)*$/"\2 \3"/'))" + eval "commitfiles=($(cat "$filter" | path_xargs git-diff-index --name-status -z -r -m HEAD -- | \ + perl -n0e 'chomp; if (defined $meta) { s/([\"\\])/\\\1/; print "\"$meta $_\"\n"; $meta=undef } else { $meta = $_ }'))" customfiles=1 [ "$review" ] && cat "$filter" | path_xargs git-diff-index -r -m -p HEAD -- > "$PATCH" @@ -292,8 +292,8 @@ else if [ ! "$ignorecache" ]; then # \t instead of the tab character itself works only with new # sed versions. - eval "commitfiles=($(git-diff-index -r -m HEAD | \ - sed -e 's/"\|\\/\\&/g' -e 's/^\([^ ]*\)\(.\) \(.*\)\( .*\)*$/"\2 \3"/'))" + eval "commitfiles=($(git-diff-index --name-status -z -r -m HEAD | \ + perl -n0e 'chomp; if (defined $meta) { s/([\"\\])/\\\1/; print "\"$meta $_\"\n"; $meta=undef } else { $meta = $_ }'))" if [ -s "$_git/commit-ignore" ]; then newcommitfiles=() @@ -439,7 +439,7 @@ __END__ exit 1 fi if [ ! "$ignorecache" ] && [ ! "$merging" ] && [ ! "$review" ]; then - eval "newcommitfiles=($(grep ^CG:F "$LOGMSG2" | sed 's/^CG:F *\(.*\)$/"\1"/'))" + eval "newcommitfiles=($(grep ^CG:F "$LOGMSG2" | sed -e 's/\"/\\&/g' -e 's/^CG:F *\(.*\)$/"\1"/'))" if [ ! "$force" ] && [ ! "${newcommitfiles[*]}" ]; then rm "$LOGMSG" "$LOGMSG2" [ "$quiet" ] && exit 0 || die 'Nothing to commit' diff --git a/t/t9900-specialchars.sh b/t/t9900-specialchars.sh new file mode 100755 index 0000000..a705052 --- /dev/null +++ b/t/t9900-specialchars.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2006 Yann Dirson +# +test_description="Tests various commands with shell-special chars. + +Filenames with embedded spaces, quotes, non-ascii letter, you name it." + +. ./test-lib.sh + +rm -rf .git +cg-init -m . + +touch "a space" +test_expect_success 'add file with space' 'cg-add "a space"' +test_expect_success 'commit file with space' 'cg-commit -m . "a space"' + +touch "a'quote" +test_expect_success 'add file with quote' "cg-add \"a'quote\"" +test_expect_success 'commit file with quote' "cg-commit -m . \"a'quote\"" + +touch "d\"quote" +test_expect_success 'add file with accent' 'cg-add "d\"quote"' +test_expect_success 'commit file with quote' 'cg-commit -m . "d\"quote"' + +touch "back\\slash" +test_expect_success 'add file with accent' 'cg-add "back\\slash"' +test_expect_success 'commit file with quote' 'cg-commit -m . "back\\slash"' + +touch "acc�" +test_expect_success 'add file with accent' "cg-add acc�" +test_expect_success 'commit file with quote' "cg-commit -m . acc�" + +## same without a file arg to cg-commit + +rm -rf * .git +cg-init -m . + +touch "a space" +test_expect_success 'add file with space' 'cg-add "a space"' +test_expect_success 'commit file with space' 'cg-commit -m .' + +touch "a'quote" +test_expect_success 'add file with quote' "cg-add \"a'quote\"" +test_expect_success 'commit file with quote' "cg-commit -m ." + +touch "d\"quote" +test_expect_success 'add file with accent' 'cg-add "d\"quote"' +test_expect_success 'commit file with quote' 'cg-commit -m .' + +touch "back\\slash" +test_expect_success 'add file with accent' 'cg-add "back\\slash"' +test_expect_success 'commit file with quote' 'cg-commit -m .' + +touch "acc�" +test_expect_success 'add file with accent' "cg-add acc�" +test_expect_success 'commit file with quote' "cg-commit -m ." + +test_done - : send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html