Skip to content

Commit

Permalink
merge: fix a problem with unmatchable hunks.
Browse files Browse the repository at this point in the history
If the patch contains hunks that cannot be matched, wiggle cannot to
anything really useful, but sometimes it does something bad and produces
a badly formatted result.

In these cases, the hunk must get placed somewhere, and it is possible
that two hunks could line up with different places in the same line of
the original.

As wiggle normally expands conflicts to cover whole lines, to display
this coherently, you would need something like

<<<
chosen line
||||
hunk1- before
hunk2- before
===
hunk1- after
hunk2- after
>>>

But wiggle assumes that a hunk header marks the end of a conflict, so
bad things happen here.
I don't want to display the hunk header, so I think the best option is

<<<
chosen line
|||
hunk1- before
===
hunk1- after
>>>
<<<
|||
hunk2- before
===
hunk2- after
>>>

To achieve this, we don't stop collecting a conflict when we hit a
hunk-header moving forward, but when we print the conflict out, we
detect those hunk headers, and do the above.
If the final hunk doesn't actually contain any differences, don't
bother printing it.

Signed-off-by: NeilBrown <[email protected]>
  • Loading branch information
neilbrown committed Oct 3, 2020
1 parent 2802d9a commit 2a74063
Show file tree
Hide file tree
Showing 6 changed files with 2,559 additions and 12 deletions.
71 changes: 62 additions & 9 deletions merge2.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,6 @@ int isolate_conflicts(struct file af, struct file bf, struct file cf,
/* now the forward search */
newlines = 0;
for (j = i+1; m[j].type != End; j++) {
if (m[j].type == Extraneous &&
bf.list[m[j].b].start[0] == '\0')
/* hunk header - not conflict any more */
break;
if (m[j].type == Extraneous) {
for (k = 0; k < m[j].bl; k++)
if (ends_line(bf.list[m[j].b+k]))
Expand Down Expand Up @@ -638,6 +634,9 @@ static int printrange(FILE *out, struct file *f, int start, int len,
return lines;
}

static const char *conflict_types[] = {
"", " border"," conflict"," wiggle" };

int print_merge(FILE *out, struct file *a, struct file *b, struct file *c,
int words, struct merge *merger,
struct merge *mpos, int streampos, int offsetpos)
Expand All @@ -646,6 +645,7 @@ int print_merge(FILE *out, struct file *a, struct file *b, struct file *c,
int lineno = 1;
int rv = 0;
int offset = INT_MAX;
int first_matched;

for (m = merger; m->type != End ; m++) {
struct merge *cm;
Expand All @@ -660,7 +660,7 @@ int print_merge(FILE *out, struct file *a, struct file *b, struct file *c,
m->a, m->a+m->al-1,
m->b, m->b+m->bl-1,
m->c, m->c+m->cl-1,
m->in_conflict ? " in_conflict" : "",
conflict_types[m->in_conflict],
m->lo, m->hi);

while (m->in_conflict) {
Expand All @@ -682,7 +682,7 @@ int print_merge(FILE *out, struct file *a, struct file *b, struct file *c,
rv = lineno;
if (do_trace)
for (cm = m; cm->in_conflict; cm++) {
printf("{%s: %d-%d,%d-%d,%d-%d%s(%d,%d)}\n",
printf("{%s: %d-%d,%d-%d,%d-%d%s(%d,%d)}%s\n",
cm->type==Unmatched?"Unmatched":
cm->type==Unchanged?"Unchanged":
cm->type==Extraneous?"Extraneous":
Expand All @@ -692,8 +692,12 @@ int print_merge(FILE *out, struct file *a, struct file *b, struct file *c,
cm->a, cm->a+cm->al-1,
cm->b, cm->b+cm->bl-1,
cm->c, cm->c+cm->cl-1,
cm->in_conflict ? " in_conflict" : "",
cm->lo, cm->hi);
conflict_types[m->in_conflict],
cm->lo, cm->hi,
(cm->type == Extraneous &&
b->list[cm->b].start[0] == '\0') ?
b->list[cm->b].start+1: ""
);
if (cm->in_conflict == 1 && cm != m)
break;
}
Expand Down Expand Up @@ -724,11 +728,24 @@ int print_merge(FILE *out, struct file *a, struct file *b, struct file *c,
}
if (cm == mpos && streampos == 0)
rv = lineno;
restart:
fputs(words ? "|||" : "||||||| expected\n", out);
if (!words)
lineno++;
st1 = st;
first_matched = 1;
for (cm = m; cm->in_conflict; cm++) {
if (cm->type == Extraneous &&
b->list[cm->b].start[0] == '\0') {
/* This is a hunk header, skip it and possibly
* abort this section
*/
if (first_matched)
continue;
break;
}
if (cm->type != Unchanged && cm->type != Unmatched)
first_matched = 0;
if (cm == mpos && streampos == 1)
offset = offsetpos;
if (cm->in_conflict == 1 && cm != m) {
Expand All @@ -746,7 +763,43 @@ int print_merge(FILE *out, struct file *a, struct file *b, struct file *c,
if (!words)
lineno++;
st1 = st;
first_matched = 1;
for (cm = m; cm->in_conflict; cm++) {
if (cm->type == Extraneous &&
b->list[cm->b].start[0] == '\0') {
/* This is a hunk header, skip it and possibly
* abort this section and restart.
*/
if (first_matched)
continue;
m = cm;
/* If remaining merges are all
* Extraneous, Unchanged, or Unmatched,
* we don't need them.
*/
while (cm->in_conflict > 1 &&
(cm->type == Extraneous ||
cm->type == Unmatched ||
cm->type == Unchanged))
cm ++;
if (!cm->in_conflict)
/* Nothing more to report */
break;
if (cm->in_conflict == 1 &&
(cm->type == Extraneous ||
cm->type == Unmatched ||
cm->type == Unchanged))
/* border between conflicts, but
* still nothing to report.
*/
break;
fputs(words ? ">>>" : ">>>>>>> replacement\n", out);
fputs(words ? "<<<" : "<<<<<<< found\n", out);
st = 0;
goto restart;
}
if (cm->type != Unchanged && cm->type != Unmatched)
first_matched = 0;
if (cm == mpos && streampos == 2)
offset = offsetpos;
if (cm->in_conflict == 1 && cm != m) {
Expand Down Expand Up @@ -833,7 +886,7 @@ int print_merge(FILE *out, struct file *a, struct file *b, struct file *c,
m->a, m->a+m->al-1,
m->b, m->b+m->bl-1,
m->c, m->c+m->cl-1,
m->in_conflict ? " in_conflict" : "",
conflict_types[m->in_conflict],
m->lo, m->hi);
}
if (m == mpos)
Expand Down
4 changes: 2 additions & 2 deletions tests/linux/iomap/merge
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ EXPORT_SYMBOL(ioport_unmap);
#ifdef CONFIG_PCI
/* Hide the details if this is a MMIO or PIO address space and just do what
<<<<<<< found
* you expect in the correct way. */||||||| expected
* you expect in the correct way. */
||||||| expected
* you expect from them in the correct way.
*
* @maxlen specifies the maximum length to map. If you want to get access to
Expand Down Expand Up @@ -325,7 +326,6 @@ void __iomem *pci_iomap_range(struct pci_dev *dev, int bar,
return ioremap_nocache(start, len);
}
>>>>>>> replacement

/**
* pci_iomap - create a virtual mapping cookie for a PCI BAR
* @dev: PCI device that owns the BAR
Expand Down
2 changes: 1 addition & 1 deletion tests/linux/raid1-A/merge
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
<<<<<<< found
}

atomic_inc(&r1_bio->remaining);
||||||| expected
bio_list_add(&bl, mbio);
}
Expand All @@ -930,7 +931,6 @@ static int make_request(mddev_t *mddev, struct bio * bio)
kfree(behind_pages); /* the behind pages are attached to the bios now */

>>>>>>> replacement
atomic_inc(&r1_bio->remaining);
<<<<<<< found
spin_lock_irqsave(&conf->device_lock, flags);
bio_list_add(&conf->pending_bio_list, mbio);
Expand Down
Loading

0 comments on commit 2a74063

Please sign in to comment.