comparison hgext/imerge.py @ 5225:423f4e8be115

merge with crew
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Sat, 25 Aug 2007 11:30:59 +0200
parents 3786ef8877d5
children
comparison
equal deleted inserted replaced
5224:9cd6578750b9 5225:423f4e8be115
5 imerge - interactive merge 5 imerge - interactive merge
6 ''' 6 '''
7 7
8 from mercurial.i18n import _ 8 from mercurial.i18n import _
9 from mercurial.node import * 9 from mercurial.node import *
10 from mercurial import commands, cmdutil, fancyopts, hg, merge, util 10 from mercurial import commands, cmdutil, dispatch, fancyopts, hg, merge, util
11 import os, tarfile 11 import os, tarfile
12 12
13 class InvalidStateFileException(Exception): pass 13 class InvalidStateFileException(Exception): pass
14 14
15 class ImergeStateFile(object): 15 class ImergeStateFile(object):
107 statusfile.write('\0'.join(out)) 107 statusfile.write('\0'.join(out))
108 108
109 def remaining(self): 109 def remaining(self):
110 return [f for f in self.conflicts if f not in self.resolved] 110 return [f for f in self.conflicts if f not in self.resolved]
111 111
112 def filemerge(self, fn): 112 def filemerge(self, fn, interactive=True):
113 wlock = self.repo.wlock() 113 wlock = self.repo.wlock()
114 114
115 (fd, fo) = self.conflicts[fn] 115 (fd, fo) = self.conflicts[fn]
116 p2 = self.wctx.parents()[1] 116 p1, p2 = self.wctx.parents()
117 return merge.filemerge(self.repo, fn, fd, fo, self.wctx, p2) 117
118 # this could be greatly improved
119 realmerge = os.environ.get('HGMERGE')
120 if not interactive:
121 os.environ['HGMERGE'] = 'merge'
122
123 # The filemerge ancestor algorithm does not work if self.wctx
124 # already has two parents (in normal merge it doesn't yet). But
125 # this is very dirty.
126 self.wctx._parents.pop()
127 try:
128 # TODO: we should probably revert the file if merge fails
129 return merge.filemerge(self.repo, fn, fd, fo, self.wctx, p2)
130 finally:
131 self.wctx._parents.append(p2)
132 if realmerge:
133 os.environ['HGMERGE'] = realmerge
134 elif not interactive:
135 del os.environ['HGMERGE']
118 136
119 def start(self, rev=None): 137 def start(self, rev=None):
120 _filemerge = merge.filemerge 138 _filemerge = merge.filemerge
121 def filemerge(repo, fw, fd, fo, wctx, mctx): 139 def filemerge(repo, fw, fd, fo, wctx, mctx):
122 self.conflicts[fw] = (fd, fo) 140 self.conflicts[fw] = (fd, fo)
183 rc = im.unpickle(source) 201 rc = im.unpickle(source)
184 if not rc: 202 if not rc:
185 status(im) 203 status(im)
186 return rc 204 return rc
187 205
188 def merge_(im, filename=None): 206 def merge_(im, filename=None, auto=False):
207 success = True
208 if auto and not filename:
209 for fn in im.remaining():
210 rc = im.filemerge(fn, interactive=False)
211 if rc:
212 success = False
213 else:
214 im.resolve([fn])
215 if success:
216 im.ui.write('all conflicts resolved\n')
217 else:
218 status(im)
219 return 0
220
189 if not filename: 221 if not filename:
190 filename = im.next() 222 filename = im.next()
191 if not filename: 223 if not filename:
192 im.ui.write('all conflicts resolved\n') 224 im.ui.write('all conflicts resolved\n')
193 return 0 225 return 0
194 226
195 rc = im.filemerge(filename) 227 rc = im.filemerge(filename, interactive=not auto)
196 if not rc: 228 if not rc:
197 im.resolve([filename]) 229 im.resolve([filename])
198 if not im.next(): 230 if not im.next():
199 im.ui.write('all conflicts resolved\n') 231 im.ui.write('all conflicts resolved\n')
200 return 0
201 return rc 232 return rc
202 233
203 def next(im): 234 def next(im):
204 n = im.next() 235 n = im.next()
205 if n: 236 if n:
256 raise util.Abort('unresolve requires at least one filename') 287 raise util.Abort('unresolve requires at least one filename')
257 return im.unresolve(files) 288 return im.unresolve(files)
258 289
259 subcmdtable = { 290 subcmdtable = {
260 'load': (load, []), 291 'load': (load, []),
261 'merge': (merge_, []), 292 'merge':
293 (merge_,
294 [('a', 'auto', None, _('automatically resolve if possible'))]),
262 'next': (next, []), 295 'next': (next, []),
263 'resolve': (resolve, []), 296 'resolve': (resolve, []),
264 'save': (save, []), 297 'save': (save, []),
265 'status': (status, 298 'status':
266 [('n', 'no-status', None, _('hide status prefix')), 299 (status,
267 ('', 'resolved', None, _('only show resolved conflicts')), 300 [('n', 'no-status', None, _('hide status prefix')),
268 ('', 'unresolved', None, _('only show unresolved conflicts'))]), 301 ('', 'resolved', None, _('only show resolved conflicts')),
302 ('', 'unresolved', None, _('only show unresolved conflicts'))]),
269 'unresolve': (unresolve, []) 303 'unresolve': (unresolve, [])
270 } 304 }
271 305
272 def dispatch(im, args, opts): 306 def dispatch_(im, args, opts):
273 def complete(s, choices): 307 def complete(s, choices):
274 candidates = [] 308 candidates = []
275 for choice in choices: 309 for choice in choices:
276 if choice.startswith(s): 310 if choice.startswith(s):
277 candidates.append(choice) 311 candidates.append(choice)
290 opts = {} 324 opts = {}
291 try: 325 try:
292 args = fancyopts.fancyopts(args, optlist, opts) 326 args = fancyopts.fancyopts(args, optlist, opts)
293 return func(im, *args, **opts) 327 return func(im, *args, **opts)
294 except fancyopts.getopt.GetoptError, inst: 328 except fancyopts.getopt.GetoptError, inst:
295 raise cmdutil.ParseError('imerge', '%s: %s' % (cmd, inst)) 329 raise dispatch.ParseError('imerge', '%s: %s' % (cmd, inst))
296 except TypeError: 330 except TypeError:
297 raise cmdutil.ParseError('imerge', _('%s: invalid arguments') % cmd) 331 raise dispatch.ParseError('imerge', _('%s: invalid arguments') % cmd)
298 332
299 def imerge(ui, repo, *args, **opts): 333 def imerge(ui, repo, *args, **opts):
300 '''interactive merge 334 '''interactive merge
301 335
302 imerge lets you split a merge into pieces. When you start a merge 336 imerge lets you split a merge into pieces. When you start a merge
315 349
316 The following subcommands are available: 350 The following subcommands are available:
317 351
318 status: 352 status:
319 show the current state of the merge 353 show the current state of the merge
354 options:
355 -n --no-status: do not print the status prefix
356 --resolved: only print resolved conflicts
357 --unresolved: only print unresolved conflicts
320 next: 358 next:
321 show the next unresolved file merge 359 show the next unresolved file merge
322 merge [<file>]: 360 merge [<file>]:
323 merge <file>. If the file merge is successful, the file will be 361 merge <file>. If the file merge is successful, the file will be
324 recorded as resolved. If no file is given, the next unresolved 362 recorded as resolved. If no file is given, the next unresolved
346 pass 384 pass
347 else: 385 else:
348 if args: 386 if args:
349 rev = args[0] 387 rev = args[0]
350 im.start(rev=rev) 388 im.start(rev=rev)
351 args = ['status'] 389 if opts.get('auto'):
390 args = ['merge', '--auto']
391 else:
392 args = ['status']
352 393
353 if not args: 394 if not args:
354 args = ['merge'] 395 args = ['merge']
355 396
356 return dispatch(im, args, opts) 397 return dispatch_(im, args, opts)
357 398
358 cmdtable = { 399 cmdtable = {
359 '^imerge': 400 '^imerge':
360 (imerge, 401 (imerge,
361 [('r', 'rev', '', _('revision to merge'))], 'hg imerge [command]') 402 [('r', 'rev', '', _('revision to merge')),
403 ('a', 'auto', None, _('automatically merge where possible'))],
404 'hg imerge [command]')
362 } 405 }