Download raw body.
got diff vs file names with whitespaces
after loosing my sanity in patch(1), here i come for a different flavor
of it. one thing i forgot is that you're supposed to append a tab when
cooking a ---/+++ line for a file with whitespace in it, because it's
the way patch(1) can understand that it should not split on the first
whitespace but keep them in the filename.
or at least that's the larry patch behaviour, got patch will only cut on
the first tab and ignore whitespaces, which i think it's fine for a more
civilized age.
in any case, git diff follows this, and for compatibility with other
tools let's try to cope.
I'm propend less to add this "if-theres-not-a-tab-then-split-on-space"
logic on got patch because if you get a patch that's mangled enough to
have tabs replaced by whitespaces, you also have other problems.
in any case, I've added a regress for patch as well while here for
symmetry. the patch regress is already passing, while the added diff
test is failing in main.
diff /home/op/w/got
path + /home/op/w/got
commit - fe66becbbe242300f7a2a5b9233dac96584839f004b922e11e6697ce705ed37f
blob - fdfb062cfddc34893c731ea1265005e08393962bf15d34e260dd5f55be7d3c49
file + lib/diff_output_unidiff.c
--- lib/diff_output_unidiff.c
+++ lib/diff_output_unidiff.c
@@ -240,6 +240,7 @@ output_unidiff_chunk(struct diff_output_info *outinfo,
const struct diff_chunk_context *cc)
{
int rc, left_start, left_len, right_start, right_len;
+ const char *label;
off_t outoff = 0, *offp;
uint8_t *typep;
@@ -252,8 +253,9 @@ output_unidiff_chunk(struct diff_output_info *outinfo,
}
if (print_header && !(state->header_printed)) {
- rc = fprintf(dest, "--- %s\n",
- diff_output_get_label_left(info));
+ label = diff_output_get_label_left(info);
+ rc = fprintf(dest, "--- %s%s\n", label,
+ strchr(label, ' ') != NULL ? "\t" : "");
if (rc < 0)
return errno;
if (outinfo) {
@@ -267,8 +269,9 @@ output_unidiff_chunk(struct diff_output_info *outinfo,
return ENOMEM;
*typep = DIFF_LINE_MINUS;
}
- rc = fprintf(dest, "+++ %s\n",
- diff_output_get_label_right(info));
+ label = diff_output_get_label_right(info);
+ rc = fprintf(dest, "+++ %s%s\n", label,
+ strchr(label, ' ') != NULL ? "\t" : "");
if (rc < 0)
return errno;
if (outinfo) {
commit - fe66becbbe242300f7a2a5b9233dac96584839f004b922e11e6697ce705ed37f
blob - 8e5fd4d433d4814d5a29051bd8e3c80e7cc89c7c5faffc4bde943cf8e172ba5b
file + regress/cmdline/diff.sh
--- regress/cmdline/diff.sh
+++ regress/cmdline/diff.sh
@@ -427,6 +427,80 @@ EOF
test_done "$testroot" "$ret"
}
+test_diff_filename_with_whitespaces() {
+ local testroot=`test_init diff_basic`
+ local head_rev=`git_show_head $testroot/repo`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # add a file with whitespaces in its name
+ (cd "$testroot/wt" && echo iota > 'iota file' && \
+ got add 'iota file') >/dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "failed to add iota file" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cat <<EOF > $testroot/stdout.expected
+diff $testroot/wt
+path + $testroot/wt
+commit - $head_rev
+blob - /dev/null
+file + iota file (mode 644)
+--- /dev/null
++++ iota file$(printf '\t')
+@@ -0,0 +1 @@
++iota
+EOF
+
+ (cd $testroot/wt && got diff > $testroot/stdout)
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got ci -m 'checkpoint') >/dev/null
+
+ head_rev=`git_show_head $testroot/repo`
+ local iota_blobid=`get_blob_id $testroot/repo "" "iota file"`
+
+ (cd $testroot/wt && echo 'new iota' > 'iota file')
+
+ cat <<EOF > $testroot/stdout.expected
+diff $testroot/wt
+path + $testroot/wt
+commit - $head_rev
+blob - $iota_blobid
+file + iota file
+--- iota file$(printf '\t')
++++ iota file$(printf '\t')
+@@ -1 +1 @@
+-iota
++new iota
+EOF
+
+ (cd $testroot/wt && got diff > $testroot/stdout)
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ test_done "$testroot" 0
+}
+
test_diff_shows_conflict() {
local testroot=`test_init diff_shows_conflict 1`
@@ -2519,6 +2593,7 @@ test_diff_mixed_worktree() {
test_parseargs "$@"
run_test test_diff_basic
+run_test test_diff_filename_with_whitespaces
run_test test_diff_shows_conflict
run_test test_diff_tag
run_test test_diff_lightweight_tag
commit - fe66becbbe242300f7a2a5b9233dac96584839f004b922e11e6697ce705ed37f
blob - 48b6144db3cdd955b186ad1fbb12058d4e7e796733d64160033e889a8370aa46
file + regress/cmdline/patch.sh
--- regress/cmdline/patch.sh
+++ regress/cmdline/patch.sh
@@ -151,6 +151,75 @@ EOF
test_done $testroot $ret
}
+test_patch_filename_with_whitespaces() {
+ local testroot=`test_init patch_filename_with_whitespaces`
+
+ got checkout $testroot/repo $testroot/wt >/dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ test_done $testroot $ret
+ return 1
+ fi
+
+ # add a file with a whitespace in its name
+ cat <<EOF > $testroot/wt/patch
+--- /dev/null
++++ iota file
+@@ -0,0 +1 @@
++iota is my favourite character
+EOF
+
+ (cd $testroot/wt && got patch < patch) > $testroot/stdout
+ if [ $ret -ne 0 ]; then
+ test_done "$testroot" $ret
+ return 1
+ fi
+
+ echo 'A iota file' > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done $testroot $ret
+ return 1
+ fi
+
+ echo 'iota is my favourite character' > $testroot/wt/iota.expected
+ cmp -s $testroot/wt/iota.expected $testroot/wt/'iota file'
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/wt/iota.expected $testroot/wt/iota
+ test_done "$testroot" $ret
+ return 1
+ fi
+
+ # now change it
+ cat <<EOF > $testroot/wt/patch
+--- iota file
++++ iota file
+@@ -1 +1 @@
+-iota is my favourite character
++iota is no longer my favourite character
+EOF
+
+ (cd $testroot/wt && got patch < patch) > $testroot/stdout
+ if [ $ret -ne 0 ]; then
+ test_done "$testroot" $ret
+ return 1
+ fi
+
+ echo 'M iota file' > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done $testroot $ret
+ return 1
+ fi
+
+ test_done $testroot $ret
+}
+
test_patch_dont_apply() {
local testroot=`test_init patch_dont_apply`
@@ -2149,6 +2218,7 @@ test_patch_commit_keywords() {
test_parseargs "$@"
run_test test_patch_basic
+run_test test_patch_filename_with_whitespaces
run_test test_patch_dont_apply
run_test test_patch_malformed
run_test test_patch_no_patch
got diff vs file names with whitespaces