OBS User unknown 2009-02-03 23:18:23 +00:00 committed by Git OBS Bridge
parent ea52ba878c
commit e553963af3
14 changed files with 1912 additions and 23 deletions

View File

@ -0,0 +1,92 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: diff3-style merges: add file labels
Add a --label=LABEL option for overriding the labels in the diff3-style
format. The option can be given up to three times for overriding the
old, new, and output filename.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
patch.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -82,6 +82,7 @@ static void usage (FILE *, int) __attrib
enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2, MERGE_REJECTS = 4 };
static enum mergetype mergetype;
+const char *file_label[2];
static bool make_backups;
static bool backup_if_mismatch;
static char const *version_control;
@@ -538,7 +539,7 @@ reinitialize_almost_everything (void)
skip_rest_of_patch = false;
}
-static char const shortopts[] = "bB:cd:D:eEfF:g:i:lMnNo:p:r:RstTuvV:x:Y:z:Z";
+static char const shortopts[] = "bB:cd:D:eEfF:g:i:lL:MnNo:p:r:RstTuvV:x:Y:z:Z";
static struct option const longopts[] =
{
{"backup", no_argument, NULL, 'b'},
@@ -553,6 +554,7 @@ static struct option const longopts[] =
{"get", no_argument, NULL, 'g'},
{"input", required_argument, NULL, 'i'},
{"ignore-whitespace", no_argument, NULL, 'l'},
+ {"label", required_argument, NULL, 'L'},
{"normal", no_argument, NULL, 'n'},
{"forward", no_argument, NULL, 'N'},
{"output", required_argument, NULL, 'o'},
@@ -609,6 +611,7 @@ static char const *const option_help[] =
"",
" -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
" --merge={rejects,fuzz,all} Produce a diff3-style merge.",
+" -L LABEL --label=LABEL Use LABEL instead of file name in merge.",
" -E --remove-empty-files Remove output files that are empty after patching.",
"",
" -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).",
@@ -747,6 +750,14 @@ get_some_switches (void)
case 'l':
canonicalize = true;
break;
+ case 'L':
+ if (!file_label[0])
+ file_label[0] = optarg;
+ else if (!file_label[1])
+ file_label[1] = optarg;
+ else
+ fatal ("too many file label options");
+ break;
case 'M':
mergetype |= MERGE_REJECTS;
break;
@@ -1411,7 +1422,7 @@ static bool merge_hunk (struct outstate
}
/* "From" lines in the patch */
- name = pch_name(OLD);
+ name = file_label[OLD] ? file_label[OLD] : pch_name(OLD);
if (!name)
name = "";
fprintf(fp, outstate->after_newline + "\n<<<<<<<%*s\n",
@@ -1426,7 +1437,7 @@ static bool merge_hunk (struct outstate
if (fuzz) {
/* "To" lines in the patch */
- name = pch_name(NEW);
+ name = file_label[NEW] ? file_label[NEW] : pch_name(NEW);
if (!name)
name = "";
fprintf(fp, outstate->after_newline + "\n|||||||%*s\n",
@@ -1453,7 +1464,7 @@ static bool merge_hunk (struct outstate
/* If the merge result and the new file are the same, label the merge
result with the new file's name. */
- name = fuzz ? NULL : pch_name(NEW);
+ name = fuzz ? NULL : (file_label[NEW] ? file_label[NEW] : pch_name(NEW));
if (!name)
name = "";
fprintf(fp, outstate->after_newline + "\n>>>>>>>%*s\n",

View File

@ -0,0 +1,293 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: diff3-style merges
Implement a diff3-style merge format: with the --merge option alone,
all hunks that apply without fuzz will be applied as usual, and
hunks that apply within the allowed fuzz limit will be bracketed as:
<<<<<<<
old lines from patch
|||||||
new lines from patch
=======
merge result
>>>>>>>
When the --show-all option is given in addition, hunks that apply without
fuzz will be bracketed as:
<<<<<<<
old lines from patch
=======
merge result
>>>>>>>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
patch.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 170 insertions(+), 5 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -61,6 +61,8 @@ struct outstate
static FILE *create_output_file (char const *, int);
static LINENUM locate_hunk (LINENUM);
static bool apply_hunk (struct outstate *, LINENUM);
+static bool common_context(LINENUM, LINENUM, LINENUM);
+static bool merge_hunk (struct outstate *, LINENUM, LINENUM);
static bool copy_till (struct outstate *, LINENUM);
static bool patch_match (LINENUM, LINENUM, LINENUM, LINENUM);
static bool similar (char const *, size_t, char const *, size_t);
@@ -77,6 +79,9 @@ static void reinitialize_almost_everythi
static void remove_if_needed (char const *, int volatile *);
static void usage (FILE *, int) __attribute__((noreturn));
+enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2 };
+static enum mergetype mergetype;
+
static bool make_backups;
static bool backup_if_mismatch;
static char const *version_control;
@@ -117,7 +122,7 @@ int
main (int argc, char **argv)
{
char const *val;
- bool somefailed = false;
+ bool somemerged = false, somefailed = false;
struct outstate outstate;
char numbuf[LINENUM_LENGTH_BOUND + 1];
@@ -184,6 +189,7 @@ main (int argc, char **argv)
reinitialize_almost_everything()
) { /* for each patch in patch file */
int hunk = 0;
+ int merged = 0;
int failed = 0;
bool mismatch = false;
char *outname = outfile ? outfile : inname;
@@ -295,8 +301,17 @@ main (int argc, char **argv)
} else if (!where) {
goto skip_hunk;
} else {
- if (!apply_hunk (&outstate, where))
- goto skip_hunk;
+ if ((mergetype & SHOW_ALL) ||
+ (fuzz && (mergetype & SHOW_FUZZ))) {
+ if (merge_hunk(&outstate, where, fuzz)) {
+ merged++;
+ mismatch = true;
+ } else
+ goto skip_hunk;
+ } else {
+ if (!apply_hunk (&outstate, where))
+ goto skip_hunk;
+ }
}
if (verbosity == VERBOSE
@@ -325,6 +340,9 @@ skip_hunk:
format_linenum (numbuf, newwhere));
}
+ if (merged)
+ somemerged = true;
+
if (!skip_rest_of_patch)
{
if (got_hunk < 0 && using_plan_a)
@@ -374,7 +392,8 @@ skip_hunk:
else
{
if (! outstate.zero_output
- && pch_says_nonexistent (! reverse))
+ && pch_says_nonexistent (! reverse)
+ && !merged)
{
mismatch = true;
if (verbosity != SILENT)
@@ -468,7 +487,7 @@ skip_hunk:
if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0))
write_fatal ();
cleanup ();
- if (somefailed)
+ if (somemerged || somefailed)
exit (1);
return 0;
}
@@ -544,6 +563,7 @@ static struct option const longopts[] =
{"quoting-style", required_argument, NULL, CHAR_MAX + 8},
{"unified-reject-files", no_argument, NULL, CHAR_MAX + 9},
{"global-reject-file", required_argument, NULL, CHAR_MAX + 10},
+ {"merge", required_argument, NULL, CHAR_MAX + 11},
{NULL, no_argument, NULL, 0}
};
@@ -571,6 +591,7 @@ static char const *const option_help[] =
" -r FILE --reject-file=FILE Output rejects to FILE.",
"",
" -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
+" --merge={fuzz,all} Produce a diff3-style merge.",
" -E --remove-empty-files Remove output files that are empty after patching.",
"",
" -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).",
@@ -809,6 +830,23 @@ get_some_switches (void)
case CHAR_MAX + 10:
global_reject = savestr (optarg);
break;
+ case CHAR_MAX + 11:
+ {
+ char *tok = strtok(optarg, ",");
+
+ do {
+ if (!strcmp(tok, "fuzz"))
+ mergetype |= SHOW_FUZZ;
+ else if (!strcmp(tok, "all"))
+ mergetype |= SHOW_ALL;
+ else {
+ fprintf(stderr, "%s: invalid merge option %s\n",
+ program_name, quotearg(tok));
+ usage (stderr, 2);
+ }
+ } while ((tok = strtok(NULL, ",")));
+ }
+ break;
default:
usage (stderr, 2);
}
@@ -1264,6 +1302,133 @@ apply_hunk (struct outstate *outstate, L
return true;
}
+static bool common_context(LINENUM where, LINENUM old, LINENUM new)
+{
+ size_t size;
+ const char *line;
+
+ if (pch_char(old) != ' ' || pch_char(new) != ' ')
+ return false;
+
+ line = ifetch (where, false, &size);
+ return size &&
+ (canonicalize ?
+ (similar(pfetch(old), pch_line_len(old), line, size) &&
+ similar(pfetch(new), pch_line_len(new), line, size)) :
+ (size == pch_line_len(old) && size == pch_line_len(new) &&
+ memcmp(line, pfetch(old), size) == 0 &&
+ memcmp(line, pfetch(new), size) == 0));
+}
+
+/* A FUZZ value of -1 indicates that the hunk could not be applied. */
+
+static bool merge_hunk (struct outstate *outstate, LINENUM where, LINENUM fuzz)
+{
+ register LINENUM old = 1;
+ register LINENUM lastline = pch_ptrn_lines ();
+ register LINENUM new = lastline + 1;
+ register LINENUM pat_end = pch_end ();
+ register LINENUM merge, merge_end;
+ register FILE *fp = outstate->ofp;
+ bool succeeded = true;
+
+ while (pch_char(new) == '=' || pch_char(new) == '\n' /* ??? */)
+ new++;
+
+ /* Hide common prefix context */
+ merge = where;
+ while (old <= lastline && new <= pat_end) {
+ if (!common_context(merge, old, new))
+ break;
+ old++;
+ new++;
+ merge++;
+ }
+
+ if (fuzz != -1) {
+ /* Hide common suffix context */
+ merge_end = where + lastline - 1;
+ while (old <= lastline && new <= pat_end) {
+ if (!common_context(merge_end, lastline, pat_end))
+ break;
+ lastline--;
+ pat_end--;
+ merge_end--;
+ }
+ } else {
+ LINENUM overlap = pch_suffix_context ();
+
+ /* Hide common suffix context: check how much overlap we have! */
+ merge_end = merge - 1;
+ while (overlap) {
+ LINENUM n = 0;
+
+ merge_end += overlap;
+ while (n < overlap && old <= lastline && new <= pat_end) {
+ if (!common_context(merge_end, lastline, pat_end))
+ break;
+ lastline--;
+ pat_end--;
+ merge_end--;
+ n++;
+ }
+ merge_end -= overlap - n;
+ if (n == overlap)
+ break;
+ lastline += n;
+ pat_end += n;
+ overlap--;
+ }
+ }
+
+ assert (outstate->after_newline);
+ if (last_frozen_line < merge) {
+ if (!copy_till(outstate, merge - 1))
+ return false;
+ }
+
+ /* "From" lines in the patch */
+ fprintf(fp, outstate->after_newline + "\n<<<<<<<\n");
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+ while (old <= lastline) {
+ outstate->after_newline = pch_write_line(old, fp);
+ old++;
+ }
+
+ if (fuzz) {
+ /* "To" lines in the patch */
+ fprintf(fp, outstate->after_newline + "\n|||||||\n");
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+ while (new <= pat_end) {
+ outstate->after_newline = pch_write_line(new, fp);
+ new++;
+ }
+ }
+
+ if (fuzz != -1) {
+ /* Merge result */
+ fprintf(fp, outstate->after_newline + "\n=======\n");
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+
+ succeeded = apply_hunk(outstate, where) &&
+ copy_till(outstate, merge_end);
+ }
+
+ fprintf(fp, outstate->after_newline + "\n>>>>>>>\n");
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+
+ outstate->zero_output = false;
+ return succeeded;
+}
+
/* Create an output file. */
static FILE *

View File

@ -0,0 +1,73 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: diff3-style merges: include filenames
Include the filenames from the patch header in the diff3-style format.
Use the name of the output file as the third filename.
<<<<<<< old-filename
old lines from patch
||||||| new-filename
new lines from patch
=======
merge result
>>>>>>> output-filename
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
patch.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -1353,6 +1353,7 @@ static bool merge_hunk (struct outstate
register LINENUM merge, merge_end;
register FILE *fp = outstate->ofp;
bool succeeded = true;
+ const char *name;
while (pch_char(new) == '=' || pch_char(new) == '\n' /* ??? */)
new++;
@@ -1410,7 +1411,11 @@ static bool merge_hunk (struct outstate
}
/* "From" lines in the patch */
- fprintf(fp, outstate->after_newline + "\n<<<<<<<\n");
+ name = pch_name(OLD);
+ if (!name)
+ name = "";
+ fprintf(fp, outstate->after_newline + "\n<<<<<<<%*s\n",
+ strlen(name) ? strlen(name) + 1 : 0, name);
if (ferror (fp))
write_fatal ();
outstate->after_newline = true;
@@ -1421,7 +1426,11 @@ static bool merge_hunk (struct outstate
if (fuzz) {
/* "To" lines in the patch */
- fprintf(fp, outstate->after_newline + "\n|||||||\n");
+ name = pch_name(NEW);
+ if (!name)
+ name = "";
+ fprintf(fp, outstate->after_newline + "\n|||||||%*s\n",
+ strlen(name) ? strlen(name) + 1 : 0, name);
if (ferror (fp))
write_fatal ();
outstate->after_newline = true;
@@ -1442,7 +1451,13 @@ static bool merge_hunk (struct outstate
copy_till(outstate, merge_end);
}
- fprintf(fp, outstate->after_newline + "\n>>>>>>>\n");
+ /* If the merge result and the new file are the same, label the merge
+ result with the new file's name. */
+ name = fuzz ? NULL : pch_name(NEW);
+ if (!name)
+ name = "";
+ fprintf(fp, outstate->after_newline + "\n>>>>>>>%*s\n",
+ strlen(name) ? strlen(name) + 1 : 0, name);
if (ferror (fp))
write_fatal ();
outstate->after_newline = true;

View File

@ -0,0 +1,110 @@
---
patch.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 72 insertions(+), 6 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -62,6 +62,8 @@ static FILE *create_output_file (char co
static LINENUM locate_hunk (LINENUM);
static bool apply_hunk (struct outstate *, LINENUM);
static bool common_context(LINENUM, LINENUM, LINENUM);
+static LINENUM min_mismatches(LINENUM, LINENUM);
+static LINENUM locate_merge (void);
static bool merge_hunk (struct outstate *, LINENUM, LINENUM);
static void merge_ends_here(struct outstate *outstate);
static bool copy_till (struct outstate *, LINENUM);
@@ -304,15 +306,11 @@ main (int argc, char **argv)
goto skip_hunk;
} else if (!where) {
if (mergetype & MERGE_REJECTS) {
- LINENUM guess = pch_first () + last_offset;
-
- if (merge_hunk(&outstate, guess, -1)) {
+ if (merge_hunk(&outstate, locate_merge(), -1)) {
merged++;
mismatch = 1;
- } else {
- /* FIXME: guess harder! */
+ } else
goto skip_hunk;
- }
} else
goto skip_hunk;
} else {
@@ -1356,6 +1354,74 @@ static bool common_context(LINENUM where
memcmp(line, pfetch(new), size) == 0));
}
+static LINENUM min_mismatches(LINENUM where, LINENUM lowest)
+{
+ register LINENUM ptrn_lines = pch_ptrn_lines();
+ register LINENUM old, mismatched = 0;
+
+ for (old = 1; old <= ptrn_lines; old++, where++) {
+ size_t size;
+ const char *line;
+
+ line = ifetch (where, false, &size);
+ if (!size ||
+ !(canonicalize ?
+ similar(pfetch(old), pch_line_len(old), line, size) :
+ (size == pch_line_len(old) &&
+ memcmp(line, pfetch(old), size) == 0))) {
+ mismatched++;
+ if (mismatched >= lowest)
+ break;
+ }
+ }
+ return mismatched;
+}
+
+static LINENUM locate_merge ()
+{
+ register LINENUM first_guess = pch_first () + last_offset;
+ register LINENUM lowest = input_lines, where = first_guess;
+ register LINENUM offset;
+ LINENUM pat_lines = pch_ptrn_lines();
+ LINENUM suffix_context = pch_suffix_context ();
+ LINENUM max_where = input_lines - (pat_lines - suffix_context) + 1;
+ LINENUM min_where = last_frozen_line + 1;
+ LINENUM max_pos_offset = max_where - first_guess;
+ LINENUM max_neg_offset = first_guess - min_where;
+ LINENUM max_offset = (max_pos_offset < max_neg_offset
+ ? max_neg_offset : max_pos_offset);
+
+ /* Do not try lines <= 0. */
+ if (first_guess <= max_neg_offset)
+ max_neg_offset = first_guess - 1;
+
+ for (offset = 0; offset <= max_offset; offset++) {
+ if (offset <= max_pos_offset) {
+ register LINENUM mismatched;
+
+ mismatched = min_mismatches(first_guess - offset, lowest);
+ if (mismatched < lowest) {
+ lowest = mismatched;
+ where = first_guess - offset;
+ if (lowest == 1)
+ break;
+ }
+ }
+ if (0 < offset && offset <= max_neg_offset) {
+ register LINENUM mismatched;
+
+ mismatched = min_mismatches(first_guess + offset, lowest);
+ if (mismatched < lowest) {
+ lowest = mismatched;
+ where = first_guess + offset;
+ if (lowest == 1)
+ break;
+ }
+ }
+ }
+ return where;
+}
+
/* A FUZZ value of -1 indicates that the hunk could not be applied. */
static bool merge_hunk (struct outstate *outstate, LINENUM where, LINENUM fuzz)

View File

@ -0,0 +1,36 @@
---
patch.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -1459,6 +1459,18 @@ static bool merge_hunk (struct outstate
R_merge_end--;
}
} else {
+#if 1
+ /* Hide common suffix context */
+ R_merge_end = where + lastline - 1;
+ while (old <= lastline && new <= pat_end) {
+ if (!common_context(R_merge_end, lastline, pat_end))
+ break;
+ lastline--;
+ pat_end--;
+ R_merge_end--;
+ }
+ R_merge_end = merge - 1;
+#else
LINENUM overlap = pch_suffix_context ();
/* Hide common suffix context: check how much overlap we have! */
@@ -1482,6 +1494,8 @@ static bool merge_hunk (struct outstate
pat_end += n;
overlap--;
}
+ /*assert(R_merge_end == merge - 1);*/
+#endif
}
assert (outstate->after_newline);

View File

@ -0,0 +1,249 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: diff3-style merges: overlapping merges
In some situations, hunks in a patch may apply so that their context
lines overlap. Patch never commits context lines to the output until
their contents are fully determined.
The diff3-style merge format may include context lines. For example,
when he following patch:
# --- a
# +++ b
# @@ -2,3 +2,3 @@
# x
# -3
# +3b
# x
is applied to `seq 1 6` file with --merge=all, this is what you get (with
fuzz 1):
1
<<<<<<< a
x
3
x
||||||| b
x
3b
x
=======
2
3b
4
>>>>>>>
5
6
At this point, the first four lines of the output file are "frozen", and
the next hunk cannot modify the fourth line anymore. This can cause the diff3-
style merge format to reject hunks that would otherwise be accepted. To
avoid this regression, this patch adds delayed printing of the end marker,
with this effect on the merge format:
1
<<<<<<< a
x
3
x
||||||| b
x
3b
x
=======
2
3b
>>>>>>>
<<<<<<< a
x
4
x
||||||| b
x
4b
x
=======
4b
5
>>>>>>>
6
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
patch.c | 71 +++++++++++++++++++++++++++++++++++++++++++---------------------
1 file changed, 48 insertions(+), 23 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -63,6 +63,7 @@ static LINENUM locate_hunk (LINENUM);
static bool apply_hunk (struct outstate *, LINENUM);
static bool common_context(LINENUM, LINENUM, LINENUM);
static bool merge_hunk (struct outstate *, LINENUM, LINENUM);
+static void merge_ends_here(struct outstate *outstate);
static bool copy_till (struct outstate *, LINENUM);
static bool patch_match (LINENUM, LINENUM, LINENUM, LINENUM);
static bool similar (char const *, size_t, char const *, size_t);
@@ -81,6 +82,8 @@ static void usage (FILE *, int) __attrib
enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2, MERGE_REJECTS = 4 };
static enum mergetype mergetype;
+static LINENUM merge_end = -1;
+static const char *merge_name;
const char *file_label[2];
static bool make_backups;
@@ -1361,7 +1364,7 @@ static bool merge_hunk (struct outstate
register LINENUM lastline = pch_ptrn_lines ();
register LINENUM new = lastline + 1;
register LINENUM pat_end = pch_end ();
- register LINENUM merge, merge_end;
+ register LINENUM merge, R_merge_end;
register FILE *fp = outstate->ofp;
bool succeeded = true;
const char *name;
@@ -1381,32 +1384,32 @@ static bool merge_hunk (struct outstate
if (fuzz != -1) {
/* Hide common suffix context */
- merge_end = where + lastline - 1;
+ R_merge_end = where + lastline - 1;
while (old <= lastline && new <= pat_end) {
- if (!common_context(merge_end, lastline, pat_end))
+ if (!common_context(R_merge_end, lastline, pat_end))
break;
lastline--;
pat_end--;
- merge_end--;
+ R_merge_end--;
}
} else {
LINENUM overlap = pch_suffix_context ();
/* Hide common suffix context: check how much overlap we have! */
- merge_end = merge - 1;
+ R_merge_end = merge - 1;
while (overlap) {
LINENUM n = 0;
- merge_end += overlap;
+ R_merge_end += overlap;
while (n < overlap && old <= lastline && new <= pat_end) {
- if (!common_context(merge_end, lastline, pat_end))
+ if (!common_context(R_merge_end, lastline, pat_end))
break;
lastline--;
pat_end--;
- merge_end--;
+ R_merge_end--;
n++;
}
- merge_end -= overlap - n;
+ R_merge_end -= overlap - n;
if (n == overlap)
break;
lastline += n;
@@ -1419,7 +1422,8 @@ static bool merge_hunk (struct outstate
if (last_frozen_line < merge) {
if (!copy_till(outstate, merge - 1))
return false;
- }
+ } else
+ merge_ends_here(outstate);
/* "From" lines in the patch */
name = file_label[OLD] ? file_label[OLD] : pch_name(OLD);
@@ -1458,25 +1462,41 @@ static bool merge_hunk (struct outstate
write_fatal ();
outstate->after_newline = true;
- succeeded = apply_hunk(outstate, where) &&
- copy_till(outstate, merge_end);
+ succeeded = apply_hunk(outstate, where);
}
+ assert(merge_end == -1);
+ merge_end = R_merge_end;
+
/* If the merge result and the new file are the same, label the merge
result with the new file's name. */
- name = fuzz ? NULL : (file_label[NEW] ? file_label[NEW] : pch_name(NEW));
- if (!name)
- name = "";
- fprintf(fp, outstate->after_newline + "\n>>>>>>>%*s\n",
- strlen(name) ? strlen(name) + 1 : 0, name);
- if (ferror (fp))
- write_fatal ();
- outstate->after_newline = true;
+ merge_name = fuzz ? NULL : (file_label[NEW] ? file_label[NEW] :
+ pch_name(NEW));
outstate->zero_output = false;
return succeeded;
}
+static void
+merge_ends_here(struct outstate *outstate)
+{
+ register FILE *fp = outstate->ofp;
+
+ if (merge_end != -1)
+ {
+ if (!merge_name)
+ merge_name = "";
+ fprintf(fp, outstate->after_newline + "\n>>>>>>>%*s\n",
+ strlen(merge_name) ? strlen(merge_name) + 1 : 0,
+ merge_name);
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+ outstate->zero_output = false;
+ merge_end = -1;
+ }
+}
+
/* Create an output file. */
static FILE *
@@ -1516,6 +1536,7 @@ static bool
copy_till (register struct outstate *outstate, register LINENUM lastline)
{
register LINENUM R_last_frozen_line = last_frozen_line;
+ register LINENUM R_merge_end = (merge_end != -1) ? merge_end : lastline;
register FILE *fp = outstate->ofp;
register char const *s;
size_t size;
@@ -1527,6 +1548,9 @@ copy_till (register struct outstate *out
}
while (R_last_frozen_line < lastline)
{
+ if (R_merge_end == R_last_frozen_line)
+ merge_ends_here(outstate);
+
s = ifetch (++R_last_frozen_line, false, &size);
if (size)
{
@@ -1538,6 +1562,8 @@ copy_till (register struct outstate *out
}
}
last_frozen_line = R_last_frozen_line;
+ if (merge_end != -1)
+ merge_ends_here(outstate);
return true;
}
@@ -1555,9 +1581,8 @@ spew_output (struct outstate *outstate)
format_linenum (numbuf1, last_frozen_line));
}
- if (last_frozen_line < input_lines)
- if (! copy_till (outstate, input_lines))
- return false;
+ if (! copy_till (outstate, input_lines))
+ return false;
if (outstate->ofp && ! outfile)
{

View File

@ -0,0 +1,281 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: diff3-style merges: pch_name()
Make a pch_name() function available for accessing the old and the new
filename in the patch header.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
pch.c | 88 ++++++++++++++++++++++++++++++++++--------------------------------
pch.h | 3 ++
2 files changed, 49 insertions(+), 42 deletions(-)
Index: b/pch.c
===================================================================
--- a/pch.c
+++ b/pch.c
@@ -43,6 +43,7 @@ static int p_says_nonexistent[2]; /* [0]
1 for existent and probably (but not necessarily) empty,
2 for nonexistent */
static int p_rfc934_nesting; /* RFC 934 nesting level */
+static char *p_name[3]; /* filenames in patch headers */
static time_t p_timestamp[2]; /* timestamps in patch headers */
static off_t p_filesize; /* size of the patch file */
static LINENUM p_first; /* 1st line number */
@@ -70,8 +71,6 @@ static LINENUM p_efake = -1; /* end of
static LINENUM p_bfake = -1; /* beg of faked up lines */
static char *p_c_function; /* the C function a hunk is in */
-enum nametype { OLD, NEW, INDEX, NONE };
-
static char *scan_linenum (char *, LINENUM *);
static enum diff intuit_diff_type (void);
static enum nametype best_name (char * const *, int const *);
@@ -300,13 +299,17 @@ intuit_diff_type (void)
register bool this_is_a_command = false;
register bool stars_this_line = false;
enum nametype i;
- char *name[3];
struct stat st[3];
int stat_errno[3];
int version_controlled[3];
register enum diff retval;
- name[OLD] = name[NEW] = name[INDEX] = 0;
+ for (i = OLD; i <= INDEX; i++)
+ if (p_name[i]) {
+ free (p_name[i]);
+ p_name[i] = 0;
+ }
+
version_controlled[OLD] = -1;
version_controlled[NEW] = -1;
version_controlled[INDEX] = -1;
@@ -365,16 +368,16 @@ intuit_diff_type (void)
p_strip_trailing_cr = strip_trailing_cr;
}
if (!stars_last_line && strnEQ(s, "*** ", 4))
- name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
+ p_name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
else if (strnEQ(s, "+++ ", 4))
{
/* Swap with NEW below. */
- name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
+ p_name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
p_strip_trailing_cr = strip_trailing_cr;
}
else if (strnEQ(s, "Index:", 6))
{
- name[INDEX] = fetchname (s+6, strippath, (time_t *) 0);
+ p_name[INDEX] = fetchname (s+6, strippath, (time_t *) 0);
p_strip_trailing_cr = strip_trailing_cr;
}
else if (strnEQ(s, "Prereq:", 7)) {
@@ -410,7 +413,7 @@ intuit_diff_type (void)
if (strnEQ(t, "--- ", 4))
{
time_t timestamp = (time_t) -1;
- name[NEW] = fetchname (t+4, strippath, &timestamp);
+ p_name[NEW] = fetchname (t+4, strippath, &timestamp);
if (timestamp != (time_t) -1)
{
p_timestamp[NEW] = timestamp;
@@ -430,13 +433,13 @@ intuit_diff_type (void)
if ((diff_type == NO_DIFF || diff_type == UNI_DIFF)
&& strnEQ(s, "@@ -", 4)) {
- /* `name' and `p_timestamp' are backwards; swap them. */
+ /* `p_name' and `p_timestamp' are backwards; swap them. */
time_t ti = p_timestamp[OLD];
p_timestamp[OLD] = p_timestamp[NEW];
p_timestamp[NEW] = ti;
- t = name[OLD];
- name[OLD] = name[NEW];
- name[NEW] = t;
+ t = p_name[OLD];
+ p_name[OLD] = p_name[NEW];
+ p_name[NEW] = t;
s += 4;
if (s[0] == '0' && !ISDIGIT (s[1]))
@@ -451,9 +454,9 @@ intuit_diff_type (void)
p_start = this_line;
p_sline = p_input_line;
retval = UNI_DIFF;
- if (! ((name[OLD] || ! p_timestamp[OLD])
- && (name[NEW] || ! p_timestamp[NEW]))
- && ! name[INDEX])
+ if (! ((p_name[OLD] || ! p_timestamp[OLD])
+ && (p_name[NEW] || ! p_timestamp[NEW]))
+ && ! p_name[INDEX])
{
char numbuf[LINENUM_LENGTH_BOUND + 1];
say ("missing header for unified diff at line %s of patch\n",
@@ -492,9 +495,9 @@ intuit_diff_type (void)
next_intuit_at (saved_p_base, saved_p_bline);
}
- if (! ((name[OLD] || ! p_timestamp[OLD])
- && (name[NEW] || ! p_timestamp[NEW]))
- && ! name[INDEX])
+ if (! ((p_name[OLD] || ! p_timestamp[OLD])
+ && (p_name[NEW] || ! p_timestamp[NEW]))
+ && ! p_name[INDEX])
{
char numbuf[LINENUM_LENGTH_BOUND + 1];
say ("missing header for context diff at line %s of patch\n",
@@ -543,23 +546,23 @@ intuit_diff_type (void)
{
enum nametype i0 = NONE;
- if (! posixly_correct && (name[OLD] || name[NEW]) && name[INDEX])
+ if (! posixly_correct && (p_name[OLD] || p_name[NEW]) && p_name[INDEX])
{
- free (name[INDEX]);
- name[INDEX] = 0;
+ free (p_name[INDEX]);
+ p_name[INDEX] = 0;
}
for (i = OLD; i <= INDEX; i++)
- if (name[i])
+ if (p_name[i])
{
- if (i0 != NONE && strcmp (name[i0], name[i]) == 0)
+ if (i0 != NONE && strcmp (p_name[i0], p_name[i]) == 0)
{
/* It's the same name as before; reuse stat results. */
stat_errno[i] = stat_errno[i0];
if (! stat_errno[i])
st[i] = st[i0];
}
- else if (stat (name[i], &st[i]) != 0)
+ else if (stat (p_name[i], &st[i]) != 0)
stat_errno[i] = errno;
else
{
@@ -574,30 +577,30 @@ intuit_diff_type (void)
{
bool is_empty;
- i = best_name (name, stat_errno);
+ i = best_name (p_name, stat_errno);
if (i == NONE && patch_get)
{
enum nametype nope = NONE;
for (i = OLD; i <= INDEX; i++)
- if (name[i])
+ if (p_name[i])
{
char const *cs;
char *getbuf;
char *diffbuf;
bool readonly = (outfile
- && strcmp (outfile, name[i]) != 0);
+ && strcmp (outfile, p_name[i]) != 0);
- if (nope == NONE || strcmp (name[nope], name[i]) != 0)
+ if (nope == NONE || strcmp (p_name[nope], p_name[i]) != 0)
{
cs = (version_controller
- (name[i], readonly, (struct stat *) 0,
+ (p_name[i], readonly, (struct stat *) 0,
&getbuf, &diffbuf));
version_controlled[i] = !! cs;
if (cs)
{
- if (version_get (name[i], cs, false, readonly,
+ if (version_get (p_name[i], cs, false, readonly,
getbuf, &st[i]))
stat_errno[i] = 0;
else
@@ -627,7 +630,7 @@ intuit_diff_type (void)
(i == NONE ? "delete"
: st[i].st_size == 0 ? "empty out"
: "create"),
- quotearg (name[i == NONE || st[i].st_size == 0 ? i0 : i]),
+ quotearg (p_name[i == NONE || st[i].st_size == 0 ? i0 : i]),
(i == NONE ? "does not exist"
: st[i].st_size == 0 ? "is already empty"
: "already exists"));
@@ -640,19 +643,19 @@ intuit_diff_type (void)
int distance_from_minimum[3];
for (i = OLD; i <= INDEX; i++)
- if (name[i])
+ if (p_name[i])
{
- newdirs[i] = (prefix_components (name[i], false)
- - prefix_components (name[i], true));
+ newdirs[i] = (prefix_components (p_name[i], false)
+ - prefix_components (p_name[i], true));
if (newdirs[i] < newdirs_min)
newdirs_min = newdirs[i];
}
for (i = OLD; i <= INDEX; i++)
- if (name[i])
+ if (p_name[i])
distance_from_minimum[i] = newdirs[i] - newdirs_min;
- i = best_name (name, distance_from_minimum);
+ i = best_name (p_name, distance_from_minimum);
}
}
}
@@ -661,17 +664,12 @@ intuit_diff_type (void)
inerrno = -1;
else
{
- inname = name[i];
- name[i] = 0;
+ inname = savestr(p_name[i]);
inerrno = stat_errno[i];
invc = version_controlled[i];
instat = st[i];
}
- for (i = OLD; i <= INDEX; i++)
- if (name[i])
- free (name[i]);
-
return retval;
}
@@ -1803,6 +1801,12 @@ pch_says_nonexistent (bool which)
/* Return timestamp of patch header for file WHICH (false = old, true = new),
or -1 if there was no timestamp or an error in the timestamp. */
+const char *
+pch_name (enum nametype type)
+{
+ return type == NONE ? NULL : p_name[type];
+}
+
time_t
pch_timestamp (bool which)
{
Index: b/pch.h
===================================================================
--- a/pch.h
+++ b/pch.h
@@ -22,6 +22,8 @@
If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+enum nametype { OLD, NEW, INDEX, NONE };
+
LINENUM pch_end (void);
LINENUM pch_first (void);
LINENUM pch_hunk_beg (void);
@@ -39,6 +41,7 @@ char pch_char (LINENUM);
int another_hunk (enum diff, bool);
int pch_says_nonexistent (bool);
size_t pch_line_len (LINENUM);
+const char *pch_name(enum nametype);
time_t pch_timestamp (bool);
void do_ed_script (FILE *);
void open_patch_file (char const *);

View File

@ -0,0 +1,61 @@
---
patch.c | 42 ++++++++++++++++++++----------------------
1 file changed, 20 insertions(+), 22 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -286,32 +286,30 @@ main (int argc, char **argv)
newwhere = pch_newfirst() + last_offset;
if (skip_rest_of_patch) {
goto skip_hunk;
- }
- else if (!where
- || (where == 1 && pch_says_nonexistent (reverse) == 2
- && instat.st_size)) {
-
- if (where)
- say ("Patch attempted to create file %s, which already exists.\n",
- quotearg (inname));
+ } else if (where == 1 && pch_says_nonexistent (reverse) == 2
+ && instat.st_size) {
+ say ("Patch attempted to create file %s, "
+ "which already exists.\n", quotearg (inname));
goto skip_hunk;
- }
- else if (! apply_hunk (&outstate, where)) {
+ } else if (!where) {
goto skip_hunk;
} else {
- if (verbosity == VERBOSE
- || (verbosity != SILENT && (fuzz || last_offset))) {
- say ("Hunk #%d succeeded at %s", hunk,
- format_linenum (numbuf, newwhere));
- if (fuzz)
- say (" with fuzz %s", format_linenum (numbuf, fuzz));
- if (last_offset)
- say (" (offset %s line%s)",
- format_linenum (numbuf, last_offset),
- "s" + (last_offset == 1));
- say (".\n");
- }
+ if (!apply_hunk (&outstate, where))
+ goto skip_hunk;
+ }
+
+ if (verbosity == VERBOSE
+ || (verbosity != SILENT && (fuzz || last_offset))) {
+ say ("Hunk #%d succeeded at %s", hunk,
+ format_linenum (numbuf, newwhere));
+ if (fuzz)
+ say (" with fuzz %s", format_linenum (numbuf, fuzz));
+ if (last_offset)
+ say (" (offset %s line%s)",
+ format_linenum (numbuf, last_offset),
+ "s" + (last_offset == 1));
+ say (".\n");
}
continue;

View File

@ -0,0 +1,67 @@
---
patch.c | 36 +++++++++++++++---------------------
1 file changed, 15 insertions(+), 21 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -285,13 +285,7 @@ main (int argc, char **argv)
newwhere = pch_newfirst() + last_offset;
if (skip_rest_of_patch) {
- if (!failed)
- reject_header(outname);
- abort_hunk();
- failed++;
- if (verbosity == VERBOSE)
- say ("Hunk #%d ignored at %s.\n", hunk,
- format_linenum (numbuf, newwhere));
+ goto skip_hunk;
}
else if (!where
|| (where == 1 && pch_says_nonexistent (reverse) == 2
@@ -301,22 +295,10 @@ main (int argc, char **argv)
say ("Patch attempted to create file %s, which already exists.\n",
quotearg (inname));
- if (!failed)
- reject_header(outname);
- abort_hunk();
- failed++;
- if (verbosity != SILENT)
- say ("Hunk #%d FAILED at %s.\n", hunk,
- format_linenum (numbuf, newwhere));
+ goto skip_hunk;
}
else if (! apply_hunk (&outstate, where)) {
- if (!failed)
- reject_header(outname);
- abort_hunk ();
- failed++;
- if (verbosity != SILENT)
- say ("Hunk #%d FAILED at %s.\n", hunk,
- format_linenum (numbuf, newwhere));
+ goto skip_hunk;
} else {
if (verbosity == VERBOSE
|| (verbosity != SILENT && (fuzz || last_offset))) {
@@ -331,6 +313,18 @@ main (int argc, char **argv)
say (".\n");
}
}
+ continue;
+
+skip_hunk:
+ if (!failed)
+ reject_header(outname);
+ abort_hunk ();
+ failed++;
+ if (verbosity == VERBOSE ||
+ (!skip_rest_of_patch && verbosity != SILENT))
+ say ("Hunk #%d %s at %s.\n", hunk,
+ skip_rest_of_patch ? "ignored" : "FAILED",
+ format_linenum (numbuf, newwhere));
}
if (!skip_rest_of_patch)

View File

@ -0,0 +1,116 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: diff3-style merges: merge rejects
With the --merge-all option, hunks which do not apply and which would
end up in a *.rej file will also get added to output files. They will
be bracketed like this:
<<<<<<<
old lines from patch
|||||||
new lines from patch
>>>>>>>
With this change, all pieces of a patch can be applied, and all the
resulting merge conflicts can be fixed in the patched files instead
of looking at the reject files.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
patch.c | 40 +++++++++++++++++++++++++++++++---------
1 file changed, 31 insertions(+), 9 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -79,7 +79,7 @@ static void reinitialize_almost_everythi
static void remove_if_needed (char const *, int volatile *);
static void usage (FILE *, int) __attribute__((noreturn));
-enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2 };
+enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2, MERGE_REJECTS = 4 };
static enum mergetype mergetype;
static bool make_backups;
@@ -299,7 +299,18 @@ main (int argc, char **argv)
goto skip_hunk;
} else if (!where) {
- goto skip_hunk;
+ if (mergetype & MERGE_REJECTS) {
+ LINENUM guess = pch_first () + last_offset;
+
+ if (merge_hunk(&outstate, guess, -1)) {
+ merged++;
+ mismatch = 1;
+ } else {
+ /* FIXME: guess harder! */
+ goto skip_hunk;
+ }
+ } else
+ goto skip_hunk;
} else {
if ((mergetype & SHOW_ALL) ||
(fuzz && (mergetype & SHOW_FUZZ))) {
@@ -316,10 +327,16 @@ main (int argc, char **argv)
if (verbosity == VERBOSE
|| (verbosity != SILENT && (fuzz || last_offset))) {
- say ("Hunk #%d succeeded at %s", hunk,
- format_linenum (numbuf, newwhere));
- if (fuzz)
- say (" with fuzz %s", format_linenum (numbuf, fuzz));
+ if (fuzz > mymaxfuzz) {
+ say ("Hunk #%d merged at %s with errors", hunk,
+ format_linenum (numbuf, newwhere));
+ somefailed = true;
+ } else {
+ say ("Hunk #%d succeeded at %s", hunk,
+ format_linenum (numbuf, newwhere));
+ if (fuzz)
+ say (" with fuzz %s", format_linenum (numbuf, fuzz));
+ }
if (last_offset)
say (" (offset %s line%s)",
format_linenum (numbuf, last_offset),
@@ -521,7 +538,7 @@ reinitialize_almost_everything (void)
skip_rest_of_patch = false;
}
-static char const shortopts[] = "bB:cd:D:eEfF:g:i:lnNo:p:r:RstTuvV:x:Y:z:Z";
+static char const shortopts[] = "bB:cd:D:eEfF:g:i:lMnNo:p:r:RstTuvV:x:Y:z:Z";
static struct option const longopts[] =
{
{"backup", no_argument, NULL, 'b'},
@@ -591,7 +608,7 @@ static char const *const option_help[] =
" -r FILE --reject-file=FILE Output rejects to FILE.",
"",
" -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
-" --merge={fuzz,all} Produce a diff3-style merge.",
+" --merge={rejects,fuzz,all} Produce a diff3-style merge.",
" -E --remove-empty-files Remove output files that are empty after patching.",
"",
" -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).",
@@ -730,6 +747,9 @@ get_some_switches (void)
case 'l':
canonicalize = true;
break;
+ case 'M':
+ mergetype |= MERGE_REJECTS;
+ break;
case 'n':
diff_type = NORMAL_DIFF;
break;
@@ -835,7 +855,9 @@ get_some_switches (void)
char *tok = strtok(optarg, ",");
do {
- if (!strcmp(tok, "fuzz"))
+ if (!strcmp(tok, "rejects"))
+ mergetype |= MERGE_REJECTS;
+ else if (!strcmp(tok, "fuzz"))
mergetype |= SHOW_FUZZ;
else if (!strcmp(tok, "all"))
mergetype |= SHOW_ALL;

View File

@ -0,0 +1,492 @@
---
merge-tests/diff3-merge.test | 35 +++++++++
merge-tests/locate-rejects.test | 77 ++++++++++++++++++++
merge-tests/modes.test | 148 ++++++++++++++++++++++++++++++++++++++++
merge-tests/overlap-patch.test | 94 +++++++++++++++++++++++++
merge-tests/prefix-suffix.test | 105 ++++++++++++++++++++++++++++
5 files changed, 459 insertions(+)
Index: b/merge-tests/diff3-merge.test
===================================================================
--- /dev/null
+++ b/merge-tests/diff3-merge.test
@@ -0,0 +1,35 @@
+$ tmpdir=$(mktemp -d)
+$ trap "cd /; rm -rf $tmpdir" EXIT
+$ cd $tmpdir
+
+ $ seq 1 4 > a
+ $ sed -e 's/2/2b/' a > b
+ $ sed -e 's/4/4d/' a > c
+
+Diff3 will merge changes if they are one line apart:
+
+ $ diff3 -m b a c
+ > 1
+ > 2b
+ > 3
+ > 4d
+
+But it will not merge adjacent changes:
+
+ $ sed -e 's/3/3c/' a > d
+
+ $ diff3 -m b a d
+ > 1
+ > <<<<<<< b
+ > 2b
+ > 3
+ > ||||||| a
+ > 2
+ > 3
+ > =======
+ > 2
+ > 3c
+ > >>>>>>> d
+ > 4
+
+Patch will merge the changes in either case.
Index: b/merge-tests/modes.test
===================================================================
--- /dev/null
+++ b/merge-tests/modes.test
@@ -0,0 +1,148 @@
+$ tmpdir=$(mktemp -d)
+$ trap "cd /; rm -rf $tmpdir" EXIT
+$ cd $tmpdir
+
+$ cat > clean.diff
+< --- a
+< +++ b
+< @@ -2 +2 @@
+< -2
+< +2clean
+
+$ seq 1 3 > c ; patch c < clean.diff
+> patching file c
+
+$ cat c
+> 1
+> 2clean
+> 3
+
+$ seq 1 3 > c ; patch --merge=all c < clean.diff
+> patching file c
+
+$ cat c
+> 1
+> <<<<<<< a
+> 2
+> =======
+> 2clean
+> >>>>>>> b
+> 3
+
+$ seq 1 3 > c ; patch --merge=fuzz c < clean.diff
+> patching file c
+
+$ cat c
+> 1
+> 2clean
+> 3
+
+$ seq 1 3 > c ; patch --merge=rejects c < clean.diff
+> patching file c
+
+$ cat c
+> 1
+> 2clean
+> 3
+
+$ cat > fuzz.diff
+< --- a
+< +++ b
+< @@ -1,3 +1,3 @@
+< x
+< -2
+< +2fuzz
+< x
+
+$ seq 1 3 > c ; patch c < fuzz.diff
+> patching file c
+> Hunk #1 succeeded at 1 with fuzz 1.
+
+$ cat c
+> 1
+> 2fuzz
+> 3
+
+$ seq 1 3 > c ; patch --merge=all c < fuzz.diff
+> patching file c
+> Hunk #1 succeeded at 1 with fuzz 1.
+
+$ cat c
+> <<<<<<< a
+> x
+> 2
+> x
+> ||||||| b
+> x
+> 2fuzz
+> x
+> =======
+> 1
+> 2fuzz
+> 3
+> >>>>>>>
+
+$ seq 1 3 > c ; patch --merge=fuzz c < fuzz.diff
+> patching file c
+> Hunk #1 succeeded at 1 with fuzz 1.
+
+$ cat c
+> <<<<<<< a
+> x
+> 2
+> x
+> ||||||| b
+> x
+> 2fuzz
+> x
+> =======
+> 1
+> 2fuzz
+> 3
+> >>>>>>>
+
+$ seq 1 3 > c ; patch --merge=rejects c < fuzz.diff
+> patching file c
+> Hunk #1 succeeded at 1 with fuzz 1.
+
+$ cat c
+> 1
+> 2fuzz
+> 3
+
+$ cat > reject.diff
+< --- a
+< +++ b
+< @@ -2 +2 @@
+< -2reject
+< +2reject
+
+$ seq 1 3 > c ; patch c < reject.diff
+> patching file c
+> Hunk #1 FAILED at 2.
+> 1 out of 1 hunk FAILED -- saving rejects to file c.rej
+
+$ seq 1 3 > c ; patch --merge=all c < reject.diff
+> patching file c
+> Hunk #1 FAILED at 2.
+> 1 out of 1 hunk FAILED -- saving rejects to file c.rej
+
+$ seq 1 3 > c ; patch --merge=fuzz c < reject.diff
+> patching file c
+> Hunk #1 FAILED at 2.
+> 1 out of 1 hunk FAILED -- saving rejects to file c.rej
+
+$ seq 1 3 > c ; patch --merge=rejects c < reject.diff
+> patching file c
+> Hunk #1 merged at 2 with errors.
+
+$ cat c
+> 1
+> <<<<<<< a
+> 2reject
+> ||||||| b
+> 2reject
+> >>>>>>>
+> 2
+> 3
+
Index: b/merge-tests/prefix-suffix.test
===================================================================
--- /dev/null
+++ b/merge-tests/prefix-suffix.test
@@ -0,0 +1,105 @@
+$ tmpdir=$(mktemp -d)
+$ trap "cd /; rm -rf $tmpdir" EXIT
+$ cd $tmpdir
+
+$ seq 1 7 > a
+$ seq 1 7 | sed -e '4d' > b
+$ diff -u -L a -L b a b > ab.diff
+$ diff -u -L b -L a b a > ba.diff
+
+$ cp a c
+$ patch --merge=all c < ab.diff
+> patching file c
+
+$ cat c
+> 1
+> 2
+> 3
+> <<<<<<< a
+> 4
+> =======
+> >>>>>>> b
+> 5
+> 6
+> 7
+
+$ cp b c
+$ patch --merge=all c < ba.diff
+> patching file c
+
+$ cat c
+> 1
+> 2
+> 3
+> <<<<<<< b
+> =======
+> 4
+> >>>>>>> a
+> 5
+> 6
+> 7
+
+$ diff -u /dev/null a > a.diff
+$ echo -n '' > c
+$ patch --merge=all c < a.diff
+> patching file c
+
+$ cat c
+> <<<<<<<
+> =======
+> 1
+> 2
+> 3
+> 4
+> 5
+> 6
+> 7
+> >>>>>>> a
+
+$ diff -u a /dev/null > a-.diff
+$ cp a c
+$ patch --merge=all c < a-.diff
+> patching file c
+
+$ cat c
+#
+> <<<<<<< a
+> 1
+> 2
+> 3
+> 4
+> 5
+> 6
+> 7
+> =======
+> >>>>>>>
+
+$ seq -f '%gc' 1 7 > c
+$ patch --merge=rejects c < ab.diff
+> patching file c
+> Hunk #1 merged at 1 with errors.
+
+$ cat c
+> <<<<<<< a
+> 1
+> 2
+> 3
+> 4
+> 5
+> 6
+> 7
+> ||||||| b
+> 1
+> 2
+> 3
+> 5
+> 6
+> 7
+> >>>>>>>
+> 1c
+> 2c
+> 3c
+> 4c
+> 5c
+> 6c
+> 7c
Index: b/merge-tests/overlap-patch.test
===================================================================
--- /dev/null
+++ b/merge-tests/overlap-patch.test
@@ -0,0 +1,94 @@
+$ tmpdir=$(mktemp -d)
+$ trap "cd /; rm -rf $tmpdir" EXIT
+$ cd $tmpdir
+
+$ cat > patch
+< --- a
+< +++ b
+< @@ -2,3 +2,3 @@
+< x
+< -3
+< +3b
+< x
+
+$ seq 1 6 > file
+$ patch file < patch
+> patching file file
+> Hunk #1 succeeded at 2 with fuzz 1.
+
+$ seq 1 6 > file
+$ patch --merge=all file < patch
+> patching file file
+> Hunk #1 succeeded at 2 with fuzz 1.
+
+$ cat file
+> 1
+> <<<<<<< a
+> x
+> 3
+> x
+> ||||||| b
+> x
+> 3b
+> x
+> =======
+> 2
+> 3b
+> 4
+> >>>>>>>
+> 5
+> 6
+
+$ cat > patch
+< --- a
+< +++ b
+< @@ -2,3 +2,3 @@
+< x
+< -3
+< +3b
+< x
+< @@ -3,3 +3,3 @@
+< x
+< -4
+< +4b
+< x
+
+$ seq 1 6 > file
+$ patch file < patch
+> patching file file
+> Hunk #1 succeeded at 2 with fuzz 1.
+> Hunk #2 succeeded at 3 with fuzz 1.
+
+$ seq 1 6 > file
+$ patch --merge=all file < patch
+> patching file file
+> Hunk #1 succeeded at 2 with fuzz 1.
+> Hunk #2 succeeded at 3 with fuzz 1.
+
+$ cat file
+> 1
+> <<<<<<< a
+> x
+> 3
+> x
+> ||||||| b
+> x
+> 3b
+> x
+> =======
+> 2
+> 3b
+> >>>>>>>
+> <<<<<<< a
+> x
+> 4
+> x
+> ||||||| b
+> x
+> 4b
+> x
+> =======
+> 4b
+> 5
+> >>>>>>>
+> 6
Index: b/merge-tests/locate-rejects.test
===================================================================
--- /dev/null
+++ b/merge-tests/locate-rejects.test
@@ -0,0 +1,77 @@
+$ tmpdir=$(mktemp -d)
+$ trap "cd /; rm -rf $tmpdir" EXIT
+$ cd $tmpdir
+
+$ seq 1 7 > a
+$ seq 1 7 | sed -e 's/4/4b/' > b
+$ seq 1 7 | sed -e 's/4/4c/' > c
+$ seq 1 7 | sed -e '4d' > d
+
+$ diff -u a b > ab.diff
+
+$ patch c < ab.diff
+> patching file c
+> Hunk #1 FAILED at 1.
+> 1 out of 1 hunk FAILED -- saving rejects to file c.rej
+
+$ patch --merge=rejects c < ab.diff
+> patching file c
+> Hunk #1 merged at 1 with errors.
+
+$ cat c
+> 1
+> 2
+> 3
+> <<<<<<< a
+> 4
+> 5
+> 6
+> 7
+> ||||||| b
+> 4b
+> 5
+> 6
+> 7
+> >>>>>>>
+> 4c
+> 5
+> 6
+> 7
+
+$ (seq 1 3; echo 7) > c
+$ patch --merge=rejects c < ab.diff
+> patching file c
+> Hunk #1 merged at 1 with errors.
+
+$ cat c
+> 1
+> 2
+> 3
+> <<<<<<< a
+> 4
+> 5
+> 6
+> ||||||| b
+> 4b
+> 5
+> 6
+> >>>>>>>
+> 7
+
+$ patch --merge=rejects d < ab.diff
+> patching file d
+> Hunk #1 merged at 1 with errors.
+
+$ cat d
+> 1
+> 2
+> 3
+> <<<<<<< a
+> 4
+> ||||||| b
+> 4b
+> >>>>>>>
+> 5
+> 6
+> 7
+

View File

@ -1,19 +0,0 @@
$ mkdir d
$ cd d
$ mkdir sub
$ echo 1 > f
$ echo 2 > f.new
$ diff -Nu f f.new > f.diff
$ mv f.new f
$ echo 3 > f.new
$ diff -Nu f f.new >> f.diff
$ rm f.new
$ echo 1 > f
$ chmod a=r f
$ strace -o ../log patch -p0 --backup < f.diff
> patching file f
> patching file f
$ cd ..
$ rm -rf d

View File

@ -1,3 +1,9 @@
-------------------------------------------------------------------
Tue Feb 3 06:10:49 CET 2009 - agruen@suse.de
- Implement diff3-style merges (including several fixes and
improvements).
-------------------------------------------------------------------
Wed Apr 23 10:53:19 CEST 2008 - agruen@suse.de

View File

@ -1,10 +1,17 @@
#
# spec file for package patch (Version 2.5.9)
#
# Copyright (c) 2008 SUSE LINUX Products GmbH, Nuernberg, Germany.
# This file and all modifications and additions to the pristine
# package are under the same license as the package itself.
# Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
@ -16,7 +23,7 @@ License: GPL v2 or later
Group: Productivity/Text/Utilities
AutoReqProv: on
Version: 2.5.9
Release: 252
Release: 287
Summary: GNU patch
Source: ftp://prep.ai.mit.edu/pub/gnu/patch/%{name}-%{version}.tar.bz2
Url: ftp://alpha.gnu.org/gnu/diffutils/
@ -28,6 +35,17 @@ Patch4: if_else_endif_comments.diff
Patch5: patch-2.5.9-cat_if_device.diff
Patch6: patch-man-unified-reject.diff
Patch7: fix-partial-context.diff
Patch8: diff3-style-merges-tests.diff
Patch9: diff3-style-merges-refactoring.diff
Patch10: diff3-style-merges-refactoring-2.diff
Patch11: diff3-style-merges-base.diff
Patch12: diff3-style-merges-rejects.diff
Patch13: diff3-style-merges-pch_name.diff
Patch14: diff3-style-merges-include-filenames.diff
Patch15: diff3-style-merges-add-file-labels.diff
Patch16: diff3-style-merges-overlap.diff
Patch17: diff3-style-merges-locate-merge.diff
Patch18: diff3-style-merges-other-strategy.diff
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
@ -51,6 +69,17 @@ Authors:
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%build
aclocal --acdir=m4
@ -76,6 +105,9 @@ make install \
%doc %{_mandir}/man1/patch.1.gz
%changelog
* Tue Feb 03 2009 agruen@suse.de
- Implement diff3-style merges (including several fixes and
improvements).
* Wed Apr 23 2008 agruen@suse.de
- remember-backup-files.diff: Fix bug when a file is touched by
the same patch more than twice. Move the test cases from the