~bzr-pqm/bzr/bzr.dev

2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2004, 2005 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
821 by Martin Pool
- start code for built-in diff3-style resolve
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
821 by Martin Pool
- start code for built-in diff3-style resolve
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
821 by Martin Pool
- start code for built-in diff3-style resolve
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
823 by Martin Pool
quote
18
# mbp: "you know that thing where cvs gives you conflict markers?"
19
# s: "i hate that."
20
21
1185.24.1 by Aaron Bentley
Got reprocessing working
22
from bzrlib.errors import CantReprocessAndShowBase
1711.2.23 by John Arbash Meinel
Late bind to PatienceSequenceMatcher in merge3.py
23
import bzrlib.patiencediff
1558.15.11 by Aaron Bentley
Apply merge review suggestions
24
from bzrlib.textfile import check_text_lines
821 by Martin Pool
- start code for built-in diff3-style resolve
25
1711.2.11 by John Arbash Meinel
Rename patiencediff.SequenceMatcher => PatienceSequenceMatcher and knit.SequenceMatcher => KnitSequenceMatcher
26
821 by Martin Pool
- start code for built-in diff3-style resolve
27
def intersect(ra, rb):
28
    """Given two ranges return the range where they intersect or None.
29
30
    >>> intersect((0, 10), (0, 6))
31
    (0, 6)
32
    >>> intersect((0, 10), (5, 15))
33
    (5, 10)
34
    >>> intersect((0, 10), (10, 15))
35
    >>> intersect((0, 9), (10, 15))
36
    >>> intersect((0, 9), (7, 15))
37
    (7, 9)
38
    """
39
    assert ra[0] <= ra[1]
40
    assert rb[0] <= rb[1]
41
    
42
    sa = max(ra[0], rb[0])
43
    sb = min(ra[1], rb[1])
44
    if sa < sb:
45
        return sa, sb
46
    else:
47
        return None
48
49
839 by Martin Pool
- avoid copying string lists when handling unmatched regions
50
def compare_range(a, astart, aend, b, bstart, bend):
51
    """Compare a[astart:aend] == b[bstart:bend], without slicing.
52
    """
53
    if (aend-astart) != (bend-bstart):
54
        return False
55
    for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)):
56
        if a[ia] != b[ib]:
57
            return False
58
    else:
59
        return True
60
        
61
62
822 by Martin Pool
- Renamed merge3 test suite for easier access.
63
821 by Martin Pool
- start code for built-in diff3-style resolve
64
class Merge3(object):
65
    """3-way merge of texts.
66
67
    Given BASE, OTHER, THIS, tries to produce a combined text
68
    incorporating the changes from both BASE->OTHER and BASE->THIS.
69
    All three will typically be sequences of lines."""
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
70
    def __init__(self, base, a, b, is_cherrypick=False):
1558.15.4 by Aaron Bentley
Fixed binary handling in Merge3
71
        check_text_lines(base)
72
        check_text_lines(a)
73
        check_text_lines(b)
821 by Martin Pool
- start code for built-in diff3-style resolve
74
        self.base = base
75
        self.a = a
76
        self.b = b
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
77
        self.is_cherrypick = is_cherrypick
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
78
828 by Martin Pool
- code to represent merges in regular text conflict form
79
    def merge_lines(self,
829 by Martin Pool
- More merge3 cvs-form stuff
80
                    name_a=None,
81
                    name_b=None,
1185.18.1 by Aaron Bentley
Added --show-base to merge
82
                    name_base=None,
1148 by Martin Pool
- change conflict markers to suit smerge, etc
83
                    start_marker='<<<<<<<',
84
                    mid_marker='=======',
85
                    end_marker='>>>>>>>',
1185.24.1 by Aaron Bentley
Got reprocessing working
86
                    base_marker=None,
87
                    reprocess=False):
828 by Martin Pool
- code to represent merges in regular text conflict form
88
        """Return merge in cvs-like form.
89
        """
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
90
        newline = '\n'
91
        if len(self.a) > 0:
92
            if self.a[0].endswith('\r\n'):
93
                newline = '\r\n'
94
            elif self.a[0].endswith('\r'):
95
                newline = '\r'
1185.24.1 by Aaron Bentley
Got reprocessing working
96
        if base_marker and reprocess:
