##// END OF EJS Templates
graft: introduce --base option for using custom base revision while merging...
Mads Kiilerich -
r40460:3c0d5016 default
parent child Browse files
Show More
@@ -2249,6 +2249,8 b' def forget(ui, repo, *pats, **opts):'
2249 @command(
2249 @command(
2250 'graft',
2250 'graft',
2251 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2251 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2252 ('', 'base', '',
2253 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2252 ('c', 'continue', False, _('resume interrupted graft')),
2254 ('c', 'continue', False, _('resume interrupted graft')),
2253 ('', 'stop', False, _('stop interrupted graft')),
2255 ('', 'stop', False, _('stop interrupted graft')),
2254 ('', 'abort', False, _('abort interrupted graft')),
2256 ('', 'abort', False, _('abort interrupted graft')),
@@ -2294,6 +2296,35 b' def graft(ui, repo, *revs, **opts):'
2294
2296
2295 .. container:: verbose
2297 .. container:: verbose
2296
2298
2299 The --base option exposes more of how graft internally uses merge with a
2300 custom base revision. --base can be used to specify another ancestor than
2301 the first and only parent.
2302
2303 The command::
2304
2305 hg graft -r 345 --base 234
2306
2307 is thus pretty much the same as::
2308
2309 hg diff -r 234 -r 345 | hg import
2310
2311 but using merge to resolve conflicts and track moved files.
2312
2313 The result of a merge can thus be backported as a single commit by
2314 specifying one of the merge parents as base, and thus effectively
2315 grafting the changes from the other side.
2316
2317 It is also possible to collapse multiple changesets and clean up history
2318 by specifying another ancestor as base, much like rebase --collapse
2319 --keep.
2320
2321 The commit message can be tweaked after the fact using commit --amend .
2322
2323 For using non-ancestors as the base to backout changes, see the backout
2324 command and the hidden --parent option.
2325
2326 .. container:: verbose
2327
2297 Examples:
2328 Examples:
2298
2329
2299 - copy a single change to the stable branch and edit its description::
2330 - copy a single change to the stable branch and edit its description::
@@ -2317,6 +2348,15 b' def graft(ui, repo, *revs, **opts):'
2317
2348
2318 hg log -r "sort(all(), date)"
2349 hg log -r "sort(all(), date)"
2319
2350
2351 - backport the result of a merge as a single commit::
2352
2353 hg graft -r 123 --base 123^
2354
2355 - land a feature branch as one changeset::
2356
2357 hg up -cr default
2358 hg graft -r featureX --base "ancestor('featureX', 'default')"
2359
2320 See :hg:`help revisions` for more about specifying revisions.
2360 See :hg:`help revisions` for more about specifying revisions.
2321
2361
2322 Returns 0 on successful completion.
2362 Returns 0 on successful completion.
@@ -2332,6 +2372,9 b' def _dograft(ui, repo, *revs, **opts):'
2332
2372
2333 revs = list(revs)
2373 revs = list(revs)
2334 revs.extend(opts.get('rev'))
2374 revs.extend(opts.get('rev'))
2375 basectx = None
2376 if opts.get('base'):
2377 basectx = scmutil.revsingle(repo, opts['base'], None)
2335 # a dict of data to be stored in state file
2378 # a dict of data to be stored in state file
2336 statedata = {}
2379 statedata = {}
2337 # list of new nodes created by ongoing graft
2380 # list of new nodes created by ongoing graft
@@ -2411,13 +2454,16 b' def _dograft(ui, repo, *revs, **opts):'
2411 revs = scmutil.revrange(repo, revs)
2454 revs = scmutil.revrange(repo, revs)
2412
2455
2413 skipped = set()
2456 skipped = set()
2414 # check for merges
2457 if basectx is None:
2415 for rev in repo.revs('%ld and merge()', revs):
2458 # check for merges
2416 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2459 for rev in repo.revs('%ld and merge()', revs):
2417 skipped.add(rev)
2460 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2461 skipped.add(rev)
2418 revs = [r for r in revs if r not in skipped]
2462 revs = [r for r in revs if r not in skipped]
2419 if not revs:
2463 if not revs:
2420 return -1
2464 return -1
2465 if basectx is not None and len(revs) != 1:
2466 raise error.Abort(_('only one revision allowed with --base '))
2421
2467
2422 # Don't check in the --continue case, in effect retaining --force across
2468 # Don't check in the --continue case, in effect retaining --force across
2423 # --continues. That's because without --force, any revisions we decided to
2469 # --continues. That's because without --force, any revisions we decided to
@@ -2425,7 +2471,7 b' def _dograft(ui, repo, *revs, **opts):'
2425 # way to the graftstate. With --force, any revisions we would have otherwise
2471 # way to the graftstate. With --force, any revisions we would have otherwise
2426 # skipped would not have been filtered out, and if they hadn't been applied
2472 # skipped would not have been filtered out, and if they hadn't been applied
2427 # already, they'd have been in the graftstate.
2473 # already, they'd have been in the graftstate.
2428 if not (cont or opts.get('force')):
2474 if not (cont or opts.get('force')) and basectx is None:
2429 # check for ancestors of dest branch
2475 # check for ancestors of dest branch
2430 crev = repo['.'].rev()
2476 crev = repo['.'].rev()
2431 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2477 ancestors = repo.changelog.ancestors([crev], inclusive=True)
@@ -2521,8 +2567,9 b' def _dograft(ui, repo, *revs, **opts):'
2521 if not cont:
2567 if not cont:
2522 # perform the graft merge with p1(rev) as 'ancestor'
2568 # perform the graft merge with p1(rev) as 'ancestor'
2523 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2569 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2570 base = ctx.p1() if basectx is None else basectx
2524 with ui.configoverride(overrides, 'graft'):
2571 with ui.configoverride(overrides, 'graft'):
2525 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2572 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2526 # report any conflicts
2573 # report any conflicts
2527 if stats.unresolvedcount > 0:
2574 if stats.unresolvedcount > 0:
2528 # write out state for --continue
2575 # write out state for --continue
@@ -308,7 +308,7 b' Show all commands + options'
308 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
308 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
309 files: rev, print0, include, exclude, template, subrepos
309 files: rev, print0, include, exclude, template, subrepos
310 forget: interactive, include, exclude, dry-run
310 forget: interactive, include, exclude, dry-run
311 graft: rev, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
311 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
312 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
312 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
313 heads: rev, topo, active, closed, style, template
313 heads: rev, topo, active, closed, style, template
314 help: extension, command, keyword, system
314 help: extension, command, keyword, system
@@ -25,7 +25,7 b' Create a repo with some stuff in it:'
25 $ echo b > e
25 $ echo b > e
26 $ hg branch -q stable
26 $ hg branch -q stable
27 $ hg ci -m5
27 $ hg ci -m5
28 $ hg merge -q default --tool internal:local
28 $ hg merge -q default --tool internal:local # for conflicts in e, choose 5 and ignore 4
29 $ hg branch -q default
29 $ hg branch -q default
30 $ hg ci -m6
30 $ hg ci -m6
31 $ hg phase --public 3
31 $ hg phase --public 3
@@ -46,8 +46,40 b' Create a repo with some stuff in it:'
46 |
46 |
47 o test@0.public: 0
47 o test@0.public: 0
48
48
49 Test --base for grafting the merge of 4 from the perspective of 5, thus only getting the change to d
50
51 $ hg up -cqr 3
52 $ hg graft -r 6 --base 5
53 grafting 6:25a2b029d3ae "6" (tip)
54 merging e
55 $ hg st --change .
56 M d
57
58 $ hg -q strip . --config extensions.strip=
59
60 Test --base for collapsing changesets 2 and 3, thus getting both b and c
61
62 $ hg up -cqr 0
63 $ hg graft -r 3 --base 1
64 grafting 3:4c60f11aa304 "3"
65 merging a and b to b
66 merging a and c to c
67 $ hg st --change .
68 A b
69 A c
70 R a
71
72 $ hg -q strip . --config extensions.strip=
73
74 Specifying child as --base revision fails safely (perhaps slightly confusing, but consistent)
75
76 $ hg graft -r 2 --base 3
77 grafting 2:5c095ad7e90f "2"
78 note: graft of 2:5c095ad7e90f created no changes to commit
79
49 Can't continue without starting:
80 Can't continue without starting:
50
81
82 $ hg -q up -cr tip
51 $ hg rm -q e
83 $ hg rm -q e
52 $ hg graft --continue
84 $ hg graft --continue
53 abort: no graft in progress
85 abort: no graft in progress
General Comments 0
You need to be logged in to leave comments. Login now