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