summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-08-06 14:26:24 -0700
committerJunio C Hamano <gitster@pobox.com>2014-08-07 12:17:07 -0700
commitd487b0ba50884fb1fd1767ac8c9adc58066ad999 (patch)
tree50b9d8db8606b6d8e8875051a6583b4a076c2033
parentd31f3ad23dd1aee3c3e1015a43b02b995c01a9a1 (diff)
downloadgit-d487b0ba50884fb1fd1767ac8c9adc58066ad999.tar.gz
apply: use the right attribute for paths in non-Git patches
We parse each patchfile and find the name of the path the patch applies to, and then use that name to consult the attribute system to find the whitespace rules to be used, and also the target file (either in the working tree or in the index) to replay the changes against. Unlike a Git-generated patch, a non-Git patch is taken to have the pathnames relative to the current working directory. The names found in such a patch are modified by prepending the prefix by the prefix_patches() helper function introduced in 56185f49 (git-apply: require -p<n> when working in a subdirectory., 2007-02-19). However, this prefixing is done after the patch is fully parsed and affects only what target files are patched. Because the attributes are checked against the names found in the patch during the parsing, not against the final pathname, the whitespace check that is done during parsing ends up using attributes for a wrong path for non-Git patches. Fix this by doing the prefix much earlier, immediately after the header part of each patch is parsed and we learn the name of the path the patch affects. Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--builtin/apply.c41
-rwxr-xr-xt/t4119-apply-config.sh17
2 files changed, 36 insertions, 22 deletions
diff --git a/builtin/apply.c b/builtin/apply.c
index 6013e1913c..4270cded0b 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1920,6 +1920,23 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
return used;
}
+static void prefix_one(char **name)
+{
+ char *old_name = *name;
+ if (!old_name)
+ return;
+ *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
+ free(old_name);
+}
+
+static void prefix_patch(struct patch *p)
+{
+ if (!prefix || p->is_toplevel_relative)
+ return;
+ prefix_one(&p->new_name);
+ prefix_one(&p->old_name);
+}
+
/*
* Read the patch text in "buffer" that extends for "size" bytes; stop
* reading after seeing a single patch (i.e. changes to a single file).
@@ -1935,6 +1952,8 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
if (offset < 0)
return offset;
+ prefix_patch(patch);
+
patch->ws_rule = whitespace_rule(patch->new_name
? patch->new_name
: patch->old_name);
@@ -4164,26 +4183,6 @@ static int use_patch(struct patch *p)
return !has_include;
}
-
-static void prefix_one(char **name)
-{
- char *old_name = *name;
- if (!old_name)
- return;
- *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
- free(old_name);
-}
-
-static void prefix_patches(struct patch *p)
-{
- if (!prefix || p->is_toplevel_relative)
- return;
- for ( ; p; p = p->next) {
- prefix_one(&p->new_name);
- prefix_one(&p->old_name);
- }
-}
-
#define INACCURATE_EOF (1<<0)
#define RECOUNT (1<<1)
@@ -4209,8 +4208,6 @@ static int apply_patch(int fd, const char *filename, int options)
break;
if (apply_in_reverse)
reverse_patches(patch);
- if (prefix)
- prefix_patches(patch);
if (use_patch(patch)) {
patch_stats(patch);
*listp = patch;
diff --git a/t/t4119-apply-config.sh b/t/t4119-apply-config.sh
index 3d0384daa8..be325fa1ae 100755
--- a/t/t4119-apply-config.sh
+++ b/t/t4119-apply-config.sh
@@ -159,4 +159,21 @@ test_expect_success 'same but with traditional patch input of depth 2' '
check_result sub/file1
'
+test_expect_success 'in subdir with traditional patch input' '
+ cd "$D" &&
+ git config apply.whitespace strip &&
+ cat >.gitattributes <<-EOF &&
+ /* whitespace=blank-at-eol
+ sub/* whitespace=-blank-at-eol
+ EOF
+ rm -f sub/file1 &&
+ cp saved sub/file1 &&
+ git update-index --refresh &&
+
+ cd sub &&
+ git apply ../gpatch.file &&
+ echo "B " >expect &&
+ test_cmp expect file1
+'
+
test_done