apply: do not patch lines that were already patched
When looking for a place to apply a hunk, we used to check lines that match the preimage of it, starting from the line that the patch wants to apply the hunk at, looking forward and backward with increasing offsets until we find a match. Colin Guthrie found an interesting case where this misapplied a patch that wanted to touch a preimage that consists of } } return 0; } which is a rather unfortunately common pattern. The target version of the file originally had only one such location, but the hunk immediately before that created another instance of such block of lines, and find_pos() happily reported that the preimage of the hunk matched what it wanted to modify. Oops. By marking the lines application of earlier hunks touched and preventing match_fragment() from considering them as a match with preimage of other hunks, we can reduce such an accident. I also considered to teach apply_one_fragment() to take the offset we have found while applying the previous hunk into account when looking for a match with find_pos(), but dismissed that approach, because it would sometimes work better but sometimes worse, depending on the difference between the version the patch was created against and the version the patch is being applied. This does _not_ prevent misapplication of patches to a file that has many similar looking blocks of lines and a preimage cannot identify which one of them should be applied. For that, we would need to scan beyond the first match in find_pos(), and issue a warning (or error out). That will be a separate topic. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
964498e7f9
commit
9d158601b3
@ -204,6 +204,7 @@ struct line {
|
|||||||
unsigned hash : 24;
|
unsigned hash : 24;
|
||||||
unsigned flag : 8;
|
unsigned flag : 8;
|
||||||
#define LINE_COMMON 1
|
#define LINE_COMMON 1
|
||||||
|
#define LINE_PATCHED 2
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2085,7 +2086,8 @@ static int match_fragment(struct image *img,
|
|||||||
|
|
||||||
/* Quick hash check */
|
/* Quick hash check */
|
||||||
for (i = 0; i < preimage_limit; i++)
|
for (i = 0; i < preimage_limit; i++)
|
||||||
if (preimage->line[i].hash != img->line[try_lno + i].hash)
|
if ((img->line[try_lno + i].flag & LINE_PATCHED) ||
|
||||||
|
(preimage->line[i].hash != img->line[try_lno + i].hash))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (preimage_limit == preimage->nr) {
|
if (preimage_limit == preimage->nr) {
|
||||||
@ -2428,6 +2430,9 @@ static void update_image(struct image *img,
|
|||||||
memcpy(img->line + applied_pos,
|
memcpy(img->line + applied_pos,
|
||||||
postimage->line,
|
postimage->line,
|
||||||
postimage->nr * sizeof(*img->line));
|
postimage->nr * sizeof(*img->line));
|
||||||
|
for (i = 0; i < postimage->nr; i++)
|
||||||
|
img->line[applied_pos + i].flag |= LINE_PATCHED;
|
||||||
|
|
||||||
img->nr = nr;
|
img->nr = nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user