##// END OF EJS Templates
merge: add some useful documentation
Ryan McElroy -
r28070:a504794c default
parent child Browse files
Show More
@@ -1,417 +1,420 b''
1 # Copyright (C) 2004, 2005 Canonical Ltd
1 # Copyright (C) 2004, 2005 Canonical Ltd
2 #
2 #
3 # This program is free software; you can redistribute it and/or modify
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
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
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
6 # (at your option) any later version.
7 #
7 #
8 # This program is distributed in the hope that it will be useful,
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
11 # GNU General Public License for more details.
12 #
12 #
13 # You should have received a copy of the GNU General Public License
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, see <http://www.gnu.org/licenses/>.
14 # along with this program; if not, see <http://www.gnu.org/licenses/>.
15
15
16 # mbp: "you know that thing where cvs gives you conflict markers?"
16 # mbp: "you know that thing where cvs gives you conflict markers?"
17 # s: "i hate that."
17 # s: "i hate that."
18
18
19 from __future__ import absolute_import
19 from __future__ import absolute_import
20
20
21 import os
21 import os
22 import sys
22 import sys
23
23
24 from .i18n import _
24 from .i18n import _
25 from . import (
25 from . import (
26 error,
26 error,
27 mdiff,
27 mdiff,
28 scmutil,
28 scmutil,
29 util,
29 util,
30 )
30 )
31
31
32 class CantReprocessAndShowBase(Exception):
32 class CantReprocessAndShowBase(Exception):
33 pass
33 pass
34
34
35 def intersect(ra, rb):
35 def intersect(ra, rb):
36 """Given two ranges return the range where they intersect or None.
36 """Given two ranges return the range where they intersect or None.
37
37
38 >>> intersect((0, 10), (0, 6))
38 >>> intersect((0, 10), (0, 6))
39 (0, 6)
39 (0, 6)
40 >>> intersect((0, 10), (5, 15))
40 >>> intersect((0, 10), (5, 15))
41 (5, 10)
41 (5, 10)
42 >>> intersect((0, 10), (10, 15))
42 >>> intersect((0, 10), (10, 15))
43 >>> intersect((0, 9), (10, 15))
43 >>> intersect((0, 9), (10, 15))
44 >>> intersect((0, 9), (7, 15))
44 >>> intersect((0, 9), (7, 15))
45 (7, 9)
45 (7, 9)
46 """
46 """
47 assert ra[0] <= ra[1]
47 assert ra[0] <= ra[1]
48 assert rb[0] <= rb[1]
48 assert rb[0] <= rb[1]
49
49
50 sa = max(ra[0], rb[0])
50 sa = max(ra[0], rb[0])
51 sb = min(ra[1], rb[1])
51 sb = min(ra[1], rb[1])
52 if sa < sb:
52 if sa < sb:
53 return sa, sb
53 return sa, sb
54 else:
54 else:
55 return None
55 return None
56
56
57 def compare_range(a, astart, aend, b, bstart, bend):
57 def compare_range(a, astart, aend, b, bstart, bend):
58 """Compare a[astart:aend] == b[bstart:bend], without slicing.
58 """Compare a[astart:aend] == b[bstart:bend], without slicing.
59 """
59 """
60 if (aend - astart) != (bend - bstart):
60 if (aend - astart) != (bend - bstart):
61 return False
61 return False
62 for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)):
62 for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)):
63 if a[ia] != b[ib]:
63 if a[ia] != b[ib]:
64 return False
64 return False
65 else:
65 else:
66 return True
66 return True
67
67
68 class Merge3Text(object):
68 class Merge3Text(object):
69 """3-way merge of texts.
69 """3-way merge of texts.
70
70
71 Given strings BASE, OTHER, THIS, tries to produce a combined text
71 Given strings BASE, OTHER, THIS, tries to produce a combined text
72 incorporating the changes from both BASE->OTHER and BASE->THIS."""
72 incorporating the changes from both BASE->OTHER and BASE->THIS."""
73 def __init__(self, basetext, atext, btext, base=None, a=None, b=None):
73 def __init__(self, basetext, atext, btext, base=None, a=None, b=None):
74 self.basetext = basetext
74 self.basetext = basetext
75 self.atext = atext
75 self.atext = atext
76 self.btext = btext
76 self.btext = btext
77 if base is None:
77 if base is None:
78 base = mdiff.splitnewlines(basetext)
78 base = mdiff.splitnewlines(basetext)
79 if a is None:
79 if a is None:
80 a = mdiff.splitnewlines(atext)
80 a = mdiff.splitnewlines(atext)
81 if b is None:
81 if b is None:
82 b = mdiff.splitnewlines(btext)
82 b = mdiff.splitnewlines(btext)
83 self.base = base
83 self.base = base
84 self.a = a
84 self.a = a
85 self.b = b
85 self.b = b
86
86
87 def merge_lines(self,
87 def merge_lines(self,
88 name_a=None,
88 name_a=None,
89 name_b=None,
89 name_b=None,
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 """Return merge in cvs-like form.
96 """Return merge in cvs-like form.
97 """
97 """
98 self.conflicts = False
98 self.conflicts = False
99 newline = '\n'
99 newline = '\n'
100 if len(self.a) > 0:
100 if len(self.a) > 0:
101 if self.a[0].endswith('\r\n'):
101 if self.a[0].endswith('\r\n'):
102 newline = '\r\n'
102 newline = '\r\n'
103 elif self.a[0].endswith('\r'):
103 elif self.a[0].endswith('\r'):
104 newline = '\r'
104 newline = '\r'
105 if name_a and start_marker:
105 if name_a and start_marker:
106 start_marker = start_marker + ' ' + name_a
106 start_marker = start_marker + ' ' + name_a
107 if name_b and end_marker:
107 if name_b and end_marker:
108 end_marker = end_marker + ' ' + name_b
108 end_marker = end_marker + ' ' + name_b
109 if name_base and base_marker:
109 if name_base and base_marker:
110 base_marker = base_marker + ' ' + name_base
110 base_marker = base_marker + ' ' + name_base
111 merge_regions = self.merge_regions()
111 merge_regions = self.merge_regions()
112 for t in merge_regions:
112 for t in merge_regions:
113 what = t[0]
113 what = t[0]
114 if what == 'unchanged':
114 if what == 'unchanged':
115 for i in range(t[1], t[2]):
115 for i in range(t[1], t[2]):
116 yield self.base[i]
116 yield self.base[i]
117 elif what == 'a' or what == 'same':
117 elif what == 'a' or what == 'same':
118 for i in range(t[1], t[2]):
118 for i in range(t[1], t[2]):
119 yield self.a[i]
119 yield self.a[i]
120 elif what == 'b':
120 elif what == 'b':
121 for i in range(t[1], t[2]):
121 for i in range(t[1], t[2]):
122 yield self.b[i]
122 yield self.b[i]
123 elif what == 'conflict':
123 elif what == 'conflict':
124 if localorother == 'local':
124 if localorother == 'local':
125 for i in range(t[3], t[4]):
125 for i in range(t[3], t[4]):
126 yield self.a[i]
126 yield self.a[i]
127 elif localorother == 'other':
127 elif localorother == 'other':
128 for i in range(t[5], t[6]):
128 for i in range(t[5], t[6]):
129 yield self.b[i]
129 yield self.b[i]
130 else:
130 else:
131 self.conflicts = True
131 self.conflicts = True
132 if start_marker is not None:
132 if start_marker is not None:
133 yield start_marker + newline
133 yield start_marker + newline
134 for i in range(t[3], t[4]):
134 for i in range(t[3], t[4]):
135 yield self.a[i]
135 yield self.a[i]
136 if base_marker is not None:
136 if base_marker is not None:
137 yield base_marker + newline
137 yield base_marker + newline
138 for i in range(t[1], t[2]):
138 for i in range(t[1], t[2]):
139 yield self.base[i]
139 yield self.base[i]
140 if mid_marker is not None:
140 if mid_marker is not None:
141 yield mid_marker + newline
141 yield mid_marker + newline
142 for i in range(t[5], t[6]):
142 for i in range(t[5], t[6]):
143 yield self.b[i]
143 yield self.b[i]
144 if end_marker is not None:
144 if end_marker is not None:
145 yield end_marker + newline
145 yield end_marker + newline
146 else:
146 else:
147 raise ValueError(what)
147 raise ValueError(what)
148
148
149 def merge_groups(self):
149 def merge_groups(self):
150 """Yield sequence of line groups. Each one is a tuple:
150 """Yield sequence of line groups. Each one is a tuple:
151
151
152 'unchanged', lines
152 'unchanged', lines
153 Lines unchanged from base
153 Lines unchanged from base
154
154
155 'a', lines
155 'a', lines
156 Lines taken from a
156 Lines taken from a
157
157
158 'same', lines
158 'same', lines
159 Lines taken from a (and equal to b)
159 Lines taken from a (and equal to b)
160
160
161 'b', lines
161 'b', lines
162 Lines taken from b
162 Lines taken from b
163
163
164 'conflict', base_lines, a_lines, b_lines
164 'conflict', base_lines, a_lines, b_lines
165 Lines from base were changed to either a or b and conflict.
165 Lines from base were changed to either a or b and conflict.
166 """
166 """
167 for t in self.merge_regions():
167 for t in self.merge_regions():
168 what = t[0]
168 what = t[0]
169 if what == 'unchanged':
169 if what == 'unchanged':
170 yield what, self.base[t[1]:t[2]]
170 yield what, self.base[t[1]:t[2]]
171 elif what == 'a' or what == 'same':
171 elif what == 'a' or what == 'same':
172 yield what, self.a[t[1]:t[2]]
172 yield what, self.a[t[1]:t[2]]
173 elif what == 'b':
173 elif what == 'b':
174 yield what, self.b[t[1]:t[2]]
174 yield what, self.b[t[1]:t[2]]
175 elif what == 'conflict':
175 elif what == 'conflict':
176 yield (what,
176 yield (what,
177 self.base[t[1]:t[2]],
177 self.base[t[1]:t[2]],
178 self.a[t[3]:t[4]],
178 self.a[t[3]:t[4]],
179 self.b[t[5]:t[6]])
179 self.b[t[5]:t[6]])
180 else:
180 else:
181 raise ValueError(what)
181 raise ValueError(what)
182
182
183 def merge_regions(self):
183 def merge_regions(self):
184 """Return sequences of matching and conflicting regions.
184 """Return sequences of matching and conflicting regions.
185
185
186 This returns tuples, where the first value says what kind we
186 This returns tuples, where the first value says what kind we
187 have:
187 have:
188
188
189 'unchanged', start, end
189 'unchanged', start, end
190 Take a region of base[start:end]
190 Take a region of base[start:end]
191
191
192 'same', astart, aend
192 'same', astart, aend
193 b and a are different from base but give the same result
193 b and a are different from base but give the same result
194
194
195 'a', start, end
195 'a', start, end
196 Non-clashing insertion from a[start:end]
196 Non-clashing insertion from a[start:end]
197
197
198 'conflict', zstart, zend, astart, aend, bstart, bend
199 Conflict between a and b, with z as common ancestor
200
198 Method is as follows:
201 Method is as follows:
199
202
200 The two sequences align only on regions which match the base
203 The two sequences align only on regions which match the base
201 and both descendants. These are found by doing a two-way diff
204 and both descendants. These are found by doing a two-way diff
202 of each one against the base, and then finding the
205 of each one against the base, and then finding the
203 intersections between those regions. These "sync regions"
206 intersections between those regions. These "sync regions"
204 are by definition unchanged in both and easily dealt with.
207 are by definition unchanged in both and easily dealt with.
205
208
206 The regions in between can be in any of three cases:
209 The regions in between can be in any of three cases:
207 conflicted, or changed on only one side.
210 conflicted, or changed on only one side.
208 """
211 """
209
212
210 # section a[0:ia] has been disposed of, etc
213 # section a[0:ia] has been disposed of, etc
211 iz = ia = ib = 0
214 iz = ia = ib = 0
212
215
213 for region in self.find_sync_regions():
216 for region in self.find_sync_regions():
214 zmatch, zend, amatch, aend, bmatch, bend = region
217 zmatch, zend, amatch, aend, bmatch, bend = region
215 #print 'match base [%d:%d]' % (zmatch, zend)
218 #print 'match base [%d:%d]' % (zmatch, zend)
216
219
217 matchlen = zend - zmatch
220 matchlen = zend - zmatch
218 assert matchlen >= 0
221 assert matchlen >= 0
219 assert matchlen == (aend - amatch)
222 assert matchlen == (aend - amatch)
220 assert matchlen == (bend - bmatch)
223 assert matchlen == (bend - bmatch)
221
224
222 len_a = amatch - ia
225 len_a = amatch - ia
223 len_b = bmatch - ib
226 len_b = bmatch - ib
224 len_base = zmatch - iz
227 len_base = zmatch - iz
225 assert len_a >= 0
228 assert len_a >= 0
226 assert len_b >= 0
229 assert len_b >= 0
227 assert len_base >= 0
230 assert len_base >= 0
228
231
229 #print 'unmatched a=%d, b=%d' % (len_a, len_b)
232 #print 'unmatched a=%d, b=%d' % (len_a, len_b)
230
233
231 if len_a or len_b:
234 if len_a or len_b:
232 # try to avoid actually slicing the lists
235 # try to avoid actually slicing the lists
233 equal_a = compare_range(self.a, ia, amatch,
236 equal_a = compare_range(self.a, ia, amatch,
234 self.base, iz, zmatch)
237 self.base, iz, zmatch)
235 equal_b = compare_range(self.b, ib, bmatch,
238 equal_b = compare_range(self.b, ib, bmatch,
236 self.base, iz, zmatch)
239 self.base, iz, zmatch)
237 same = compare_range(self.a, ia, amatch,
240 same = compare_range(self.a, ia, amatch,
238 self.b, ib, bmatch)
241 self.b, ib, bmatch)
239
242
240 if same:
243 if same:
241 yield 'same', ia, amatch
244 yield 'same', ia, amatch
242 elif equal_a and not equal_b:
245 elif equal_a and not equal_b:
243 yield 'b', ib, bmatch
246 yield 'b', ib, bmatch
244 elif equal_b and not equal_a:
247 elif equal_b and not equal_a:
245 yield 'a', ia, amatch
248 yield 'a', ia, amatch
246 elif not equal_a and not equal_b:
249 elif not equal_a and not equal_b:
247 yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
250 yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
248 else:
251 else:
249 raise AssertionError("can't handle a=b=base but unmatched")
252 raise AssertionError("can't handle a=b=base but unmatched")
250
253
251 ia = amatch
254 ia = amatch
252 ib = bmatch
255 ib = bmatch
253 iz = zmatch
256 iz = zmatch
254
257
255 # if the same part of the base was deleted on both sides
258 # if the same part of the base was deleted on both sides
256 # that's OK, we can just skip it.
259 # that's OK, we can just skip it.
257
260
258
261
259 if matchlen > 0:
262 if matchlen > 0:
260 assert ia == amatch
263 assert ia == amatch
261 assert ib == bmatch
264 assert ib == bmatch
262 assert iz == zmatch
265 assert iz == zmatch
263
266
264 yield 'unchanged', zmatch, zend
267 yield 'unchanged', zmatch, zend
265 iz = zend
268 iz = zend
266 ia = aend
269 ia = aend
267 ib = bend
270 ib = bend
268
271
269 def find_sync_regions(self):
272 def find_sync_regions(self):
270 """Return a list of sync regions, where both descendants match the base.
273 """Return a list of sync regions, where both descendants match the base.
271
274
272 Generates a list of (base1, base2, a1, a2, b1, b2). There is
275 Generates a list of (base1, base2, a1, a2, b1, b2). There is
273 always a zero-length sync region at the end of all the files.
276 always a zero-length sync region at the end of all the files.
274 """
277 """
275
278
276 ia = ib = 0
279 ia = ib = 0
277 amatches = mdiff.get_matching_blocks(self.basetext, self.atext)
280 amatches = mdiff.get_matching_blocks(self.basetext, self.atext)
278 bmatches = mdiff.get_matching_blocks(self.basetext, self.btext)
281 bmatches = mdiff.get_matching_blocks(self.basetext, self.btext)
279 len_a = len(amatches)
282 len_a = len(amatches)
280 len_b = len(bmatches)
283 len_b = len(bmatches)
281
284
282 sl = []
285 sl = []
283
286
284 while ia < len_a and ib < len_b:
287 while ia < len_a and ib < len_b:
285 abase, amatch, alen = amatches[ia]
288 abase, amatch, alen = amatches[ia]
286 bbase, bmatch, blen = bmatches[ib]
289 bbase, bmatch, blen = bmatches[ib]
287
290
288 # there is an unconflicted block at i; how long does it
291 # there is an unconflicted block at i; how long does it
289 # extend? until whichever one ends earlier.
292 # extend? until whichever one ends earlier.
290 i = intersect((abase, abase + alen), (bbase, bbase + blen))
293 i = intersect((abase, abase + alen), (bbase, bbase + blen))
291 if i:
294 if i:
292 intbase = i[0]
295 intbase = i[0]
293 intend = i[1]
296 intend = i[1]
294 intlen = intend - intbase
297 intlen = intend - intbase
295
298
296 # found a match of base[i[0], i[1]]; this may be less than
299 # found a match of base[i[0], i[1]]; this may be less than
297 # the region that matches in either one
300 # the region that matches in either one
298 assert intlen <= alen
301 assert intlen <= alen
299 assert intlen <= blen
302 assert intlen <= blen
300 assert abase <= intbase
303 assert abase <= intbase
301 assert bbase <= intbase
304 assert bbase <= intbase
302
305
303 asub = amatch + (intbase - abase)
306 asub = amatch + (intbase - abase)
304 bsub = bmatch + (intbase - bbase)
307 bsub = bmatch + (intbase - bbase)
305 aend = asub + intlen
308 aend = asub + intlen
306 bend = bsub + intlen
309 bend = bsub + intlen
307
310
308 assert self.base[intbase:intend] == self.a[asub:aend], \
311 assert self.base[intbase:intend] == self.a[asub:aend], \
309 (self.base[intbase:intend], self.a[asub:aend])
312 (self.base[intbase:intend], self.a[asub:aend])
310
313
311 assert self.base[intbase:intend] == self.b[bsub:bend]
314 assert self.base[intbase:intend] == self.b[bsub:bend]
312
315
313 sl.append((intbase, intend,
316 sl.append((intbase, intend,
314 asub, aend,
317 asub, aend,
315 bsub, bend))
318 bsub, bend))
316
319
317 # advance whichever one ends first in the base text
320 # advance whichever one ends first in the base text
318 if (abase + alen) < (bbase + blen):
321 if (abase + alen) < (bbase + blen):
319 ia += 1
322 ia += 1
320 else:
323 else:
321 ib += 1
324 ib += 1
322
325
323 intbase = len(self.base)
326 intbase = len(self.base)
324 abase = len(self.a)
327 abase = len(self.a)
325 bbase = len(self.b)
328 bbase = len(self.b)
326 sl.append((intbase, intbase, abase, abase, bbase, bbase))
329 sl.append((intbase, intbase, abase, abase, bbase, bbase))
327
330
328 return sl
331 return sl
329
332
330 def find_unconflicted(self):
333 def find_unconflicted(self):
331 """Return a list of ranges in base that are not conflicted."""
334 """Return a list of ranges in base that are not conflicted."""
332 am = mdiff.get_matching_blocks(self.basetext, self.atext)
335 am = mdiff.get_matching_blocks(self.basetext, self.atext)
333 bm = mdiff.get_matching_blocks(self.basetext, self.btext)
336 bm = mdiff.get_matching_blocks(self.basetext, self.btext)
334
337
335 unc = []
338 unc = []
336
339
337 while am and bm:
340 while am and bm:
338 # there is an unconflicted block at i; how long does it
341 # there is an unconflicted block at i; how long does it
339 # extend? until whichever one ends earlier.
342 # extend? until whichever one ends earlier.
340 a1 = am[0][0]
343 a1 = am[0][0]
341 a2 = a1 + am[0][2]
344 a2 = a1 + am[0][2]
342 b1 = bm[0][0]
345 b1 = bm[0][0]
343 b2 = b1 + bm[0][2]
346 b2 = b1 + bm[0][2]
344 i = intersect((a1, a2), (b1, b2))
347 i = intersect((a1, a2), (b1, b2))
345 if i:
348 if i:
346 unc.append(i)
349 unc.append(i)
347
350
348 if a2 < b2:
351 if a2 < b2:
349 del am[0]
352 del am[0]
350 else:
353 else:
351 del bm[0]
354 del bm[0]
352
355
353 return unc
356 return unc
354
357
355 def simplemerge(ui, local, base, other, **opts):
358 def simplemerge(ui, local, base, other, **opts):
356 def readfile(filename):
359 def readfile(filename):
357 f = open(filename, "rb")
360 f = open(filename, "rb")
358 text = f.read()
361 text = f.read()
359 f.close()
362 f.close()
360 if util.binary(text):
363 if util.binary(text):
361 msg = _("%s looks like a binary file.") % filename
364 msg = _("%s looks like a binary file.") % filename
362 if not opts.get('quiet'):
365 if not opts.get('quiet'):
363 ui.warn(_('warning: %s\n') % msg)
366 ui.warn(_('warning: %s\n') % msg)
364 if not opts.get('text'):
367 if not opts.get('text'):
365 raise error.Abort(msg)
368 raise error.Abort(msg)
366 return text
369 return text
367
370
368 mode = opts.get('mode','merge')
371 mode = opts.get('mode','merge')
369 if mode == 'union':
372 if mode == 'union':
370 name_a = None
373 name_a = None
371 name_b = None
374 name_b = None
372 name_base = None
375 name_base = None
373 else:
376 else:
374 name_a = local
377 name_a = local
375 name_b = other
378 name_b = other
376 name_base = None
379 name_base = None
377 labels = opts.get('label', [])
380 labels = opts.get('label', [])
378 if len(labels) > 0:
381 if len(labels) > 0:
379 name_a = labels[0]
382 name_a = labels[0]
380 if len(labels) > 1:
383 if len(labels) > 1:
381 name_b = labels[1]
384 name_b = labels[1]
382 if len(labels) > 2:
385 if len(labels) > 2:
383 name_base = labels[2]
386 name_base = labels[2]
384 if len(labels) > 3:
387 if len(labels) > 3:
385 raise error.Abort(_("can only specify three labels."))
388 raise error.Abort(_("can only specify three labels."))
386
389
387 try:
390 try:
388 localtext = readfile(local)
391 localtext = readfile(local)
389 basetext = readfile(base)
392 basetext = readfile(base)
390 othertext = readfile(other)
393 othertext = readfile(other)
391 except error.Abort:
394 except error.Abort:
392 return 1
395 return 1
393
396
394 local = os.path.realpath(local)
397 local = os.path.realpath(local)
395 if not opts.get('print'):
398 if not opts.get('print'):
396 opener = scmutil.opener(os.path.dirname(local))
399 opener = scmutil.opener(os.path.dirname(local))
397 out = opener(os.path.basename(local), "w", atomictemp=True)
400 out = opener(os.path.basename(local), "w", atomictemp=True)
398 else:
401 else:
399 out = sys.stdout
402 out = sys.stdout
400
403
401 m3 = Merge3Text(basetext, localtext, othertext)
404 m3 = Merge3Text(basetext, localtext, othertext)
402 extrakwargs = {"localorother": opts.get("localorother", None)}
405 extrakwargs = {"localorother": opts.get("localorother", None)}
403 if mode == 'union':
406 if mode == 'union':
404 extrakwargs['start_marker'] = None
407 extrakwargs['start_marker'] = None
405 extrakwargs['mid_marker'] = None
408 extrakwargs['mid_marker'] = None
406 extrakwargs['end_marker'] = None
409 extrakwargs['end_marker'] = None
407 elif name_base is not None:
410 elif name_base is not None:
408 extrakwargs['base_marker'] = '|||||||'
411 extrakwargs['base_marker'] = '|||||||'
409 extrakwargs['name_base'] = name_base
412 extrakwargs['name_base'] = name_base
410 for line in m3.merge_lines(name_a=name_a, name_b=name_b, **extrakwargs):
413 for line in m3.merge_lines(name_a=name_a, name_b=name_b, **extrakwargs):
411 out.write(line)
414 out.write(line)
412
415
413 if not opts.get('print'):
416 if not opts.get('print'):
414 out.close()
417 out.close()
415
418
416 if m3.conflicts and not mode == 'union':
419 if m3.conflicts and not mode == 'union':
417 return 1
420 return 1
General Comments 0
You need to be logged in to leave comments. Login now