##// END OF EJS Templates
transplant: don't honor whitespace and format-changing diffopts...
Siddharth Agarwal -
r23452:86c0d8c1 default
parent child Browse files
Show More
@@ -1,691 +1,691 b''
1 1 # Patch transplanting extension for Mercurial
2 2 #
3 3 # Copyright 2006, 2007 Brendan Cully <brendan@kublai.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''command to transplant changesets from another branch
9 9
10 10 This extension allows you to transplant changes to another parent revision,
11 11 possibly in another repository. The transplant is done using 'diff' patches.
12 12
13 13 Transplanted patches are recorded in .hg/transplant/transplants, as a
14 14 map from a changeset hash to its hash in the source repository.
15 15 '''
16 16
17 17 from mercurial.i18n import _
18 18 import os, tempfile
19 19 from mercurial.node import short
20 20 from mercurial import bundlerepo, hg, merge, match
21 21 from mercurial import patch, revlog, scmutil, util, error, cmdutil
22 22 from mercurial import revset, templatekw, exchange
23 23
24 24 class TransplantError(error.Abort):
25 25 pass
26 26
27 27 cmdtable = {}
28 28 command = cmdutil.command(cmdtable)
29 29 testedwith = 'internal'
30 30
31 31 class transplantentry(object):
32 32 def __init__(self, lnode, rnode):
33 33 self.lnode = lnode
34 34 self.rnode = rnode
35 35
36 36 class transplants(object):
37 37 def __init__(self, path=None, transplantfile=None, opener=None):
38 38 self.path = path
39 39 self.transplantfile = transplantfile
40 40 self.opener = opener
41 41
42 42 if not opener:
43 43 self.opener = scmutil.opener(self.path)
44 44 self.transplants = {}
45 45 self.dirty = False
46 46 self.read()
47 47
48 48 def read(self):
49 49 abspath = os.path.join(self.path, self.transplantfile)
50 50 if self.transplantfile and os.path.exists(abspath):
51 51 for line in self.opener.read(self.transplantfile).splitlines():
52 52 lnode, rnode = map(revlog.bin, line.split(':'))
53 53 list = self.transplants.setdefault(rnode, [])
54 54 list.append(transplantentry(lnode, rnode))
55 55
56 56 def write(self):
57 57 if self.dirty and self.transplantfile:
58 58 if not os.path.isdir(self.path):
59 59 os.mkdir(self.path)
60 60 fp = self.opener(self.transplantfile, 'w')
61 61 for list in self.transplants.itervalues():
62 62 for t in list:
63 63 l, r = map(revlog.hex, (t.lnode, t.rnode))
64 64 fp.write(l + ':' + r + '\n')
65 65 fp.close()
66 66 self.dirty = False
67 67
68 68 def get(self, rnode):
69 69 return self.transplants.get(rnode) or []
70 70
71 71 def set(self, lnode, rnode):
72 72 list = self.transplants.setdefault(rnode, [])
73 73 list.append(transplantentry(lnode, rnode))
74 74 self.dirty = True
75 75
76 76 def remove(self, transplant):
77 77 list = self.transplants.get(transplant.rnode)
78 78 if list:
79 79 del list[list.index(transplant)]
80 80 self.dirty = True
81 81
82 82 class transplanter(object):
83 83 def __init__(self, ui, repo, opts):
84 84 self.ui = ui
85 85 self.path = repo.join('transplant')
86 86 self.opener = scmutil.opener(self.path)
87 87 self.transplants = transplants(self.path, 'transplants',
88 88 opener=self.opener)
89 89 def getcommiteditor():
90 90 editform = cmdutil.mergeeditform(repo[None], 'transplant')
91 91 return cmdutil.getcommiteditor(editform=editform, **opts)
92 92 self.getcommiteditor = getcommiteditor
93 93
94 94 def applied(self, repo, node, parent):
95 95 '''returns True if a node is already an ancestor of parent
96 96 or is parent or has already been transplanted'''
97 97 if hasnode(repo, parent):
98 98 parentrev = repo.changelog.rev(parent)
99 99 if hasnode(repo, node):
100 100 rev = repo.changelog.rev(node)
101 101 reachable = repo.changelog.ancestors([parentrev], rev,
102 102 inclusive=True)
103 103 if rev in reachable:
104 104 return True
105 105 for t in self.transplants.get(node):
106 106 # it might have been stripped
107 107 if not hasnode(repo, t.lnode):
108 108 self.transplants.remove(t)
109 109 return False
110 110 lnoderev = repo.changelog.rev(t.lnode)
111 111 if lnoderev in repo.changelog.ancestors([parentrev], lnoderev,
112 112 inclusive=True):
113 113 return True
114 114 return False
115 115
116 116 def apply(self, repo, source, revmap, merges, opts={}):
117 117 '''apply the revisions in revmap one by one in revision order'''
118 118 revs = sorted(revmap)
119 119 p1, p2 = repo.dirstate.parents()
120 120 pulls = []
121 diffopts = patch.diffopts(self.ui, opts)
121 diffopts = patch.difffeatureopts(self.ui, opts)
122 122 diffopts.git = True
123 123
124 124 lock = wlock = tr = None
125 125 try:
126 126 wlock = repo.wlock()
127 127 lock = repo.lock()
128 128 tr = repo.transaction('transplant')
129 129 for rev in revs:
130 130 node = revmap[rev]
131 131 revstr = '%s:%s' % (rev, short(node))
132 132
133 133 if self.applied(repo, node, p1):
134 134 self.ui.warn(_('skipping already applied revision %s\n') %
135 135 revstr)
136 136 continue
137 137
138 138 parents = source.changelog.parents(node)
139 139 if not (opts.get('filter') or opts.get('log')):
140 140 # If the changeset parent is the same as the
141 141 # wdir's parent, just pull it.
142 142 if parents[0] == p1:
143 143 pulls.append(node)
144 144 p1 = node
145 145 continue
146 146 if pulls:
147 147 if source != repo:
148 148 exchange.pull(repo, source.peer(), heads=pulls)
149 149 merge.update(repo, pulls[-1], False, False, None)
150 150 p1, p2 = repo.dirstate.parents()
151 151 pulls = []
152 152
153 153 domerge = False
154 154 if node in merges:
155 155 # pulling all the merge revs at once would mean we
156 156 # couldn't transplant after the latest even if
157 157 # transplants before them fail.
158 158 domerge = True
159 159 if not hasnode(repo, node):
160 160 exchange.pull(repo, source.peer(), heads=[node])
161 161
162 162 skipmerge = False
163 163 if parents[1] != revlog.nullid:
164 164 if not opts.get('parent'):
165 165 self.ui.note(_('skipping merge changeset %s:%s\n')
166 166 % (rev, short(node)))
167 167 skipmerge = True
168 168 else:
169 169 parent = source.lookup(opts['parent'])
170 170 if parent not in parents:
171 171 raise util.Abort(_('%s is not a parent of %s') %
172 172 (short(parent), short(node)))
173 173 else:
174 174 parent = parents[0]
175 175
176 176 if skipmerge:
177 177 patchfile = None
178 178 else:
179 179 fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
180 180 fp = os.fdopen(fd, 'w')
181 181 gen = patch.diff(source, parent, node, opts=diffopts)
182 182 for chunk in gen:
183 183 fp.write(chunk)
184 184 fp.close()
185 185
186 186 del revmap[rev]
187 187 if patchfile or domerge:
188 188 try:
189 189 try:
190 190 n = self.applyone(repo, node,
191 191 source.changelog.read(node),
192 192 patchfile, merge=domerge,
193 193 log=opts.get('log'),
194 194 filter=opts.get('filter'))
195 195 except TransplantError:
196 196 # Do not rollback, it is up to the user to
197 197 # fix the merge or cancel everything
198 198 tr.close()
199 199 raise
200 200 if n and domerge:
201 201 self.ui.status(_('%s merged at %s\n') % (revstr,
202 202 short(n)))
203 203 elif n:
204 204 self.ui.status(_('%s transplanted to %s\n')
205 205 % (short(node),
206 206 short(n)))
207 207 finally:
208 208 if patchfile:
209 209 os.unlink(patchfile)
210 210 tr.close()
211 211 if pulls:
212 212 exchange.pull(repo, source.peer(), heads=pulls)
213 213 merge.update(repo, pulls[-1], False, False, None)
214 214 finally:
215 215 self.saveseries(revmap, merges)
216 216 self.transplants.write()
217 217 if tr:
218 218 tr.release()
219 219 lock.release()
220 220 wlock.release()
221 221
222 222 def filter(self, filter, node, changelog, patchfile):
223 223 '''arbitrarily rewrite changeset before applying it'''
224 224
225 225 self.ui.status(_('filtering %s\n') % patchfile)
226 226 user, date, msg = (changelog[1], changelog[2], changelog[4])
227 227 fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-')
228 228 fp = os.fdopen(fd, 'w')
229 229 fp.write("# HG changeset patch\n")
230 230 fp.write("# User %s\n" % user)
231 231 fp.write("# Date %d %d\n" % date)
232 232 fp.write(msg + '\n')
233 233 fp.close()
234 234
235 235 try:
236 236 self.ui.system('%s %s %s' % (filter, util.shellquote(headerfile),
237 237 util.shellquote(patchfile)),
238 238 environ={'HGUSER': changelog[1],
239 239 'HGREVISION': revlog.hex(node),
240 240 },
241 241 onerr=util.Abort, errprefix=_('filter failed'))
242 242 user, date, msg = self.parselog(file(headerfile))[1:4]
243 243 finally:
244 244 os.unlink(headerfile)
245 245
246 246 return (user, date, msg)
247 247
248 248 def applyone(self, repo, node, cl, patchfile, merge=False, log=False,
249 249 filter=None):
250 250 '''apply the patch in patchfile to the repository as a transplant'''
251 251 (manifest, user, (time, timezone), files, message) = cl[:5]
252 252 date = "%d %d" % (time, timezone)
253 253 extra = {'transplant_source': node}
254 254 if filter:
255 255 (user, date, message) = self.filter(filter, node, cl, patchfile)
256 256
257 257 if log:
258 258 # we don't translate messages inserted into commits
259 259 message += '\n(transplanted from %s)' % revlog.hex(node)
260 260
261 261 self.ui.status(_('applying %s\n') % short(node))
262 262 self.ui.note('%s %s\n%s\n' % (user, date, message))
263 263
264 264 if not patchfile and not merge:
265 265 raise util.Abort(_('can only omit patchfile if merging'))
266 266 if patchfile:
267 267 try:
268 268 files = set()
269 269 patch.patch(self.ui, repo, patchfile, files=files, eolmode=None)
270 270 files = list(files)
271 271 except Exception, inst:
272 272 seriespath = os.path.join(self.path, 'series')
273 273 if os.path.exists(seriespath):
274 274 os.unlink(seriespath)
275 275 p1 = repo.dirstate.p1()
276 276 p2 = node
277 277 self.log(user, date, message, p1, p2, merge=merge)
278 278 self.ui.write(str(inst) + '\n')
279 279 raise TransplantError(_('fix up the merge and run '
280 280 'hg transplant --continue'))
281 281 else:
282 282 files = None
283 283 if merge:
284 284 p1, p2 = repo.dirstate.parents()
285 285 repo.setparents(p1, node)
286 286 m = match.always(repo.root, '')
287 287 else:
288 288 m = match.exact(repo.root, '', files)
289 289
290 290 n = repo.commit(message, user, date, extra=extra, match=m,
291 291 editor=self.getcommiteditor())
292 292 if not n:
293 293 self.ui.warn(_('skipping emptied changeset %s\n') % short(node))
294 294 return None
295 295 if not merge:
296 296 self.transplants.set(n, node)
297 297
298 298 return n
299 299
300 300 def resume(self, repo, source, opts):
301 301 '''recover last transaction and apply remaining changesets'''
302 302 if os.path.exists(os.path.join(self.path, 'journal')):
303 303 n, node = self.recover(repo, source, opts)
304 304 self.ui.status(_('%s transplanted as %s\n') % (short(node),
305 305 short(n)))
306 306 seriespath = os.path.join(self.path, 'series')
307 307 if not os.path.exists(seriespath):
308 308 self.transplants.write()
309 309 return
310 310 nodes, merges = self.readseries()
311 311 revmap = {}
312 312 for n in nodes:
313 313 revmap[source.changelog.rev(n)] = n
314 314 os.unlink(seriespath)
315 315
316 316 self.apply(repo, source, revmap, merges, opts)
317 317
318 318 def recover(self, repo, source, opts):
319 319 '''commit working directory using journal metadata'''
320 320 node, user, date, message, parents = self.readlog()
321 321 merge = False
322 322
323 323 if not user or not date or not message or not parents[0]:
324 324 raise util.Abort(_('transplant log file is corrupt'))
325 325
326 326 parent = parents[0]
327 327 if len(parents) > 1:
328 328 if opts.get('parent'):
329 329 parent = source.lookup(opts['parent'])
330 330 if parent not in parents:
331 331 raise util.Abort(_('%s is not a parent of %s') %
332 332 (short(parent), short(node)))
333 333 else:
334 334 merge = True
335 335
336 336 extra = {'transplant_source': node}
337 337 wlock = repo.wlock()
338 338 try:
339 339 p1, p2 = repo.dirstate.parents()
340 340 if p1 != parent:
341 341 raise util.Abort(
342 342 _('working dir not at transplant parent %s') %
343 343 revlog.hex(parent))
344 344 if merge:
345 345 repo.setparents(p1, parents[1])
346 346 n = repo.commit(message, user, date, extra=extra,
347 347 editor=self.getcommiteditor())
348 348 if not n:
349 349 raise util.Abort(_('commit failed'))
350 350 if not merge:
351 351 self.transplants.set(n, node)
352 352 self.unlog()
353 353
354 354 return n, node
355 355 finally:
356 356 wlock.release()
357 357
358 358 def readseries(self):
359 359 nodes = []
360 360 merges = []
361 361 cur = nodes
362 362 for line in self.opener.read('series').splitlines():
363 363 if line.startswith('# Merges'):
364 364 cur = merges
365 365 continue
366 366 cur.append(revlog.bin(line))
367 367
368 368 return (nodes, merges)
369 369
370 370 def saveseries(self, revmap, merges):
371 371 if not revmap:
372 372 return
373 373
374 374 if not os.path.isdir(self.path):
375 375 os.mkdir(self.path)
376 376 series = self.opener('series', 'w')
377 377 for rev in sorted(revmap):
378 378 series.write(revlog.hex(revmap[rev]) + '\n')
379 379 if merges:
380 380 series.write('# Merges\n')
381 381 for m in merges:
382 382 series.write(revlog.hex(m) + '\n')
383 383 series.close()
384 384
385 385 def parselog(self, fp):
386 386 parents = []
387 387 message = []
388 388 node = revlog.nullid
389 389 inmsg = False
390 390 user = None
391 391 date = None
392 392 for line in fp.read().splitlines():
393 393 if inmsg:
394 394 message.append(line)
395 395 elif line.startswith('# User '):
396 396 user = line[7:]
397 397 elif line.startswith('# Date '):
398 398 date = line[7:]
399 399 elif line.startswith('# Node ID '):
400 400 node = revlog.bin(line[10:])
401 401 elif line.startswith('# Parent '):
402 402 parents.append(revlog.bin(line[9:]))
403 403 elif not line.startswith('# '):
404 404 inmsg = True
405 405 message.append(line)
406 406 if None in (user, date):
407 407 raise util.Abort(_("filter corrupted changeset (no user or date)"))
408 408 return (node, user, date, '\n'.join(message), parents)
409 409
410 410 def log(self, user, date, message, p1, p2, merge=False):
411 411 '''journal changelog metadata for later recover'''
412 412
413 413 if not os.path.isdir(self.path):
414 414 os.mkdir(self.path)
415 415 fp = self.opener('journal', 'w')
416 416 fp.write('# User %s\n' % user)
417 417 fp.write('# Date %s\n' % date)
418 418 fp.write('# Node ID %s\n' % revlog.hex(p2))
419 419 fp.write('# Parent ' + revlog.hex(p1) + '\n')
420 420 if merge:
421 421 fp.write('# Parent ' + revlog.hex(p2) + '\n')
422 422 fp.write(message.rstrip() + '\n')
423 423 fp.close()
424 424
425 425 def readlog(self):
426 426 return self.parselog(self.opener('journal'))
427 427
428 428 def unlog(self):
429 429 '''remove changelog journal'''
430 430 absdst = os.path.join(self.path, 'journal')
431 431 if os.path.exists(absdst):
432 432 os.unlink(absdst)
433 433
434 434 def transplantfilter(self, repo, source, root):
435 435 def matchfn(node):
436 436 if self.applied(repo, node, root):
437 437 return False
438 438 if source.changelog.parents(node)[1] != revlog.nullid:
439 439 return False
440 440 extra = source.changelog.read(node)[5]
441 441 cnode = extra.get('transplant_source')
442 442 if cnode and self.applied(repo, cnode, root):
443 443 return False
444 444 return True
445 445
446 446 return matchfn
447 447
448 448 def hasnode(repo, node):
449 449 try:
450 450 return repo.changelog.rev(node) is not None
451 451 except error.RevlogError:
452 452 return False
453 453
454 454 def browserevs(ui, repo, nodes, opts):
455 455 '''interactively transplant changesets'''
456 456 displayer = cmdutil.show_changeset(ui, repo, opts)
457 457 transplants = []
458 458 merges = []
459 459 prompt = _('apply changeset? [ynmpcq?]:'
460 460 '$$ &yes, transplant this changeset'
461 461 '$$ &no, skip this changeset'
462 462 '$$ &merge at this changeset'
463 463 '$$ show &patch'
464 464 '$$ &commit selected changesets'
465 465 '$$ &quit and cancel transplant'
466 466 '$$ &? (show this help)')
467 467 for node in nodes:
468 468 displayer.show(repo[node])
469 469 action = None
470 470 while not action:
471 471 action = 'ynmpcq?'[ui.promptchoice(prompt)]
472 472 if action == '?':
473 473 for c, t in ui.extractchoices(prompt)[1]:
474 474 ui.write('%s: %s\n' % (c, t))
475 475 action = None
476 476 elif action == 'p':
477 477 parent = repo.changelog.parents(node)[0]
478 478 for chunk in patch.diff(repo, parent, node):
479 479 ui.write(chunk)
480 480 action = None
481 481 if action == 'y':
482 482 transplants.append(node)
483 483 elif action == 'm':
484 484 merges.append(node)
485 485 elif action == 'c':
486 486 break
487 487 elif action == 'q':
488 488 transplants = ()
489 489 merges = ()
490 490 break
491 491 displayer.close()
492 492 return (transplants, merges)
493 493
494 494 @command('transplant',
495 495 [('s', 'source', '', _('transplant changesets from REPO'), _('REPO')),
496 496 ('b', 'branch', [], _('use this source changeset as head'), _('REV')),
497 497 ('a', 'all', None, _('pull all changesets up to the --branch revisions')),
498 498 ('p', 'prune', [], _('skip over REV'), _('REV')),
499 499 ('m', 'merge', [], _('merge at REV'), _('REV')),
500 500 ('', 'parent', '',
501 501 _('parent to choose when transplanting merge'), _('REV')),
502 502 ('e', 'edit', False, _('invoke editor on commit messages')),
503 503 ('', 'log', None, _('append transplant info to log message')),
504 504 ('c', 'continue', None, _('continue last transplant session '
505 505 'after fixing conflicts')),
506 506 ('', 'filter', '',
507 507 _('filter changesets through command'), _('CMD'))],
508 508 _('hg transplant [-s REPO] [-b BRANCH [-a]] [-p REV] '
509 509 '[-m REV] [REV]...'))
510 510 def transplant(ui, repo, *revs, **opts):
511 511 '''transplant changesets from another branch
512 512
513 513 Selected changesets will be applied on top of the current working
514 514 directory with the log of the original changeset. The changesets
515 515 are copied and will thus appear twice in the history with different
516 516 identities.
517 517
518 518 Consider using the graft command if everything is inside the same
519 519 repository - it will use merges and will usually give a better result.
520 520 Use the rebase extension if the changesets are unpublished and you want
521 521 to move them instead of copying them.
522 522
523 523 If --log is specified, log messages will have a comment appended
524 524 of the form::
525 525
526 526 (transplanted from CHANGESETHASH)
527 527
528 528 You can rewrite the changelog message with the --filter option.
529 529 Its argument will be invoked with the current changelog message as
530 530 $1 and the patch as $2.
531 531
532 532 --source/-s specifies another repository to use for selecting changesets,
533 533 just as if it temporarily had been pulled.
534 534 If --branch/-b is specified, these revisions will be used as
535 535 heads when deciding which changesets to transplant, just as if only
536 536 these revisions had been pulled.
537 537 If --all/-a is specified, all the revisions up to the heads specified
538 538 with --branch will be transplanted.
539 539
540 540 Example:
541 541
542 542 - transplant all changes up to REV on top of your current revision::
543 543
544 544 hg transplant --branch REV --all
545 545
546 546 You can optionally mark selected transplanted changesets as merge
547 547 changesets. You will not be prompted to transplant any ancestors
548 548 of a merged transplant, and you can merge descendants of them
549 549 normally instead of transplanting them.
550 550
551 551 Merge changesets may be transplanted directly by specifying the
552 552 proper parent changeset by calling :hg:`transplant --parent`.
553 553
554 554 If no merges or revisions are provided, :hg:`transplant` will
555 555 start an interactive changeset browser.
556 556
557 557 If a changeset application fails, you can fix the merge by hand
558 558 and then resume where you left off by calling :hg:`transplant
559 559 --continue/-c`.
560 560 '''
561 561 def incwalk(repo, csets, match=util.always):
562 562 for node in csets:
563 563 if match(node):
564 564 yield node
565 565
566 566 def transplantwalk(repo, dest, heads, match=util.always):
567 567 '''Yield all nodes that are ancestors of a head but not ancestors
568 568 of dest.
569 569 If no heads are specified, the heads of repo will be used.'''
570 570 if not heads:
571 571 heads = repo.heads()
572 572 ancestors = []
573 573 ctx = repo[dest]
574 574 for head in heads:
575 575 ancestors.append(ctx.ancestor(repo[head]).node())
576 576 for node in repo.changelog.nodesbetween(ancestors, heads)[0]:
577 577 if match(node):
578 578 yield node
579 579
580 580 def checkopts(opts, revs):
581 581 if opts.get('continue'):
582 582 if opts.get('branch') or opts.get('all') or opts.get('merge'):
583 583 raise util.Abort(_('--continue is incompatible with '
584 584 '--branch, --all and --merge'))
585 585 return
586 586 if not (opts.get('source') or revs or
587 587 opts.get('merge') or opts.get('branch')):
588 588 raise util.Abort(_('no source URL, branch revision or revision '
589 589 'list provided'))
590 590 if opts.get('all'):
591 591 if not opts.get('branch'):
592 592 raise util.Abort(_('--all requires a branch revision'))
593 593 if revs:
594 594 raise util.Abort(_('--all is incompatible with a '
595 595 'revision list'))
596 596
597 597 checkopts(opts, revs)
598 598
599 599 if not opts.get('log'):
600 600 opts['log'] = ui.config('transplant', 'log')
601 601 if not opts.get('filter'):
602 602 opts['filter'] = ui.config('transplant', 'filter')
603 603
604 604 tp = transplanter(ui, repo, opts)
605 605
606 606 cmdutil.checkunfinished(repo)
607 607 p1, p2 = repo.dirstate.parents()
608 608 if len(repo) > 0 and p1 == revlog.nullid:
609 609 raise util.Abort(_('no revision checked out'))
610 610 if not opts.get('continue'):
611 611 if p2 != revlog.nullid:
612 612 raise util.Abort(_('outstanding uncommitted merges'))
613 613 m, a, r, d = repo.status()[:4]
614 614 if m or a or r or d:
615 615 raise util.Abort(_('outstanding local changes'))
616 616
617 617 sourcerepo = opts.get('source')
618 618 if sourcerepo:
619 619 peer = hg.peer(repo, opts, ui.expandpath(sourcerepo))
620 620 heads = map(peer.lookup, opts.get('branch', ()))
621 621 source, csets, cleanupfn = bundlerepo.getremotechanges(ui, repo, peer,
622 622 onlyheads=heads, force=True)
623 623 else:
624 624 source = repo
625 625 heads = map(source.lookup, opts.get('branch', ()))
626 626 cleanupfn = None
627 627
628 628 try:
629 629 if opts.get('continue'):
630 630 tp.resume(repo, source, opts)
631 631 return
632 632
633 633 tf = tp.transplantfilter(repo, source, p1)
634 634 if opts.get('prune'):
635 635 prune = set(source.lookup(r)
636 636 for r in scmutil.revrange(source, opts.get('prune')))
637 637 matchfn = lambda x: tf(x) and x not in prune
638 638 else:
639 639 matchfn = tf
640 640 merges = map(source.lookup, opts.get('merge', ()))
641 641 revmap = {}
642 642 if revs:
643 643 for r in scmutil.revrange(source, revs):
644 644 revmap[int(r)] = source.lookup(r)
645 645 elif opts.get('all') or not merges:
646 646 if source != repo:
647 647 alltransplants = incwalk(source, csets, match=matchfn)
648 648 else:
649 649 alltransplants = transplantwalk(source, p1, heads,
650 650 match=matchfn)
651 651 if opts.get('all'):
652 652 revs = alltransplants
653 653 else:
654 654 revs, newmerges = browserevs(ui, source, alltransplants, opts)
655 655 merges.extend(newmerges)
656 656 for r in revs:
657 657 revmap[source.changelog.rev(r)] = r
658 658 for r in merges:
659 659 revmap[source.changelog.rev(r)] = r
660 660
661 661 tp.apply(repo, source, revmap, merges, opts)
662 662 finally:
663 663 if cleanupfn:
664 664 cleanupfn()
665 665
666 666 def revsettransplanted(repo, subset, x):
667 667 """``transplanted([set])``
668 668 Transplanted changesets in set, or all transplanted changesets.
669 669 """
670 670 if x:
671 671 s = revset.getset(repo, subset, x)
672 672 else:
673 673 s = subset
674 674 return revset.baseset([r for r in s if
675 675 repo[r].extra().get('transplant_source')])
676 676
677 677 def kwtransplanted(repo, ctx, **args):
678 678 """:transplanted: String. The node identifier of the transplanted
679 679 changeset if any."""
680 680 n = ctx.extra().get('transplant_source')
681 681 return n and revlog.hex(n) or ''
682 682
683 683 def extsetup(ui):
684 684 revset.symbols['transplanted'] = revsettransplanted
685 685 templatekw.keywords['transplanted'] = kwtransplanted
686 686 cmdutil.unfinishedstates.append(
687 687 ['series', True, False, _('transplant in progress'),
688 688 _("use 'hg transplant --continue' or 'hg update' to abort")])
689 689
690 690 # tell hggettext to extract docstrings from these functions:
691 691 i18nfunctions = [revsettransplanted, kwtransplanted]
@@ -1,775 +1,776 b''
1 1 #require killdaemons
2 2
3 3 $ cat <<EOF >> $HGRCPATH
4 4 > [extensions]
5 5 > transplant=
6 6 > EOF
7 7
8 8 $ hg init t
9 9 $ cd t
10 10 $ echo r1 > r1
11 11 $ hg ci -Amr1 -d'0 0'
12 12 adding r1
13 13 $ echo r2 > r2
14 14 $ hg ci -Amr2 -d'1 0'
15 15 adding r2
16 16 $ hg up 0
17 17 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
18 18
19 19 $ echo b1 > b1
20 20 $ hg ci -Amb1 -d '0 0'
21 21 adding b1
22 22 created new head
23 23 $ echo b2 > b2
24 24 $ hg ci -Amb2 -d '1 0'
25 25 adding b2
26 26 $ echo b3 > b3
27 27 $ hg ci -Amb3 -d '2 0'
28 28 adding b3
29 29
30 30 $ hg log --template '{rev} {parents} {desc}\n'
31 31 4 b3
32 32 3 b2
33 33 2 0:17ab29e464c6 b1
34 34 1 r2
35 35 0 r1
36 36
37 37 $ hg clone . ../rebase
38 38 updating to branch default
39 39 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
40 40 $ cd ../rebase
41 41
42 42 $ hg up -C 1
43 43 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
44 44
45 45 rebase b onto r1
46 46 (this also tests that editor is not invoked if '--edit' is not specified)
47 47
48 48 $ HGEDITOR=cat hg transplant -a -b tip
49 49 applying 37a1297eb21b
50 50 37a1297eb21b transplanted to e234d668f844
51 51 applying 722f4667af76
52 52 722f4667af76 transplanted to 539f377d78df
53 53 applying a53251cdf717
54 54 a53251cdf717 transplanted to ffd6818a3975
55 55 $ hg log --template '{rev} {parents} {desc}\n'
56 56 7 b3
57 57 6 b2
58 58 5 1:d11e3596cc1a b1
59 59 4 b3
60 60 3 b2
61 61 2 0:17ab29e464c6 b1
62 62 1 r2
63 63 0 r1
64 64
65 65 test transplanted revset
66 66
67 67 $ hg log -r 'transplanted()' --template '{rev} {parents} {desc}\n'
68 68 5 1:d11e3596cc1a b1
69 69 6 b2
70 70 7 b3
71 71 $ hg help revsets | grep transplanted
72 72 "transplanted([set])"
73 73 Transplanted changesets in set, or all transplanted changesets.
74 74
75 75 test transplanted keyword
76 76
77 77 $ hg log --template '{rev} {transplanted}\n'
78 78 7 a53251cdf717679d1907b289f991534be05c997a
79 79 6 722f4667af767100cb15b6a79324bf8abbfe1ef4
80 80 5 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21
81 81 4
82 82 3
83 83 2
84 84 1
85 85 0
86 86
87 87 test destination() revset predicate with a transplant of a transplant; new
88 88 clone so subsequent rollback isn't affected
89 89 (this also tests that editor is invoked if '--edit' is specified)
90 90
91 91 $ hg clone -q . ../destination
92 92 $ cd ../destination
93 93 $ hg up -Cq 0
94 94 $ hg branch -q b4
95 95 $ hg ci -qm "b4"
96 96 $ hg status --rev "7^1" --rev 7
97 97 A b3
98 98 $ cat > $TESTTMP/checkeditform.sh <<EOF
99 99 > env | grep HGEDITFORM
100 100 > true
101 101 > EOF
102 102 $ cat > $TESTTMP/checkeditform-n-cat.sh <<EOF
103 103 > env | grep HGEDITFORM
104 104 > cat \$*
105 105 > EOF
106 106 $ HGEDITOR="sh $TESTTMP/checkeditform-n-cat.sh" hg transplant --edit 7
107 107 applying ffd6818a3975
108 108 HGEDITFORM=transplant.normal
109 109 b3
110 110
111 111
112 112 HG: Enter commit message. Lines beginning with 'HG:' are removed.
113 113 HG: Leave message empty to abort commit.
114 114 HG: --
115 115 HG: user: test
116 116 HG: branch 'b4'
117 117 HG: added b3
118 118 ffd6818a3975 transplanted to 502236fa76bb
119 119
120 120
121 121 $ hg log -r 'destination()'
122 122 changeset: 5:e234d668f844
123 123 parent: 1:d11e3596cc1a
124 124 user: test
125 125 date: Thu Jan 01 00:00:00 1970 +0000
126 126 summary: b1
127 127
128 128 changeset: 6:539f377d78df
129 129 user: test
130 130 date: Thu Jan 01 00:00:01 1970 +0000
131 131 summary: b2
132 132
133 133 changeset: 7:ffd6818a3975
134 134 user: test
135 135 date: Thu Jan 01 00:00:02 1970 +0000
136 136 summary: b3
137 137
138 138 changeset: 9:502236fa76bb
139 139 branch: b4
140 140 tag: tip
141 141 user: test
142 142 date: Thu Jan 01 00:00:02 1970 +0000
143 143 summary: b3
144 144
145 145 $ hg log -r 'destination(a53251cdf717)'
146 146 changeset: 7:ffd6818a3975
147 147 user: test
148 148 date: Thu Jan 01 00:00:02 1970 +0000
149 149 summary: b3
150 150
151 151 changeset: 9:502236fa76bb
152 152 branch: b4
153 153 tag: tip
154 154 user: test
155 155 date: Thu Jan 01 00:00:02 1970 +0000
156 156 summary: b3
157 157
158 158
159 159 test subset parameter in reverse order
160 160 $ hg log -r 'reverse(all()) and destination(a53251cdf717)'
161 161 changeset: 9:502236fa76bb
162 162 branch: b4
163 163 tag: tip
164 164 user: test
165 165 date: Thu Jan 01 00:00:02 1970 +0000
166 166 summary: b3
167 167
168 168 changeset: 7:ffd6818a3975
169 169 user: test
170 170 date: Thu Jan 01 00:00:02 1970 +0000
171 171 summary: b3
172 172
173 173
174 174 back to the original dir
175 175 $ cd ../rebase
176 176
177 177 rollback the transplant
178 178 $ hg rollback
179 179 repository tip rolled back to revision 4 (undo transplant)
180 180 working directory now based on revision 1
181 181 $ hg tip -q
182 182 4:a53251cdf717
183 183 $ hg parents -q
184 184 1:d11e3596cc1a
185 185 $ hg status
186 186 ? b1
187 187 ? b2
188 188 ? b3
189 189
190 190 $ hg clone ../t ../prune
191 191 updating to branch default
192 192 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
193 193 $ cd ../prune
194 194
195 195 $ hg up -C 1
196 196 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
197 197
198 198 rebase b onto r1, skipping b2
199 199
200 200 $ hg transplant -a -b tip -p 3
201 201 applying 37a1297eb21b
202 202 37a1297eb21b transplanted to e234d668f844
203 203 applying a53251cdf717
204 204 a53251cdf717 transplanted to 7275fda4d04f
205 205 $ hg log --template '{rev} {parents} {desc}\n'
206 206 6 b3
207 207 5 1:d11e3596cc1a b1
208 208 4 b3
209 209 3 b2
210 210 2 0:17ab29e464c6 b1
211 211 1 r2
212 212 0 r1
213 213
214 214 test same-parent transplant with --log
215 215
216 216 $ hg clone -r 1 ../t ../sameparent
217 217 adding changesets
218 218 adding manifests
219 219 adding file changes
220 220 added 2 changesets with 2 changes to 2 files
221 221 updating to branch default
222 222 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
223 223 $ cd ../sameparent
224 224 $ hg transplant --log -s ../prune 5
225 225 searching for changes
226 226 applying e234d668f844
227 227 e234d668f844 transplanted to e07aea8ecf9c
228 228 $ hg log --template '{rev} {parents} {desc}\n'
229 229 2 b1
230 230 (transplanted from e234d668f844e1b1a765f01db83a32c0c7bfa170)
231 231 1 r2
232 232 0 r1
233 remote transplant
233 remote transplant, and also test that transplant doesn't break with
234 format-breaking diffopts
234 235
235 236 $ hg clone -r 1 ../t ../remote
236 237 adding changesets
237 238 adding manifests
238 239 adding file changes
239 240 added 2 changesets with 2 changes to 2 files
240 241 updating to branch default
241 242 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 243 $ cd ../remote
243 $ hg transplant --log -s ../t 2 4
244 $ hg --config diff.noprefix=True transplant --log -s ../t 2 4
244 245 searching for changes
245 246 applying 37a1297eb21b
246 247 37a1297eb21b transplanted to c19cf0ccb069
247 248 applying a53251cdf717
248 249 a53251cdf717 transplanted to f7fe5bf98525
249 250 $ hg log --template '{rev} {parents} {desc}\n'
250 251 3 b3
251 252 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
252 253 2 b1
253 254 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
254 255 1 r2
255 256 0 r1
256 257
257 258 skip previous transplants
258 259
259 260 $ hg transplant -s ../t -a -b 4
260 261 searching for changes
261 262 applying 722f4667af76
262 263 722f4667af76 transplanted to 47156cd86c0b
263 264 $ hg log --template '{rev} {parents} {desc}\n'
264 265 4 b2
265 266 3 b3
266 267 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
267 268 2 b1
268 269 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
269 270 1 r2
270 271 0 r1
271 272
272 273 skip local changes transplanted to the source
273 274
274 275 $ echo b4 > b4
275 276 $ hg ci -Amb4 -d '3 0'
276 277 adding b4
277 278 $ hg clone ../t ../pullback
278 279 updating to branch default
279 280 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 281 $ cd ../pullback
281 282 $ hg transplant -s ../remote -a -b tip
282 283 searching for changes
283 284 applying 4333daefcb15
284 285 4333daefcb15 transplanted to 5f42c04e07cc
285 286
286 287
287 288 remote transplant with pull
288 289
289 290 $ hg -R ../t serve -p $HGPORT -d --pid-file=../t.pid
290 291 $ cat ../t.pid >> $DAEMON_PIDS
291 292
292 293 $ hg clone -r 0 ../t ../rp
293 294 adding changesets
294 295 adding manifests
295 296 adding file changes
296 297 added 1 changesets with 1 changes to 1 files
297 298 updating to branch default
298 299 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 300 $ cd ../rp
300 301 $ hg transplant -s http://localhost:$HGPORT/ 2 4
301 302 searching for changes
302 303 searching for changes
303 304 adding changesets
304 305 adding manifests
305 306 adding file changes
306 307 added 1 changesets with 1 changes to 1 files
307 308 applying a53251cdf717
308 309 a53251cdf717 transplanted to 8d9279348abb
309 310 $ hg log --template '{rev} {parents} {desc}\n'
310 311 2 b3
311 312 1 b1
312 313 0 r1
313 314
314 315 remote transplant without pull
315 316
316 317 $ hg pull -q http://localhost:$HGPORT/
317 318 $ hg transplant -s http://localhost:$HGPORT/ 2 4
318 319 searching for changes
319 320 skipping already applied revision 2:8d9279348abb
320 321 applying 722f4667af76
321 322 722f4667af76 transplanted to 76e321915884
322 323
323 324 transplant --continue
324 325
325 326 $ hg init ../tc
326 327 $ cd ../tc
327 328 $ cat <<EOF > foo
328 329 > foo
329 330 > bar
330 331 > baz
331 332 > EOF
332 333 $ echo toremove > toremove
333 334 $ echo baz > baz
334 335 $ hg ci -Amfoo
335 336 adding baz
336 337 adding foo
337 338 adding toremove
338 339 $ cat <<EOF > foo
339 340 > foo2
340 341 > bar2
341 342 > baz2
342 343 > EOF
343 344 $ rm toremove
344 345 $ echo added > added
345 346 $ hg ci -Amfoo2
346 347 adding added
347 348 removing toremove
348 349 $ echo bar > bar
349 350 $ cat > baz <<EOF
350 351 > before baz
351 352 > baz
352 353 > after baz
353 354 > EOF
354 355 $ hg ci -Ambar
355 356 adding bar
356 357 $ echo bar2 >> bar
357 358 $ hg ci -mbar2
358 359 $ hg up 0
359 360 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
360 361 $ echo foobar > foo
361 362 $ hg ci -mfoobar
362 363 created new head
363 364 $ hg transplant 1:3
364 365 applying 46ae92138f3c
365 366 patching file foo
366 367 Hunk #1 FAILED at 0
367 368 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
368 369 patch failed to apply
369 370 abort: fix up the merge and run hg transplant --continue
370 371 [255]
371 372
372 373 transplant -c shouldn't use an old changeset
373 374
374 375 $ hg up -C
375 376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 377 $ rm added
377 378 $ hg transplant 1
378 379 applying 46ae92138f3c
379 380 patching file foo
380 381 Hunk #1 FAILED at 0
381 382 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
382 383 patch failed to apply
383 384 abort: fix up the merge and run hg transplant --continue
384 385 [255]
385 386 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e
386 387 HGEDITFORM=transplant.normal
387 388 46ae92138f3c transplanted as 9159dada197d
388 389 $ hg transplant 1:3
389 390 skipping already applied revision 1:46ae92138f3c
390 391 applying 9d6d6b5a8275
391 392 9d6d6b5a8275 transplanted to 2d17a10c922f
392 393 applying 1dab759070cf
393 394 1dab759070cf transplanted to e06a69927eb0
394 395 $ hg locate
395 396 added
396 397 bar
397 398 baz
398 399 foo
399 400
400 401 test multiple revisions and --continue
401 402
402 403 $ hg up -qC 0
403 404 $ echo bazbaz > baz
404 405 $ hg ci -Am anotherbaz baz
405 406 created new head
406 407 $ hg transplant 1:3
407 408 applying 46ae92138f3c
408 409 46ae92138f3c transplanted to 1024233ea0ba
409 410 applying 9d6d6b5a8275
410 411 patching file baz
411 412 Hunk #1 FAILED at 0
412 413 1 out of 1 hunks FAILED -- saving rejects to file baz.rej
413 414 patch failed to apply
414 415 abort: fix up the merge and run hg transplant --continue
415 416 [255]
416 417 $ echo fixed > baz
417 418 $ hg transplant --continue
418 419 9d6d6b5a8275 transplanted as d80c49962290
419 420 applying 1dab759070cf
420 421 1dab759070cf transplanted to aa0ffe6bd5ae
421 422
422 423 $ cd ..
423 424
424 425 Issue1111: Test transplant --merge
425 426
426 427 $ hg init t1111
427 428 $ cd t1111
428 429 $ echo a > a
429 430 $ hg ci -Am adda
430 431 adding a
431 432 $ echo b >> a
432 433 $ hg ci -m appendb
433 434 $ echo c >> a
434 435 $ hg ci -m appendc
435 436 $ hg up -C 0
436 437 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 438 $ echo d >> a
438 439 $ hg ci -m appendd
439 440 created new head
440 441
441 442 transplant
442 443
443 444 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant -m 1 -e
444 445 applying 42dc4432fd35
445 446 HGEDITFORM=transplant.merge
446 447 1:42dc4432fd35 merged at a9f4acbac129
447 448 $ hg update -q -C 2
448 449 $ cat > a <<EOF
449 450 > x
450 451 > y
451 452 > z
452 453 > EOF
453 454 $ hg commit -m replace
454 455 $ hg update -q -C 4
455 456 $ hg transplant -m 5
456 457 applying 600a3cdcb41d
457 458 patching file a
458 459 Hunk #1 FAILED at 0
459 460 1 out of 1 hunks FAILED -- saving rejects to file a.rej
460 461 patch failed to apply
461 462 abort: fix up the merge and run hg transplant --continue
462 463 [255]
463 464 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e
464 465 HGEDITFORM=transplant.merge
465 466 600a3cdcb41d transplanted as a3f88be652e0
466 467
467 468 $ cd ..
468 469
469 470 test transplant into empty repository
470 471
471 472 $ hg init empty
472 473 $ cd empty
473 474 $ hg transplant -s ../t -b tip -a
474 475 adding changesets
475 476 adding manifests
476 477 adding file changes
477 478 added 4 changesets with 4 changes to 4 files
478 479
479 480 test "--merge" causing pull from source repository on local host
480 481
481 482 $ hg --config extensions.mq= -q strip 2
482 483 $ hg transplant -s ../t --merge tip
483 484 searching for changes
484 485 searching for changes
485 486 adding changesets
486 487 adding manifests
487 488 adding file changes
488 489 added 2 changesets with 2 changes to 2 files
489 490 applying a53251cdf717
490 491 4:a53251cdf717 merged at 4831f4dc831a
491 492
492 493 test interactive transplant
493 494
494 495 $ hg --config extensions.strip= -q strip 0
495 496 $ hg -R ../t log -G --template "{rev}:{node|short}"
496 497 @ 4:a53251cdf717
497 498 |
498 499 o 3:722f4667af76
499 500 |
500 501 o 2:37a1297eb21b
501 502 |
502 503 | o 1:d11e3596cc1a
503 504 |/
504 505 o 0:17ab29e464c6
505 506
506 507 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
507 508 > p
508 509 > y
509 510 > n
510 511 > n
511 512 > m
512 513 > c
513 514 > EOF
514 515 0:17ab29e464c6
515 516 apply changeset? [ynmpcq?]: p
516 517 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
517 518 +++ b/r1 Thu Jan 01 00:00:00 1970 +0000
518 519 @@ -0,0 +1,1 @@
519 520 +r1
520 521 apply changeset? [ynmpcq?]: y
521 522 1:d11e3596cc1a
522 523 apply changeset? [ynmpcq?]: n
523 524 2:37a1297eb21b
524 525 apply changeset? [ynmpcq?]: n
525 526 3:722f4667af76
526 527 apply changeset? [ynmpcq?]: m
527 528 4:a53251cdf717
528 529 apply changeset? [ynmpcq?]: c
529 530 $ hg log -G --template "{node|short}"
530 531 @ 88be5dde5260
531 532 |\
532 533 | o 722f4667af76
533 534 | |
534 535 | o 37a1297eb21b
535 536 |/
536 537 o 17ab29e464c6
537 538
538 539 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
539 540 > x
540 541 > ?
541 542 > y
542 543 > q
543 544 > EOF
544 545 1:d11e3596cc1a
545 546 apply changeset? [ynmpcq?]: x
546 547 unrecognized response
547 548 apply changeset? [ynmpcq?]: ?
548 549 y: yes, transplant this changeset
549 550 n: no, skip this changeset
550 551 m: merge at this changeset
551 552 p: show patch
552 553 c: commit selected changesets
553 554 q: quit and cancel transplant
554 555 ?: ? (show this help)
555 556 apply changeset? [ynmpcq?]: y
556 557 4:a53251cdf717
557 558 apply changeset? [ynmpcq?]: q
558 559 $ hg heads --template "{node|short}\n"
559 560 88be5dde5260
560 561
561 562 $ cd ..
562 563
563 564
564 565 #if unix-permissions system-sh
565 566
566 567 test filter
567 568
568 569 $ hg init filter
569 570 $ cd filter
570 571 $ cat <<'EOF' >test-filter
571 572 > #!/bin/sh
572 573 > sed 's/r1/r2/' $1 > $1.new
573 574 > mv $1.new $1
574 575 > EOF
575 576 $ chmod +x test-filter
576 577 $ hg transplant -s ../t -b tip -a --filter ./test-filter
577 578 filtering * (glob)
578 579 applying 17ab29e464c6
579 580 17ab29e464c6 transplanted to e9ffc54ea104
580 581 filtering * (glob)
581 582 applying 37a1297eb21b
582 583 37a1297eb21b transplanted to 348b36d0b6a5
583 584 filtering * (glob)
584 585 applying 722f4667af76
585 586 722f4667af76 transplanted to 0aa6979afb95
586 587 filtering * (glob)
587 588 applying a53251cdf717
588 589 a53251cdf717 transplanted to 14f8512272b5
589 590 $ hg log --template '{rev} {parents} {desc}\n'
590 591 3 b3
591 592 2 b2
592 593 1 b1
593 594 0 r2
594 595 $ cd ..
595 596
596 597
597 598 test filter with failed patch
598 599
599 600 $ cd filter
600 601 $ hg up 0
601 602 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
602 603 $ echo foo > b1
603 604 $ hg ci -Am foo
604 605 adding b1
605 606 adding test-filter
606 607 created new head
607 608 $ hg transplant 1 --filter ./test-filter
608 609 filtering * (glob)
609 610 applying 348b36d0b6a5
610 611 file b1 already exists
611 612 1 out of 1 hunks FAILED -- saving rejects to file b1.rej
612 613 patch failed to apply
613 614 abort: fix up the merge and run hg transplant --continue
614 615 [255]
615 616 $ cd ..
616 617
617 618 test environment passed to filter
618 619
619 620 $ hg init filter-environment
620 621 $ cd filter-environment
621 622 $ cat <<'EOF' >test-filter-environment
622 623 > #!/bin/sh
623 624 > echo "Transplant by $HGUSER" >> $1
624 625 > echo "Transplant from rev $HGREVISION" >> $1
625 626 > EOF
626 627 $ chmod +x test-filter-environment
627 628 $ hg transplant -s ../t --filter ./test-filter-environment 0
628 629 filtering * (glob)
629 630 applying 17ab29e464c6
630 631 17ab29e464c6 transplanted to 5190e68026a0
631 632
632 633 $ hg log --template '{rev} {parents} {desc}\n'
633 634 0 r1
634 635 Transplant by test
635 636 Transplant from rev 17ab29e464c6ca53e329470efe2a9918ac617a6f
636 637 $ cd ..
637 638
638 639 test transplant with filter handles invalid changelog
639 640
640 641 $ hg init filter-invalid-log
641 642 $ cd filter-invalid-log
642 643 $ cat <<'EOF' >test-filter-invalid-log
643 644 > #!/bin/sh
644 645 > echo "" > $1
645 646 > EOF
646 647 $ chmod +x test-filter-invalid-log
647 648 $ hg transplant -s ../t --filter ./test-filter-invalid-log 0
648 649 filtering * (glob)
649 650 abort: filter corrupted changeset (no user or date)
650 651 [255]
651 652 $ cd ..
652 653
653 654 #endif
654 655
655 656
656 657 test with a win32ext like setup (differing EOLs)
657 658
658 659 $ hg init twin1
659 660 $ cd twin1
660 661 $ echo a > a
661 662 $ echo b > b
662 663 $ echo b >> b
663 664 $ hg ci -Am t
664 665 adding a
665 666 adding b
666 667 $ echo a > b
667 668 $ echo b >> b
668 669 $ hg ci -m changeb
669 670 $ cd ..
670 671
671 672 $ hg init twin2
672 673 $ cd twin2
673 674 $ echo '[patch]' >> .hg/hgrc
674 675 $ echo 'eol = crlf' >> .hg/hgrc
675 676 $ $PYTHON -c "file('b', 'wb').write('b\r\nb\r\n')"
676 677 $ hg ci -Am addb
677 678 adding b
678 679 $ hg transplant -s ../twin1 tip
679 680 searching for changes
680 681 warning: repository is unrelated
681 682 applying 2e849d776c17
682 683 2e849d776c17 transplanted to 8e65bebc063e
683 684 $ cat b
684 685 a\r (esc)
685 686 b\r (esc)
686 687 $ cd ..
687 688
688 689 test transplant with merge changeset is skipped
689 690
690 691 $ hg init merge1a
691 692 $ cd merge1a
692 693 $ echo a > a
693 694 $ hg ci -Am a
694 695 adding a
695 696 $ hg branch b
696 697 marked working directory as branch b
697 698 (branches are permanent and global, did you want a bookmark?)
698 699 $ hg ci -m branchb
699 700 $ echo b > b
700 701 $ hg ci -Am b
701 702 adding b
702 703 $ hg update default
703 704 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
704 705 $ hg merge b
705 706 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
706 707 (branch merge, don't forget to commit)
707 708 $ hg ci -m mergeb
708 709 $ cd ..
709 710
710 711 $ hg init merge1b
711 712 $ cd merge1b
712 713 $ hg transplant -s ../merge1a tip
713 714 $ cd ..
714 715
715 716 test transplant with merge changeset accepts --parent
716 717
717 718 $ hg init merge2a
718 719 $ cd merge2a
719 720 $ echo a > a
720 721 $ hg ci -Am a
721 722 adding a
722 723 $ hg branch b
723 724 marked working directory as branch b
724 725 (branches are permanent and global, did you want a bookmark?)
725 726 $ hg ci -m branchb
726 727 $ echo b > b
727 728 $ hg ci -Am b
728 729 adding b
729 730 $ hg update default
730 731 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
731 732 $ hg merge b
732 733 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
733 734 (branch merge, don't forget to commit)
734 735 $ hg ci -m mergeb
735 736 $ cd ..
736 737
737 738 $ hg init merge2b
738 739 $ cd merge2b
739 740 $ hg transplant -s ../merge2a --parent 0 tip
740 741 applying be9f9b39483f
741 742 be9f9b39483f transplanted to 9959e51f94d1
742 743 $ cd ..
743 744
744 745 test transplanting a patch turning into a no-op
745 746
746 747 $ hg init binarysource
747 748 $ cd binarysource
748 749 $ echo a > a
749 750 $ hg ci -Am adda a
750 751 >>> file('b', 'wb').write('\0b1')
751 752 $ hg ci -Am addb b
752 753 >>> file('b', 'wb').write('\0b2')
753 754 $ hg ci -m changeb b
754 755 $ cd ..
755 756
756 757 $ hg clone -r0 binarysource binarydest
757 758 adding changesets
758 759 adding manifests
759 760 adding file changes
760 761 added 1 changesets with 1 changes to 1 files
761 762 updating to branch default
762 763 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
763 764 $ cd binarydest
764 765 $ cp ../binarysource/b b
765 766 $ hg ci -Am addb2 b
766 767 $ hg transplant -s ../binarysource 2
767 768 searching for changes
768 769 applying 7a7d57e15850
769 770 skipping emptied changeset 7a7d57e15850
770 771 $ cd ..
771 772
772 773 Explicitly kill daemons to let the test exit on Windows
773 774
774 775 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
775 776
General Comments 0
You need to be logged in to leave comments. Login now