##// END OF EJS Templates
rebase: skip resolved but emptied revisions...
Patrick Mezard -
r16509:eab9119c stable
parent child Browse files
Show More
@@ -1,759 +1,767 b''
1 1 # dirstate.py - working directory tracking for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.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 import errno
8 8
9 9 from node import nullid
10 10 from i18n import _
11 11 import scmutil, util, ignore, osutil, parsers, encoding
12 12 import struct, os, stat, errno
13 13 import cStringIO
14 14
15 15 _format = ">cllll"
16 16 propertycache = util.propertycache
17 17 filecache = scmutil.filecache
18 18
19 19 class repocache(filecache):
20 20 """filecache for files in .hg/"""
21 21 def join(self, obj, fname):
22 22 return obj._opener.join(fname)
23 23
24 24 class rootcache(filecache):
25 25 """filecache for files in the repository root"""
26 26 def join(self, obj, fname):
27 27 return obj._join(fname)
28 28
29 29 def _finddirs(path):
30 30 pos = path.rfind('/')
31 31 while pos != -1:
32 32 yield path[:pos]
33 33 pos = path.rfind('/', 0, pos)
34 34
35 35 def _incdirs(dirs, path):
36 36 for base in _finddirs(path):
37 37 if base in dirs:
38 38 dirs[base] += 1
39 39 return
40 40 dirs[base] = 1
41 41
42 42 def _decdirs(dirs, path):
43 43 for base in _finddirs(path):
44 44 if dirs[base] > 1:
45 45 dirs[base] -= 1
46 46 return
47 47 del dirs[base]
48 48
49 49 class dirstate(object):
50 50
51 51 def __init__(self, opener, ui, root, validate):
52 52 '''Create a new dirstate object.
53 53
54 54 opener is an open()-like callable that can be used to open the
55 55 dirstate file; root is the root of the directory tracked by
56 56 the dirstate.
57 57 '''
58 58 self._opener = opener
59 59 self._validate = validate
60 60 self._root = root
61 61 self._rootdir = os.path.join(root, '')
62 62 self._dirty = False
63 63 self._dirtypl = False
64 64 self._lastnormaltime = 0
65 65 self._ui = ui
66 66 self._filecache = {}
67 67
68 68 @propertycache
69 69 def _map(self):
70 70 '''Return the dirstate contents as a map from filename to
71 71 (state, mode, size, time).'''
72 72 self._read()
73 73 return self._map
74 74
75 75 @propertycache
76 76 def _copymap(self):
77 77 self._read()
78 78 return self._copymap
79 79
80 80 @propertycache
81 81 def _foldmap(self):
82 82 f = {}
83 83 for name in self._map:
84 84 f[util.normcase(name)] = name
85 85 for name in self._dirs:
86 86 f[util.normcase(name)] = name
87 87 f['.'] = '.' # prevents useless util.fspath() invocation
88 88 return f
89 89
90 90 @repocache('branch')
91 91 def _branch(self):
92 92 try:
93 93 return self._opener.read("branch").strip() or "default"
94 94 except IOError, inst:
95 95 if inst.errno != errno.ENOENT:
96 96 raise
97 97 return "default"
98 98
99 99 @propertycache
100 100 def _pl(self):
101 101 try:
102 102 fp = self._opener("dirstate")
103 103 st = fp.read(40)
104 104 fp.close()
105 105 l = len(st)
106 106 if l == 40:
107 107 return st[:20], st[20:40]
108 108 elif l > 0 and l < 40:
109 109 raise util.Abort(_('working directory state appears damaged!'))
110 110 except IOError, err:
111 111 if err.errno != errno.ENOENT:
112 112 raise
113 113 return [nullid, nullid]
114 114
115 115 @propertycache
116 116 def _dirs(self):
117 117 dirs = {}
118 118 for f, s in self._map.iteritems():
119 119 if s[0] != 'r':
120 120 _incdirs(dirs, f)
121 121 return dirs
122 122
123 123 def dirs(self):
124 124 return self._dirs
125 125
126 126 @rootcache('.hgignore')
127 127 def _ignore(self):
128 128 files = [self._join('.hgignore')]
129 129 for name, path in self._ui.configitems("ui"):
130 130 if name == 'ignore' or name.startswith('ignore.'):
131 131 files.append(util.expandpath(path))
132 132 return ignore.ignore(self._root, files, self._ui.warn)
133 133
134 134 @propertycache
135 135 def _slash(self):
136 136 return self._ui.configbool('ui', 'slash') and os.sep != '/'
137 137
138 138 @propertycache
139 139 def _checklink(self):
140 140 return util.checklink(self._root)
141 141
142 142 @propertycache
143 143 def _checkexec(self):
144 144 return util.checkexec(self._root)
145 145
146 146 @propertycache
147 147 def _checkcase(self):
148 148 return not util.checkcase(self._join('.hg'))
149 149
150 150 def _join(self, f):
151 151 # much faster than os.path.join()
152 152 # it's safe because f is always a relative path
153 153 return self._rootdir + f
154 154
155 155 def flagfunc(self, buildfallback):
156 156 if self._checklink and self._checkexec:
157 157 def f(x):
158 158 p = self._join(x)
159 159 if os.path.islink(p):
160 160 return 'l'
161 161 if util.isexec(p):
162 162 return 'x'
163 163 return ''
164 164 return f
165 165
166 166 fallback = buildfallback()
167 167 if self._checklink:
168 168 def f(x):
169 169 if os.path.islink(self._join(x)):
170 170 return 'l'
171 171 if 'x' in fallback(x):
172 172 return 'x'
173 173 return ''
174 174 return f
175 175 if self._checkexec:
176 176 def f(x):
177 177 if 'l' in fallback(x):
178 178 return 'l'
179 179 if util.isexec(self._join(x)):
180 180 return 'x'
181 181 return ''
182 182 return f
183 183 else:
184 184 return fallback
185 185
186 186 def getcwd(self):
187 187 cwd = os.getcwd()
188 188 if cwd == self._root:
189 189 return ''
190 190 # self._root ends with a path separator if self._root is '/' or 'C:\'
191 191 rootsep = self._root
192 192 if not util.endswithsep(rootsep):
193 193 rootsep += os.sep
194 194 if cwd.startswith(rootsep):
195 195 return cwd[len(rootsep):]
196 196 else:
197 197 # we're outside the repo. return an absolute path.
198 198 return cwd
199 199
200 200 def pathto(self, f, cwd=None):
201 201 if cwd is None:
202 202 cwd = self.getcwd()
203 203 path = util.pathto(self._root, cwd, f)
204 204 if self._slash:
205 205 return util.normpath(path)
206 206 return path
207 207
208 208 def __getitem__(self, key):
209 209 '''Return the current state of key (a filename) in the dirstate.
210 210
211 211 States are:
212 212 n normal
213 213 m needs merging
214 214 r marked for removal
215 215 a marked for addition
216 216 ? not tracked
217 217 '''
218 218 return self._map.get(key, ("?",))[0]
219 219
220 220 def __contains__(self, key):
221 221 return key in self._map
222 222
223 223 def __iter__(self):
224 224 for x in sorted(self._map):
225 225 yield x
226 226
227 227 def parents(self):
228 228 return [self._validate(p) for p in self._pl]
229 229
230 230 def p1(self):
231 231 return self._validate(self._pl[0])
232 232
233 233 def p2(self):
234 234 return self._validate(self._pl[1])
235 235
236 236 def branch(self):
237 237 return encoding.tolocal(self._branch)
238 238
239 239 def setparents(self, p1, p2=nullid):
240 240 self._dirty = self._dirtypl = True
241 oldp2 = self._pl[1]
241 242 self._pl = p1, p2
243 if oldp2 != nullid and p2 == nullid:
244 # Discard 'm' markers when moving away from a merge state
245 for f, s in self._map.iteritems():
246 if s[0] == 'm':
247 self.normallookup(f)
242 248
243 249 def setbranch(self, branch):
244 250 if branch in ['tip', '.', 'null']:
245 251 raise util.Abort(_('the name \'%s\' is reserved') % branch)
246 252 self._branch = encoding.fromlocal(branch)
247 253 f = self._opener('branch', 'w', atomictemp=True)
248 254 try:
249 255 f.write(self._branch + '\n')
250 256 finally:
251 257 f.close()
252 258
253 259 def _read(self):
254 260 self._map = {}
255 261 self._copymap = {}
256 262 try:
257 263 st = self._opener.read("dirstate")
258 264 except IOError, err:
259 265 if err.errno != errno.ENOENT:
260 266 raise
261 267 return
262 268 if not st:
263 269 return
264 270
265 271 p = parsers.parse_dirstate(self._map, self._copymap, st)
266 272 if not self._dirtypl:
267 273 self._pl = p
268 274
269 275 def invalidate(self):
270 276 for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
271 277 "_ignore"):
272 278 if a in self.__dict__:
273 279 delattr(self, a)
274 280 self._lastnormaltime = 0
275 281 self._dirty = False
276 282
277 283 def copy(self, source, dest):
278 284 """Mark dest as a copy of source. Unmark dest if source is None."""
279 285 if source == dest:
280 286 return
281 287 self._dirty = True
282 288 if source is not None:
283 289 self._copymap[dest] = source
284 290 elif dest in self._copymap:
285 291 del self._copymap[dest]
286 292
287 293 def copied(self, file):
288 294 return self._copymap.get(file, None)
289 295
290 296 def copies(self):
291 297 return self._copymap
292 298
293 299 def _droppath(self, f):
294 300 if self[f] not in "?r" and "_dirs" in self.__dict__:
295 301 _decdirs(self._dirs, f)
296 302
297 303 def _addpath(self, f, check=False):
298 304 oldstate = self[f]
299 305 if check or oldstate == "r":
300 306 scmutil.checkfilename(f)
301 307 if f in self._dirs:
302 308 raise util.Abort(_('directory %r already in dirstate') % f)
303 309 # shadows
304 310 for d in _finddirs(f):
305 311 if d in self._dirs:
306 312 break
307 313 if d in self._map and self[d] != 'r':
308 314 raise util.Abort(
309 315 _('file %r in dirstate clashes with %r') % (d, f))
310 316 if oldstate in "?r" and "_dirs" in self.__dict__:
311 317 _incdirs(self._dirs, f)
312 318
313 319 def normal(self, f):
314 320 '''Mark a file normal and clean.'''
315 321 self._dirty = True
316 322 self._addpath(f)
317 323 s = os.lstat(self._join(f))
318 324 mtime = int(s.st_mtime)
319 325 self._map[f] = ('n', s.st_mode, s.st_size, mtime)
320 326 if f in self._copymap:
321 327 del self._copymap[f]
322 328 if mtime > self._lastnormaltime:
323 329 # Remember the most recent modification timeslot for status(),
324 330 # to make sure we won't miss future size-preserving file content
325 331 # modifications that happen within the same timeslot.
326 332 self._lastnormaltime = mtime
327 333
328 334 def normallookup(self, f):
329 335 '''Mark a file normal, but possibly dirty.'''
330 336 if self._pl[1] != nullid and f in self._map:
331 337 # if there is a merge going on and the file was either
332 338 # in state 'm' (-1) or coming from other parent (-2) before
333 339 # being removed, restore that state.
334 340 entry = self._map[f]
335 341 if entry[0] == 'r' and entry[2] in (-1, -2):
336 342 source = self._copymap.get(f)
337 343 if entry[2] == -1:
338 344 self.merge(f)
339 345 elif entry[2] == -2:
340 346 self.otherparent(f)
341 347 if source:
342 348 self.copy(source, f)
343 349 return
344 350 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
345 351 return
346 352 self._dirty = True
347 353 self._addpath(f)
348 354 self._map[f] = ('n', 0, -1, -1)
349 355 if f in self._copymap:
350 356 del self._copymap[f]
351 357
352 358 def otherparent(self, f):
353 359 '''Mark as coming from the other parent, always dirty.'''
354 360 if self._pl[1] == nullid:
355 361 raise util.Abort(_("setting %r to other parent "
356 362 "only allowed in merges") % f)
357 363 self._dirty = True
358 364 self._addpath(f)
359 365 self._map[f] = ('n', 0, -2, -1)
360 366 if f in self._copymap:
361 367 del self._copymap[f]
362 368
363 369 def add(self, f):
364 370 '''Mark a file added.'''
365 371 self._dirty = True
366 372 self._addpath(f, True)
367 373 self._map[f] = ('a', 0, -1, -1)
368 374 if f in self._copymap:
369 375 del self._copymap[f]
370 376
371 377 def remove(self, f):
372 378 '''Mark a file removed.'''
373 379 self._dirty = True
374 380 self._droppath(f)
375 381 size = 0
376 382 if self._pl[1] != nullid and f in self._map:
377 383 # backup the previous state
378 384 entry = self._map[f]
379 385 if entry[0] == 'm': # merge
380 386 size = -1
381 387 elif entry[0] == 'n' and entry[2] == -2: # other parent
382 388 size = -2
383 389 self._map[f] = ('r', 0, size, 0)
384 390 if size == 0 and f in self._copymap:
385 391 del self._copymap[f]
386 392
387 393 def merge(self, f):
388 394 '''Mark a file merged.'''
395 if self._pl[1] == nullid:
396 return self.normallookup(f)
389 397 self._dirty = True
390 398 s = os.lstat(self._join(f))
391 399 self._addpath(f)
392 400 self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
393 401 if f in self._copymap:
394 402 del self._copymap[f]
395 403
396 404 def drop(self, f):
397 405 '''Drop a file from the dirstate'''
398 406 if f in self._map:
399 407 self._dirty = True
400 408 self._droppath(f)
401 409 del self._map[f]
402 410
403 411 def _normalize(self, path, isknown):
404 412 normed = util.normcase(path)
405 413 folded = self._foldmap.get(normed, None)
406 414 if folded is None:
407 415 if isknown or not os.path.lexists(os.path.join(self._root, path)):
408 416 folded = path
409 417 else:
410 418 # recursively normalize leading directory components
411 419 # against dirstate
412 420 if '/' in normed:
413 421 d, f = normed.rsplit('/', 1)
414 422 d = self._normalize(d, isknown)
415 423 r = self._root + "/" + d
416 424 folded = d + "/" + util.fspath(f, r)
417 425 else:
418 426 folded = util.fspath(normed, self._root)
419 427 self._foldmap[normed] = folded
420 428
421 429 return folded
422 430
423 431 def normalize(self, path, isknown=False):
424 432 '''
425 433 normalize the case of a pathname when on a casefolding filesystem
426 434
427 435 isknown specifies whether the filename came from walking the
428 436 disk, to avoid extra filesystem access
429 437
430 438 The normalized case is determined based on the following precedence:
431 439
432 440 - version of name already stored in the dirstate
433 441 - version of name stored on disk
434 442 - version provided via command arguments
435 443 '''
436 444
437 445 if self._checkcase:
438 446 return self._normalize(path, isknown)
439 447 return path
440 448
441 449 def clear(self):
442 450 self._map = {}
443 451 if "_dirs" in self.__dict__:
444 452 delattr(self, "_dirs")
445 453 self._copymap = {}
446 454 self._pl = [nullid, nullid]
447 455 self._lastnormaltime = 0
448 456 self._dirty = True
449 457
450 458 def rebuild(self, parent, files):
451 459 self.clear()
452 460 for f in files:
453 461 if 'x' in files.flags(f):
454 462 self._map[f] = ('n', 0777, -1, 0)
455 463 else:
456 464 self._map[f] = ('n', 0666, -1, 0)
457 465 self._pl = (parent, nullid)
458 466 self._dirty = True
459 467
460 468 def write(self):
461 469 if not self._dirty:
462 470 return
463 471 st = self._opener("dirstate", "w", atomictemp=True)
464 472
465 473 # use the modification time of the newly created temporary file as the
466 474 # filesystem's notion of 'now'
467 475 now = int(util.fstat(st).st_mtime)
468 476
469 477 cs = cStringIO.StringIO()
470 478 copymap = self._copymap
471 479 pack = struct.pack
472 480 write = cs.write
473 481 write("".join(self._pl))
474 482 for f, e in self._map.iteritems():
475 483 if e[0] == 'n' and e[3] == now:
476 484 # The file was last modified "simultaneously" with the current
477 485 # write to dirstate (i.e. within the same second for file-
478 486 # systems with a granularity of 1 sec). This commonly happens
479 487 # for at least a couple of files on 'update'.
480 488 # The user could change the file without changing its size
481 489 # within the same second. Invalidate the file's stat data in
482 490 # dirstate, forcing future 'status' calls to compare the
483 491 # contents of the file. This prevents mistakenly treating such
484 492 # files as clean.
485 493 e = (e[0], 0, -1, -1) # mark entry as 'unset'
486 494 self._map[f] = e
487 495
488 496 if f in copymap:
489 497 f = "%s\0%s" % (f, copymap[f])
490 498 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
491 499 write(e)
492 500 write(f)
493 501 st.write(cs.getvalue())
494 502 st.close()
495 503 self._lastnormaltime = 0
496 504 self._dirty = self._dirtypl = False
497 505
498 506 def _dirignore(self, f):
499 507 if f == '.':
500 508 return False
501 509 if self._ignore(f):
502 510 return True
503 511 for p in _finddirs(f):
504 512 if self._ignore(p):
505 513 return True
506 514 return False
507 515
508 516 def walk(self, match, subrepos, unknown, ignored):
509 517 '''
510 518 Walk recursively through the directory tree, finding all files
511 519 matched by match.
512 520
513 521 Return a dict mapping filename to stat-like object (either
514 522 mercurial.osutil.stat instance or return value of os.stat()).
515 523 '''
516 524
517 525 def fwarn(f, msg):
518 526 self._ui.warn('%s: %s\n' % (self.pathto(f), msg))
519 527 return False
520 528
521 529 def badtype(mode):
522 530 kind = _('unknown')
523 531 if stat.S_ISCHR(mode):
524 532 kind = _('character device')
525 533 elif stat.S_ISBLK(mode):
526 534 kind = _('block device')
527 535 elif stat.S_ISFIFO(mode):
528 536 kind = _('fifo')
529 537 elif stat.S_ISSOCK(mode):
530 538 kind = _('socket')
531 539 elif stat.S_ISDIR(mode):
532 540 kind = _('directory')
533 541 return _('unsupported file type (type is %s)') % kind
534 542
535 543 ignore = self._ignore
536 544 dirignore = self._dirignore
537 545 if ignored:
538 546 ignore = util.never
539 547 dirignore = util.never
540 548 elif not unknown:
541 549 # if unknown and ignored are False, skip step 2
542 550 ignore = util.always
543 551 dirignore = util.always
544 552
545 553 matchfn = match.matchfn
546 554 badfn = match.bad
547 555 dmap = self._map
548 556 normpath = util.normpath
549 557 listdir = osutil.listdir
550 558 lstat = os.lstat
551 559 getkind = stat.S_IFMT
552 560 dirkind = stat.S_IFDIR
553 561 regkind = stat.S_IFREG
554 562 lnkkind = stat.S_IFLNK
555 563 join = self._join
556 564 work = []
557 565 wadd = work.append
558 566
559 567 exact = skipstep3 = False
560 568 if matchfn == match.exact: # match.exact
561 569 exact = True
562 570 dirignore = util.always # skip step 2
563 571 elif match.files() and not match.anypats(): # match.match, no patterns
564 572 skipstep3 = True
565 573
566 574 if not exact and self._checkcase:
567 575 normalize = self._normalize
568 576 skipstep3 = False
569 577 else:
570 578 normalize = lambda x, y: x
571 579
572 580 files = sorted(match.files())
573 581 subrepos.sort()
574 582 i, j = 0, 0
575 583 while i < len(files) and j < len(subrepos):
576 584 subpath = subrepos[j] + "/"
577 585 if files[i] < subpath:
578 586 i += 1
579 587 continue
580 588 while i < len(files) and files[i].startswith(subpath):
581 589 del files[i]
582 590 j += 1
583 591
584 592 if not files or '.' in files:
585 593 files = ['']
586 594 results = dict.fromkeys(subrepos)
587 595 results['.hg'] = None
588 596
589 597 # step 1: find all explicit files
590 598 for ff in files:
591 599 nf = normalize(normpath(ff), False)
592 600 if nf in results:
593 601 continue
594 602
595 603 try:
596 604 st = lstat(join(nf))
597 605 kind = getkind(st.st_mode)
598 606 if kind == dirkind:
599 607 skipstep3 = False
600 608 if nf in dmap:
601 609 #file deleted on disk but still in dirstate
602 610 results[nf] = None
603 611 match.dir(nf)
604 612 if not dirignore(nf):
605 613 wadd(nf)
606 614 elif kind == regkind or kind == lnkkind:
607 615 results[nf] = st
608 616 else:
609 617 badfn(ff, badtype(kind))
610 618 if nf in dmap:
611 619 results[nf] = None
612 620 except OSError, inst:
613 621 if nf in dmap: # does it exactly match a file?
614 622 results[nf] = None
615 623 else: # does it match a directory?
616 624 prefix = nf + "/"
617 625 for fn in dmap:
618 626 if fn.startswith(prefix):
619 627 match.dir(nf)
620 628 skipstep3 = False
621 629 break
622 630 else:
623 631 badfn(ff, inst.strerror)
624 632
625 633 # step 2: visit subdirectories
626 634 while work:
627 635 nd = work.pop()
628 636 skip = None
629 637 if nd == '.':
630 638 nd = ''
631 639 else:
632 640 skip = '.hg'
633 641 try:
634 642 entries = listdir(join(nd), stat=True, skip=skip)
635 643 except OSError, inst:
636 644 if inst.errno == errno.EACCES:
637 645 fwarn(nd, inst.strerror)
638 646 continue
639 647 raise
640 648 for f, kind, st in entries:
641 649 nf = normalize(nd and (nd + "/" + f) or f, True)
642 650 if nf not in results:
643 651 if kind == dirkind:
644 652 if not ignore(nf):
645 653 match.dir(nf)
646 654 wadd(nf)
647 655 if nf in dmap and matchfn(nf):
648 656 results[nf] = None
649 657 elif kind == regkind or kind == lnkkind:
650 658 if nf in dmap:
651 659 if matchfn(nf):
652 660 results[nf] = st
653 661 elif matchfn(nf) and not ignore(nf):
654 662 results[nf] = st
655 663 elif nf in dmap and matchfn(nf):
656 664 results[nf] = None
657 665
658 666 # step 3: report unseen items in the dmap hash
659 667 if not skipstep3 and not exact:
660 668 visit = sorted([f for f in dmap if f not in results and matchfn(f)])
661 669 for nf, st in zip(visit, util.statfiles([join(i) for i in visit])):
662 670 if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
663 671 st = None
664 672 results[nf] = st
665 673 for s in subrepos:
666 674 del results[s]
667 675 del results['.hg']
668 676 return results
669 677
670 678 def status(self, match, subrepos, ignored, clean, unknown):
671 679 '''Determine the status of the working copy relative to the
672 680 dirstate and return a tuple of lists (unsure, modified, added,
673 681 removed, deleted, unknown, ignored, clean), where:
674 682
675 683 unsure:
676 684 files that might have been modified since the dirstate was
677 685 written, but need to be read to be sure (size is the same
678 686 but mtime differs)
679 687 modified:
680 688 files that have definitely been modified since the dirstate
681 689 was written (different size or mode)
682 690 added:
683 691 files that have been explicitly added with hg add
684 692 removed:
685 693 files that have been explicitly removed with hg remove
686 694 deleted:
687 695 files that have been deleted through other means ("missing")
688 696 unknown:
689 697 files not in the dirstate that are not ignored
690 698 ignored:
691 699 files not in the dirstate that are ignored
692 700 (by _dirignore())
693 701 clean:
694 702 files that have definitely not been modified since the
695 703 dirstate was written
696 704 '''
697 705 listignored, listclean, listunknown = ignored, clean, unknown
698 706 lookup, modified, added, unknown, ignored = [], [], [], [], []
699 707 removed, deleted, clean = [], [], []
700 708
701 709 dmap = self._map
702 710 ladd = lookup.append # aka "unsure"
703 711 madd = modified.append
704 712 aadd = added.append
705 713 uadd = unknown.append
706 714 iadd = ignored.append
707 715 radd = removed.append
708 716 dadd = deleted.append
709 717 cadd = clean.append
710 718
711 719 lnkkind = stat.S_IFLNK
712 720
713 721 for fn, st in self.walk(match, subrepos, listunknown,
714 722 listignored).iteritems():
715 723 if fn not in dmap:
716 724 if (listignored or match.exact(fn)) and self._dirignore(fn):
717 725 if listignored:
718 726 iadd(fn)
719 727 elif listunknown:
720 728 uadd(fn)
721 729 continue
722 730
723 731 state, mode, size, time = dmap[fn]
724 732
725 733 if not st and state in "nma":
726 734 dadd(fn)
727 735 elif state == 'n':
728 736 # The "mode & lnkkind != lnkkind or self._checklink"
729 737 # lines are an expansion of "islink => checklink"
730 738 # where islink means "is this a link?" and checklink
731 739 # means "can we check links?".
732 740 mtime = int(st.st_mtime)
733 741 if (size >= 0 and
734 742 (size != st.st_size
735 743 or ((mode ^ st.st_mode) & 0100 and self._checkexec))
736 744 and (mode & lnkkind != lnkkind or self._checklink)
737 745 or size == -2 # other parent
738 746 or fn in self._copymap):
739 747 madd(fn)
740 748 elif (mtime != time
741 749 and (mode & lnkkind != lnkkind or self._checklink)):
742 750 ladd(fn)
743 751 elif mtime == self._lastnormaltime:
744 752 # fn may have been changed in the same timeslot without
745 753 # changing its size. This can happen if we quickly do
746 754 # multiple commits in a single transaction.
747 755 # Force lookup, so we don't miss such a racy file change.
748 756 ladd(fn)
749 757 elif listclean:
750 758 cadd(fn)
751 759 elif state == 'm':
752 760 madd(fn)
753 761 elif state == 'a':
754 762 aadd(fn)
755 763 elif state == 'r':
756 764 radd(fn)
757 765
758 766 return (lookup, modified, added, removed, deleted, unknown, ignored,
759 767 clean)
@@ -1,290 +1,277 b''
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 --config extensions.graphlog= 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
54 54 skipping ancestor revision 2
55 55 [255]
56 56
57 57 Can't graft with dirty wd:
58 58
59 59 $ hg up -q 0
60 60 $ echo foo > a
61 61 $ hg graft 1
62 62 abort: outstanding uncommitted changes
63 63 [255]
64 64 $ hg revert a
65 65
66 66 Graft a rename:
67 67
68 68 $ hg graft 2 -u foo
69 69 grafting revision 2
70 70 merging a and b to b
71 71 $ hg export tip --git
72 72 # HG changeset patch
73 73 # User foo
74 74 # Date 0 0
75 75 # Node ID d2e44c99fd3f31c176ea4efb9eca9f6306c81756
76 76 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
77 77 2
78 78
79 79 diff --git a/a b/b
80 80 rename from a
81 81 rename to b
82 82 --- a/a
83 83 +++ b/b
84 84 @@ -1,1 +1,1 @@
85 85 -a
86 86 +b
87 87
88 88 Look for extra:source
89 89
90 90 $ hg log --debug -r tip
91 91 changeset: 7:d2e44c99fd3f31c176ea4efb9eca9f6306c81756
92 92 tag: tip
93 93 phase: draft
94 94 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
95 95 parent: -1:0000000000000000000000000000000000000000
96 96 manifest: 7:5d59766436fd8fbcd38e7bebef0f6eaf3eebe637
97 97 user: foo
98 98 date: Thu Jan 01 00:00:00 1970 +0000
99 99 files+: b
100 100 files-: a
101 101 extra: branch=default
102 102 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
103 103 description:
104 104 2
105 105
106 106
107 107
108 108 Graft out of order, skipping a merge and a duplicate
109 109
110 110 $ hg graft 1 5 4 3 'merge()' 2 -n
111 111 skipping ungraftable merge revision 6
112 112 skipping already grafted revision 2
113 113 grafting revision 1
114 114 grafting revision 5
115 115 grafting revision 4
116 116 grafting revision 3
117 117
118 118 $ hg graft 1 5 4 3 'merge()' 2 --debug
119 119 skipping ungraftable merge revision 6
120 120 scanning for duplicate grafts
121 121 skipping already grafted revision 2
122 122 grafting revision 1
123 123 searching for copies back to rev 1
124 124 unmatched files in local:
125 125 b
126 126 all copies found (* = to merge, ! = divergent):
127 127 b -> a *
128 128 checking for directory renames
129 129 resolving manifests
130 130 overwrite: False, partial: False
131 131 ancestor: 68795b066622, local: d2e44c99fd3f+, remote: 5d205f8b35b6
132 132 b: local copied/moved to a -> m
133 133 preserving b for resolve of b
134 134 updating: b 1/1 files (100.00%)
135 b
136 b: searching for copy revision for a
137 b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
138 135 grafting revision 5
139 136 searching for copies back to rev 1
140 137 resolving manifests
141 138 overwrite: False, partial: False
142 ancestor: 4c60f11aa304, local: 6f5ea6ac8b70+, remote: 97f8bfe72746
139 ancestor: 4c60f11aa304, local: d2e44c99fd3f+, remote: 97f8bfe72746
143 140 e: remote is newer -> g
144 141 updating: e 1/1 files (100.00%)
145 142 getting e
146 143 e
147 144 grafting revision 4
148 145 searching for copies back to rev 1
149 146 resolving manifests
150 147 overwrite: False, partial: False
151 ancestor: 4c60f11aa304, local: 77eb504366ab+, remote: 9c233e8e184d
148 ancestor: 4c60f11aa304, local: 839a7e8fcf80+, remote: 9c233e8e184d
152 149 e: versions differ -> m
153 150 d: remote is newer -> g
154 151 preserving e for resolve of e
155 152 updating: d 1/2 files (50.00%)
156 153 getting d
157 154 updating: e 2/2 files (100.00%)
158 155 picked tool 'internal:merge' for e (binary False symlink False)
159 156 merging e
160 my e@77eb504366ab+ other e@9c233e8e184d ancestor e@68795b066622
157 my e@839a7e8fcf80+ other e@9c233e8e184d ancestor e@68795b066622
161 158 warning: conflicts during merge.
162 159 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
163 160 abort: unresolved conflicts, can't continue
164 161 (use hg resolve and hg graft --continue)
165 162 [255]
166 163
167 164 Continue without resolve should fail:
168 165
169 166 $ hg graft -c
170 167 grafting revision 4
171 168 abort: unresolved merge conflicts (see hg help resolve)
172 169 [255]
173 170
174 171 Fix up:
175 172
176 173 $ echo b > e
177 174 $ hg resolve -m e
178 175
179 176 Continue with a revision should fail:
180 177
181 178 $ hg graft -c 6
182 179 abort: can't specify --continue and revisions
183 180 [255]
184 181
185 182 Continue for real, clobber usernames
186 183
187 184 $ hg graft -c -U
188 185 grafting revision 4
189 186 grafting revision 3
190 187
191 188 Compare with original:
192 189
193 190 $ hg diff -r 6
194 191 $ hg status --rev 0:. -C
195 192 M d
196 193 M e
197 194 A b
198 195 a
199 196 A c
200 197 a
201 198 R a
202 199
203 200 View graph:
204 201
205 202 $ hg --config extensions.graphlog= log -G --template '{author}@{rev}.{phase}: {desc}\n'
206 @ test@11.draft: 3
207 |
208 o test@10.draft: 4
203 @ test@10.draft: 3
209 204 |
210 o test@9.draft: 5
205 o test@9.draft: 4
211 206 |
212 o bar@8.draft: 1
207 o test@8.draft: 5
213 208 |
214 209 o foo@7.draft: 2
215 210 |
216 211 | o test@6.secret: 6
217 212 | |\
218 213 | | o test@5.draft: 5
219 214 | | |
220 215 | o | test@4.draft: 4
221 216 | |/
222 217 | o baz@3.public: 3
223 218 | |
224 219 | o test@2.public: 2
225 220 | |
226 221 | o bar@1.public: 1
227 222 |/
228 223 o test@0.public: 0
229 224
230 $ hg export --git 8
231 # HG changeset patch
232 # User bar
233 # Date 0 0
234 # Node ID 6f5ea6ac8b705521c6d5f49a04ed142e3f76645d
235 # Parent d2e44c99fd3f31c176ea4efb9eca9f6306c81756
236 1
237
238 225 Graft again onto another branch should preserve the original source
239 226 $ hg up -q 0
240 227 $ echo 'g'>g
241 228 $ hg add g
242 229 $ hg ci -m 7
243 230 created new head
244 231 $ hg graft 7
245 232 grafting revision 7
246 233
247 234 $ hg log -r 7 --template '{rev}:{node}\n'
248 235 7:d2e44c99fd3f31c176ea4efb9eca9f6306c81756
249 236 $ hg log -r 2 --template '{rev}:{node}\n'
250 237 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
251 238
252 239 $ hg log --debug -r tip
253 changeset: 13:95adbe5de6b10f376b699ece9ed5a57cd7b4b0f6
240 changeset: 12:95adbe5de6b10f376b699ece9ed5a57cd7b4b0f6
254 241 tag: tip
255 242 phase: draft
256 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
243 parent: 11:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
257 244 parent: -1:0000000000000000000000000000000000000000
258 manifest: 13:9944044f82a462bbaccc9bdf7e0ac5b811db7d1b
245 manifest: 12:9944044f82a462bbaccc9bdf7e0ac5b811db7d1b
259 246 user: foo
260 247 date: Thu Jan 01 00:00:00 1970 +0000
261 248 files+: b
262 249 files-: a
263 250 extra: branch=default
264 251 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
265 252 description:
266 253 2
267 254
268 255
269 256 Disallow grafting an already grafted cset onto its original branch
270 257 $ hg up -q 6
271 258 $ hg graft 7
272 259 skipping already grafted revision 7 (was grafted from 2)
273 260 [255]
274 261
275 262 Disallow grafting already grafted csets with the same origin onto each other
276 $ hg up -q 13
263 $ hg up -q 12
277 264 $ hg graft 2
278 265 skipping already grafted revision 2
279 266 [255]
280 267 $ hg graft 7
281 268 skipping already grafted revision 7 (same origin 2)
282 269 [255]
283 270
284 271 $ hg up -q 7
285 272 $ hg graft 2
286 273 skipping already grafted revision 2
287 274 [255]
288 275 $ hg graft tip
289 skipping already grafted revision 13 (same origin 2)
276 skipping already grafted revision 12 (same origin 2)
290 277 [255]
@@ -1,408 +1,398 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 6 > [phases]
7 7 > publish=False
8 8 >
9 9 > [alias]
10 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
11 11 > EOF
12 12
13 13
14 14 $ hg init a
15 15 $ cd a
16 16 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
17 17 adding changesets
18 18 adding manifests
19 19 adding file changes
20 20 added 8 changesets with 7 changes to 7 files (+2 heads)
21 21 (run 'hg heads' to see heads, 'hg merge' to merge)
22 22 $ hg up tip
23 23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 24
25 25 $ cd ..
26 26
27 27
28 28 Rebasing D onto H detaching from C:
29 29
30 30 $ hg clone -q -u . a a1
31 31 $ cd a1
32 32
33 33 $ hg tglog
34 34 @ 7: 'H'
35 35 |
36 36 | o 6: 'G'
37 37 |/|
38 38 o | 5: 'F'
39 39 | |
40 40 | o 4: 'E'
41 41 |/
42 42 | o 3: 'D'
43 43 | |
44 44 | o 2: 'C'
45 45 | |
46 46 | o 1: 'B'
47 47 |/
48 48 o 0: 'A'
49 49
50 50 $ hg phase --force --secret 3
51 51 $ hg rebase --detach -s 3 -d 7
52 52 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
53 53
54 54 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
55 55 @ 7:secret 'D'
56 56 |
57 57 o 6:draft 'H'
58 58 |
59 59 | o 5:draft 'G'
60 60 |/|
61 61 o | 4:draft 'F'
62 62 | |
63 63 | o 3:draft 'E'
64 64 |/
65 65 | o 2:draft 'C'
66 66 | |
67 67 | o 1:draft 'B'
68 68 |/
69 69 o 0:draft 'A'
70 70
71 71 $ hg manifest
72 72 A
73 73 D
74 74 F
75 75 H
76 76
77 77 $ cd ..
78 78
79 79
80 80 Rebasing C onto H detaching from B:
81 81
82 82 $ hg clone -q -u . a a2
83 83 $ cd a2
84 84
85 85 $ hg tglog
86 86 @ 7: 'H'
87 87 |
88 88 | o 6: 'G'
89 89 |/|
90 90 o | 5: 'F'
91 91 | |
92 92 | o 4: 'E'
93 93 |/
94 94 | o 3: 'D'
95 95 | |
96 96 | o 2: 'C'
97 97 | |
98 98 | o 1: 'B'
99 99 |/
100 100 o 0: 'A'
101 101
102 102 $ hg rebase --detach -s 2 -d 7
103 103 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
104 104
105 105 $ hg tglog
106 106 @ 7: 'D'
107 107 |
108 108 o 6: 'C'
109 109 |
110 110 o 5: 'H'
111 111 |
112 112 | o 4: 'G'
113 113 |/|
114 114 o | 3: 'F'
115 115 | |
116 116 | o 2: 'E'
117 117 |/
118 118 | o 1: 'B'
119 119 |/
120 120 o 0: 'A'
121 121
122 122 $ hg manifest
123 123 A
124 124 C
125 125 D
126 126 F
127 127 H
128 128
129 129 $ cd ..
130 130
131 131
132 132 Rebasing B onto H using detach (same as not using it):
133 133
134 134 $ hg clone -q -u . a a3
135 135 $ cd a3
136 136
137 137 $ hg tglog
138 138 @ 7: 'H'
139 139 |
140 140 | o 6: 'G'
141 141 |/|
142 142 o | 5: 'F'
143 143 | |
144 144 | o 4: 'E'
145 145 |/
146 146 | o 3: 'D'
147 147 | |
148 148 | o 2: 'C'
149 149 | |
150 150 | o 1: 'B'
151 151 |/
152 152 o 0: 'A'
153 153
154 154 $ hg rebase --detach -s 1 -d 7
155 155 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
156 156
157 157 $ hg tglog
158 158 @ 7: 'D'
159 159 |
160 160 o 6: 'C'
161 161 |
162 162 o 5: 'B'
163 163 |
164 164 o 4: 'H'
165 165 |
166 166 | o 3: 'G'
167 167 |/|
168 168 o | 2: 'F'
169 169 | |
170 170 | o 1: 'E'
171 171 |/
172 172 o 0: 'A'
173 173
174 174 $ hg manifest
175 175 A
176 176 B
177 177 C
178 178 D
179 179 F
180 180 H
181 181
182 182 $ cd ..
183 183
184 184
185 185 Rebasing C onto H detaching from B and collapsing:
186 186
187 187 $ hg clone -q -u . a a4
188 188 $ cd a4
189 189 $ hg phase --force --secret 3
190 190
191 191 $ hg tglog
192 192 @ 7: 'H'
193 193 |
194 194 | o 6: 'G'
195 195 |/|
196 196 o | 5: 'F'
197 197 | |
198 198 | o 4: 'E'
199 199 |/
200 200 | o 3: 'D'
201 201 | |
202 202 | o 2: 'C'
203 203 | |
204 204 | o 1: 'B'
205 205 |/
206 206 o 0: 'A'
207 207
208 208 $ hg rebase --detach --collapse -s 2 -d 7
209 209 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
210 210
211 211 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
212 212 @ 6:secret 'Collapsed revision
213 213 | * C
214 214 | * D'
215 215 o 5:draft 'H'
216 216 |
217 217 | o 4:draft 'G'
218 218 |/|
219 219 o | 3:draft 'F'
220 220 | |
221 221 | o 2:draft 'E'
222 222 |/
223 223 | o 1:draft 'B'
224 224 |/
225 225 o 0:draft 'A'
226 226
227 227 $ hg manifest
228 228 A
229 229 C
230 230 D
231 231 F
232 232 H
233 233
234 234 $ cd ..
235 235
236 236 Rebasing across null as ancestor
237 237 $ hg clone -q -U a a5
238 238
239 239 $ cd a5
240 240
241 241 $ echo x > x
242 242
243 243 $ hg add x
244 244
245 245 $ hg ci -m "extra branch"
246 246 created new head
247 247
248 248 $ hg tglog
249 249 @ 8: 'extra branch'
250 250
251 251 o 7: 'H'
252 252 |
253 253 | o 6: 'G'
254 254 |/|
255 255 o | 5: 'F'
256 256 | |
257 257 | o 4: 'E'
258 258 |/
259 259 | o 3: 'D'
260 260 | |
261 261 | o 2: 'C'
262 262 | |
263 263 | o 1: 'B'
264 264 |/
265 265 o 0: 'A'
266 266
267 267 $ hg rebase --detach -s 1 -d tip
268 268 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
269 269
270 270 $ hg tglog
271 271 @ 8: 'D'
272 272 |
273 273 o 7: 'C'
274 274 |
275 275 o 6: 'B'
276 276 |
277 277 o 5: 'extra branch'
278 278
279 279 o 4: 'H'
280 280 |
281 281 | o 3: 'G'
282 282 |/|
283 283 o | 2: 'F'
284 284 | |
285 285 | o 1: 'E'
286 286 |/
287 287 o 0: 'A'
288 288
289 289
290 290 $ hg rebase -d 5 -s 7
291 291 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/13547172c9c0-backup.hg (glob)
292 292 $ hg tglog
293 293 @ 8: 'D'
294 294 |
295 295 o 7: 'C'
296 296 |
297 297 | o 6: 'B'
298 298 |/
299 299 o 5: 'extra branch'
300 300
301 301 o 4: 'H'
302 302 |
303 303 | o 3: 'G'
304 304 |/|
305 305 o | 2: 'F'
306 306 | |
307 307 | o 1: 'E'
308 308 |/
309 309 o 0: 'A'
310 310
311 311 $ cd ..
312 312
313 313 Verify that target is not selected as external rev (issue3085)
314 314
315 315 $ hg clone -q -U a a6
316 316 $ cd a6
317 317 $ hg up -q 6
318 318
319 319 $ echo "I" >> E
320 320 $ hg ci -m "I"
321 321 $ hg merge 7
322 322 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
323 323 (branch merge, don't forget to commit)
324 324 $ hg ci -m "Merge"
325 325 $ echo "J" >> F
326 326 $ hg ci -m "J"
327 327
328 328 $ hg rebase -s 8 -d 7 --collapse --detach --config ui.merge=internal:other
329 329 remote changed E which local deleted
330 330 use (c)hanged version or leave (d)eleted? c
331 331 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
332 332
333 333 $ hg tglog
334 334 @ 8: 'Collapsed revision
335 335 | * I
336 336 | * Merge
337 337 | * J'
338 338 o 7: 'H'
339 339 |
340 340 | o 6: 'G'
341 341 |/|
342 342 o | 5: 'F'
343 343 | |
344 344 | o 4: 'E'
345 345 |/
346 346 | o 3: 'D'
347 347 | |
348 348 | o 2: 'C'
349 349 | |
350 350 | o 1: 'B'
351 351 |/
352 352 o 0: 'A'
353 353
354 354
355 355 $ hg parents
356 356 changeset: 8:9472f4b1d736
357 357 tag: tip
358 358 user: test
359 359 date: Thu Jan 01 00:00:00 1970 +0000
360 360 summary: Collapsed revision
361 361
362 362
363 363 $ cd ..
364 364
365 365 Ensure --continue restores a correct state (issue3046) and phase:
366 366 $ hg clone -q a a7
367 367 $ cd a7
368 368 $ hg up -q 3
369 369 $ echo 'H2' > H
370 370 $ hg ci -A -m 'H2'
371 371 adding H
372 372 $ hg phase --force --secret 8
373 373 $ hg rebase -s 8 -d 7 --detach --config ui.merge=internal:fail
374 374 merging H
375 375 warning: conflicts during merge.
376 376 merging H incomplete! (edit conflicts, then use 'hg resolve --mark')
377 377 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
378 378 [255]
379 379 $ hg resolve --all -t internal:local
380 380 $ hg rebase -c
381 381 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6215fafa5447-backup.hg (glob)
382 382 $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
383 @ 8:secret 'H2'
384 |
385 o 7:draft 'H'
383 @ 7:draft 'H'
386 384 |
387 385 | o 6:draft 'G'
388 386 |/|
389 387 o | 5:draft 'F'
390 388 | |
391 389 | o 4:draft 'E'
392 390 |/
393 391 | o 3:draft 'D'
394 392 | |
395 393 | o 2:draft 'C'
396 394 | |
397 395 | o 1:draft 'B'
398 396 |/
399 397 o 0:draft 'A'
400 398
401 $ hg export --git 8
402 # HG changeset patch
403 # User test
404 # Date 0 0
405 # Node ID 248209b40064fe67181915fa7a4f3395520f700a
406 # Parent 02de42196ebee42ef284b6780a87cdc96e8eaab6
407 H2
408
@@ -1,147 +1,137 b''
1 1 This emulates the effects of an hg pull --rebase in which the remote repo
2 2 already has one local mq patch
3 3
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [extensions]
6 6 > graphlog=
7 7 > rebase=
8 8 > mq=
9 9 >
10 10 > [phases]
11 11 > publish=False
12 12 >
13 13 > [alias]
14 14 > tglog = log -G --template "{rev}: '{desc}' tags: {tags}\n"
15 15 > EOF
16 16
17 17
18 18 $ hg init a
19 19 $ cd a
20 20 $ hg qinit -c
21 21
22 22 $ echo c1 > c1
23 23 $ hg add c1
24 24 $ hg ci -m C1
25 25
26 26 $ echo r1 > r1
27 27 $ hg add r1
28 28 $ hg ci -m R1
29 29
30 30 $ hg up -q 0
31 31
32 32 $ hg qnew p0.patch
33 33 $ echo p0 > p0
34 34 $ hg add p0
35 35 $ hg qref -m P0
36 36
37 37 $ hg qnew p1.patch
38 38 $ echo p1 > p1
39 39 $ hg add p1
40 40 $ hg qref -m P1
41 41
42 42 $ hg export qtip > p1.patch
43 43
44 44 $ hg up -q -C 1
45 45
46 46 $ hg import p1.patch
47 47 applying p1.patch
48 48
49 49 $ rm p1.patch
50 50
51 51 $ hg up -q -C qtip
52 52
53 53 $ hg rebase
54 54 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
55 55
56 56 $ hg tglog
57 57 @ 3: 'P0' tags: p0.patch qbase qtip tip
58 58 |
59 59 o 2: 'P1' tags: qparent
60 60 |
61 61 o 1: 'R1' tags:
62 62 |
63 63 o 0: 'C1' tags:
64 64
65 65 $ cd ..
66 66
67 67
68 68 $ hg init b
69 69 $ cd b
70 70 $ hg qinit -c
71 71
72 72 $ for i in r0 r1 r2 r3 r4 r5 r6;
73 73 > do
74 74 > echo $i > $i
75 75 > hg ci -Am $i
76 76 > done
77 77 adding r0
78 78 adding r1
79 79 adding r2
80 80 adding r3
81 81 adding r4
82 82 adding r5
83 83 adding r6
84 84
85 85 $ hg qimport -r 1:tip
86 86
87 87 $ hg up -q 0
88 88
89 89 $ for i in r1 r3 r7 r8;
90 90 > do
91 91 > echo $i > $i
92 92 > hg ci -Am branch2-$i
93 93 > done
94 94 adding r1
95 95 created new head
96 96 adding r3
97 97 adding r7
98 98 adding r8
99 99
100 100 $ echo somethingelse > r4
101 101 $ hg ci -Am branch2-r4
102 102 adding r4
103 103
104 104 $ echo r6 > r6
105 105 $ hg ci -Am branch2-r6
106 106 adding r6
107 107
108 108 $ hg up -q qtip
109 109
110 110 $ HGMERGE=internal:fail hg rebase
111 111 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
112 112 [255]
113 113
114 114 $ HGMERGE=internal:local hg resolve --all
115 115
116 116 $ hg rebase --continue
117 117 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
118 118
119 119 $ hg tglog
120 @ 9: 'r5' tags: 5.diff qtip tip
121 |
122 o 8: 'r4' tags: 4.diff
120 @ 8: 'r5' tags: 5.diff qtip tip
123 121 |
124 122 o 7: 'r2' tags: 2.diff qbase
125 123 |
126 124 o 6: 'branch2-r6' tags: qparent
127 125 |
128 126 o 5: 'branch2-r4' tags:
129 127 |
130 128 o 4: 'branch2-r8' tags:
131 129 |
132 130 o 3: 'branch2-r7' tags:
133 131 |
134 132 o 2: 'branch2-r3' tags:
135 133 |
136 134 o 1: 'branch2-r1' tags:
137 135 |
138 136 o 0: 'r0' tags:
139 137
140 $ hg export --git 4.diff
141 # HG changeset patch
142 # User test
143 # Date 0 0
144 # Node ID 315eb21a13c2b06e787f5d0000e36f8f8f3a1768
145 # Parent 1660ab13ce9aea3da22ea54926bd49aeff8a4e20
146 r4
147
General Comments 0
You need to be logged in to leave comments. Login now