2447 repo[None].forget(forget) |
2447 repo[None].forget(forget) |
2448 return errs |
2448 return errs |
2449 |
2449 |
2450 @command( |
2450 @command( |
2451 'graft', |
2451 'graft', |
2452 [('e', 'edit', False, _('invoke editor on commit messages')), |
2452 [('c', 'continue', False, _('resume interrupted graft')), |
2453 ('D', 'currentdate', False, |
2453 ('e', 'edit', False, _('invoke editor on commit messages')), |
2454 _('record the current date as commit date')), |
2454 ('D', 'currentdate', False, |
2455 ('U', 'currentuser', False, |
2455 _('record the current date as commit date')), |
2456 _('record the current user as committer'), _('DATE'))] |
2456 ('U', 'currentuser', False, |
|
2457 _('record the current user as committer'), _('DATE'))] |
2457 + commitopts2 + mergetoolopts, |
2458 + commitopts2 + mergetoolopts, |
2458 _('[OPTION]... REVISION...')) |
2459 _('[OPTION]... REVISION...')) |
2459 def graft(ui, repo, rev, *revs, **opts): |
2460 def graft(ui, repo, *revs, **opts): |
2460 '''copy changes from other branches onto the current branch |
2461 '''copy changes from other branches onto the current branch |
2461 |
2462 |
2462 This command uses Mercurial's merge logic to copy individual |
2463 This command uses Mercurial's merge logic to copy individual |
2463 changes from other branches without merging branches in the |
2464 changes from other branches without merging branches in the |
2464 history graph. This is sometimes known as 'backporting' or |
2465 history graph. This is sometimes known as 'backporting' or |
2465 'cherry-picking'. |
2466 'cherry-picking'. |
2466 |
2467 |
2467 Changesets that are ancestors of the current revision, that have |
2468 Changesets that are ancestors of the current revision, that have |
2468 already been grafted, or that are merges will be skipped. |
2469 already been grafted, or that are merges will be skipped. |
2469 |
2470 |
|
2471 If a graft merge results in conflicts, the graft process is |
|
2472 aborted so that the current merge can be manually resolved. Once |
|
2473 all conflicts are addressed, the graft process can be continued |
|
2474 with the -c/--continue option. |
|
2475 |
|
2476 .. note:: |
|
2477 The -c/--continue option does not reapply earlier options. |
|
2478 |
2470 Returns 0 on successful completion. |
2479 Returns 0 on successful completion. |
2471 ''' |
2480 ''' |
2472 |
|
2473 cmdutil.bailifchanged(repo) |
|
2474 |
2481 |
2475 if not opts.get('user') and opts.get('currentuser'): |
2482 if not opts.get('user') and opts.get('currentuser'): |
2476 opts['user'] = ui.username() |
2483 opts['user'] = ui.username() |
2477 if not opts.get('date') and opts.get('currentdate'): |
2484 if not opts.get('date') and opts.get('currentdate'): |
2478 opts['date'] = "%d %d" % util.makedate() |
2485 opts['date'] = "%d %d" % util.makedate() |
2479 |
2486 |
2480 editor = None |
2487 editor = None |
2481 if opts.get('edit'): |
2488 if opts.get('edit'): |
2482 editor = cmdutil.commitforceeditor |
2489 editor = cmdutil.commitforceeditor |
2483 |
2490 |
2484 revs = [rev] + list(revs) |
2491 cont = False |
2485 revs = scmutil.revrange(repo, revs) |
2492 if opts['continue']: |
|
2493 cont = True |
|
2494 if revs: |
|
2495 raise util.Abort(_("can't specify --continue and revisions")) |
|
2496 # read in unfinished revisions |
|
2497 try: |
|
2498 nodes = repo.opener.read('graftstate').splitlines() |
|
2499 revs = [repo[node].rev() for node in nodes] |
|
2500 except IOError, inst: |
|
2501 if inst.errno != errno.ENOENT: |
|
2502 raise |
|
2503 raise util.Abort(_("no graft state found, can't continue")) |
|
2504 else: |
|
2505 cmdutil.bailifchanged(repo) |
|
2506 if not revs: |
|
2507 raise util.Abort(_('no revisions specified')) |
|
2508 revs = scmutil.revrange(repo, revs) |
2486 |
2509 |
2487 # check for merges |
2510 # check for merges |
2488 for ctx in repo.set('%ld and merge()', revs): |
2511 for ctx in repo.set('%ld and merge()', revs): |
2489 ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev()) |
2512 ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev()) |
2490 revs.remove(ctx.rev()) |
2513 revs.remove(ctx.rev()) |
2507 ui.warn(_('skipping already grafted revision %s\n') % r) |
2530 ui.warn(_('skipping already grafted revision %s\n') % r) |
2508 revs.remove(r) |
2531 revs.remove(r) |
2509 if not revs: |
2532 if not revs: |
2510 return -1 |
2533 return -1 |
2511 |
2534 |
2512 for ctx in repo.set("%ld", revs): |
2535 for pos, ctx in enumerate(repo.set("%ld", revs)): |
2513 current = repo['.'] |
2536 current = repo['.'] |
2514 ui.debug('grafting revision %s', ctx.rev()) |
2537 ui.debug('grafting revision %s', ctx.rev()) |
2515 # perform the graft merge with p1(rev) as 'ancestor' |
2538 |
2516 try: |
2539 # we don't merge the first commit when continuing |
2517 # ui.forcemerge is an internal variable, do not document |
2540 if not cont: |
2518 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', '')) |
2541 # perform the graft merge with p1(rev) as 'ancestor' |
2519 stats = mergemod.update(repo, ctx.node(), True, True, False, |
2542 try: |
2520 ctx.p1().node()) |
2543 # ui.forcemerge is an internal variable, do not document |
2521 finally: |
2544 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', '')) |
2522 ui.setconfig('ui', 'forcemerge', '') |
2545 stats = mergemod.update(repo, ctx.node(), True, True, False, |
2523 # drop the second merge parent |
2546 ctx.p1().node()) |
2524 repo.dirstate.setparents(current.node(), nullid) |
2547 finally: |
2525 repo.dirstate.write() |
2548 ui.setconfig('ui', 'forcemerge', '') |
2526 # fix up dirstate for copies and renames |
2549 # drop the second merge parent |
2527 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid) |
2550 repo.dirstate.setparents(current.node(), nullid) |
2528 # report any conflicts |
2551 repo.dirstate.write() |
2529 if stats and stats[3] > 0: |
2552 # fix up dirstate for copies and renames |
2530 raise util.Abort(_("unresolved conflicts, can't continue"), |
2553 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid) |
2531 hint=_('use hg resolve and hg graft --continue')) |
2554 # report any conflicts |
|
2555 if stats and stats[3] > 0: |
|
2556 # write out state for --continue |
|
2557 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]] |
|
2558 repo.opener.write('graftstate', ''.join(nodelines)) |
|
2559 raise util.Abort( |
|
2560 _("unresolved conflicts, can't continue"), |
|
2561 hint=_('use hg resolve and hg graft --continue')) |
|
2562 else: |
|
2563 cont = False |
|
2564 |
2532 # commit |
2565 # commit |
2533 extra = {'source': ctx.hex()} |
2566 extra = {'source': ctx.hex()} |
2534 user = ctx.user() |
2567 user = ctx.user() |
2535 if opts.get('user'): |
2568 if opts.get('user'): |
2536 user = opts['user'] |
2569 user = opts['user'] |
2537 date = ctx.date() |
2570 date = ctx.date() |
2538 if opts.get('date'): |
2571 if opts.get('date'): |
2539 date = opts['date'] |
2572 date = opts['date'] |
2540 repo.commit(text=ctx.description(), user=user, |
2573 repo.commit(text=ctx.description(), user=user, |
2541 date=date, extra=extra, editor=editor) |
2574 date=date, extra=extra, editor=editor) |
|
2575 |
|
2576 # remove state when we complete successfully |
|
2577 if os.path.exists(repo.join('graftstate')): |
|
2578 util.unlinkpath(repo.join('graftstate')) |
2542 |
2579 |
2543 return 0 |
2580 return 0 |
2544 |
2581 |
2545 @command('grep', |
2582 @command('grep', |
2546 [('0', 'print0', None, _('end fields with NUL')), |
2583 [('0', 'print0', None, _('end fields with NUL')), |