##// END OF EJS Templates
Merge with crew-stable
Martin Geisler -
r9435:aa92ce95 merge default
parent child Browse files
Show More
@@ -1,606 +1,606 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, incorporated herein by reference.
7 7
8 8 '''command to transplant changesets from another branch
9 9
10 10 This extension allows you to transplant patches from another branch.
11 11
12 12 Transplanted patches are recorded in .hg/transplant/transplants, as a
13 13 map from a changeset hash to its hash in the source repository.
14 14 '''
15 15
16 16 from mercurial.i18n import _
17 17 import os, tempfile
18 18 from mercurial import bundlerepo, changegroup, cmdutil, hg, merge, match
19 19 from mercurial import patch, revlog, util, error
20 20
21 21 class transplantentry(object):
22 22 def __init__(self, lnode, rnode):
23 23 self.lnode = lnode
24 24 self.rnode = rnode
25 25
26 26 class transplants(object):
27 27 def __init__(self, path=None, transplantfile=None, opener=None):
28 28 self.path = path
29 29 self.transplantfile = transplantfile
30 30 self.opener = opener
31 31
32 32 if not opener:
33 33 self.opener = util.opener(self.path)
34 34 self.transplants = []
35 35 self.dirty = False
36 36 self.read()
37 37
38 38 def read(self):
39 39 abspath = os.path.join(self.path, self.transplantfile)
40 40 if self.transplantfile and os.path.exists(abspath):
41 41 for line in self.opener(self.transplantfile).read().splitlines():
42 42 lnode, rnode = map(revlog.bin, line.split(':'))
43 43 self.transplants.append(transplantentry(lnode, rnode))
44 44
45 45 def write(self):
46 46 if self.dirty and self.transplantfile:
47 47 if not os.path.isdir(self.path):
48 48 os.mkdir(self.path)
49 49 fp = self.opener(self.transplantfile, 'w')
50 50 for c in self.transplants:
51 51 l, r = map(revlog.hex, (c.lnode, c.rnode))
52 52 fp.write(l + ':' + r + '\n')
53 53 fp.close()
54 54 self.dirty = False
55 55
56 56 def get(self, rnode):
57 57 return [t for t in self.transplants if t.rnode == rnode]
58 58
59 59 def set(self, lnode, rnode):
60 60 self.transplants.append(transplantentry(lnode, rnode))
61 61 self.dirty = True
62 62
63 63 def remove(self, transplant):
64 64 del self.transplants[self.transplants.index(transplant)]
65 65 self.dirty = True
66 66
67 67 class transplanter(object):
68 68 def __init__(self, ui, repo):
69 69 self.ui = ui
70 70 self.path = repo.join('transplant')
71 71 self.opener = util.opener(self.path)
72 72 self.transplants = transplants(self.path, 'transplants',
73 73 opener=self.opener)
74 74
75 75 def applied(self, repo, node, parent):
76 76 '''returns True if a node is already an ancestor of parent
77 77 or has already been transplanted'''
78 78 if hasnode(repo, node):
79 79 if node in repo.changelog.reachable(parent, stop=node):
80 80 return True
81 81 for t in self.transplants.get(node):
82 82 # it might have been stripped
83 83 if not hasnode(repo, t.lnode):
84 84 self.transplants.remove(t)
85 85 return False
86 86 if t.lnode in repo.changelog.reachable(parent, stop=t.lnode):
87 87 return True
88 88 return False
89 89
90 90 def apply(self, repo, source, revmap, merges, opts={}):
91 91 '''apply the revisions in revmap one by one in revision order'''
92 92 revs = sorted(revmap)
93 93 p1, p2 = repo.dirstate.parents()
94 94 pulls = []
95 95 diffopts = patch.diffopts(self.ui, opts)
96 96 diffopts.git = True
97 97
98 98 lock = wlock = None
99 99 try:
100 100 wlock = repo.wlock()
101 101 lock = repo.lock()
102 102 for rev in revs:
103 103 node = revmap[rev]
104 104 revstr = '%s:%s' % (rev, revlog.short(node))
105 105
106 106 if self.applied(repo, node, p1):
107 107 self.ui.warn(_('skipping already applied revision %s\n') %
108 108 revstr)
109 109 continue
110 110
111 111 parents = source.changelog.parents(node)
112 112 if not opts.get('filter'):
113 113 # If the changeset parent is the same as the
114 114 # wdir's parent, just pull it.
115 115 if parents[0] == p1:
116 116 pulls.append(node)
117 117 p1 = node
118 118 continue
119 119 if pulls:
120 120 if source != repo:
121 121 repo.pull(source, heads=pulls)
122 122 merge.update(repo, pulls[-1], False, False, None)
123 123 p1, p2 = repo.dirstate.parents()
124 124 pulls = []
125 125
126 126 domerge = False
127 127 if node in merges:
128 128 # pulling all the merge revs at once would mean we
129 129 # couldn't transplant after the latest even if
130 130 # transplants before them fail.
131 131 domerge = True
132 132 if not hasnode(repo, node):
133 133 repo.pull(source, heads=[node])
134 134
135 135 if parents[1] != revlog.nullid:
136 136 self.ui.note(_('skipping merge changeset %s:%s\n')
137 137 % (rev, revlog.short(node)))
138 138 patchfile = None
139 139 else:
140 140 fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
141 141 fp = os.fdopen(fd, 'w')
142 142 gen = patch.diff(source, parents[0], node, opts=diffopts)
143 143 for chunk in gen:
144 144 fp.write(chunk)
145 145 fp.close()
146 146
147 147 del revmap[rev]
148 148 if patchfile or domerge:
149 149 try:
150 150 n = self.applyone(repo, node,
151 151 source.changelog.read(node),
152 152 patchfile, merge=domerge,
153 153 log=opts.get('log'),
154 154 filter=opts.get('filter'))
155 155 if n and domerge:
156 156 self.ui.status(_('%s merged at %s\n') % (revstr,
157 157 revlog.short(n)))
158 158 elif n:
159 159 self.ui.status(_('%s transplanted to %s\n')
160 160 % (revlog.short(node),
161 161 revlog.short(n)))
162 162 finally:
163 163 if patchfile:
164 164 os.unlink(patchfile)
165 165 if pulls:
166 166 repo.pull(source, heads=pulls)
167 167 merge.update(repo, pulls[-1], False, False, None)
168 168 finally:
169 169 self.saveseries(revmap, merges)
170 170 self.transplants.write()
171 171 lock.release()
172 172 wlock.release()
173 173
174 174 def filter(self, filter, changelog, patchfile):
175 175 '''arbitrarily rewrite changeset before applying it'''
176 176
177 177 self.ui.status(_('filtering %s\n') % patchfile)
178 178 user, date, msg = (changelog[1], changelog[2], changelog[4])
179 179
180 180 fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-')
181 181 fp = os.fdopen(fd, 'w')
182 182 fp.write("# HG changeset patch\n")
183 183 fp.write("# User %s\n" % user)
184 184 fp.write("# Date %d %d\n" % date)
185 fp.write(changelog[4])
185 fp.write(msg + '\n')
186 186 fp.close()
187 187
188 188 try:
189 189 util.system('%s %s %s' % (filter, util.shellquote(headerfile),
190 190 util.shellquote(patchfile)),
191 191 environ={'HGUSER': changelog[1]},
192 192 onerr=util.Abort, errprefix=_('filter failed'))
193 193 user, date, msg = self.parselog(file(headerfile))[1:4]
194 194 finally:
195 195 os.unlink(headerfile)
196 196
197 197 return (user, date, msg)
198 198
199 199 def applyone(self, repo, node, cl, patchfile, merge=False, log=False,
200 200 filter=None):
201 201 '''apply the patch in patchfile to the repository as a transplant'''
202 202 (manifest, user, (time, timezone), files, message) = cl[:5]
203 203 date = "%d %d" % (time, timezone)
204 204 extra = {'transplant_source': node}
205 205 if filter:
206 206 (user, date, message) = self.filter(filter, cl, patchfile)
207 207
208 208 if log:
209 209 # we don't translate messages inserted into commits
210 210 message += '\n(transplanted from %s)' % revlog.hex(node)
211 211
212 212 self.ui.status(_('applying %s\n') % revlog.short(node))
213 213 self.ui.note('%s %s\n%s\n' % (user, date, message))
214 214
215 215 if not patchfile and not merge:
216 216 raise util.Abort(_('can only omit patchfile if merging'))
217 217 if patchfile:
218 218 try:
219 219 files = {}
220 220 try:
221 221 patch.patch(patchfile, self.ui, cwd=repo.root,
222 222 files=files, eolmode=None)
223 223 if not files:
224 224 self.ui.warn(_('%s: empty changeset')
225 225 % revlog.hex(node))
226 226 return None
227 227 finally:
228 228 files = patch.updatedir(self.ui, repo, files)
229 229 except Exception, inst:
230 230 if filter:
231 231 os.unlink(patchfile)
232 232 seriespath = os.path.join(self.path, 'series')
233 233 if os.path.exists(seriespath):
234 234 os.unlink(seriespath)
235 235 p1 = repo.dirstate.parents()[0]
236 236 p2 = node
237 237 self.log(user, date, message, p1, p2, merge=merge)
238 238 self.ui.write(str(inst) + '\n')
239 239 raise util.Abort(_('Fix up the merge and run '
240 240 'hg transplant --continue'))
241 241 else:
242 242 files = None
243 243 if merge:
244 244 p1, p2 = repo.dirstate.parents()
245 245 repo.dirstate.setparents(p1, node)
246 246 m = match.always(repo.root, '')
247 247 else:
248 248 m = match.exact(repo.root, '', files)
249 249
250 250 n = repo.commit(message, user, date, extra=extra, match=m)
251 251 if not merge:
252 252 self.transplants.set(n, node)
253 253
254 254 return n
255 255
256 256 def resume(self, repo, source, opts=None):
257 257 '''recover last transaction and apply remaining changesets'''
258 258 if os.path.exists(os.path.join(self.path, 'journal')):
259 259 n, node = self.recover(repo)
260 260 self.ui.status(_('%s transplanted as %s\n') % (revlog.short(node),
261 261 revlog.short(n)))
262 262 seriespath = os.path.join(self.path, 'series')
263 263 if not os.path.exists(seriespath):
264 264 self.transplants.write()
265 265 return
266 266 nodes, merges = self.readseries()
267 267 revmap = {}
268 268 for n in nodes:
269 269 revmap[source.changelog.rev(n)] = n
270 270 os.unlink(seriespath)
271 271
272 272 self.apply(repo, source, revmap, merges, opts)
273 273
274 274 def recover(self, repo):
275 275 '''commit working directory using journal metadata'''
276 276 node, user, date, message, parents = self.readlog()
277 277 merge = len(parents) == 2
278 278
279 279 if not user or not date or not message or not parents[0]:
280 280 raise util.Abort(_('transplant log file is corrupt'))
281 281
282 282 extra = {'transplant_source': node}
283 283 wlock = repo.wlock()
284 284 try:
285 285 p1, p2 = repo.dirstate.parents()
286 286 if p1 != parents[0]:
287 287 raise util.Abort(
288 288 _('working dir not at transplant parent %s') %
289 289 revlog.hex(parents[0]))
290 290 if merge:
291 291 repo.dirstate.setparents(p1, parents[1])
292 292 n = repo.commit(message, user, date, extra=extra)
293 293 if not n:
294 294 raise util.Abort(_('commit failed'))
295 295 if not merge:
296 296 self.transplants.set(n, node)
297 297 self.unlog()
298 298
299 299 return n, node
300 300 finally:
301 301 wlock.release()
302 302
303 303 def readseries(self):
304 304 nodes = []
305 305 merges = []
306 306 cur = nodes
307 307 for line in self.opener('series').read().splitlines():
308 308 if line.startswith('# Merges'):
309 309 cur = merges
310 310 continue
311 311 cur.append(revlog.bin(line))
312 312
313 313 return (nodes, merges)
314 314
315 315 def saveseries(self, revmap, merges):
316 316 if not revmap:
317 317 return
318 318
319 319 if not os.path.isdir(self.path):
320 320 os.mkdir(self.path)
321 321 series = self.opener('series', 'w')
322 322 for rev in sorted(revmap):
323 323 series.write(revlog.hex(revmap[rev]) + '\n')
324 324 if merges:
325 325 series.write('# Merges\n')
326 326 for m in merges:
327 327 series.write(revlog.hex(m) + '\n')
328 328 series.close()
329 329
330 330 def parselog(self, fp):
331 331 parents = []
332 332 message = []
333 333 node = revlog.nullid
334 334 inmsg = False
335 335 for line in fp.read().splitlines():
336 336 if inmsg:
337 337 message.append(line)
338 338 elif line.startswith('# User '):
339 339 user = line[7:]
340 340 elif line.startswith('# Date '):
341 341 date = line[7:]
342 342 elif line.startswith('# Node ID '):
343 343 node = revlog.bin(line[10:])
344 344 elif line.startswith('# Parent '):
345 345 parents.append(revlog.bin(line[9:]))
346 346 elif not line.startswith('#'):
347 347 inmsg = True
348 348 message.append(line)
349 349 return (node, user, date, '\n'.join(message), parents)
350 350
351 351 def log(self, user, date, message, p1, p2, merge=False):
352 352 '''journal changelog metadata for later recover'''
353 353
354 354 if not os.path.isdir(self.path):
355 355 os.mkdir(self.path)
356 356 fp = self.opener('journal', 'w')
357 357 fp.write('# User %s\n' % user)
358 358 fp.write('# Date %s\n' % date)
359 359 fp.write('# Node ID %s\n' % revlog.hex(p2))
360 360 fp.write('# Parent ' + revlog.hex(p1) + '\n')
361 361 if merge:
362 362 fp.write('# Parent ' + revlog.hex(p2) + '\n')
363 363 fp.write(message.rstrip() + '\n')
364 364 fp.close()
365 365
366 366 def readlog(self):
367 367 return self.parselog(self.opener('journal'))
368 368
369 369 def unlog(self):
370 370 '''remove changelog journal'''
371 371 absdst = os.path.join(self.path, 'journal')
372 372 if os.path.exists(absdst):
373 373 os.unlink(absdst)
374 374
375 375 def transplantfilter(self, repo, source, root):
376 376 def matchfn(node):
377 377 if self.applied(repo, node, root):
378 378 return False
379 379 if source.changelog.parents(node)[1] != revlog.nullid:
380 380 return False
381 381 extra = source.changelog.read(node)[5]
382 382 cnode = extra.get('transplant_source')
383 383 if cnode and self.applied(repo, cnode, root):
384 384 return False
385 385 return True
386 386
387 387 return matchfn
388 388
389 389 def hasnode(repo, node):
390 390 try:
391 391 return repo.changelog.rev(node) != None
392 392 except error.RevlogError:
393 393 return False
394 394
395 395 def browserevs(ui, repo, nodes, opts):
396 396 '''interactively transplant changesets'''
397 397 def browsehelp(ui):
398 398 ui.write('y: transplant this changeset\n'
399 399 'n: skip this changeset\n'
400 400 'm: merge at this changeset\n'
401 401 'p: show patch\n'
402 402 'c: commit selected changesets\n'
403 403 'q: cancel transplant\n'
404 404 '?: show this help\n')
405 405
406 406 displayer = cmdutil.show_changeset(ui, repo, opts)
407 407 transplants = []
408 408 merges = []
409 409 for node in nodes:
410 410 displayer.show(repo[node])
411 411 action = None
412 412 while not action:
413 413 action = ui.prompt(_('apply changeset? [ynmpcq?]:'))
414 414 if action == '?':
415 415 browsehelp(ui)
416 416 action = None
417 417 elif action == 'p':
418 418 parent = repo.changelog.parents(node)[0]
419 419 for chunk in patch.diff(repo, parent, node):
420 420 ui.write(chunk)
421 421 action = None
422 422 elif action not in ('y', 'n', 'm', 'c', 'q'):
423 423 ui.write('no such option\n')
424 424 action = None
425 425 if action == 'y':
426 426 transplants.append(node)
427 427 elif action == 'm':
428 428 merges.append(node)
429 429 elif action == 'c':
430 430 break
431 431 elif action == 'q':
432 432 transplants = ()
433 433 merges = ()
434 434 break
435 435 return (transplants, merges)
436 436
437 437 def transplant(ui, repo, *revs, **opts):
438 438 '''transplant changesets from another branch
439 439
440 440 Selected changesets will be applied on top of the current working
441 441 directory with the log of the original changeset. If --log is
442 442 specified, log messages will have a comment appended of the form::
443 443
444 444 (transplanted from CHANGESETHASH)
445 445
446 446 You can rewrite the changelog message with the --filter option.
447 447 Its argument will be invoked with the current changelog message as
448 448 $1 and the patch as $2.
449 449
450 450 If --source/-s is specified, selects changesets from the named
451 451 repository. If --branch/-b is specified, selects changesets from
452 452 the branch holding the named revision, up to that revision. If
453 453 --all/-a is specified, all changesets on the branch will be
454 454 transplanted, otherwise you will be prompted to select the
455 455 changesets you want.
456 456
457 457 hg transplant --branch REVISION --all will rebase the selected
458 458 branch (up to the named revision) onto your current working
459 459 directory.
460 460
461 461 You can optionally mark selected transplanted changesets as merge
462 462 changesets. You will not be prompted to transplant any ancestors
463 463 of a merged transplant, and you can merge descendants of them
464 464 normally instead of transplanting them.
465 465
466 466 If no merges or revisions are provided, hg transplant will start
467 467 an interactive changeset browser.
468 468
469 469 If a changeset application fails, you can fix the merge by hand
470 470 and then resume where you left off by calling hg transplant
471 471 --continue/-c.
472 472 '''
473 473 def getremotechanges(repo, url):
474 474 sourcerepo = ui.expandpath(url)
475 475 source = hg.repository(ui, sourcerepo)
476 476 common, incoming, rheads = repo.findcommonincoming(source, force=True)
477 477 if not incoming:
478 478 return (source, None, None)
479 479
480 480 bundle = None
481 481 if not source.local():
482 482 if source.capable('changegroupsubset'):
483 483 cg = source.changegroupsubset(incoming, rheads, 'incoming')
484 484 else:
485 485 cg = source.changegroup(incoming, 'incoming')
486 486 bundle = changegroup.writebundle(cg, None, 'HG10UN')
487 487 source = bundlerepo.bundlerepository(ui, repo.root, bundle)
488 488
489 489 return (source, incoming, bundle)
490 490
491 491 def incwalk(repo, incoming, branches, match=util.always):
492 492 if not branches:
493 493 branches=None
494 494 for node in repo.changelog.nodesbetween(incoming, branches)[0]:
495 495 if match(node):
496 496 yield node
497 497
498 498 def transplantwalk(repo, root, branches, match=util.always):
499 499 if not branches:
500 500 branches = repo.heads()
501 501 ancestors = []
502 502 for branch in branches:
503 503 ancestors.append(repo.changelog.ancestor(root, branch))
504 504 for node in repo.changelog.nodesbetween(ancestors, branches)[0]:
505 505 if match(node):
506 506 yield node
507 507
508 508 def checkopts(opts, revs):
509 509 if opts.get('continue'):
510 510 if filter(lambda opt: opts.get(opt), ('branch', 'all', 'merge')):
511 511 raise util.Abort(_('--continue is incompatible with '
512 512 'branch, all or merge'))
513 513 return
514 514 if not (opts.get('source') or revs or
515 515 opts.get('merge') or opts.get('branch')):
516 516 raise util.Abort(_('no source URL, branch tag or revision '
517 517 'list provided'))
518 518 if opts.get('all'):
519 519 if not opts.get('branch'):
520 520 raise util.Abort(_('--all requires a branch revision'))
521 521 if revs:
522 522 raise util.Abort(_('--all is incompatible with a '
523 523 'revision list'))
524 524
525 525 checkopts(opts, revs)
526 526
527 527 if not opts.get('log'):
528 528 opts['log'] = ui.config('transplant', 'log')
529 529 if not opts.get('filter'):
530 530 opts['filter'] = ui.config('transplant', 'filter')
531 531
532 532 tp = transplanter(ui, repo)
533 533
534 534 p1, p2 = repo.dirstate.parents()
535 535 if len(repo) > 0 and p1 == revlog.nullid:
536 536 raise util.Abort(_('no revision checked out'))
537 537 if not opts.get('continue'):
538 538 if p2 != revlog.nullid:
539 539 raise util.Abort(_('outstanding uncommitted merges'))
540 540 m, a, r, d = repo.status()[:4]
541 541 if m or a or r or d:
542 542 raise util.Abort(_('outstanding local changes'))
543 543
544 544 bundle = None
545 545 source = opts.get('source')
546 546 if source:
547 547 (source, incoming, bundle) = getremotechanges(repo, source)
548 548 else:
549 549 source = repo
550 550
551 551 try:
552 552 if opts.get('continue'):
553 553 tp.resume(repo, source, opts)
554 554 return
555 555
556 556 tf=tp.transplantfilter(repo, source, p1)
557 557 if opts.get('prune'):
558 558 prune = [source.lookup(r)
559 559 for r in cmdutil.revrange(source, opts.get('prune'))]
560 560 matchfn = lambda x: tf(x) and x not in prune
561 561 else:
562 562 matchfn = tf
563 563 branches = map(source.lookup, opts.get('branch', ()))
564 564 merges = map(source.lookup, opts.get('merge', ()))
565 565 revmap = {}
566 566 if revs:
567 567 for r in cmdutil.revrange(source, revs):
568 568 revmap[int(r)] = source.lookup(r)
569 569 elif opts.get('all') or not merges:
570 570 if source != repo:
571 571 alltransplants = incwalk(source, incoming, branches,
572 572 match=matchfn)
573 573 else:
574 574 alltransplants = transplantwalk(source, p1, branches,
575 575 match=matchfn)
576 576 if opts.get('all'):
577 577 revs = alltransplants
578 578 else:
579 579 revs, newmerges = browserevs(ui, source, alltransplants, opts)
580 580 merges.extend(newmerges)
581 581 for r in revs:
582 582 revmap[source.changelog.rev(r)] = r
583 583 for r in merges:
584 584 revmap[source.changelog.rev(r)] = r
585 585
586 586 tp.apply(repo, source, revmap, merges, opts)
587 587 finally:
588 588 if bundle:
589 589 source.close()
590 590 os.unlink(bundle)
591 591
592 592 cmdtable = {
593 593 "transplant":
594 594 (transplant,
595 595 [('s', 'source', '', _('pull patches from REPOSITORY')),
596 596 ('b', 'branch', [], _('pull patches from branch BRANCH')),
597 597 ('a', 'all', None, _('pull all changesets up to BRANCH')),
598 598 ('p', 'prune', [], _('skip over REV')),
599 599 ('m', 'merge', [], _('merge at REV')),
600 600 ('', 'log', None, _('append transplant info to log message')),
601 601 ('c', 'continue', None, _('continue last transplant session '
602 602 'after repair')),
603 603 ('', 'filter', '', _('filter changesets through FILTER'))],
604 604 _('hg transplant [-s REPOSITORY] [-b BRANCH [-a]] [-p REV] '
605 605 '[-m REV] [REV]...'))
606 606 }
@@ -1,173 +1,173 b''
1 1 #!/bin/sh
2 2
3 3 "$TESTDIR/hghave" git || exit 80
4 4
5 5 echo "[extensions]" >> $HGRCPATH
6 6 echo "convert=" >> $HGRCPATH
7 7 echo 'hgext.graphlog =' >> $HGRCPATH
8 8
9 9 GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
10 10 GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
11 11 GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
12 12 GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
13 13 GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
14 14 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
15 15
16 16 count=10
17 17 commit()
18 18 {
19 19 GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
20 20 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
21 21 git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
22 22 count=`expr $count + 1`
23 23 }
24 24
25 25 mkdir git-repo
26 26 cd git-repo
27 27 git init-db >/dev/null 2>/dev/null
28 28 echo a > a
29 29 mkdir d
30 30 echo b > d/b
31 31 git add a d
32 32 commit -a -m t1
33 33
34 34 # Remove the directory, then try to replace it with a file
35 35 # (issue 754)
36 36 git rm -f d/b
37 37 commit -m t2
38 38 echo d > d
39 39 git add d
40 40 commit -m t3
41 41
42 42 echo b >> a
43 43 commit -a -m t4.1
44 44
45 git checkout -b other HEAD^ >/dev/null 2>/dev/null
45 git checkout -b other HEAD~ >/dev/null 2>/dev/null
46 46 echo c > a
47 47 echo a >> a
48 48 commit -a -m t4.2
49 49
50 50 git checkout master >/dev/null 2>/dev/null
51 51 git pull --no-commit . other > /dev/null 2>/dev/null
52 52 commit -m 'Merge branch other'
53 53 cd ..
54 54
55 55 hg convert --datesort git-repo
56 56 hg up -q -R git-repo-hg
57 57 hg -R git-repo-hg tip -v
58 58
59 59 count=10
60 60 mkdir git-repo2
61 61 cd git-repo2
62 62 git init-db >/dev/null 2>/dev/null
63 63
64 64 echo foo > foo
65 65 git add foo
66 66 commit -a -m 'add foo'
67 67
68 68 echo >> foo
69 69 commit -a -m 'change foo'
70 70
71 git checkout -b Bar HEAD^ >/dev/null 2>/dev/null
71 git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
72 72 echo quux >> quux
73 73 git add quux
74 74 commit -a -m 'add quux'
75 75
76 76 echo bar > bar
77 77 git add bar
78 78 commit -a -m 'add bar'
79 79
80 git checkout -b Baz HEAD^ >/dev/null 2>/dev/null
80 git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
81 81 echo baz > baz
82 82 git add baz
83 83 commit -a -m 'add baz'
84 84
85 85 git checkout master >/dev/null 2>/dev/null
86 86 git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
87 87 commit -m 'Octopus merge'
88 88
89 89 echo bar >> bar
90 90 commit -a -m 'change bar'
91 91
92 git checkout -b Foo HEAD^ >/dev/null 2>/dev/null
92 git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
93 93 echo >> foo
94 94 commit -a -m 'change foo'
95 95
96 96 git checkout master >/dev/null 2>/dev/null
97 97 git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
98 98 commit -m 'Discard change to foo'
99 99
100 100 cd ..
101 101
102 102 glog()
103 103 {
104 104 hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
105 105 }
106 106
107 107 splitrepo()
108 108 {
109 109 msg="$1"
110 110 files="$2"
111 111 opts=$3
112 112 echo "% $files: $msg"
113 113 prefix=`echo "$files" | sed -e 's/ /-/g'`
114 114 fmap="$prefix.fmap"
115 115 repo="$prefix.repo"
116 116 for i in $files; do
117 117 echo "include $i" >> "$fmap"
118 118 done
119 119 hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
120 120 hg up -q -R "$repo"
121 121 glog -R "$repo"
122 122 hg -R "$repo" manifest --debug
123 123 }
124 124
125 125 echo '% full conversion'
126 126 hg -q convert --datesort git-repo2 fullrepo
127 127 hg up -q -R fullrepo
128 128 glog -R fullrepo
129 129 hg -R fullrepo manifest --debug
130 130
131 131 splitrepo 'octopus merge' 'foo bar baz'
132 132
133 133 splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
134 134
135 135 echo
136 136 echo '% test binary conversion (issue 1359)'
137 137 mkdir git-repo3
138 138 cd git-repo3
139 139 git init-db >/dev/null 2>/dev/null
140 140 python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
141 141 git add b
142 142 commit -a -m addbinary
143 143 cd ..
144 144
145 145 echo '% convert binary file'
146 146 hg convert git-repo3 git-repo3-hg
147 147
148 148 cd git-repo3-hg
149 149 hg up -C
150 150 python -c 'print len(file("b", "rb").read())'
151 151 cd ..
152 152
153 153 echo
154 154 echo '% test author vs committer'
155 155 mkdir git-repo4
156 156 cd git-repo4
157 157 git init-db >/dev/null 2>/dev/null
158 158 echo >> foo
159 159 git add foo
160 160 commit -a -m addfoo
161 161 echo >> foo
162 162 GIT_AUTHOR_NAME="nottest"
163 163 commit -a -m addfoo2
164 164 cd ..
165 165
166 166 echo '% convert author committer'
167 167 hg convert git-repo4 git-repo4-hg
168 168 hg -R git-repo4-hg log -v
169 169
170 170 echo '% --sourceorder should fail'
171 171 hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
172 172
173 173 true
General Comments 0
You need to be logged in to leave comments. Login now