Mercurial > hg-stable
comparison mercurial/simplemerge.py @ 28072:c3e9269d9602
merge: minimize conflicts when common base is not shown (issue4447)
Previously, two changes that were nearly, but not quite, identical would result
in large merge conflict regions that looked very similar, and were thus very
confusing to users, and lead people used to other source control systems to
claim that "mercurial's merge algorithms suck". In the relatively common case
of a new file being introduced in two branches with very slight modifications,
the old behavior would show the entire file as a conflict, and it would be very
difficult for a user to determine what was going on.
In the past, mercurial attempted to solve this with a "very smart" algorithm
that would find all common lines, but this has significant problems as
described in 2ea6d906cf9b.
Instead, we use a "very dumb" algorithm introduced in the previous patch that
simply matches lines at the periphery of conflict regions. This minimizes most
conflict regions well, though there may still be some degenerate edge cases,
like small modification to the beginning and end of a large file.
author | Ryan McElroy <rmcelroy@fb.com> |
---|---|
date | Wed, 10 Feb 2016 09:06:08 -0800 |
parents | 261324dd5f5b |
children | 5f7d13d3bd4d |
comparison
equal
deleted
inserted
replaced
28071:261324dd5f5b | 28072:c3e9269d9602 |
---|---|
90 name_base=None, | 90 name_base=None, |
91 start_marker='<<<<<<<', | 91 start_marker='<<<<<<<', |
92 mid_marker='=======', | 92 mid_marker='=======', |
93 end_marker='>>>>>>>', | 93 end_marker='>>>>>>>', |
94 base_marker=None, | 94 base_marker=None, |
95 localorother=None): | 95 localorother=None, |
96 minimize=False): | |
96 """Return merge in cvs-like form. | 97 """Return merge in cvs-like form. |
97 """ | 98 """ |
98 self.conflicts = False | 99 self.conflicts = False |
99 newline = '\n' | 100 newline = '\n' |
100 if len(self.a) > 0: | 101 if len(self.a) > 0: |
107 if name_b and end_marker: | 108 if name_b and end_marker: |
108 end_marker = end_marker + ' ' + name_b | 109 end_marker = end_marker + ' ' + name_b |
109 if name_base and base_marker: | 110 if name_base and base_marker: |
110 base_marker = base_marker + ' ' + name_base | 111 base_marker = base_marker + ' ' + name_base |
111 merge_regions = self.merge_regions() | 112 merge_regions = self.merge_regions() |
113 if minimize: | |
114 merge_regions = self.minimize(merge_regions) | |
112 for t in merge_regions: | 115 for t in merge_regions: |
113 what = t[0] | 116 what = t[0] |
114 if what == 'unchanged': | 117 if what == 'unchanged': |
115 for i in range(t[1], t[2]): | 118 for i in range(t[1], t[2]): |
116 yield self.base[i] | 119 yield self.base[i] |
439 out = opener(os.path.basename(local), "w", atomictemp=True) | 442 out = opener(os.path.basename(local), "w", atomictemp=True) |
440 else: | 443 else: |
441 out = sys.stdout | 444 out = sys.stdout |
442 | 445 |
443 m3 = Merge3Text(basetext, localtext, othertext) | 446 m3 = Merge3Text(basetext, localtext, othertext) |
444 extrakwargs = {"localorother": opts.get("localorother", None)} | 447 extrakwargs = { |
448 "localorother": opts.get("localorother", None), | |
449 'minimize': True, | |
450 } | |
445 if mode == 'union': | 451 if mode == 'union': |
446 extrakwargs['start_marker'] = None | 452 extrakwargs['start_marker'] = None |
447 extrakwargs['mid_marker'] = None | 453 extrakwargs['mid_marker'] = None |
448 extrakwargs['end_marker'] = None | 454 extrakwargs['end_marker'] = None |
449 elif name_base is not None: | 455 elif name_base is not None: |
450 extrakwargs['base_marker'] = '|||||||' | 456 extrakwargs['base_marker'] = '|||||||' |
451 extrakwargs['name_base'] = name_base | 457 extrakwargs['name_base'] = name_base |
458 extrakwargs['minimize'] = False | |
452 for line in m3.merge_lines(name_a=name_a, name_b=name_b, **extrakwargs): | 459 for line in m3.merge_lines(name_a=name_a, name_b=name_b, **extrakwargs): |
453 out.write(line) | 460 out.write(line) |
454 | 461 |
455 if not opts.get('print'): | 462 if not opts.get('print'): |
456 out.close() | 463 out.close() |