97
            raise CantReprocessAndShowBase()
829 by Martin Pool
- More merge3 cvs-form stuff
98
        if name_a:
99
            start_marker = start_marker + ' ' + name_a
100
        if name_b:
101
            end_marker = end_marker + ' ' + name_b
1185.18.1 by Aaron Bentley
Added --show-base to merge
102
        if name_base and base_marker:
103
            base_marker = base_marker + ' ' + name_base
1185.24.1 by Aaron Bentley
Got reprocessing working
104
        merge_regions = self.merge_regions()
105
        if reprocess is True:
106
            merge_regions = self.reprocess_merge_regions(merge_regions)
107
        for t in merge_regions:
828 by Martin Pool
- code to represent merges in regular text conflict form
108
            what = t[0]
109
            if what == 'unchanged':
110
                for i in range(t[1], t[2]):
111
                    yield self.base[i]
830 by Martin Pool
- handle chunks which differ from the base but agree
112
            elif what == 'a' or what == 'same':
828 by Martin Pool
- code to represent merges in regular text conflict form
113
                for i in range(t[1], t[2]):
114
                    yield self.a[i]
115
            elif what == 'b':
116
                for i in range(t[1], t[2]):
117
                    yield self.b[i]
118
            elif what == 'conflict':
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
119
                yield start_marker + newline
828 by Martin Pool
- code to represent merges in regular text conflict form
120
                for i in range(t[3], t[4]):
121
                    yield self.a[i]
1185.18.1 by Aaron Bentley
Added --show-base to merge
122
                if base_marker is not None:
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
123
                    yield base_marker + newline
1185.18.1 by Aaron Bentley
Added --show-base to merge
124
                    for i in range(t[1], t[2]):
125
                        yield self.base[i]
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
126
                yield mid_marker + newline
828 by Martin Pool
- code to represent merges in regular text conflict form
127
                for i in range(t[5], t[6]):
128
                    yield self.b[i]
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
129
                yield end_marker + newline
828 by Martin Pool
- code to represent merges in regular text conflict form
130
            else:
131
                raise ValueError(what)
132
832 by Martin Pool
- New Merge3.merge_annotated method for debugging.
133
    def merge_annotated(self):
134
        """Return merge with conflicts, showing origin of lines.
135
136
        Most useful for debugging merge.        
137
        """
138
        for t in self.merge_regions():
139
            what = t[0]
140
            if what == 'unchanged':
141
                for i in range(t[1], t[2]):
142
                    yield 'u | ' + self.base[i]
143
            elif what == 'a' or what == 'same':
144
                for i in range(t[1], t[2]):
145
                    yield what[0] + ' | ' + self.a[i]
146
            elif what == 'b':
147
                for i in range(t[1], t[2]):
148
                    yield 'b | ' + self.b[i]
149
            elif what == 'conflict':
150
                yield '<<<<\n'
151
                for i in range(t[3], t[4]):
152
                    yield 'A | ' + self.a[i]
153
                yield '----\n'
154
                for i in range(t[5], t[6]):
155
                    yield 'B | ' + self.b[i]
156
                yield '>>>>\n'
157
            else:
158
                raise ValueError(what)
159
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
160
    def merge_groups(self):
161
        """Yield sequence of line groups.  Each one is a tuple:
162
163
        'unchanged', lines
164
             Lines unchanged from base
165
166
        'a', lines
167
             Lines taken from a
168
830 by Martin Pool
- handle chunks which differ from the base but agree
169
        'same', lines
170
             Lines taken from a (and equal to b)
171
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
172
        'b', lines
173
             Lines taken from b
174
175
        'conflict', base_lines, a_lines, b_lines
176
             Lines from base were changed to either a or b and conflict.
177
        """
178
        for t in self.merge_regions():
179
            what = t[0]
180
            if what == 'unchanged':
181
                yield what, self.base[t[1]:t[2]]
830 by Martin Pool
- handle chunks which differ from the base but agree
182
            elif what == 'a' or what == 'same':
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
183
                yield what, self.a[t[1]:t[2]]
184
            elif what == 'b':
185
                yield what, self.b[t[1]:t[2]]
186
            elif what == 'conflict':
187
                yield (what,
188
                       self.base[t[1]:t[2]],
189
                       self.a[t[3]:t[4]],
190
                       self.b[t[5]:t[6]])
