Skip to content

Commit d487b0b

Browse files
committed
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 56185f4 (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 <[email protected]>
1 parent d31f3ad commit d487b0b

File tree

2 files changed

+36
-22
lines changed

2 files changed

+36
-22
lines changed

builtin/apply.c

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,23 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
19201920
return used;
19211921
}
19221922

1923+
static void prefix_one(char **name)
1924+
{
1925+
char *old_name = *name;
1926+
if (!old_name)
1927+
return;
1928+
*name = xstrdup(prefix_filename(prefix, prefix_length, *name));
1929+
free(old_name);
1930+
}
1931+
1932+
static void prefix_patch(struct patch *p)
1933+
{
1934+
if (!prefix || p->is_toplevel_relative)
1935+
return;
1936+
prefix_one(&p->new_name);
1937+
prefix_one(&p->old_name);
1938+
}
1939+
19231940
/*
19241941
* Read the patch text in "buffer" that extends for "size" bytes; stop
19251942
* 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)
19351952
if (offset < 0)
19361953
return offset;
19371954

1955+
prefix_patch(patch);
1956+
19381957
patch->ws_rule = whitespace_rule(patch->new_name
19391958
? patch->new_name
19401959
: patch->old_name);
@@ -4164,26 +4183,6 @@ static int use_patch(struct patch *p)
41644183
return !has_include;
41654184
}
41664185

4167-
4168-
static void prefix_one(char **name)
4169-
{
4170-
char *old_name = *name;
4171-
if (!old_name)
4172-
return;
4173-
*name = xstrdup(prefix_filename(prefix, prefix_length, *name));
4174-
free(old_name);
4175-
}
4176-
4177-
static void prefix_patches(struct patch *p)
4178-
{
4179-
if (!prefix || p->is_toplevel_relative)
4180-
return;
4181-
for ( ; p; p = p->next) {
4182-
prefix_one(&p->new_name);
4183-
prefix_one(&p->old_name);
4184-
}
4185-
}
4186-
41874186
#define INACCURATE_EOF (1<<0)
41884187
#define RECOUNT (1<<1)
41894188

@@ -4209,8 +4208,6 @@ static int apply_patch(int fd, const char *filename, int options)
42094208
break;
42104209
if (apply_in_reverse)
42114210
reverse_patches(patch);
4212-
if (prefix)
4213-
prefix_patches(patch);
42144211
if (use_patch(patch)) {
42154212
patch_stats(patch);
42164213
*listp = patch;

t/t4119-apply-config.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,21 @@ test_expect_success 'same but with traditional patch input of depth 2' '
159159
check_result sub/file1
160160
'
161161

162+
test_expect_success 'in subdir with traditional patch input' '
163+
cd "$D" &&
164+
git config apply.whitespace strip &&
165+
cat >.gitattributes <<-EOF &&
166+
/* whitespace=blank-at-eol
167+
sub/* whitespace=-blank-at-eol
168+
EOF
169+
rm -f sub/file1 &&
170+
cp saved sub/file1 &&
171+
git update-index --refresh &&
172+
173+
cd sub &&
174+
git apply ../gpatch.file &&
175+
echo "B " >expect &&
176+
test_cmp expect file1
177+
'
178+
162179
test_done

0 commit comments

Comments
 (0)