Mercurial > hg > mercurial-crew-with-dirclash
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 } |