191
            else:
192
                raise ValueError(what)
193
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
194
    def merge_regions(self):
822 by Martin Pool
- Renamed merge3 test suite for easier access.
195
        """Return sequences of matching and conflicting regions.
196
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
197
        This returns tuples, where the first value says what kind we
198
        have:
199
200
        'unchanged', start, end
201
             Take a region of base[start:end]
202
830 by Martin Pool
- handle chunks which differ from the base but agree
203
        'same', astart, aend
204
             b and a are different from base but give the same result
205
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
206
        'a', start, end
207
             Non-clashing insertion from a[start:end]
208
822 by Martin Pool
- Renamed merge3 test suite for easier access.
209
        Method is as follows:
210
211
        The two sequences align only on regions which match the base
212
        and both descendents.  These are found by doing a two-way diff
213
        of each one against the base, and then finding the
214
        intersections between those regions.  These "sync regions"
215
        are by definition unchanged in both and easily dealt with.
216
217
        The regions in between can be in any of three cases:
218
        conflicted, or changed on only one side.
219
        """
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
220
221
        # section a[0:ia] has been disposed of, etc
222
        iz = ia = ib = 0
223
        
224
        for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions():
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
225
            #print 'match base [%d:%d]' % (zmatch, zend)
226
            
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
227
            matchlen = zend - zmatch
228
            assert matchlen >= 0
229
            assert matchlen == (aend - amatch)
230
            assert matchlen == (bend - bmatch)
231
            
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
232
            len_a = amatch - ia
233
            len_b = bmatch - ib
234
            len_base = zmatch - iz
235
            assert len_a >= 0
236
            assert len_b >= 0
237
            assert len_base >= 0
238
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
239
            #print 'unmatched a=%d, b=%d' % (len_a, len_b)
240
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
241
            if len_a or len_b:
839 by Martin Pool
- avoid copying string lists when handling unmatched regions
242
                # try to avoid actually slicing the lists
243
                same = compare_range(self.a, ia, amatch,
244
                                     self.b, ib, bmatch)
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
245
830 by Martin Pool
- handle chunks which differ from the base but agree
246
                if same:
247
                    yield 'same', ia, amatch
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
248
                else:
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
249
                    equal_a = compare_range(self.a, ia, amatch,
250
                                            self.base, iz, zmatch)
251
                    equal_b = compare_range(self.b, ib, bmatch,
252
                                            self.base, iz, zmatch)
253
                    if equal_a and not equal_b:
254
                        yield 'b', ib, bmatch
255
                    elif equal_b and not equal_a:
256
                        yield 'a', ia, amatch
257
                    elif not equal_a and not equal_b:
258
                        if self.is_cherrypick:
259
                            for node in self._refine_cherrypick_conflict(
260
                                                    iz, zmatch, ia, amatch,
261
                                                    ib, bmatch):
262
                                yield node
263
                        else:
264
                            yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
265
                    else:
266
                        raise AssertionError("can't handle a=b=base but unmatched")
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
267
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
268
                ia = amatch
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
269
                ib = bmatch
270
            iz = zmatch
271
272
            # if the same part of the base was deleted on both sides
273
            # that's OK, we can just skip it.
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
274
275
            if matchlen > 0:
276
                assert ia == amatch
277
                assert ib == bmatch
278
                assert iz == zmatch
279
                
280
                yield 'unchanged', zmatch, zend
281
                iz = zend
282
                ia = aend
283
                ib = bend
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
284
285
    def _refine_cherrypick_conflict(self, zstart, zend, astart, aend, bstart, bend):
286
        """When cherrypicking b => a, ignore matches with b and base."""
287
        # Do not emit regions which match, only regions which do not match
288
        matches = bzrlib.patiencediff.PatienceSequenceMatcher(None,
289
            self.base[zstart:zend], self.b[bstart:bend]).get_matching_blocks()
3249.3.2 by John Arbash Meinel
review feedback from Robert
290
        last_base_idx = 0
291
        last_b_idx = 0
292
        last_b_idx = 0
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
293
        yielded_a = False
3249.3.2 by John Arbash Meinel
review feedback from Robert
294
        for base_idx, b_idx, match_len in matches:
295
            conflict_z_len = base_idx - last_base_idx
