##// END OF EJS Templates
convert: update 'intermediate-source' in the destination's extras dictionary
Matt Harbison -
r25589:273d9425 default
parent child Browse files
Show More
@@ -1,560 +1,561
1 1 # hg.py - hg backend for convert extension
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
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 # Notes for hg->hg conversion:
9 9 #
10 10 # * Old versions of Mercurial didn't trim the whitespace from the ends
11 11 # of commit messages, but new versions do. Changesets created by
12 12 # those older versions, then converted, may thus have different
13 13 # hashes for changesets that are otherwise identical.
14 14 #
15 15 # * Using "--config convert.hg.saverev=true" will make the source
16 16 # identifier to be stored in the converted revision. This will cause
17 17 # the converted revision to have a different identity than the
18 18 # source.
19 19
20 20
21 21 import os, time, cStringIO
22 22 from mercurial.i18n import _
23 23 from mercurial.node import bin, hex, nullid
24 24 from mercurial import hg, util, context, bookmarks, error, scmutil, exchange
25 25 from mercurial import phases
26 26
27 27 from common import NoRepo, commit, converter_source, converter_sink, mapfile
28 28
29 29 import re
30 30 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
31 31
32 32 class mercurial_sink(converter_sink):
33 33 def __init__(self, ui, path):
34 34 converter_sink.__init__(self, ui, path)
35 35 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
36 36 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
37 37 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
38 38 self.lastbranch = None
39 39 if os.path.isdir(path) and len(os.listdir(path)) > 0:
40 40 try:
41 41 self.repo = hg.repository(self.ui, path)
42 42 if not self.repo.local():
43 43 raise NoRepo(_('%s is not a local Mercurial repository')
44 44 % path)
45 45 except error.RepoError, err:
46 46 ui.traceback()
47 47 raise NoRepo(err.args[0])
48 48 else:
49 49 try:
50 50 ui.status(_('initializing destination %s repository\n') % path)
51 51 self.repo = hg.repository(self.ui, path, create=True)
52 52 if not self.repo.local():
53 53 raise NoRepo(_('%s is not a local Mercurial repository')
54 54 % path)
55 55 self.created.append(path)
56 56 except error.RepoError:
57 57 ui.traceback()
58 58 raise NoRepo(_("could not create hg repository %s as sink")
59 59 % path)
60 60 self.lock = None
61 61 self.wlock = None
62 62 self.filemapmode = False
63 63 self.subrevmaps = {}
64 64
65 65 def before(self):
66 66 self.ui.debug('run hg sink pre-conversion action\n')
67 67 self.wlock = self.repo.wlock()
68 68 self.lock = self.repo.lock()
69 69
70 70 def after(self):
71 71 self.ui.debug('run hg sink post-conversion action\n')
72 72 if self.lock:
73 73 self.lock.release()
74 74 if self.wlock:
75 75 self.wlock.release()
76 76
77 77 def revmapfile(self):
78 78 return self.repo.join("shamap")
79 79
80 80 def authorfile(self):
81 81 return self.repo.join("authormap")
82 82
83 83 def setbranch(self, branch, pbranches):
84 84 if not self.clonebranches:
85 85 return
86 86
87 87 setbranch = (branch != self.lastbranch)
88 88 self.lastbranch = branch
89 89 if not branch:
90 90 branch = 'default'
91 91 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
92 92 if pbranches:
93 93 pbranch = pbranches[0][1]
94 94 else:
95 95 pbranch = 'default'
96 96
97 97 branchpath = os.path.join(self.path, branch)
98 98 if setbranch:
99 99 self.after()
100 100 try:
101 101 self.repo = hg.repository(self.ui, branchpath)
102 102 except Exception:
103 103 self.repo = hg.repository(self.ui, branchpath, create=True)
104 104 self.before()
105 105
106 106 # pbranches may bring revisions from other branches (merge parents)
107 107 # Make sure we have them, or pull them.
108 108 missings = {}
109 109 for b in pbranches:
110 110 try:
111 111 self.repo.lookup(b[0])
112 112 except Exception:
113 113 missings.setdefault(b[1], []).append(b[0])
114 114
115 115 if missings:
116 116 self.after()
117 117 for pbranch, heads in sorted(missings.iteritems()):
118 118 pbranchpath = os.path.join(self.path, pbranch)
119 119 prepo = hg.peer(self.ui, {}, pbranchpath)
120 120 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
121 121 exchange.pull(self.repo, prepo,
122 122 [prepo.lookup(h) for h in heads])
123 123 self.before()
124 124
125 125 def _rewritetags(self, source, revmap, data):
126 126 fp = cStringIO.StringIO()
127 127 for line in data.splitlines():
128 128 s = line.split(' ', 1)
129 129 if len(s) != 2:
130 130 continue
131 131 revid = revmap.get(source.lookuprev(s[0]))
132 132 if not revid:
133 133 if s[0] == hex(nullid):
134 134 revid = s[0]
135 135 else:
136 136 continue
137 137 fp.write('%s %s\n' % (revid, s[1]))
138 138 return fp.getvalue()
139 139
140 140 def _rewritesubstate(self, source, data):
141 141 fp = cStringIO.StringIO()
142 142 for line in data.splitlines():
143 143 s = line.split(' ', 1)
144 144 if len(s) != 2:
145 145 continue
146 146
147 147 revid = s[0]
148 148 subpath = s[1]
149 149 if revid != hex(nullid):
150 150 revmap = self.subrevmaps.get(subpath)
151 151 if revmap is None:
152 152 revmap = mapfile(self.ui,
153 153 self.repo.wjoin(subpath, '.hg/shamap'))
154 154 self.subrevmaps[subpath] = revmap
155 155
156 156 # It is reasonable that one or more of the subrepos don't
157 157 # need to be converted, in which case they can be cloned
158 158 # into place instead of converted. Therefore, only warn
159 159 # once.
160 160 msg = _('no ".hgsubstate" updates will be made for "%s"\n')
161 161 if len(revmap) == 0:
162 162 sub = self.repo.wvfs.reljoin(subpath, '.hg')
163 163
164 164 if self.repo.wvfs.exists(sub):
165 165 self.ui.warn(msg % subpath)
166 166
167 167 newid = revmap.get(revid)
168 168 if not newid:
169 169 if len(revmap) > 0:
170 170 self.ui.warn(_("%s is missing from %s/.hg/shamap\n") %
171 171 (revid, subpath))
172 172 else:
173 173 revid = newid
174 174
175 175 fp.write('%s %s\n' % (revid, subpath))
176 176
177 177 return fp.getvalue()
178 178
179 179 def putcommit(self, files, copies, parents, commit, source, revmap, full,
180 180 cleanp2):
181 181 files = dict(files)
182 182
183 183 def getfilectx(repo, memctx, f):
184 184 if p2ctx and f in cleanp2 and f not in copies:
185 185 self.ui.debug('reusing %s from p2\n' % f)
186 186 return p2ctx[f]
187 187 try:
188 188 v = files[f]
189 189 except KeyError:
190 190 return None
191 191 data, mode = source.getfile(f, v)
192 192 if data is None:
193 193 return None
194 194 if f == '.hgtags':
195 195 data = self._rewritetags(source, revmap, data)
196 196 if f == '.hgsubstate':
197 197 data = self._rewritesubstate(source, data)
198 198 return context.memfilectx(self.repo, f, data, 'l' in mode,
199 199 'x' in mode, copies.get(f))
200 200
201 201 pl = []
202 202 for p in parents:
203 203 if p not in pl:
204 204 pl.append(p)
205 205 parents = pl
206 206 nparents = len(parents)
207 207 if self.filemapmode and nparents == 1:
208 208 m1node = self.repo.changelog.read(bin(parents[0]))[0]
209 209 parent = parents[0]
210 210
211 211 if len(parents) < 2:
212 212 parents.append(nullid)
213 213 if len(parents) < 2:
214 214 parents.append(nullid)
215 215 p2 = parents.pop(0)
216 216
217 217 text = commit.desc
218 218
219 219 sha1s = re.findall(sha1re, text)
220 220 for sha1 in sha1s:
221 221 oldrev = source.lookuprev(sha1)
222 222 newrev = revmap.get(oldrev)
223 223 if newrev is not None:
224 224 text = text.replace(sha1, newrev[:len(sha1)])
225 225
226 226 extra = commit.extra.copy()
227 227
228 for label in ('source', 'transplant_source', 'rebase_source'):
228 for label in ('source', 'transplant_source', 'rebase_source',
229 'intermediate-source'):
229 230 node = extra.get(label)
230 231
231 232 if node is None:
232 233 continue
233 234
234 235 # Only transplant stores its reference in binary
235 236 if label == 'transplant_source':
236 237 node = hex(node)
237 238
238 239 newrev = revmap.get(node)
239 240 if newrev is not None:
240 241 if label == 'transplant_source':
241 242 newrev = bin(newrev)
242 243
243 244 extra[label] = newrev
244 245
245 246 if self.branchnames and commit.branch:
246 247 extra['branch'] = commit.branch
247 248 if commit.rev and commit.saverev:
248 249 extra['convert_revision'] = commit.rev
249 250
250 251 while parents:
251 252 p1 = p2
252 253 p2 = parents.pop(0)
253 254 p2ctx = None
254 255 if p2 != nullid:
255 256 p2ctx = self.repo[p2]
256 257 fileset = set(files)
257 258 if full:
258 259 fileset.update(self.repo[p1])
259 260 fileset.update(self.repo[p2])
260 261 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
261 262 getfilectx, commit.author, commit.date, extra)
262 263
263 264 # We won't know if the conversion changes the node until after the
264 265 # commit, so copy the source's phase for now.
265 266 self.repo.ui.setconfig('phases', 'new-commit',
266 267 phases.phasenames[commit.phase], 'convert')
267 268
268 269 tr = self.repo.transaction("convert")
269 270
270 271 try:
271 272 node = hex(self.repo.commitctx(ctx))
272 273
273 274 # If the node value has changed, but the phase is lower than
274 275 # draft, set it back to draft since it hasn't been exposed
275 276 # anywhere.
276 277 if commit.rev != node:
277 278 ctx = self.repo[node]
278 279 if ctx.phase() < phases.draft:
279 280 phases.retractboundary(self.repo, tr, phases.draft,
280 281 [ctx.node()])
281 282 tr.close()
282 283 finally:
283 284 tr.release()
284 285
285 286 text = "(octopus merge fixup)\n"
286 287 p2 = hex(self.repo.changelog.tip())
287 288
288 289 if self.filemapmode and nparents == 1:
289 290 man = self.repo.manifest
290 291 mnode = self.repo.changelog.read(bin(p2))[0]
291 292 closed = 'close' in commit.extra
292 293 if not closed and not man.cmp(m1node, man.revision(mnode)):
293 294 self.ui.status(_("filtering out empty revision\n"))
294 295 self.repo.rollback(force=True)
295 296 return parent
296 297 return p2
297 298
298 299 def puttags(self, tags):
299 300 try:
300 301 parentctx = self.repo[self.tagsbranch]
301 302 tagparent = parentctx.node()
302 303 except error.RepoError:
303 304 parentctx = None
304 305 tagparent = nullid
305 306
306 307 oldlines = set()
307 308 for branch, heads in self.repo.branchmap().iteritems():
308 309 for h in heads:
309 310 if '.hgtags' in self.repo[h]:
310 311 oldlines.update(
311 312 set(self.repo[h]['.hgtags'].data().splitlines(True)))
312 313 oldlines = sorted(list(oldlines))
313 314
314 315 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
315 316 if newlines == oldlines:
316 317 return None, None
317 318
318 319 # if the old and new tags match, then there is nothing to update
319 320 oldtags = set()
320 321 newtags = set()
321 322 for line in oldlines:
322 323 s = line.strip().split(' ', 1)
323 324 if len(s) != 2:
324 325 continue
325 326 oldtags.add(s[1])
326 327 for line in newlines:
327 328 s = line.strip().split(' ', 1)
328 329 if len(s) != 2:
329 330 continue
330 331 if s[1] not in oldtags:
331 332 newtags.add(s[1].strip())
332 333
333 334 if not newtags:
334 335 return None, None
335 336
336 337 data = "".join(newlines)
337 338 def getfilectx(repo, memctx, f):
338 339 return context.memfilectx(repo, f, data, False, False, None)
339 340
340 341 self.ui.status(_("updating tags\n"))
341 342 date = "%s 0" % int(time.mktime(time.gmtime()))
342 343 extra = {'branch': self.tagsbranch}
343 344 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
344 345 [".hgtags"], getfilectx, "convert-repo", date,
345 346 extra)
346 347 self.repo.commitctx(ctx)
347 348 return hex(self.repo.changelog.tip()), hex(tagparent)
348 349
349 350 def setfilemapmode(self, active):
350 351 self.filemapmode = active
351 352
352 353 def putbookmarks(self, updatedbookmark):
353 354 if not len(updatedbookmark):
354 355 return
355 356
356 357 self.ui.status(_("updating bookmarks\n"))
357 358 destmarks = self.repo._bookmarks
358 359 for bookmark in updatedbookmark:
359 360 destmarks[bookmark] = bin(updatedbookmark[bookmark])
360 361 destmarks.write()
361 362
362 363 def hascommitfrommap(self, rev):
363 364 # the exact semantics of clonebranches is unclear so we can't say no
364 365 return rev in self.repo or self.clonebranches
365 366
366 367 def hascommitforsplicemap(self, rev):
367 368 if rev not in self.repo and self.clonebranches:
368 369 raise util.Abort(_('revision %s not found in destination '
369 370 'repository (lookups with clonebranches=true '
370 371 'are not implemented)') % rev)
371 372 return rev in self.repo
372 373
373 374 class mercurial_source(converter_source):
374 375 def __init__(self, ui, path, rev=None):
375 376 converter_source.__init__(self, ui, path, rev)
376 377 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
377 378 self.ignored = set()
378 379 self.saverev = ui.configbool('convert', 'hg.saverev', False)
379 380 try:
380 381 self.repo = hg.repository(self.ui, path)
381 382 # try to provoke an exception if this isn't really a hg
382 383 # repo, but some other bogus compatible-looking url
383 384 if not self.repo.local():
384 385 raise error.RepoError
385 386 except error.RepoError:
386 387 ui.traceback()
387 388 raise NoRepo(_("%s is not a local Mercurial repository") % path)
388 389 self.lastrev = None
389 390 self.lastctx = None
390 391 self._changescache = None, None
391 392 self.convertfp = None
392 393 # Restrict converted revisions to startrev descendants
393 394 startnode = ui.config('convert', 'hg.startrev')
394 395 hgrevs = ui.config('convert', 'hg.revs')
395 396 if hgrevs is None:
396 397 if startnode is not None:
397 398 try:
398 399 startnode = self.repo.lookup(startnode)
399 400 except error.RepoError:
400 401 raise util.Abort(_('%s is not a valid start revision')
401 402 % startnode)
402 403 startrev = self.repo.changelog.rev(startnode)
403 404 children = {startnode: 1}
404 405 for r in self.repo.changelog.descendants([startrev]):
405 406 children[self.repo.changelog.node(r)] = 1
406 407 self.keep = children.__contains__
407 408 else:
408 409 self.keep = util.always
409 410 if rev:
410 411 self._heads = [self.repo[rev].node()]
411 412 else:
412 413 self._heads = self.repo.heads()
413 414 else:
414 415 if rev or startnode is not None:
415 416 raise util.Abort(_('hg.revs cannot be combined with '
416 417 'hg.startrev or --rev'))
417 418 nodes = set()
418 419 parents = set()
419 420 for r in scmutil.revrange(self.repo, [hgrevs]):
420 421 ctx = self.repo[r]
421 422 nodes.add(ctx.node())
422 423 parents.update(p.node() for p in ctx.parents())
423 424 self.keep = nodes.__contains__
424 425 self._heads = nodes - parents
425 426
426 427 def changectx(self, rev):
427 428 if self.lastrev != rev:
428 429 self.lastctx = self.repo[rev]
429 430 self.lastrev = rev
430 431 return self.lastctx
431 432
432 433 def parents(self, ctx):
433 434 return [p for p in ctx.parents() if p and self.keep(p.node())]
434 435
435 436 def getheads(self):
436 437 return [hex(h) for h in self._heads if self.keep(h)]
437 438
438 439 def getfile(self, name, rev):
439 440 try:
440 441 fctx = self.changectx(rev)[name]
441 442 return fctx.data(), fctx.flags()
442 443 except error.LookupError:
443 444 return None, None
444 445
445 446 def getchanges(self, rev, full):
446 447 ctx = self.changectx(rev)
447 448 parents = self.parents(ctx)
448 449 if full or not parents:
449 450 files = copyfiles = ctx.manifest()
450 451 if parents:
451 452 if self._changescache[0] == rev:
452 453 m, a, r = self._changescache[1]
453 454 else:
454 455 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
455 456 if not full:
456 457 files = m + a + r
457 458 copyfiles = m + a
458 459 # getcopies() is also run for roots and before filtering so missing
459 460 # revlogs are detected early
460 461 copies = self.getcopies(ctx, parents, copyfiles)
461 462 cleanp2 = set()
462 463 if len(parents) == 2:
463 464 cleanp2.update(self.repo.status(parents[1].node(), ctx.node(),
464 465 clean=True).clean)
465 466 changes = [(f, rev) for f in files if f not in self.ignored]
466 467 changes.sort()
467 468 return changes, copies, cleanp2
468 469
469 470 def getcopies(self, ctx, parents, files):
470 471 copies = {}
471 472 for name in files:
472 473 if name in self.ignored:
473 474 continue
474 475 try:
475 476 copysource, _copynode = ctx.filectx(name).renamed()
476 477 if copysource in self.ignored:
477 478 continue
478 479 # Ignore copy sources not in parent revisions
479 480 found = False
480 481 for p in parents:
481 482 if copysource in p:
482 483 found = True
483 484 break
484 485 if not found:
485 486 continue
486 487 copies[name] = copysource
487 488 except TypeError:
488 489 pass
489 490 except error.LookupError, e:
490 491 if not self.ignoreerrors:
491 492 raise
492 493 self.ignored.add(name)
493 494 self.ui.warn(_('ignoring: %s\n') % e)
494 495 return copies
495 496
496 497 def getcommit(self, rev):
497 498 ctx = self.changectx(rev)
498 499 parents = [p.hex() for p in self.parents(ctx)]
499 500 crev = rev
500 501
501 502 return commit(author=ctx.user(),
502 503 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
503 504 desc=ctx.description(), rev=crev, parents=parents,
504 505 branch=ctx.branch(), extra=ctx.extra(),
505 506 sortkey=ctx.rev(), saverev=self.saverev,
506 507 phase=ctx.phase())
507 508
508 509 def gettags(self):
509 510 # This will get written to .hgtags, filter non global tags out.
510 511 tags = [t for t in self.repo.tagslist()
511 512 if self.repo.tagtype(t[0]) == 'global']
512 513 return dict([(name, hex(node)) for name, node in tags
513 514 if self.keep(node)])
514 515
515 516 def getchangedfiles(self, rev, i):
516 517 ctx = self.changectx(rev)
517 518 parents = self.parents(ctx)
518 519 if not parents and i is None:
519 520 i = 0
520 521 changes = [], ctx.manifest().keys(), []
521 522 else:
522 523 i = i or 0
523 524 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
524 525 changes = [[f for f in l if f not in self.ignored] for l in changes]
525 526
526 527 if i == 0:
527 528 self._changescache = (rev, changes)
528 529
529 530 return changes[0] + changes[1] + changes[2]
530 531
531 532 def converted(self, rev, destrev):
532 533 if self.convertfp is None:
533 534 self.convertfp = open(self.repo.join('shamap'), 'a')
534 535 self.convertfp.write('%s %s\n' % (destrev, rev))
535 536 self.convertfp.flush()
536 537
537 538 def before(self):
538 539 self.ui.debug('run hg source pre-conversion action\n')
539 540
540 541 def after(self):
541 542 self.ui.debug('run hg source post-conversion action\n')
542 543
543 544 def hasnativeorder(self):
544 545 return True
545 546
546 547 def hasnativeclose(self):
547 548 return True
548 549
549 550 def lookuprev(self, rev):
550 551 try:
551 552 return hex(self.repo.lookup(rev))
552 553 except (error.RepoError, error.LookupError):
553 554 return None
554 555
555 556 def getbookmarks(self):
556 557 return bookmarks.listbookmarks(self.repo)
557 558
558 559 def checkrevformat(self, revstr, mapname='splicemap'):
559 560 """ Mercurial, revision string is a 40 byte hex """
560 561 self.checkhexformat(revstr, mapname)
@@ -1,769 +1,771
1 1 Create a repo with some stuff in it:
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ echo a > a
6 6 $ echo a > d
7 7 $ echo a > e
8 8 $ hg ci -qAm0
9 9 $ echo b > a
10 10 $ hg ci -m1 -u bar
11 11 $ hg mv a b
12 12 $ hg ci -m2
13 13 $ hg cp b c
14 14 $ hg ci -m3 -u baz
15 15 $ echo b > d
16 16 $ echo f > e
17 17 $ hg ci -m4
18 18 $ hg up -q 3
19 19 $ echo b > e
20 20 $ hg branch -q stable
21 21 $ hg ci -m5
22 22 $ hg merge -q default --tool internal:local
23 23 $ hg branch -q default
24 24 $ hg ci -m6
25 25 $ hg phase --public 3
26 26 $ hg phase --force --secret 6
27 27
28 28 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
29 29 @ test@6.secret: 6
30 30 |\
31 31 | o test@5.draft: 5
32 32 | |
33 33 o | test@4.draft: 4
34 34 |/
35 35 o baz@3.public: 3
36 36 |
37 37 o test@2.public: 2
38 38 |
39 39 o bar@1.public: 1
40 40 |
41 41 o test@0.public: 0
42 42
43 43
44 44 Need to specify a rev:
45 45
46 46 $ hg graft
47 47 abort: no revisions specified
48 48 [255]
49 49
50 50 Can't graft ancestor:
51 51
52 52 $ hg graft 1 2
53 53 skipping ancestor revision 1:5d205f8b35b6
54 54 skipping ancestor revision 2:5c095ad7e90f
55 55 [255]
56 56
57 57 Specify revisions with -r:
58 58
59 59 $ hg graft -r 1 -r 2
60 60 skipping ancestor revision 1:5d205f8b35b6
61 61 skipping ancestor revision 2:5c095ad7e90f
62 62 [255]
63 63
64 64 $ hg graft -r 1 2
65 65 skipping ancestor revision 2:5c095ad7e90f
66 66 skipping ancestor revision 1:5d205f8b35b6
67 67 [255]
68 68
69 69 Can't graft with dirty wd:
70 70
71 71 $ hg up -q 0
72 72 $ echo foo > a
73 73 $ hg graft 1
74 74 abort: uncommitted changes
75 75 [255]
76 76 $ hg revert a
77 77
78 78 Graft a rename:
79 79 (this also tests that editor is invoked if '--edit' is specified)
80 80
81 81 $ hg status --rev "2^1" --rev 2
82 82 A b
83 83 R a
84 84 $ HGEDITOR=cat hg graft 2 -u foo --edit
85 85 grafting 2:5c095ad7e90f "2"
86 86 merging a and b to b
87 87 2
88 88
89 89
90 90 HG: Enter commit message. Lines beginning with 'HG:' are removed.
91 91 HG: Leave message empty to abort commit.
92 92 HG: --
93 93 HG: user: foo
94 94 HG: branch 'default'
95 95 HG: added b
96 96 HG: removed a
97 97 $ hg export tip --git
98 98 # HG changeset patch
99 99 # User foo
100 100 # Date 0 0
101 101 # Thu Jan 01 00:00:00 1970 +0000
102 102 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
103 103 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
104 104 2
105 105
106 106 diff --git a/a b/b
107 107 rename from a
108 108 rename to b
109 109
110 110 Look for extra:source
111 111
112 112 $ hg log --debug -r tip
113 113 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
114 114 tag: tip
115 115 phase: draft
116 116 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
117 117 parent: -1:0000000000000000000000000000000000000000
118 118 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
119 119 user: foo
120 120 date: Thu Jan 01 00:00:00 1970 +0000
121 121 files+: b
122 122 files-: a
123 123 extra: branch=default
124 124 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
125 125 description:
126 126 2
127 127
128 128
129 129
130 130 Graft out of order, skipping a merge and a duplicate
131 131 (this also tests that editor is not invoked if '--edit' is not specified)
132 132
133 133 $ hg graft 1 5 4 3 'merge()' 2 -n
134 134 skipping ungraftable merge revision 6
135 135 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
136 136 grafting 1:5d205f8b35b6 "1"
137 137 grafting 5:97f8bfe72746 "5"
138 138 grafting 4:9c233e8e184d "4"
139 139 grafting 3:4c60f11aa304 "3"
140 140
141 141 $ HGEDITOR=cat hg graft 1 5 4 3 'merge()' 2 --debug
142 142 skipping ungraftable merge revision 6
143 143 scanning for duplicate grafts
144 144 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
145 145 grafting 1:5d205f8b35b6 "1"
146 146 searching for copies back to rev 1
147 147 unmatched files in local:
148 148 b
149 149 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
150 150 src: 'a' -> dst: 'b' *
151 151 checking for directory renames
152 152 resolving manifests
153 153 branchmerge: True, force: True, partial: False
154 154 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
155 155 preserving b for resolve of b
156 156 b: local copied/moved from a -> m
157 157 picked tool 'internal:merge' for b (binary False symlink False)
158 158 merging b and a to b
159 159 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
160 160 premerge successful
161 161 committing files:
162 162 b
163 163 committing manifest
164 164 committing changelog
165 165 grafting 5:97f8bfe72746 "5"
166 166 searching for copies back to rev 1
167 167 resolving manifests
168 168 branchmerge: True, force: True, partial: False
169 169 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
170 170 e: remote is newer -> g
171 171 getting e
172 172 b: remote unchanged -> k
173 173 committing files:
174 174 e
175 175 committing manifest
176 176 committing changelog
177 177 grafting 4:9c233e8e184d "4"
178 178 searching for copies back to rev 1
179 179 resolving manifests
180 180 branchmerge: True, force: True, partial: False
181 181 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
182 182 preserving e for resolve of e
183 183 d: remote is newer -> g
184 184 getting d
185 185 b: remote unchanged -> k
186 186 e: versions differ -> m
187 187 picked tool 'internal:merge' for e (binary False symlink False)
188 188 merging e
189 189 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
190 190 warning: conflicts during merge.
191 191 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
192 192 abort: unresolved conflicts, can't continue
193 193 (use hg resolve and hg graft --continue)
194 194 [255]
195 195
196 196 Commit while interrupted should fail:
197 197
198 198 $ hg ci -m 'commit interrupted graft'
199 199 abort: graft in progress
200 200 (use 'hg graft --continue' or 'hg update' to abort)
201 201 [255]
202 202
203 203 Abort the graft and try committing:
204 204
205 205 $ hg up -C .
206 206 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 207 $ echo c >> e
208 208 $ hg ci -mtest
209 209
210 210 $ hg strip . --config extensions.strip=
211 211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 212 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
213 213
214 214 Graft again:
215 215
216 216 $ hg graft 1 5 4 3 'merge()' 2
217 217 skipping ungraftable merge revision 6
218 218 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
219 219 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
220 220 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
221 221 grafting 4:9c233e8e184d "4"
222 222 merging e
223 223 warning: conflicts during merge.
224 224 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
225 225 abort: unresolved conflicts, can't continue
226 226 (use hg resolve and hg graft --continue)
227 227 [255]
228 228
229 229 Continue without resolve should fail:
230 230
231 231 $ hg graft -c
232 232 grafting 4:9c233e8e184d "4"
233 233 abort: unresolved merge conflicts (see "hg help resolve")
234 234 [255]
235 235
236 236 Fix up:
237 237
238 238 $ echo b > e
239 239 $ hg resolve -m e
240 240 (no more unresolved files)
241 241
242 242 Continue with a revision should fail:
243 243
244 244 $ hg graft -c 6
245 245 abort: can't specify --continue and revisions
246 246 [255]
247 247
248 248 $ hg graft -c -r 6
249 249 abort: can't specify --continue and revisions
250 250 [255]
251 251
252 252 Continue for real, clobber usernames
253 253
254 254 $ hg graft -c -U
255 255 grafting 4:9c233e8e184d "4"
256 256 grafting 3:4c60f11aa304 "3"
257 257
258 258 Compare with original:
259 259
260 260 $ hg diff -r 6
261 261 $ hg status --rev 0:. -C
262 262 M d
263 263 M e
264 264 A b
265 265 a
266 266 A c
267 267 a
268 268 R a
269 269
270 270 View graph:
271 271
272 272 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
273 273 @ test@11.draft: 3
274 274 |
275 275 o test@10.draft: 4
276 276 |
277 277 o test@9.draft: 5
278 278 |
279 279 o bar@8.draft: 1
280 280 |
281 281 o foo@7.draft: 2
282 282 |
283 283 | o test@6.secret: 6
284 284 | |\
285 285 | | o test@5.draft: 5
286 286 | | |
287 287 | o | test@4.draft: 4
288 288 | |/
289 289 | o baz@3.public: 3
290 290 | |
291 291 | o test@2.public: 2
292 292 | |
293 293 | o bar@1.public: 1
294 294 |/
295 295 o test@0.public: 0
296 296
297 297 Graft again onto another branch should preserve the original source
298 298 $ hg up -q 0
299 299 $ echo 'g'>g
300 300 $ hg add g
301 301 $ hg ci -m 7
302 302 created new head
303 303 $ hg graft 7
304 304 grafting 7:ef0ef43d49e7 "2"
305 305
306 306 $ hg log -r 7 --template '{rev}:{node}\n'
307 307 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
308 308 $ hg log -r 2 --template '{rev}:{node}\n'
309 309 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
310 310
311 311 $ hg log --debug -r tip
312 312 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
313 313 tag: tip
314 314 phase: draft
315 315 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
316 316 parent: -1:0000000000000000000000000000000000000000
317 317 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
318 318 user: foo
319 319 date: Thu Jan 01 00:00:00 1970 +0000
320 320 files+: b
321 321 files-: a
322 322 extra: branch=default
323 323 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
324 324 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
325 325 description:
326 326 2
327 327
328 328
329 329 Disallow grafting an already grafted cset onto its original branch
330 330 $ hg up -q 6
331 331 $ hg graft 7
332 332 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
333 333 [255]
334 334
335 335 Disallow grafting already grafted csets with the same origin onto each other
336 336 $ hg up -q 13
337 337 $ hg graft 2
338 338 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
339 339 [255]
340 340 $ hg graft 7
341 341 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
342 342 [255]
343 343
344 344 $ hg up -q 7
345 345 $ hg graft 2
346 346 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
347 347 [255]
348 348 $ hg graft tip
349 349 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
350 350 [255]
351 351
352 352 Graft with --log
353 353
354 354 $ hg up -Cq 1
355 355 $ hg graft 3 --log -u foo
356 356 grafting 3:4c60f11aa304 "3"
357 357 warning: can't find ancestor for 'c' copied from 'b'!
358 358 $ hg log --template '{rev} {parents} {desc}\n' -r tip
359 359 14 1:5d205f8b35b6 3
360 360 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
361 361
362 362 Resolve conflicted graft
363 363 $ hg up -q 0
364 364 $ echo b > a
365 365 $ hg ci -m 8
366 366 created new head
367 367 $ echo c > a
368 368 $ hg ci -m 9
369 369 $ hg graft 1 --tool internal:fail
370 370 grafting 1:5d205f8b35b6 "1"
371 371 abort: unresolved conflicts, can't continue
372 372 (use hg resolve and hg graft --continue)
373 373 [255]
374 374 $ hg resolve --all
375 375 merging a
376 376 warning: conflicts during merge.
377 377 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
378 378 [1]
379 379 $ cat a
380 380 <<<<<<< local: aaa4406d4f0a - test: 9
381 381 c
382 382 =======
383 383 b
384 384 >>>>>>> other: 5d205f8b35b6 - bar: 1
385 385 $ echo b > a
386 386 $ hg resolve -m a
387 387 (no more unresolved files)
388 388 $ hg graft -c
389 389 grafting 1:5d205f8b35b6 "1"
390 390 $ hg export tip --git
391 391 # HG changeset patch
392 392 # User bar
393 393 # Date 0 0
394 394 # Thu Jan 01 00:00:00 1970 +0000
395 395 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
396 396 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
397 397 1
398 398
399 399 diff --git a/a b/a
400 400 --- a/a
401 401 +++ b/a
402 402 @@ -1,1 +1,1 @@
403 403 -c
404 404 +b
405 405
406 406 Resolve conflicted graft with rename
407 407 $ echo c > a
408 408 $ hg ci -m 10
409 409 $ hg graft 2 --tool internal:fail
410 410 grafting 2:5c095ad7e90f "2"
411 411 abort: unresolved conflicts, can't continue
412 412 (use hg resolve and hg graft --continue)
413 413 [255]
414 414 $ hg resolve --all
415 415 merging a and b to b
416 416 (no more unresolved files)
417 417 $ hg graft -c
418 418 grafting 2:5c095ad7e90f "2"
419 419 $ hg export tip --git
420 420 # HG changeset patch
421 421 # User test
422 422 # Date 0 0
423 423 # Thu Jan 01 00:00:00 1970 +0000
424 424 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
425 425 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
426 426 2
427 427
428 428 diff --git a/a b/b
429 429 rename from a
430 430 rename to b
431 431
432 432 Test simple origin(), with and without args
433 433 $ hg log -r 'origin()'
434 434 changeset: 1:5d205f8b35b6
435 435 user: bar
436 436 date: Thu Jan 01 00:00:00 1970 +0000
437 437 summary: 1
438 438
439 439 changeset: 2:5c095ad7e90f
440 440 user: test
441 441 date: Thu Jan 01 00:00:00 1970 +0000
442 442 summary: 2
443 443
444 444 changeset: 3:4c60f11aa304
445 445 user: baz
446 446 date: Thu Jan 01 00:00:00 1970 +0000
447 447 summary: 3
448 448
449 449 changeset: 4:9c233e8e184d
450 450 user: test
451 451 date: Thu Jan 01 00:00:00 1970 +0000
452 452 summary: 4
453 453
454 454 changeset: 5:97f8bfe72746
455 455 branch: stable
456 456 parent: 3:4c60f11aa304
457 457 user: test
458 458 date: Thu Jan 01 00:00:00 1970 +0000
459 459 summary: 5
460 460
461 461 $ hg log -r 'origin(7)'
462 462 changeset: 2:5c095ad7e90f
463 463 user: test
464 464 date: Thu Jan 01 00:00:00 1970 +0000
465 465 summary: 2
466 466
467 467 Now transplant a graft to test following through copies
468 468 $ hg up -q 0
469 469 $ hg branch -q dev
470 470 $ hg ci -qm "dev branch"
471 471 $ hg --config extensions.transplant= transplant -q 7
472 472 $ hg log -r 'origin(.)'
473 473 changeset: 2:5c095ad7e90f
474 474 user: test
475 475 date: Thu Jan 01 00:00:00 1970 +0000
476 476 summary: 2
477 477
478 478 Test that the graft and transplant markers in extra are converted, allowing
479 479 origin() to still work. Note that these recheck the immediately preceeding two
480 480 tests.
481 481 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
482 482
483 483 The graft case
484 484 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
485 485 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
486 486 branch=default
487 487 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
488 488 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
489 489 $ hg -R ../converted log -r 'origin(7)'
490 490 changeset: 2:e0213322b2c1
491 491 user: test
492 492 date: Thu Jan 01 00:00:00 1970 +0000
493 493 summary: 2
494 494
495 Test that template correctly expands more than one 'extra' (issue4362)
496 $ hg -R ../converted log -r 7 --template "{extras % ' Extra: {extra}\n'}"
495 Test that template correctly expands more than one 'extra' (issue4362), and that
496 'intermediate-source' is converted.
497 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
497 498 Extra: branch=default
498 Extra: convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
499 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
500 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
499 501 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
500 502
501 503 The transplant case
502 504 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
503 505 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
504 506 branch=dev
505 507 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
506 508 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
507 509 `h\x9b (esc)
508 510 $ hg -R ../converted log -r 'origin(tip)'
509 511 changeset: 2:e0213322b2c1
510 512 user: test
511 513 date: Thu Jan 01 00:00:00 1970 +0000
512 514 summary: 2
513 515
514 516
515 517 Test simple destination
516 518 $ hg log -r 'destination()'
517 519 changeset: 7:ef0ef43d49e7
518 520 parent: 0:68795b066622
519 521 user: foo
520 522 date: Thu Jan 01 00:00:00 1970 +0000
521 523 summary: 2
522 524
523 525 changeset: 8:6b9e5368ca4e
524 526 user: bar
525 527 date: Thu Jan 01 00:00:00 1970 +0000
526 528 summary: 1
527 529
528 530 changeset: 9:1905859650ec
529 531 user: test
530 532 date: Thu Jan 01 00:00:00 1970 +0000
531 533 summary: 5
532 534
533 535 changeset: 10:52dc0b4c6907
534 536 user: test
535 537 date: Thu Jan 01 00:00:00 1970 +0000
536 538 summary: 4
537 539
538 540 changeset: 11:882b35362a6b
539 541 user: test
540 542 date: Thu Jan 01 00:00:00 1970 +0000
541 543 summary: 3
542 544
543 545 changeset: 13:7a4785234d87
544 546 user: foo
545 547 date: Thu Jan 01 00:00:00 1970 +0000
546 548 summary: 2
547 549
548 550 changeset: 14:f64defefacee
549 551 parent: 1:5d205f8b35b6
550 552 user: foo
551 553 date: Thu Jan 01 00:00:00 1970 +0000
552 554 summary: 3
553 555
554 556 changeset: 17:f67661df0c48
555 557 user: bar
556 558 date: Thu Jan 01 00:00:00 1970 +0000
557 559 summary: 1
558 560
559 561 changeset: 19:9627f653b421
560 562 user: test
561 563 date: Thu Jan 01 00:00:00 1970 +0000
562 564 summary: 2
563 565
564 566 changeset: 21:7e61b508e709
565 567 branch: dev
566 568 tag: tip
567 569 user: foo
568 570 date: Thu Jan 01 00:00:00 1970 +0000
569 571 summary: 2
570 572
571 573 $ hg log -r 'destination(2)'
572 574 changeset: 7:ef0ef43d49e7
573 575 parent: 0:68795b066622
574 576 user: foo
575 577 date: Thu Jan 01 00:00:00 1970 +0000
576 578 summary: 2
577 579
578 580 changeset: 13:7a4785234d87
579 581 user: foo
580 582 date: Thu Jan 01 00:00:00 1970 +0000
581 583 summary: 2
582 584
583 585 changeset: 19:9627f653b421
584 586 user: test
585 587 date: Thu Jan 01 00:00:00 1970 +0000
586 588 summary: 2
587 589
588 590 changeset: 21:7e61b508e709
589 591 branch: dev
590 592 tag: tip
591 593 user: foo
592 594 date: Thu Jan 01 00:00:00 1970 +0000
593 595 summary: 2
594 596
595 597 Transplants of grafts can find a destination...
596 598 $ hg log -r 'destination(7)'
597 599 changeset: 21:7e61b508e709
598 600 branch: dev
599 601 tag: tip
600 602 user: foo
601 603 date: Thu Jan 01 00:00:00 1970 +0000
602 604 summary: 2
603 605
604 606 ... grafts of grafts unfortunately can't
605 607 $ hg graft -q 13
606 608 warning: can't find ancestor for 'b' copied from 'a'!
607 609 $ hg log -r 'destination(13)'
608 610 All copies of a cset
609 611 $ hg log -r 'origin(13) or destination(origin(13))'
610 612 changeset: 2:5c095ad7e90f
611 613 user: test
612 614 date: Thu Jan 01 00:00:00 1970 +0000
613 615 summary: 2
614 616
615 617 changeset: 7:ef0ef43d49e7
616 618 parent: 0:68795b066622
617 619 user: foo
618 620 date: Thu Jan 01 00:00:00 1970 +0000
619 621 summary: 2
620 622
621 623 changeset: 13:7a4785234d87
622 624 user: foo
623 625 date: Thu Jan 01 00:00:00 1970 +0000
624 626 summary: 2
625 627
626 628 changeset: 19:9627f653b421
627 629 user: test
628 630 date: Thu Jan 01 00:00:00 1970 +0000
629 631 summary: 2
630 632
631 633 changeset: 21:7e61b508e709
632 634 branch: dev
633 635 user: foo
634 636 date: Thu Jan 01 00:00:00 1970 +0000
635 637 summary: 2
636 638
637 639 changeset: 22:d1cb6591fa4b
638 640 branch: dev
639 641 tag: tip
640 642 user: foo
641 643 date: Thu Jan 01 00:00:00 1970 +0000
642 644 summary: 2
643 645
644 646
645 647 graft works on complex revset
646 648
647 649 $ hg graft 'origin(13) or destination(origin(13))'
648 650 skipping ancestor revision 21:7e61b508e709
649 651 skipping ancestor revision 22:d1cb6591fa4b
650 652 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
651 653 grafting 7:ef0ef43d49e7 "2"
652 654 warning: can't find ancestor for 'b' copied from 'a'!
653 655 grafting 13:7a4785234d87 "2"
654 656 warning: can't find ancestor for 'b' copied from 'a'!
655 657 grafting 19:9627f653b421 "2"
656 658 merging b
657 659 warning: can't find ancestor for 'b' copied from 'a'!
658 660
659 661 graft with --force (still doesn't graft merges)
660 662
661 663 $ hg graft 19 0 6
662 664 skipping ungraftable merge revision 6
663 665 skipping ancestor revision 0:68795b066622
664 666 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
665 667 [255]
666 668 $ hg graft 19 0 6 --force
667 669 skipping ungraftable merge revision 6
668 670 grafting 19:9627f653b421 "2"
669 671 merging b
670 672 warning: can't find ancestor for 'b' copied from 'a'!
671 673 grafting 0:68795b066622 "0"
672 674
673 675 graft --force after backout
674 676
675 677 $ echo abc > a
676 678 $ hg ci -m 28
677 679 $ hg backout 28
678 680 reverting a
679 681 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
680 682 $ hg graft 28
681 683 skipping ancestor revision 28:50a516bb8b57
682 684 [255]
683 685 $ hg graft 28 --force
684 686 grafting 28:50a516bb8b57 "28"
685 687 merging a
686 688 $ cat a
687 689 abc
688 690
689 691 graft --continue after --force
690 692
691 693 $ echo def > a
692 694 $ hg ci -m 31
693 695 $ hg graft 28 --force --tool internal:fail
694 696 grafting 28:50a516bb8b57 "28"
695 697 abort: unresolved conflicts, can't continue
696 698 (use hg resolve and hg graft --continue)
697 699 [255]
698 700 $ hg resolve --all
699 701 merging a
700 702 warning: conflicts during merge.
701 703 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
702 704 [1]
703 705 $ echo abc > a
704 706 $ hg resolve -m a
705 707 (no more unresolved files)
706 708 $ hg graft -c
707 709 grafting 28:50a516bb8b57 "28"
708 710 $ cat a
709 711 abc
710 712
711 713 Continue testing same origin policy, using revision numbers from test above
712 714 but do some destructive editing of the repo:
713 715
714 716 $ hg up -qC 7
715 717 $ hg tag -l -r 13 tmp
716 718 $ hg --config extensions.strip= strip 2
717 719 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
718 720 $ hg graft tmp
719 721 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
720 722 [255]
721 723
722 724 Empty graft
723 725
724 726 $ hg up -qr 26
725 727 $ hg tag -f something
726 728 $ hg graft -qr 27
727 729 $ hg graft -f 27
728 730 grafting 27:ed6c7e54e319 "28"
729 731 note: graft of 27:ed6c7e54e319 created no changes to commit
730 732
731 733 $ cd ..
732 734
733 735 Graft to duplicate a commit
734 736
735 737 $ hg init graftsibling
736 738 $ cd graftsibling
737 739 $ touch a
738 740 $ hg commit -qAm a
739 741 $ touch b
740 742 $ hg commit -qAm b
741 743 $ hg log -G -T '{rev}\n'
742 744 @ 1
743 745 |
744 746 o 0
745 747
746 748 $ hg up -q 0
747 749 $ hg graft -r 1
748 750 grafting 1:0e067c57feba "b" (tip)
749 751 $ hg log -G -T '{rev}\n'
750 752 @ 2
751 753 |
752 754 | o 1
753 755 |/
754 756 o 0
755 757
756 758 Graft to duplicate a commit twice
757 759
758 760 $ hg up -q 0
759 761 $ hg graft -r 2
760 762 grafting 2:044ec77f6389 "b" (tip)
761 763 $ hg log -G -T '{rev}\n'
762 764 @ 3
763 765 |
764 766 | o 2
765 767 |/
766 768 | o 1
767 769 |/
768 770 o 0
769 771
General Comments 0
You need to be logged in to leave comments. Login now