296
            conflict_b_len = b_idx - last_b_idx
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
297
            if conflict_b_len == 0: # There are no lines in b which conflict,
298
                                    # so skip it
299
                pass
300
            else:
301
                if yielded_a:
3249.3.2 by John Arbash Meinel
review feedback from Robert
302
                    yield ('conflict',
303
                           zstart + last_base_idx, zstart + base_idx,
304
                           aend, aend, bstart + last_b_idx, bstart + b_idx)
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
305
                else:
306
                    # The first conflict gets the a-range
307
                    yielded_a = True
3249.3.2 by John Arbash Meinel
review feedback from Robert
308
                    yield ('conflict', zstart + last_base_idx, zstart +
309
                    base_idx,
310
                           astart, aend, bstart + last_b_idx, bstart + b_idx)
311
            last_base_idx = base_idx + match_len
312
            last_b_idx = b_idx + match_len
313
        if last_base_idx != zend - zstart or last_b_idx != bend - bstart:
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
314
            if yielded_a:
3249.3.2 by John Arbash Meinel
review feedback from Robert
315
                yield ('conflict', zstart + last_base_idx, zstart + base_idx,
316
                       aend, aend, bstart + last_b_idx, bstart + b_idx)
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
317
            else:
318
                # The first conflict gets the a-range
319
                yielded_a = True
3249.3.2 by John Arbash Meinel
review feedback from Robert
320
                yield ('conflict', zstart + last_base_idx, zstart + base_idx,
321
                       astart, aend, bstart + last_b_idx, bstart + b_idx)
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
322
        if not yielded_a:
323
            yield ('conflict', zstart, zend, astart, aend, bstart, bend)
1185.24.1 by Aaron Bentley
Got reprocessing working
324
325
    def reprocess_merge_regions(self, merge_regions):
1185.33.62 by Martin Pool
doc
326
        """Where there are conflict regions, remove the agreed lines.
327
328
        Lines where both A and B have made the same changes are 
329
        eliminated.
330
        """
1185.24.1 by Aaron Bentley
Got reprocessing working
331
        for region in merge_regions:
332
            if region[0] != "conflict":
333
                yield region
334
                continue
335
            type, iz, zmatch, ia, amatch, ib, bmatch = region
336
            a_region = self.a[ia:amatch]
337
            b_region = self.b[ib:bmatch]
1711.2.23 by John Arbash Meinel
Late bind to PatienceSequenceMatcher in merge3.py
338
            matches = bzrlib.patiencediff.PatienceSequenceMatcher(
339
                    None, a_region, b_region).get_matching_blocks()
1185.24.1 by Aaron Bentley
Got reprocessing working
340
            next_a = ia
341
            next_b = ib
342
            for region_ia, region_ib, region_len in matches[:-1]:
343
                region_ia += ia
344
                region_ib += ib
345
                reg = self.mismatch_region(next_a, region_ia, next_b,
346
                                           region_ib)
347
                if reg is not None:
348
                    yield reg
349
                yield 'same', region_ia, region_len+region_ia
350
                next_a = region_ia + region_len
351
                next_b = region_ib + region_len
352
            reg = self.mismatch_region(next_a, amatch, next_b, bmatch)
353
            if reg is not None:
354
                yield reg
355
356
    @staticmethod
357
    def mismatch_region(next_a, region_ia,  next_b, region_ib):
358
        if next_a < region_ia or next_b < region_ib:
359
            return 'conflict', None, None, next_a, region_ia, next_b, region_ib
360
822 by Martin Pool
- Renamed merge3 test suite for easier access.
361
    def find_sync_regions(self):
362
        """Return a list of sync regions, where both descendents match the base.
363
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
364
        Generates a list of (base1, base2, a1, a2, b1, b2).  There is
365
        always a zero-length sync region at the end of all the files.
821 by Martin Pool
- start code for built-in diff3-style resolve
366
        """
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
367
368
        ia = ib = 0
1711.2.23 by John Arbash Meinel
Late bind to PatienceSequenceMatcher in merge3.py
369
        amatches = bzrlib.patiencediff.PatienceSequenceMatcher(
370
                None, self.base, self.a).get_matching_blocks()
371
        bmatches = bzrlib.patiencediff.PatienceSequenceMatcher(
372
                None, self.base, self.b).get_matching_blocks()
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
373
        len_a = len(amatches)
374
        len_b = len(bmatches)
375
376
        sl = []
377
378
        while ia < len_a and ib < len_b:
379
            abase, amatch, alen = amatches[ia]
380
            bbase, bmatch, blen = bmatches[ib]
381
822 by Martin Pool
- Renamed merge3 test suite for easier access.
382
            # there is an unconflicted block at i; how long does it
383
            # extend?  until whichever one ends earlier.
384
            i = intersect((abase, abase+alen), (bbase, bbase+blen))
385
            if i:
386
                intbase = i[0]
387
                intend = i[1]
388
                intlen = intend - intbase
389
390
                # found a match of base[i[0], i[1]]; this may be less than
391
                # the region that matches in either one
392
                assert intlen <= alen
393
                assert intlen <= blen
394
                assert abase <= intbase
395
                assert bbase <= intbase
396
397
                asub = amatch + (intbase - abase)
398
                bsub = bmatch + (intbase - bbase)
399
                aend = asub + intlen
400
                bend = bsub + intlen
401
402
                assert self.base[intbase:intend] == self.a[asub:aend], \
403
                       (self.base[intbase:intend], self.a[asub:aend])
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
404
822 by Martin Pool
- Renamed merge3 test suite for easier access.
405
                assert self.base[intbase:intend] == self.b[bsub:bend]
406
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
407
                sl.append((intbase, intend,
408
                           asub, aend,
409
                           bsub, bend))
822 by Martin Pool
- Renamed merge3 test suite for easier access.
410
411
            # advance whichever one ends first in the base text
412
            if (abase + alen) < (bbase + blen):
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
413
                ia += 1
822 by Martin Pool
- Renamed merge3 test suite for easier access.
414
            else:
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
415
                ib += 1
416
            
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
417
        intbase = len(self.base)
418
        abase = len(self.a)
419
        bbase = len(self.b)
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
420
        sl.append((intbase, intbase, abase, abase, bbase, bbase))
421
422
        return sl
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
423
821 by Martin Pool
- start code for built-in diff3-style resolve
424
    def find_unconflicted(self):
425
        """Return a list of ranges in base that are not conflicted."""
1711.2.23 by John Arbash Meinel
Late bind to PatienceSequenceMatcher in merge3.py
426
        am = bzrlib.patiencediff.PatienceSequenceMatcher(
427
                None, self.base, self.a).get_matching_blocks()
428
        bm = bzrlib.patiencediff.PatienceSequenceMatcher(
429
                None, self.base, self.b).get_matching_blocks()
821 by Martin Pool
- start code for built-in diff3-style resolve
430
431
        unc = []
432
433
        while am and bm:
434
            # there is an unconflicted block at i; how long does it
435
            # extend?  until whichever one ends earlier.
436
            a1 = am[0][0]
437
            a2 = a1 + am[0][2]
438
            b1 = bm[0][0]
439
            b2 = b1 + bm[0][2]
440
            i = intersect((a1, a2), (b1, b2))
441
            if i:
442
                unc.append(i)
443
444
            if a2 < b2:
445
                del am[0]
446
            else:
447
                del bm[0]
448
                
449
        return unc
829 by Martin Pool
- More merge3 cvs-form stuff
450
451
452
def main(argv):
830 by Martin Pool
- handle chunks which differ from the base but agree
453
    # as for diff3 and meld the syntax is "MINE BASE OTHER"
454
    a = file(argv[1], 'rt').readlines()
455
    base = file(argv[2], 'rt').readlines()
829 by Martin Pool
- More merge3 cvs-form stuff
456
    b = file(argv[3], 'rt').readlines()
457
458
    m3 = Merge3(base, a, b)
459
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
460
    #for sr in m3.find_sync_regions():
461
    #    print sr
462
832 by Martin Pool
- New Merge3.merge_annotated method for debugging.
463
    # sys.stdout.writelines(m3.merge_lines(name_a=argv[1], name_b=argv[3]))
464
    sys.stdout.writelines(m3.merge_annotated())
829 by Martin Pool
- More merge3 cvs-form stuff
465
466
467
if __name__ == '__main__':
468
    import sys
469
    sys.exit(main(sys.argv))