##// END OF EJS Templates
shelve: don't crash on file with unexpected extension in .hg/shelved/...
Martin von Zweigbergk -
r47007:c062874a default
parent child Browse files
Show More
@@ -1,1173 +1,1173 b''
1 1 # shelve.py - save/restore working directory state
2 2 #
3 3 # Copyright 2013 Facebook, Inc.
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 """save and restore changes to the working directory
9 9
10 10 The "hg shelve" command saves changes made to the working directory
11 11 and reverts those changes, resetting the working directory to a clean
12 12 state.
13 13
14 14 Later on, the "hg unshelve" command restores the changes saved by "hg
15 15 shelve". Changes can be restored even after updating to a different
16 16 parent, in which case Mercurial's merge machinery will resolve any
17 17 conflicts if necessary.
18 18
19 19 You can have more than one shelved change outstanding at a time; each
20 20 shelved change has a distinct name. For details, see the help for "hg
21 21 shelve".
22 22 """
23 23 from __future__ import absolute_import
24 24
25 25 import collections
26 26 import errno
27 27 import itertools
28 28 import stat
29 29
30 30 from .i18n import _
31 31 from .node import (
32 32 bin,
33 33 hex,
34 34 nullid,
35 35 nullrev,
36 36 )
37 37 from . import (
38 38 bookmarks,
39 39 bundle2,
40 40 changegroup,
41 41 cmdutil,
42 42 discovery,
43 43 error,
44 44 exchange,
45 45 hg,
46 46 lock as lockmod,
47 47 mdiff,
48 48 merge,
49 49 mergestate as mergestatemod,
50 50 patch,
51 51 phases,
52 52 pycompat,
53 53 repair,
54 54 scmutil,
55 55 templatefilters,
56 56 util,
57 57 vfs as vfsmod,
58 58 )
59 59 from .utils import (
60 60 dateutil,
61 61 stringutil,
62 62 )
63 63
64 64 backupdir = b'shelve-backup'
65 65 shelvedir = b'shelved'
66 66 shelvefileextensions = [b'hg', b'patch', b'shelve']
67 67 # universal extension is present in all types of shelves
68 68 patchextension = b'patch'
69 69
70 70 # we never need the user, so we use a
71 71 # generic user for all shelve operations
72 72 shelveuser = b'shelve@localhost'
73 73
74 74
75 75 class Shelf(object):
76 76 """Represents a shelf, including possibly multiple files storing it.
77 77
78 78 Old shelves will have a .patch and a .hg file. Newer shelves will
79 79 also have a .shelve file. This class abstracts away some of the
80 80 differences and lets you work with the shelf as a whole.
81 81 """
82 82
83 83 def __init__(self, repo, name):
84 84 self.repo = repo
85 85 self.name = name
86 86 self.vfs = vfsmod.vfs(repo.vfs.join(shelvedir))
87 87 self.backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
88 88
89 89 def exists(self):
90 90 return self.vfs.exists(
91 91 self.name + b'.' + patchextension
92 92 ) and self.vfs.exists(self.name + b'.hg')
93 93
94 94 def mtime(self):
95 95 return self.vfs.stat(self.name + b'.' + patchextension)[stat.ST_MTIME]
96 96
97 97 def writeinfo(self, info):
98 98 scmutil.simplekeyvaluefile(self.vfs, self.name + b'.shelve').write(info)
99 99
100 100 def hasinfo(self):
101 101 return self.vfs.exists(self.name + b'.shelve')
102 102
103 103 def readinfo(self):
104 104 return scmutil.simplekeyvaluefile(
105 105 self.vfs, self.name + b'.shelve'
106 106 ).read()
107 107
108 108 def writebundle(self, bases, node):
109 109 cgversion = changegroup.safeversion(self.repo)
110 110 if cgversion == b'01':
111 111 btype = b'HG10BZ'
112 112 compression = None
113 113 else:
114 114 btype = b'HG20'
115 115 compression = b'BZ'
116 116
117 117 repo = self.repo.unfiltered()
118 118
119 119 outgoing = discovery.outgoing(
120 120 repo, missingroots=bases, ancestorsof=[node]
121 121 )
122 122 cg = changegroup.makechangegroup(repo, outgoing, cgversion, b'shelve')
123 123
124 124 bundle_filename = self.vfs.join(self.name + b'.hg')
125 125 bundle2.writebundle(
126 126 self.repo.ui,
127 127 cg,
128 128 bundle_filename,
129 129 btype,
130 130 self.vfs,
131 131 compression=compression,
132 132 )
133 133
134 134 def applybundle(self, tr):
135 135 filename = self.name + b'.hg'
136 136 fp = self.vfs(filename)
137 137 try:
138 138 targetphase = phases.internal
139 139 if not phases.supportinternal(self.repo):
140 140 targetphase = phases.secret
141 141 gen = exchange.readbundle(self.repo.ui, fp, filename, self.vfs)
142 142 pretip = self.repo[b'tip']
143 143 bundle2.applybundle(
144 144 self.repo,
145 145 gen,
146 146 tr,
147 147 source=b'unshelve',
148 148 url=b'bundle:' + self.vfs.join(filename),
149 149 targetphase=targetphase,
150 150 )
151 151 shelvectx = self.repo[b'tip']
152 152 if pretip == shelvectx:
153 153 shelverev = tr.changes[b'revduplicates'][-1]
154 154 shelvectx = self.repo[shelverev]
155 155 return shelvectx
156 156 finally:
157 157 fp.close()
158 158
159 159 def open_patch(self, mode=b'rb'):
160 160 return self.vfs(self.name + b'.patch', mode)
161 161
162 162 def _backupfilename(self, filename):
163 163 def gennames(base):
164 164 yield base
165 165 base, ext = base.rsplit(b'.', 1)
166 166 for i in itertools.count(1):
167 167 yield b'%s-%d.%s' % (base, i, ext)
168 168
169 169 for n in gennames(filename):
170 170 if not self.backupvfs.exists(n):
171 171 return self.backupvfs.join(n)
172 172
173 173 def movetobackup(self):
174 174 if not self.backupvfs.isdir():
175 175 self.backupvfs.makedir()
176 176 for suffix in shelvefileextensions:
177 177 filename = self.name + b'.' + suffix
178 178 if self.vfs.exists(filename):
179 179 util.rename(
180 180 self.vfs.join(filename), self._backupfilename(filename)
181 181 )
182 182
183 183
184 184 class shelvedstate(object):
185 185 """Handle persistence during unshelving operations.
186 186
187 187 Handles saving and restoring a shelved state. Ensures that different
188 188 versions of a shelved state are possible and handles them appropriately.
189 189 """
190 190
191 191 _version = 2
192 192 _filename = b'shelvedstate'
193 193 _keep = b'keep'
194 194 _nokeep = b'nokeep'
195 195 # colon is essential to differentiate from a real bookmark name
196 196 _noactivebook = b':no-active-bookmark'
197 197 _interactive = b'interactive'
198 198
199 199 @classmethod
200 200 def _verifyandtransform(cls, d):
201 201 """Some basic shelvestate syntactic verification and transformation"""
202 202 try:
203 203 d[b'originalwctx'] = bin(d[b'originalwctx'])
204 204 d[b'pendingctx'] = bin(d[b'pendingctx'])
205 205 d[b'parents'] = [bin(h) for h in d[b'parents'].split(b' ')]
206 206 d[b'nodestoremove'] = [
207 207 bin(h) for h in d[b'nodestoremove'].split(b' ')
208 208 ]
209 209 except (ValueError, TypeError, KeyError) as err:
210 210 raise error.CorruptedState(pycompat.bytestr(err))
211 211
212 212 @classmethod
213 213 def _getversion(cls, repo):
214 214 """Read version information from shelvestate file"""
215 215 fp = repo.vfs(cls._filename)
216 216 try:
217 217 version = int(fp.readline().strip())
218 218 except ValueError as err:
219 219 raise error.CorruptedState(pycompat.bytestr(err))
220 220 finally:
221 221 fp.close()
222 222 return version
223 223
224 224 @classmethod
225 225 def _readold(cls, repo):
226 226 """Read the old position-based version of a shelvestate file"""
227 227 # Order is important, because old shelvestate file uses it
228 228 # to detemine values of fields (i.g. name is on the second line,
229 229 # originalwctx is on the third and so forth). Please do not change.
230 230 keys = [
231 231 b'version',
232 232 b'name',
233 233 b'originalwctx',
234 234 b'pendingctx',
235 235 b'parents',
236 236 b'nodestoremove',
237 237 b'branchtorestore',
238 238 b'keep',
239 239 b'activebook',
240 240 ]
241 241 # this is executed only seldomly, so it is not a big deal
242 242 # that we open this file twice
243 243 fp = repo.vfs(cls._filename)
244 244 d = {}
245 245 try:
246 246 for key in keys:
247 247 d[key] = fp.readline().strip()
248 248 finally:
249 249 fp.close()
250 250 return d
251 251
252 252 @classmethod
253 253 def load(cls, repo):
254 254 version = cls._getversion(repo)
255 255 if version < cls._version:
256 256 d = cls._readold(repo)
257 257 elif version == cls._version:
258 258 d = scmutil.simplekeyvaluefile(repo.vfs, cls._filename).read(
259 259 firstlinenonkeyval=True
260 260 )
261 261 else:
262 262 raise error.Abort(
263 263 _(
264 264 b'this version of shelve is incompatible '
265 265 b'with the version used in this repo'
266 266 )
267 267 )
268 268
269 269 cls._verifyandtransform(d)
270 270 try:
271 271 obj = cls()
272 272 obj.name = d[b'name']
273 273 obj.wctx = repo[d[b'originalwctx']]
274 274 obj.pendingctx = repo[d[b'pendingctx']]
275 275 obj.parents = d[b'parents']
276 276 obj.nodestoremove = d[b'nodestoremove']
277 277 obj.branchtorestore = d.get(b'branchtorestore', b'')
278 278 obj.keep = d.get(b'keep') == cls._keep
279 279 obj.activebookmark = b''
280 280 if d.get(b'activebook', b'') != cls._noactivebook:
281 281 obj.activebookmark = d.get(b'activebook', b'')
282 282 obj.interactive = d.get(b'interactive') == cls._interactive
283 283 except (error.RepoLookupError, KeyError) as err:
284 284 raise error.CorruptedState(pycompat.bytestr(err))
285 285
286 286 return obj
287 287
288 288 @classmethod
289 289 def save(
290 290 cls,
291 291 repo,
292 292 name,
293 293 originalwctx,
294 294 pendingctx,
295 295 nodestoremove,
296 296 branchtorestore,
297 297 keep=False,
298 298 activebook=b'',
299 299 interactive=False,
300 300 ):
301 301 info = {
302 302 b"name": name,
303 303 b"originalwctx": hex(originalwctx.node()),
304 304 b"pendingctx": hex(pendingctx.node()),
305 305 b"parents": b' '.join([hex(p) for p in repo.dirstate.parents()]),
306 306 b"nodestoremove": b' '.join([hex(n) for n in nodestoremove]),
307 307 b"branchtorestore": branchtorestore,
308 308 b"keep": cls._keep if keep else cls._nokeep,
309 309 b"activebook": activebook or cls._noactivebook,
310 310 }
311 311 if interactive:
312 312 info[b'interactive'] = cls._interactive
313 313 scmutil.simplekeyvaluefile(repo.vfs, cls._filename).write(
314 314 info, firstline=(b"%d" % cls._version)
315 315 )
316 316
317 317 @classmethod
318 318 def clear(cls, repo):
319 319 repo.vfs.unlinkpath(cls._filename, ignoremissing=True)
320 320
321 321
322 322 def cleanupoldbackups(repo):
323 323 vfs = vfsmod.vfs(repo.vfs.join(backupdir))
324 324 maxbackups = repo.ui.configint(b'shelve', b'maxbackups')
325 325 hgfiles = [f for f in vfs.listdir() if f.endswith(b'.' + patchextension)]
326 326 hgfiles = sorted([(vfs.stat(f)[stat.ST_MTIME], f) for f in hgfiles])
327 327 if maxbackups > 0 and maxbackups < len(hgfiles):
328 328 bordermtime = hgfiles[-maxbackups][0]
329 329 else:
330 330 bordermtime = None
331 331 for mtime, f in hgfiles[: len(hgfiles) - maxbackups]:
332 332 if mtime == bordermtime:
333 333 # keep it, because timestamp can't decide exact order of backups
334 334 continue
335 335 base = f[: -(1 + len(patchextension))]
336 336 for ext in shelvefileextensions:
337 337 vfs.tryunlink(base + b'.' + ext)
338 338
339 339
340 340 def _backupactivebookmark(repo):
341 341 activebookmark = repo._activebookmark
342 342 if activebookmark:
343 343 bookmarks.deactivate(repo)
344 344 return activebookmark
345 345
346 346
347 347 def _restoreactivebookmark(repo, mark):
348 348 if mark:
349 349 bookmarks.activate(repo, mark)
350 350
351 351
352 352 def _aborttransaction(repo, tr):
353 353 """Abort current transaction for shelve/unshelve, but keep dirstate"""
354 354 dirstatebackupname = b'dirstate.shelve'
355 355 repo.dirstate.savebackup(tr, dirstatebackupname)
356 356 tr.abort()
357 357 repo.dirstate.restorebackup(None, dirstatebackupname)
358 358
359 359
360 360 def getshelvename(repo, parent, opts):
361 361 """Decide on the name this shelve is going to have"""
362 362
363 363 def gennames():
364 364 yield label
365 365 for i in itertools.count(1):
366 366 yield b'%s-%02d' % (label, i)
367 367
368 368 name = opts.get(b'name')
369 369 label = repo._activebookmark or parent.branch() or b'default'
370 370 # slashes aren't allowed in filenames, therefore we rename it
371 371 label = label.replace(b'/', b'_')
372 372 label = label.replace(b'\\', b'_')
373 373 # filenames must not start with '.' as it should not be hidden
374 374 if label.startswith(b'.'):
375 375 label = label.replace(b'.', b'_', 1)
376 376
377 377 if name:
378 378 if Shelf(repo, name).exists():
379 379 e = _(b"a shelved change named '%s' already exists") % name
380 380 raise error.Abort(e)
381 381
382 382 # ensure we are not creating a subdirectory or a hidden file
383 383 if b'/' in name or b'\\' in name:
384 384 raise error.Abort(
385 385 _(b'shelved change names can not contain slashes')
386 386 )
387 387 if name.startswith(b'.'):
388 388 raise error.Abort(_(b"shelved change names can not start with '.'"))
389 389
390 390 else:
391 391 for n in gennames():
392 392 if not Shelf(repo, n).exists():
393 393 name = n
394 394 break
395 395
396 396 return name
397 397
398 398
399 399 def mutableancestors(ctx):
400 400 """return all mutable ancestors for ctx (included)
401 401
402 402 Much faster than the revset ancestors(ctx) & draft()"""
403 403 seen = {nullrev}
404 404 visit = collections.deque()
405 405 visit.append(ctx)
406 406 while visit:
407 407 ctx = visit.popleft()
408 408 yield ctx.node()
409 409 for parent in ctx.parents():
410 410 rev = parent.rev()
411 411 if rev not in seen:
412 412 seen.add(rev)
413 413 if parent.mutable():
414 414 visit.append(parent)
415 415
416 416
417 417 def getcommitfunc(extra, interactive, editor=False):
418 418 def commitfunc(ui, repo, message, match, opts):
419 419 hasmq = util.safehasattr(repo, b'mq')
420 420 if hasmq:
421 421 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
422 422
423 423 targetphase = phases.internal
424 424 if not phases.supportinternal(repo):
425 425 targetphase = phases.secret
426 426 overrides = {(b'phases', b'new-commit'): targetphase}
427 427 try:
428 428 editor_ = False
429 429 if editor:
430 430 editor_ = cmdutil.getcommiteditor(
431 431 editform=b'shelve.shelve', **pycompat.strkwargs(opts)
432 432 )
433 433 with repo.ui.configoverride(overrides):
434 434 return repo.commit(
435 435 message,
436 436 shelveuser,
437 437 opts.get(b'date'),
438 438 match,
439 439 editor=editor_,
440 440 extra=extra,
441 441 )
442 442 finally:
443 443 if hasmq:
444 444 repo.mq.checkapplied = saved
445 445
446 446 def interactivecommitfunc(ui, repo, *pats, **opts):
447 447 opts = pycompat.byteskwargs(opts)
448 448 match = scmutil.match(repo[b'.'], pats, {})
449 449 message = opts[b'message']
450 450 return commitfunc(ui, repo, message, match, opts)
451 451
452 452 return interactivecommitfunc if interactive else commitfunc
453 453
454 454
455 455 def _nothingtoshelvemessaging(ui, repo, pats, opts):
456 456 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
457 457 if stat.deleted:
458 458 ui.status(
459 459 _(b"nothing changed (%d missing files, see 'hg status')\n")
460 460 % len(stat.deleted)
461 461 )
462 462 else:
463 463 ui.status(_(b"nothing changed\n"))
464 464
465 465
466 466 def _shelvecreatedcommit(repo, node, name, match):
467 467 info = {b'node': hex(node)}
468 468 shelf = Shelf(repo, name)
469 469 shelf.writeinfo(info)
470 470 bases = list(mutableancestors(repo[node]))
471 471 shelf.writebundle(bases, node)
472 472 with shelf.open_patch(b'wb') as fp:
473 473 cmdutil.exportfile(
474 474 repo, [node], fp, opts=mdiff.diffopts(git=True), match=match
475 475 )
476 476
477 477
478 478 def _includeunknownfiles(repo, pats, opts, extra):
479 479 s = repo.status(match=scmutil.match(repo[None], pats, opts), unknown=True)
480 480 if s.unknown:
481 481 extra[b'shelve_unknown'] = b'\0'.join(s.unknown)
482 482 repo[None].add(s.unknown)
483 483
484 484
485 485 def _finishshelve(repo, tr):
486 486 if phases.supportinternal(repo):
487 487 tr.close()
488 488 else:
489 489 _aborttransaction(repo, tr)
490 490
491 491
492 492 def createcmd(ui, repo, pats, opts):
493 493 """subcommand that creates a new shelve"""
494 494 with repo.wlock():
495 495 cmdutil.checkunfinished(repo)
496 496 return _docreatecmd(ui, repo, pats, opts)
497 497
498 498
499 499 def _docreatecmd(ui, repo, pats, opts):
500 500 wctx = repo[None]
501 501 parents = wctx.parents()
502 502 parent = parents[0]
503 503 origbranch = wctx.branch()
504 504
505 505 if parent.node() != nullid:
506 506 desc = b"changes to: %s" % parent.description().split(b'\n', 1)[0]
507 507 else:
508 508 desc = b'(changes in empty repository)'
509 509
510 510 if not opts.get(b'message'):
511 511 opts[b'message'] = desc
512 512
513 513 lock = tr = activebookmark = None
514 514 try:
515 515 lock = repo.lock()
516 516
517 517 # use an uncommitted transaction to generate the bundle to avoid
518 518 # pull races. ensure we don't print the abort message to stderr.
519 519 tr = repo.transaction(b'shelve', report=lambda x: None)
520 520
521 521 interactive = opts.get(b'interactive', False)
522 522 includeunknown = opts.get(b'unknown', False) and not opts.get(
523 523 b'addremove', False
524 524 )
525 525
526 526 name = getshelvename(repo, parent, opts)
527 527 activebookmark = _backupactivebookmark(repo)
528 528 extra = {b'internal': b'shelve'}
529 529 if includeunknown:
530 530 _includeunknownfiles(repo, pats, opts, extra)
531 531
532 532 if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts):
533 533 # In non-bare shelve we don't store newly created branch
534 534 # at bundled commit
535 535 repo.dirstate.setbranch(repo[b'.'].branch())
536 536
537 537 commitfunc = getcommitfunc(extra, interactive, editor=True)
538 538 if not interactive:
539 539 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
540 540 else:
541 541 node = cmdutil.dorecord(
542 542 ui,
543 543 repo,
544 544 commitfunc,
545 545 None,
546 546 False,
547 547 cmdutil.recordfilter,
548 548 *pats,
549 549 **pycompat.strkwargs(opts)
550 550 )
551 551 if not node:
552 552 _nothingtoshelvemessaging(ui, repo, pats, opts)
553 553 return 1
554 554
555 555 # Create a matcher so that prefetch doesn't attempt to fetch
556 556 # the entire repository pointlessly, and as an optimisation
557 557 # for movedirstate, if needed.
558 558 match = scmutil.matchfiles(repo, repo[node].files())
559 559 _shelvecreatedcommit(repo, node, name, match)
560 560
561 561 ui.status(_(b'shelved as %s\n') % name)
562 562 if opts[b'keep']:
563 563 with repo.dirstate.parentchange():
564 564 scmutil.movedirstate(repo, parent, match)
565 565 else:
566 566 hg.update(repo, parent.node())
567 567 ms = mergestatemod.mergestate.read(repo)
568 568 if not ms.unresolvedcount():
569 569 ms.reset()
570 570
571 571 if origbranch != repo[b'.'].branch() and not _isbareshelve(pats, opts):
572 572 repo.dirstate.setbranch(origbranch)
573 573
574 574 _finishshelve(repo, tr)
575 575 finally:
576 576 _restoreactivebookmark(repo, activebookmark)
577 577 lockmod.release(tr, lock)
578 578
579 579
580 580 def _isbareshelve(pats, opts):
581 581 return (
582 582 not pats
583 583 and not opts.get(b'interactive', False)
584 584 and not opts.get(b'include', False)
585 585 and not opts.get(b'exclude', False)
586 586 )
587 587
588 588
589 589 def _iswctxonnewbranch(repo):
590 590 return repo[None].branch() != repo[b'.'].branch()
591 591
592 592
593 593 def cleanupcmd(ui, repo):
594 594 """subcommand that deletes all shelves"""
595 595
596 596 with repo.wlock():
597 597 for _mtime, name in listshelves(repo):
598 598 Shelf(repo, name).movetobackup()
599 599 cleanupoldbackups(repo)
600 600
601 601
602 602 def deletecmd(ui, repo, pats):
603 603 """subcommand that deletes a specific shelve"""
604 604 if not pats:
605 605 raise error.InputError(_(b'no shelved changes specified!'))
606 606 with repo.wlock():
607 607 for name in pats:
608 608 shelf = Shelf(repo, name)
609 609 if not shelf.exists():
610 610 raise error.InputError(
611 611 _(b"shelved change '%s' not found") % name
612 612 )
613 613 shelf.movetobackup()
614 614 cleanupoldbackups(repo)
615 615
616 616
617 617 def listshelves(repo):
618 618 """return all shelves in repo as list of (time, name)"""
619 619 try:
620 620 names = repo.vfs.readdir(shelvedir)
621 621 except OSError as err:
622 622 if err.errno != errno.ENOENT:
623 623 raise
624 624 return []
625 625 info = []
626 626 seen = set()
627 627 for (filename, _type) in names:
628 name, ext = filename.rsplit(b'.', 1)
628 name = filename.rsplit(b'.', 1)[0]
629 629 if name in seen:
630 630 continue
631 631 seen.add(name)
632 632 shelf = Shelf(repo, name)
633 633 if not shelf.exists():
634 634 continue
635 635 mtime = shelf.mtime()
636 636 info.append((mtime, name))
637 637 return sorted(info, reverse=True)
638 638
639 639
640 640 def listcmd(ui, repo, pats, opts):
641 641 """subcommand that displays the list of shelves"""
642 642 pats = set(pats)
643 643 width = 80
644 644 if not ui.plain():
645 645 width = ui.termwidth()
646 646 namelabel = b'shelve.newest'
647 647 ui.pager(b'shelve')
648 648 for mtime, name in listshelves(repo):
649 649 if pats and name not in pats:
650 650 continue
651 651 ui.write(name, label=namelabel)
652 652 namelabel = b'shelve.name'
653 653 if ui.quiet:
654 654 ui.write(b'\n')
655 655 continue
656 656 ui.write(b' ' * (16 - len(name)))
657 657 used = 16
658 658 date = dateutil.makedate(mtime)
659 659 age = b'(%s)' % templatefilters.age(date, abbrev=True)
660 660 ui.write(age, label=b'shelve.age')
661 661 ui.write(b' ' * (12 - len(age)))
662 662 used += 12
663 663 with Shelf(repo, name).open_patch() as fp:
664 664 while True:
665 665 line = fp.readline()
666 666 if not line:
667 667 break
668 668 if not line.startswith(b'#'):
669 669 desc = line.rstrip()
670 670 if ui.formatted():
671 671 desc = stringutil.ellipsis(desc, width - used)
672 672 ui.write(desc)
673 673 break
674 674 ui.write(b'\n')
675 675 if not (opts[b'patch'] or opts[b'stat']):
676 676 continue
677 677 difflines = fp.readlines()
678 678 if opts[b'patch']:
679 679 for chunk, label in patch.difflabel(iter, difflines):
680 680 ui.write(chunk, label=label)
681 681 if opts[b'stat']:
682 682 for chunk, label in patch.diffstatui(difflines, width=width):
683 683 ui.write(chunk, label=label)
684 684
685 685
686 686 def patchcmds(ui, repo, pats, opts):
687 687 """subcommand that displays shelves"""
688 688 if len(pats) == 0:
689 689 shelves = listshelves(repo)
690 690 if not shelves:
691 691 raise error.Abort(_(b"there are no shelves to show"))
692 692 mtime, name = shelves[0]
693 693 pats = [name]
694 694
695 695 for shelfname in pats:
696 696 if not Shelf(repo, shelfname).exists():
697 697 raise error.Abort(_(b"cannot find shelf %s") % shelfname)
698 698
699 699 listcmd(ui, repo, pats, opts)
700 700
701 701
702 702 def checkparents(repo, state):
703 703 """check parent while resuming an unshelve"""
704 704 if state.parents != repo.dirstate.parents():
705 705 raise error.Abort(
706 706 _(b'working directory parents do not match unshelve state')
707 707 )
708 708
709 709
710 710 def _loadshelvedstate(ui, repo, opts):
711 711 try:
712 712 state = shelvedstate.load(repo)
713 713 if opts.get(b'keep') is None:
714 714 opts[b'keep'] = state.keep
715 715 except IOError as err:
716 716 if err.errno != errno.ENOENT:
717 717 raise
718 718 cmdutil.wrongtooltocontinue(repo, _(b'unshelve'))
719 719 except error.CorruptedState as err:
720 720 ui.debug(pycompat.bytestr(err) + b'\n')
721 721 if opts.get(b'continue'):
722 722 msg = _(b'corrupted shelved state file')
723 723 hint = _(
724 724 b'please run hg unshelve --abort to abort unshelve '
725 725 b'operation'
726 726 )
727 727 raise error.Abort(msg, hint=hint)
728 728 elif opts.get(b'abort'):
729 729 shelvedstate.clear(repo)
730 730 raise error.Abort(
731 731 _(
732 732 b'could not read shelved state file, your '
733 733 b'working copy may be in an unexpected state\n'
734 734 b'please update to some commit\n'
735 735 )
736 736 )
737 737 return state
738 738
739 739
740 740 def unshelveabort(ui, repo, state):
741 741 """subcommand that abort an in-progress unshelve"""
742 742 with repo.lock():
743 743 try:
744 744 checkparents(repo, state)
745 745
746 746 merge.clean_update(state.pendingctx)
747 747 if state.activebookmark and state.activebookmark in repo._bookmarks:
748 748 bookmarks.activate(repo, state.activebookmark)
749 749 mergefiles(ui, repo, state.wctx, state.pendingctx)
750 750 if not phases.supportinternal(repo):
751 751 repair.strip(
752 752 ui, repo, state.nodestoremove, backup=False, topic=b'shelve'
753 753 )
754 754 finally:
755 755 shelvedstate.clear(repo)
756 756 ui.warn(_(b"unshelve of '%s' aborted\n") % state.name)
757 757
758 758
759 759 def hgabortunshelve(ui, repo):
760 760 """logic to abort unshelve using 'hg abort"""
761 761 with repo.wlock():
762 762 state = _loadshelvedstate(ui, repo, {b'abort': True})
763 763 return unshelveabort(ui, repo, state)
764 764
765 765
766 766 def mergefiles(ui, repo, wctx, shelvectx):
767 767 """updates to wctx and merges the changes from shelvectx into the
768 768 dirstate."""
769 769 with ui.configoverride({(b'ui', b'quiet'): True}):
770 770 hg.update(repo, wctx.node())
771 771 ui.pushbuffer(True)
772 772 cmdutil.revert(ui, repo, shelvectx)
773 773 ui.popbuffer()
774 774
775 775
776 776 def restorebranch(ui, repo, branchtorestore):
777 777 if branchtorestore and branchtorestore != repo.dirstate.branch():
778 778 repo.dirstate.setbranch(branchtorestore)
779 779 ui.status(
780 780 _(b'marked working directory as branch %s\n') % branchtorestore
781 781 )
782 782
783 783
784 784 def unshelvecleanup(ui, repo, name, opts):
785 785 """remove related files after an unshelve"""
786 786 if not opts.get(b'keep'):
787 787 Shelf(repo, name).movetobackup()
788 788 cleanupoldbackups(repo)
789 789
790 790
791 791 def unshelvecontinue(ui, repo, state, opts):
792 792 """subcommand to continue an in-progress unshelve"""
793 793 # We're finishing off a merge. First parent is our original
794 794 # parent, second is the temporary "fake" commit we're unshelving.
795 795 interactive = state.interactive
796 796 basename = state.name
797 797 with repo.lock():
798 798 checkparents(repo, state)
799 799 ms = mergestatemod.mergestate.read(repo)
800 800 if list(ms.unresolved()):
801 801 raise error.Abort(
802 802 _(b"unresolved conflicts, can't continue"),
803 803 hint=_(b"see 'hg resolve', then 'hg unshelve --continue'"),
804 804 )
805 805
806 806 shelvectx = repo[state.parents[1]]
807 807 pendingctx = state.pendingctx
808 808
809 809 with repo.dirstate.parentchange():
810 810 repo.setparents(state.pendingctx.node(), nullid)
811 811 repo.dirstate.write(repo.currenttransaction())
812 812
813 813 targetphase = phases.internal
814 814 if not phases.supportinternal(repo):
815 815 targetphase = phases.secret
816 816 overrides = {(b'phases', b'new-commit'): targetphase}
817 817 with repo.ui.configoverride(overrides, b'unshelve'):
818 818 with repo.dirstate.parentchange():
819 819 repo.setparents(state.parents[0], nullid)
820 820 newnode, ispartialunshelve = _createunshelvectx(
821 821 ui, repo, shelvectx, basename, interactive, opts
822 822 )
823 823
824 824 if newnode is None:
825 825 shelvectx = state.pendingctx
826 826 msg = _(
827 827 b'note: unshelved changes already existed '
828 828 b'in the working copy\n'
829 829 )
830 830 ui.status(msg)
831 831 else:
832 832 # only strip the shelvectx if we produced one
833 833 state.nodestoremove.append(newnode)
834 834 shelvectx = repo[newnode]
835 835
836 836 merge.update(pendingctx)
837 837 mergefiles(ui, repo, state.wctx, shelvectx)
838 838 restorebranch(ui, repo, state.branchtorestore)
839 839
840 840 if not phases.supportinternal(repo):
841 841 repair.strip(
842 842 ui, repo, state.nodestoremove, backup=False, topic=b'shelve'
843 843 )
844 844 shelvedstate.clear(repo)
845 845 if not ispartialunshelve:
846 846 unshelvecleanup(ui, repo, state.name, opts)
847 847 _restoreactivebookmark(repo, state.activebookmark)
848 848 ui.status(_(b"unshelve of '%s' complete\n") % state.name)
849 849
850 850
851 851 def hgcontinueunshelve(ui, repo):
852 852 """logic to resume unshelve using 'hg continue'"""
853 853 with repo.wlock():
854 854 state = _loadshelvedstate(ui, repo, {b'continue': True})
855 855 return unshelvecontinue(ui, repo, state, {b'keep': state.keep})
856 856
857 857
858 858 def _commitworkingcopychanges(ui, repo, opts, tmpwctx):
859 859 """Temporarily commit working copy changes before moving unshelve commit"""
860 860 # Store pending changes in a commit and remember added in case a shelve
861 861 # contains unknown files that are part of the pending change
862 862 s = repo.status()
863 863 addedbefore = frozenset(s.added)
864 864 if not (s.modified or s.added or s.removed):
865 865 return tmpwctx, addedbefore
866 866 ui.status(
867 867 _(
868 868 b"temporarily committing pending changes "
869 869 b"(restore with 'hg unshelve --abort')\n"
870 870 )
871 871 )
872 872 extra = {b'internal': b'shelve'}
873 873 commitfunc = getcommitfunc(extra=extra, interactive=False, editor=False)
874 874 tempopts = {}
875 875 tempopts[b'message'] = b"pending changes temporary commit"
876 876 tempopts[b'date'] = opts.get(b'date')
877 877 with ui.configoverride({(b'ui', b'quiet'): True}):
878 878 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
879 879 tmpwctx = repo[node]
880 880 return tmpwctx, addedbefore
881 881
882 882
883 883 def _unshelverestorecommit(ui, repo, tr, basename):
884 884 """Recreate commit in the repository during the unshelve"""
885 885 repo = repo.unfiltered()
886 886 node = None
887 887 shelf = Shelf(repo, basename)
888 888 if shelf.hasinfo():
889 889 node = shelf.readinfo()[b'node']
890 890 if node is None or node not in repo:
891 891 with ui.configoverride({(b'ui', b'quiet'): True}):
892 892 shelvectx = shelf.applybundle(tr)
893 893 # We might not strip the unbundled changeset, so we should keep track of
894 894 # the unshelve node in case we need to reuse it (eg: unshelve --keep)
895 895 if node is None:
896 896 info = {b'node': hex(shelvectx.node())}
897 897 shelf.writeinfo(info)
898 898 else:
899 899 shelvectx = repo[node]
900 900
901 901 return repo, shelvectx
902 902
903 903
904 904 def _createunshelvectx(ui, repo, shelvectx, basename, interactive, opts):
905 905 """Handles the creation of unshelve commit and updates the shelve if it
906 906 was partially unshelved.
907 907
908 908 If interactive is:
909 909
910 910 * False: Commits all the changes in the working directory.
911 911 * True: Prompts the user to select changes to unshelve and commit them.
912 912 Update the shelve with remaining changes.
913 913
914 914 Returns the node of the new commit formed and a bool indicating whether
915 915 the shelve was partially unshelved.Creates a commit ctx to unshelve
916 916 interactively or non-interactively.
917 917
918 918 The user might want to unshelve certain changes only from the stored
919 919 shelve in interactive. So, we would create two commits. One with requested
920 920 changes to unshelve at that time and the latter is shelved for future.
921 921
922 922 Here, we return both the newnode which is created interactively and a
923 923 bool to know whether the shelve is partly done or completely done.
924 924 """
925 925 opts[b'message'] = shelvectx.description()
926 926 opts[b'interactive-unshelve'] = True
927 927 pats = []
928 928 if not interactive:
929 929 newnode = repo.commit(
930 930 text=shelvectx.description(),
931 931 extra=shelvectx.extra(),
932 932 user=shelvectx.user(),
933 933 date=shelvectx.date(),
934 934 )
935 935 return newnode, False
936 936
937 937 commitfunc = getcommitfunc(shelvectx.extra(), interactive=True, editor=True)
938 938 newnode = cmdutil.dorecord(
939 939 ui,
940 940 repo,
941 941 commitfunc,
942 942 None,
943 943 False,
944 944 cmdutil.recordfilter,
945 945 *pats,
946 946 **pycompat.strkwargs(opts)
947 947 )
948 948 snode = repo.commit(
949 949 text=shelvectx.description(),
950 950 extra=shelvectx.extra(),
951 951 user=shelvectx.user(),
952 952 )
953 953 if snode:
954 954 m = scmutil.matchfiles(repo, repo[snode].files())
955 955 _shelvecreatedcommit(repo, snode, basename, m)
956 956
957 957 return newnode, bool(snode)
958 958
959 959
960 960 def _rebaserestoredcommit(
961 961 ui,
962 962 repo,
963 963 opts,
964 964 tr,
965 965 oldtiprev,
966 966 basename,
967 967 pctx,
968 968 tmpwctx,
969 969 shelvectx,
970 970 branchtorestore,
971 971 activebookmark,
972 972 ):
973 973 """Rebase restored commit from its original location to a destination"""
974 974 # If the shelve is not immediately on top of the commit
975 975 # we'll be merging with, rebase it to be on top.
976 976 interactive = opts.get(b'interactive')
977 977 if tmpwctx.node() == shelvectx.p1().node() and not interactive:
978 978 # We won't skip on interactive mode because, the user might want to
979 979 # unshelve certain changes only.
980 980 return shelvectx, False
981 981
982 982 overrides = {
983 983 (b'ui', b'forcemerge'): opts.get(b'tool', b''),
984 984 (b'phases', b'new-commit'): phases.secret,
985 985 }
986 986 with repo.ui.configoverride(overrides, b'unshelve'):
987 987 ui.status(_(b'rebasing shelved changes\n'))
988 988 stats = merge.graft(
989 989 repo,
990 990 shelvectx,
991 991 labels=[b'working-copy', b'shelve'],
992 992 keepconflictparent=True,
993 993 )
994 994 if stats.unresolvedcount:
995 995 tr.close()
996 996
997 997 nodestoremove = [
998 998 repo.changelog.node(rev)
999 999 for rev in pycompat.xrange(oldtiprev, len(repo))
1000 1000 ]
1001 1001 shelvedstate.save(
1002 1002 repo,
1003 1003 basename,
1004 1004 pctx,
1005 1005 tmpwctx,
1006 1006 nodestoremove,
1007 1007 branchtorestore,
1008 1008 opts.get(b'keep'),
1009 1009 activebookmark,
1010 1010 interactive,
1011 1011 )
1012 1012 raise error.ConflictResolutionRequired(b'unshelve')
1013 1013
1014 1014 with repo.dirstate.parentchange():
1015 1015 repo.setparents(tmpwctx.node(), nullid)
1016 1016 newnode, ispartialunshelve = _createunshelvectx(
1017 1017 ui, repo, shelvectx, basename, interactive, opts
1018 1018 )
1019 1019
1020 1020 if newnode is None:
1021 1021 shelvectx = tmpwctx
1022 1022 msg = _(
1023 1023 b'note: unshelved changes already existed '
1024 1024 b'in the working copy\n'
1025 1025 )
1026 1026 ui.status(msg)
1027 1027 else:
1028 1028 shelvectx = repo[newnode]
1029 1029 merge.update(tmpwctx)
1030 1030
1031 1031 return shelvectx, ispartialunshelve
1032 1032
1033 1033
1034 1034 def _forgetunknownfiles(repo, shelvectx, addedbefore):
1035 1035 # Forget any files that were unknown before the shelve, unknown before
1036 1036 # unshelve started, but are now added.
1037 1037 shelveunknown = shelvectx.extra().get(b'shelve_unknown')
1038 1038 if not shelveunknown:
1039 1039 return
1040 1040 shelveunknown = frozenset(shelveunknown.split(b'\0'))
1041 1041 addedafter = frozenset(repo.status().added)
1042 1042 toforget = (addedafter & shelveunknown) - addedbefore
1043 1043 repo[None].forget(toforget)
1044 1044
1045 1045
1046 1046 def _finishunshelve(repo, oldtiprev, tr, activebookmark):
1047 1047 _restoreactivebookmark(repo, activebookmark)
1048 1048 # The transaction aborting will strip all the commits for us,
1049 1049 # but it doesn't update the inmemory structures, so addchangegroup
1050 1050 # hooks still fire and try to operate on the missing commits.
1051 1051 # Clean up manually to prevent this.
1052 1052 repo.unfiltered().changelog.strip(oldtiprev, tr)
1053 1053 _aborttransaction(repo, tr)
1054 1054
1055 1055
1056 1056 def _checkunshelveuntrackedproblems(ui, repo, shelvectx):
1057 1057 """Check potential problems which may result from working
1058 1058 copy having untracked changes."""
1059 1059 wcdeleted = set(repo.status().deleted)
1060 1060 shelvetouched = set(shelvectx.files())
1061 1061 intersection = wcdeleted.intersection(shelvetouched)
1062 1062 if intersection:
1063 1063 m = _(b"shelved change touches missing files")
1064 1064 hint = _(b"run hg status to see which files are missing")
1065 1065 raise error.Abort(m, hint=hint)
1066 1066
1067 1067
1068 1068 def unshelvecmd(ui, repo, *shelved, **opts):
1069 1069 opts = pycompat.byteskwargs(opts)
1070 1070 abortf = opts.get(b'abort')
1071 1071 continuef = opts.get(b'continue')
1072 1072 interactive = opts.get(b'interactive')
1073 1073 if not abortf and not continuef:
1074 1074 cmdutil.checkunfinished(repo)
1075 1075 shelved = list(shelved)
1076 1076 if opts.get(b"name"):
1077 1077 shelved.append(opts[b"name"])
1078 1078
1079 1079 if interactive and opts.get(b'keep'):
1080 1080 raise error.InputError(
1081 1081 _(b'--keep on --interactive is not yet supported')
1082 1082 )
1083 1083 if abortf or continuef:
1084 1084 if abortf and continuef:
1085 1085 raise error.InputError(_(b'cannot use both abort and continue'))
1086 1086 if shelved:
1087 1087 raise error.InputError(
1088 1088 _(
1089 1089 b'cannot combine abort/continue with '
1090 1090 b'naming a shelved change'
1091 1091 )
1092 1092 )
1093 1093 if abortf and opts.get(b'tool', False):
1094 1094 ui.warn(_(b'tool option will be ignored\n'))
1095 1095
1096 1096 state = _loadshelvedstate(ui, repo, opts)
1097 1097 if abortf:
1098 1098 return unshelveabort(ui, repo, state)
1099 1099 elif continuef and interactive:
1100 1100 raise error.InputError(
1101 1101 _(b'cannot use both continue and interactive')
1102 1102 )
1103 1103 elif continuef:
1104 1104 return unshelvecontinue(ui, repo, state, opts)
1105 1105 elif len(shelved) > 1:
1106 1106 raise error.InputError(_(b'can only unshelve one change at a time'))
1107 1107 elif not shelved:
1108 1108 shelved = listshelves(repo)
1109 1109 if not shelved:
1110 1110 raise error.StateError(_(b'no shelved changes to apply!'))
1111 1111 basename = shelved[0][1]
1112 1112 ui.status(_(b"unshelving change '%s'\n") % basename)
1113 1113 else:
1114 1114 basename = shelved[0]
1115 1115
1116 1116 if not Shelf(repo, basename).exists():
1117 1117 raise error.InputError(_(b"shelved change '%s' not found") % basename)
1118 1118
1119 1119 return _dounshelve(ui, repo, basename, opts)
1120 1120
1121 1121
1122 1122 def _dounshelve(ui, repo, basename, opts):
1123 1123 repo = repo.unfiltered()
1124 1124 lock = tr = None
1125 1125 try:
1126 1126 lock = repo.lock()
1127 1127 tr = repo.transaction(b'unshelve', report=lambda x: None)
1128 1128 oldtiprev = len(repo)
1129 1129
1130 1130 pctx = repo[b'.']
1131 1131 tmpwctx = pctx
1132 1132 # The goal is to have a commit structure like so:
1133 1133 # ...-> pctx -> tmpwctx -> shelvectx
1134 1134 # where tmpwctx is an optional commit with the user's pending changes
1135 1135 # and shelvectx is the unshelved changes. Then we merge it all down
1136 1136 # to the original pctx.
1137 1137
1138 1138 activebookmark = _backupactivebookmark(repo)
1139 1139 tmpwctx, addedbefore = _commitworkingcopychanges(
1140 1140 ui, repo, opts, tmpwctx
1141 1141 )
1142 1142 repo, shelvectx = _unshelverestorecommit(ui, repo, tr, basename)
1143 1143 _checkunshelveuntrackedproblems(ui, repo, shelvectx)
1144 1144 branchtorestore = b''
1145 1145 if shelvectx.branch() != shelvectx.p1().branch():
1146 1146 branchtorestore = shelvectx.branch()
1147 1147
1148 1148 shelvectx, ispartialunshelve = _rebaserestoredcommit(
1149 1149 ui,
1150 1150 repo,
1151 1151 opts,
1152 1152 tr,
1153 1153 oldtiprev,
1154 1154 basename,
1155 1155 pctx,
1156 1156 tmpwctx,
1157 1157 shelvectx,
1158 1158 branchtorestore,
1159 1159 activebookmark,
1160 1160 )
1161 1161 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
1162 1162 with ui.configoverride(overrides, b'unshelve'):
1163 1163 mergefiles(ui, repo, pctx, shelvectx)
1164 1164 restorebranch(ui, repo, branchtorestore)
1165 1165 shelvedstate.clear(repo)
1166 1166 _finishunshelve(repo, oldtiprev, tr, activebookmark)
1167 1167 _forgetunknownfiles(repo, shelvectx, addedbefore)
1168 1168 if not ispartialunshelve:
1169 1169 unshelvecleanup(ui, repo, basename, opts)
1170 1170 finally:
1171 1171 if tr:
1172 1172 tr.release()
1173 1173 lockmod.release(lock)
@@ -1,994 +1,994 b''
1 1 #testcases stripbased phasebased
2 2 #testcases abortflag abortcommand
3 3 #testcases continueflag continuecommand
4 4
5 5 $ cat <<EOF >> $HGRCPATH
6 6 > [extensions]
7 7 > mq =
8 8 > [defaults]
9 9 > diff = --nodates --git
10 10 > qnew = --date '0 0'
11 11 > [shelve]
12 12 > maxbackups = 2
13 13 > EOF
14 14
15 15 #if phasebased
16 16
17 17 $ cat <<EOF >> $HGRCPATH
18 18 > [format]
19 19 > internal-phase = yes
20 20 > EOF
21 21
22 22 #endif
23 23
24 24 #if abortflag
25 25 $ cat >> $HGRCPATH <<EOF
26 26 > [alias]
27 27 > abort = unshelve --abort
28 28 > EOF
29 29 #endif
30 30
31 31 #if continueflag
32 32 $ cat >> $HGRCPATH <<EOF
33 33 > [alias]
34 34 > continue = unshelve --continue
35 35 > EOF
36 36 #endif
37 37
38 38 shelve should leave dirstate clean (issue4055)
39 39
40 40 $ hg init shelverebase
41 41 $ cd shelverebase
42 42 $ printf 'x\ny\n' > x
43 43 $ echo z > z
44 44 $ hg commit -Aqm xy
45 45 $ echo z >> x
46 46 $ hg commit -Aqm z
47 47 $ hg up 5c4c67fb7dce
48 48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 49 $ printf 'a\nx\ny\nz\n' > x
50 50 $ hg commit -Aqm xyz
51 51 $ echo c >> z
52 52 $ hg shelve
53 53 shelved as default
54 54 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
55 55
56 56 $ hg rebase -d 6c103be8f4e4 --config extensions.rebase=
57 57 rebasing 2:323bfa07f744( tip)? "xyz" (re)
58 58 merging x
59 59 saved backup bundle to \$TESTTMP/shelverebase/.hg/strip-backup/323bfa07f744-(78114325|7ae538ef)-rebase.hg (re)
60 60 $ hg unshelve
61 61 unshelving change 'default'
62 62 rebasing shelved changes
63 63 $ hg status
64 64 M z
65 65
66 66 $ cd ..
67 67
68 68 shelve should only unshelve pending changes (issue4068)
69 69
70 70 $ hg init onlypendingchanges
71 71 $ cd onlypendingchanges
72 72 $ touch a
73 73 $ hg ci -Aqm a
74 74 $ touch b
75 75 $ hg ci -Aqm b
76 76 $ hg up -q 3903775176ed
77 77 $ touch c
78 78 $ hg ci -Aqm c
79 79
80 80 $ touch d
81 81 $ hg add d
82 82 $ hg shelve
83 83 shelved as default
84 84 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
85 85 $ hg up -q 0e067c57feba
86 86 $ hg unshelve
87 87 unshelving change 'default'
88 88 rebasing shelved changes
89 89 $ hg status
90 90 A d
91 91
92 92 unshelve should work on an ancestor of the original commit
93 93
94 94 $ hg shelve
95 95 shelved as default
96 96 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
97 97 $ hg up 3903775176ed
98 98 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
99 99 $ hg unshelve
100 100 unshelving change 'default'
101 101 rebasing shelved changes
102 102 $ hg status
103 103 A d
104 104
105 105 test bug 4073 we need to enable obsolete markers for it
106 106
107 107 $ cat >> $HGRCPATH << EOF
108 108 > [experimental]
109 109 > evolution.createmarkers=True
110 110 > EOF
111 111 $ hg shelve
112 112 shelved as default
113 113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 114 $ hg debugobsolete `hg log -r 0e067c57feba -T '{node}'`
115 115 1 new obsolescence markers
116 116 obsoleted 1 changesets
117 117 $ hg unshelve
118 118 unshelving change 'default'
119 119
120 120 unshelve should leave unknown files alone (issue4113)
121 121
122 122 $ echo e > e
123 123 $ hg shelve
124 124 shelved as default
125 125 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
126 126 $ hg status
127 127 ? e
128 128 $ hg unshelve
129 129 unshelving change 'default'
130 130 $ hg status
131 131 A d
132 132 ? e
133 133 $ cat e
134 134 e
135 135
136 136 unshelve should keep a copy of unknown files
137 137
138 138 $ hg add e
139 139 $ hg shelve
140 140 shelved as default
141 141 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
142 142 $ echo z > e
143 143 $ hg unshelve
144 144 unshelving change 'default'
145 145 $ cat e
146 146 e
147 147 $ cat e.orig
148 148 z
149 149 $ rm e.orig
150 150
151 151 restores backup of unknown file to right directory
152 152
153 153 $ hg shelve
154 154 shelved as default
155 155 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
156 156 $ echo z > e
157 157 $ mkdir dir
158 158 $ hg unshelve --cwd dir
159 159 unshelving change 'default'
160 160 $ rmdir dir
161 161 $ cat e
162 162 e
163 163 $ cat e.orig
164 164 z
165 165
166 166 unshelve and conflicts with tracked and untracked files
167 167
168 168 preparing:
169 169
170 170 $ rm -f *.orig
171 171 $ hg ci -qm 'commit stuff'
172 172 $ hg phase -p null:
173 173
174 174 no other changes - no merge:
175 175
176 176 $ echo f > f
177 177 $ hg add f
178 178 $ hg shelve
179 179 shelved as default
180 180 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
181 181 $ echo g > f
182 182 $ hg unshelve
183 183 unshelving change 'default'
184 184 $ hg st
185 185 A f
186 186 ? f.orig
187 187 $ cat f
188 188 f
189 189 $ cat f.orig
190 190 g
191 191
192 192 other uncommitted changes - merge:
193 193
194 194 $ hg st
195 195 A f
196 196 ? f.orig
197 197 $ hg shelve
198 198 shelved as default
199 199 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
200 200 #if repobundlerepo
201 201 $ hg log -G --template '{rev} {desc|firstline} {author}' -R bundle://.hg/shelved/default.hg -r 'bundle()' --hidden
202 202 o [48] changes to: commit stuff shelve@localhost (re)
203 203 |
204 204 ~
205 205 #endif
206 206 $ hg log -G --template '{rev} {desc|firstline} {author}'
207 207 @ [37] commit stuff test (re)
208 208 |
209 209 | o 2 c test
210 210 |/
211 211 o 0 a test
212 212
213 213 $ mv f.orig f
214 214 $ echo 1 > a
215 215 $ hg unshelve --date '1073741824 0'
216 216 unshelving change 'default'
217 217 temporarily committing pending changes (restore with 'hg unshelve --abort')
218 218 rebasing shelved changes
219 219 merging f
220 220 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
221 221 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
222 222 [240]
223 223
224 224 #if phasebased
225 225 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
226 226 @ 9 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
227 227 |
228 228 | @ 8 changes to: commit stuff shelve@localhost 1970-01-01 00:00 +0000
229 229 |/
230 230 o 7 commit stuff test 1970-01-01 00:00 +0000
231 231 |
232 232 | o 2 c test 1970-01-01 00:00 +0000
233 233 |/
234 234 o 0 a test 1970-01-01 00:00 +0000
235 235
236 236 #endif
237 237
238 238 #if stripbased
239 239 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
240 240 @ 5 changes to: commit stuff shelve@localhost 1970-01-01 00:00 +0000
241 241 |
242 242 | @ 4 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
243 243 |/
244 244 o 3 commit stuff test 1970-01-01 00:00 +0000
245 245 |
246 246 | o 2 c test 1970-01-01 00:00 +0000
247 247 |/
248 248 o 0 a test 1970-01-01 00:00 +0000
249 249
250 250 #endif
251 251
252 252 $ hg st
253 253 M f
254 254 ? f.orig
255 255 $ cat f
256 256 <<<<<<< working-copy: d44eae5c3d33 - shelve: pending changes temporary commit
257 257 g
258 258 =======
259 259 f
260 260 >>>>>>> shelve: aef214a5229c - shelve: changes to: commit stuff
261 261 $ cat f.orig
262 262 g
263 263 $ hg unshelve --abort -t false
264 264 tool option will be ignored
265 265 unshelve of 'default' aborted
266 266 $ hg st
267 267 M a
268 268 ? f.orig
269 269 $ cat f.orig
270 270 g
271 271 $ hg unshelve
272 272 unshelving change 'default'
273 273 temporarily committing pending changes (restore with 'hg unshelve --abort')
274 274 rebasing shelved changes
275 275 $ hg st
276 276 M a
277 277 A f
278 278 ? f.orig
279 279
280 280 other committed changes - merge:
281 281
282 282 $ hg shelve f
283 283 shelved as default
284 284 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
285 285 $ hg ci a -m 'intermediate other change'
286 286 $ mv f.orig f
287 287 $ hg unshelve
288 288 unshelving change 'default'
289 289 rebasing shelved changes
290 290 merging f
291 291 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
292 292 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
293 293 [240]
294 294 $ hg st
295 295 M f
296 296 ? f.orig
297 297 $ cat f
298 298 <<<<<<< working-copy: 6b563750f973 - test: intermediate other change
299 299 g
300 300 =======
301 301 f
302 302 >>>>>>> shelve: aef214a5229c - shelve: changes to: commit stuff
303 303 $ cat f.orig
304 304 g
305 305
306 306 #if abortcommand
307 307 when in dry-run mode
308 308 $ hg abort --dry-run
309 309 unshelve in progress, will be aborted
310 310 #endif
311 311
312 312 $ hg abort
313 313 unshelve of 'default' aborted
314 314 $ hg st
315 315 ? f.orig
316 316 $ cat f.orig
317 317 g
318 318 $ hg shelve --delete default
319 319 $ cd ..
320 320
321 321 you shouldn't be able to ask for the patch/stats of the most recent shelve if
322 322 there are no shelves
323 323
324 324 $ hg init noshelves
325 325 $ cd noshelves
326 326
327 327 $ hg shelve --patch
328 328 abort: there are no shelves to show
329 329 [255]
330 330 $ hg shelve --stat
331 331 abort: there are no shelves to show
332 332 [255]
333 333
334 334 $ cd ..
335 335
336 336 test .orig files go where the user wants them to
337 337 ---------------------------------------------------------------
338 338 $ hg init salvage
339 339 $ cd salvage
340 340 $ echo 'content' > root
341 341 $ hg commit -A -m 'root' -q
342 342 $ echo '' > root
343 343 $ hg shelve -q
344 344 $ echo 'contADDent' > root
345 345 $ hg unshelve -q --config 'ui.origbackuppath=.hg/origbackups'
346 346 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
347 347 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
348 348 [240]
349 349 $ ls .hg/origbackups
350 350 root
351 351 $ rm -rf .hg/origbackups
352 352
353 353 test Abort unshelve always gets user out of the unshelved state
354 354 ---------------------------------------------------------------
355 355
356 356 with a corrupted shelve state file
357 357 $ sed 's/ae8c668541e8/123456789012/' .hg/shelvedstate > ../corrupt-shelvedstate
358 358 $ mv ../corrupt-shelvedstate .hg/shelvestate
359 359 $ hg unshelve --abort 2>&1 | grep 'aborted'
360 360 unshelve of 'default' aborted
361 361 $ hg summary
362 362 parent: 0:ae8c668541e8 tip
363 363 root
364 364 branch: default
365 365 commit: 1 modified
366 366 update: (current)
367 367 phases: 1 draft
368 368 $ hg up -C .
369 369 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
370 370
371 371 $ cd ..
372 372
373 373 Shelve and unshelve unknown files. For the purposes of unshelve, a shelved
374 374 unknown file is the same as a shelved added file, except that it will be in
375 375 unknown state after unshelve if and only if it was either absent or unknown
376 376 before the unshelve operation.
377 377
378 378 $ hg init unknowns
379 379 $ cd unknowns
380 380
381 381 The simplest case is if I simply have an unknown file that I shelve and unshelve
382 382
383 383 $ echo unknown > unknown
384 384 $ hg status
385 385 ? unknown
386 386 $ hg shelve --unknown
387 387 shelved as default
388 388 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
389 389 $ hg status
390 390 $ hg unshelve
391 391 unshelving change 'default'
392 392 $ hg status
393 393 ? unknown
394 394 $ rm unknown
395 395
396 396 If I shelve, add the file, and unshelve, does it stay added?
397 397
398 398 $ echo unknown > unknown
399 399 $ hg shelve -u
400 400 shelved as default
401 401 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
402 402 $ hg status
403 403 $ touch unknown
404 404 $ hg add unknown
405 405 $ hg status
406 406 A unknown
407 407 $ hg unshelve
408 408 unshelving change 'default'
409 409 temporarily committing pending changes (restore with 'hg unshelve --abort')
410 410 rebasing shelved changes
411 411 merging unknown
412 412 $ hg status
413 413 A unknown
414 414 $ hg forget unknown
415 415 $ rm unknown
416 416
417 417 And if I shelve, commit, then unshelve, does it become modified?
418 418
419 419 $ echo unknown > unknown
420 420 $ hg shelve -u
421 421 shelved as default
422 422 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
423 423 $ hg status
424 424 $ touch unknown
425 425 $ hg add unknown
426 426 $ hg commit -qm "Add unknown"
427 427 $ hg status
428 428 $ hg unshelve
429 429 unshelving change 'default'
430 430 rebasing shelved changes
431 431 merging unknown
432 432 $ hg status
433 433 M unknown
434 434 $ hg remove --force unknown
435 435 $ hg commit -qm "Remove unknown"
436 436
437 437 $ cd ..
438 438
439 439 We expects that non-bare shelve keeps newly created branch in
440 440 working directory.
441 441
442 442 $ hg init shelve-preserve-new-branch
443 443 $ cd shelve-preserve-new-branch
444 444 $ echo "a" >> a
445 445 $ hg add a
446 446 $ echo "b" >> b
447 447 $ hg add b
448 448 $ hg commit -m "ab"
449 449 $ echo "aa" >> a
450 450 $ echo "bb" >> b
451 451 $ hg branch new-branch
452 452 marked working directory as branch new-branch
453 453 (branches are permanent and global, did you want a bookmark?)
454 454 $ hg status
455 455 M a
456 456 M b
457 457 $ hg branch
458 458 new-branch
459 459 $ hg shelve a
460 460 shelved as default
461 461 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 462 $ hg branch
463 463 new-branch
464 464 $ hg status
465 465 M b
466 466 $ touch "c" >> c
467 467 $ hg add c
468 468 $ hg status
469 469 M b
470 470 A c
471 471 $ hg shelve --exclude c
472 472 shelved as default-01
473 473 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
474 474 $ hg branch
475 475 new-branch
476 476 $ hg status
477 477 A c
478 478 $ hg shelve --include c
479 479 shelved as default-02
480 480 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
481 481 $ hg branch
482 482 new-branch
483 483 $ hg status
484 484 $ echo "d" >> d
485 485 $ hg add d
486 486 $ hg status
487 487 A d
488 488
489 489 We expect that bare-shelve will not keep branch in current working directory.
490 490
491 491 $ hg shelve
492 492 shelved as default-03
493 493 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
494 494 $ hg branch
495 495 default
496 496 $ cd ..
497 497
498 498 When i shelve commit on newly created branch i expect
499 499 that after unshelve newly created branch will be preserved.
500 500
501 501 $ hg init shelve_on_new_branch_simple
502 502 $ cd shelve_on_new_branch_simple
503 503 $ echo "aaa" >> a
504 504 $ hg commit -A -m "a"
505 505 adding a
506 506 $ hg branch
507 507 default
508 508 $ hg branch test
509 509 marked working directory as branch test
510 510 (branches are permanent and global, did you want a bookmark?)
511 511 $ echo "bbb" >> a
512 512 $ hg status
513 513 M a
514 514 $ hg shelve
515 515 shelved as default
516 516 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
517 517 $ hg branch
518 518 default
519 519 $ echo "bbb" >> b
520 520 $ hg status
521 521 ? b
522 522 $ hg unshelve
523 523 unshelving change 'default'
524 524 marked working directory as branch test
525 525 $ hg status
526 526 M a
527 527 ? b
528 528 $ hg branch
529 529 test
530 530 $ cd ..
531 531
532 532 When i shelve commit on newly created branch, make
533 533 some changes, unshelve it and running into merge
534 534 conflicts i expect that after fixing them and
535 535 running unshelve --continue newly created branch
536 536 will be preserved.
537 537
538 538 $ hg init shelve_on_new_branch_conflict
539 539 $ cd shelve_on_new_branch_conflict
540 540 $ echo "aaa" >> a
541 541 $ hg commit -A -m "a"
542 542 adding a
543 543 $ hg branch
544 544 default
545 545 $ hg branch test
546 546 marked working directory as branch test
547 547 (branches are permanent and global, did you want a bookmark?)
548 548 $ echo "bbb" >> a
549 549 $ hg status
550 550 M a
551 551 $ hg shelve
552 552 shelved as default
553 553 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
554 554 $ hg branch
555 555 default
556 556 $ echo "ccc" >> a
557 557 $ hg status
558 558 M a
559 559 $ hg unshelve
560 560 unshelving change 'default'
561 561 temporarily committing pending changes (restore with 'hg unshelve --abort')
562 562 rebasing shelved changes
563 563 merging a
564 564 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
565 565 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
566 566 [240]
567 567 $ echo "aaabbbccc" > a
568 568 $ rm a.orig
569 569 $ hg resolve --mark a
570 570 (no more unresolved files)
571 571 continue: hg unshelve --continue
572 572 $ hg continue
573 573 marked working directory as branch test
574 574 unshelve of 'default' complete
575 575 $ cat a
576 576 aaabbbccc
577 577 $ hg status
578 578 M a
579 579 $ hg branch
580 580 test
581 581 $ hg commit -m "test-commit"
582 582
583 583 When i shelve on test branch, update to default branch
584 584 and unshelve i expect that it will not preserve previous
585 585 test branch.
586 586
587 587 $ echo "xxx" > b
588 588 $ hg add b
589 589 $ hg shelve
590 590 shelved as test
591 591 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
592 592 $ hg update -r 7049e48789d7
593 593 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
594 594 $ hg unshelve
595 595 unshelving change 'test'
596 596 rebasing shelved changes
597 597 $ hg status
598 598 A b
599 599 $ hg branch
600 600 default
601 601 $ cd ..
602 602
603 603 When i unshelve resulting in merge conflicts and makes saved
604 604 file shelvedstate looks like in previous versions in
605 605 mercurial(without restore branch information in 7th line) i
606 606 expect that after resolving conflicts and successfully
607 607 running 'shelve --continue' the branch information won't be
608 608 restored and branch will be unchanged.
609 609
610 610 shelve on new branch, conflict with previous shelvedstate
611 611
612 612 $ hg init conflict
613 613 $ cd conflict
614 614 $ echo "aaa" >> a
615 615 $ hg commit -A -m "a"
616 616 adding a
617 617 $ hg branch
618 618 default
619 619 $ hg branch test
620 620 marked working directory as branch test
621 621 (branches are permanent and global, did you want a bookmark?)
622 622 $ echo "bbb" >> a
623 623 $ hg status
624 624 M a
625 625 $ hg shelve
626 626 shelved as default
627 627 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
628 628 $ hg branch
629 629 default
630 630 $ echo "ccc" >> a
631 631 $ hg status
632 632 M a
633 633 $ hg unshelve
634 634 unshelving change 'default'
635 635 temporarily committing pending changes (restore with 'hg unshelve --abort')
636 636 rebasing shelved changes
637 637 merging a
638 638 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
639 639 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
640 640 [240]
641 641
642 642 Removing restore branch information from shelvedstate file(making it looks like
643 643 in previous versions) and running unshelve --continue
644 644
645 645 $ cp .hg/shelvedstate .hg/shelvedstate_old
646 646 $ cat .hg/shelvedstate_old | grep -v 'branchtorestore' > .hg/shelvedstate
647 647
648 648 $ echo "aaabbbccc" > a
649 649 $ rm a.orig
650 650 $ hg resolve --mark a
651 651 (no more unresolved files)
652 652 continue: hg unshelve --continue
653 653
654 654 #if continuecommand
655 655 $ hg continue --dry-run
656 656 unshelve in progress, will be resumed
657 657 #endif
658 658
659 659 $ hg continue
660 660 unshelve of 'default' complete
661 661 $ cat a
662 662 aaabbbccc
663 663 $ hg status
664 664 M a
665 665 $ hg branch
666 666 default
667 667 $ cd ..
668 668
669 669 On non bare shelve the branch information shouldn't be restored
670 670
671 671 $ hg init bare_shelve_on_new_branch
672 672 $ cd bare_shelve_on_new_branch
673 673 $ echo "aaa" >> a
674 674 $ hg commit -A -m "a"
675 675 adding a
676 676 $ hg branch
677 677 default
678 678 $ hg branch test
679 679 marked working directory as branch test
680 680 (branches are permanent and global, did you want a bookmark?)
681 681 $ echo "bbb" >> a
682 682 $ hg status
683 683 M a
684 684 $ hg shelve a
685 685 shelved as default
686 686 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
687 687 $ hg branch
688 688 test
689 689 $ hg branch default
690 690 marked working directory as branch default
691 691 (branches are permanent and global, did you want a bookmark?)
692 692 $ echo "bbb" >> b
693 693 $ hg status
694 694 ? b
695 695 $ hg unshelve
696 696 unshelving change 'default'
697 697 $ hg status
698 698 M a
699 699 ? b
700 700 $ hg branch
701 701 default
702 702 $ cd ..
703 703
704 704 Prepare unshelve with a corrupted shelvedstate
705 705 $ hg init r1 && cd r1
706 706 $ echo text1 > file && hg add file
707 707 $ hg shelve
708 708 shelved as default
709 709 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
710 710 $ echo text2 > file && hg ci -Am text1
711 711 adding file
712 712 $ hg unshelve
713 713 unshelving change 'default'
714 714 rebasing shelved changes
715 715 merging file
716 716 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
717 717 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
718 718 [240]
719 719 $ echo somethingsomething > .hg/shelvedstate
720 720
721 721 Unshelve --continue fails with appropriate message if shelvedstate is corrupted
722 722 $ hg continue
723 723 abort: corrupted shelved state file
724 724 (please run hg unshelve --abort to abort unshelve operation)
725 725 [255]
726 726
727 727 Unshelve --abort works with a corrupted shelvedstate
728 728 $ hg abort
729 729 abort: could not read shelved state file, your working copy may be in an unexpected state
730 730 please update to some commit
731 731
732 732 [255]
733 733
734 734 Unshelve --abort fails with appropriate message if there's no unshelve in
735 735 progress
736 736
737 737 #if abortflag
738 738 $ hg unshelve --abort
739 739 abort: no unshelve in progress
740 740 [20]
741 741 #else
742 742 $ hg abort
743 743 aborting the merge, updating back to 9451eaa6eee3
744 744 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
745 745 #endif
746 746 $ cd ..
747 747
748 748 Test corrupt shelves (in .hg/shelved/, not .hg/shelvestate)
749 749 $ hg init corrupt-shelves
750 750 $ cd corrupt-shelves
751 751 $ mkdir .hg/shelved
752 752
753 753 # A (corrupt) .patch file without a .hg file
754 754 $ touch .hg/shelved/junk1.patch
755 755 $ hg shelve -l
756 756 $ hg unshelve
757 757 abort: no shelved changes to apply!
758 758 [20]
759 759 $ hg shelve -d junk1
760 760 abort: shelved change 'junk1' not found
761 761 [10]
762 762 $ find .hg/shelve* | sort
763 763 .hg/shelved
764 764 .hg/shelved/junk1.patch
765 765
766 766 # A .hg file without a .patch file
767 767 $ touch .hg/shelved/junk2.hg
768 768 $ hg shelve -l
769 769 $ hg unshelve
770 770 abort: no shelved changes to apply!
771 771 [20]
772 772 $ hg shelve -d junk2
773 773 abort: shelved change 'junk2' not found
774 774 [10]
775 775 $ find .hg/shelve* | sort
776 776 .hg/shelved
777 777 .hg/shelved/junk1.patch
778 778 .hg/shelved/junk2.hg
779 779
780 780 # A file with an unexpected extension
781 781 $ touch .hg/shelved/junk3
782 $ hg shelve -l 2>&1 | grep ValueError
783 ValueError: * (glob)
784 $ hg unshelve 2>&1 | grep ValueError
785 ValueError: * (glob)
782 $ hg shelve -l
783 $ hg unshelve
784 abort: no shelved changes to apply!
785 [20]
786 786 $ hg shelve -d junk3
787 787 abort: shelved change 'junk3' not found
788 788 [10]
789 789 $ find .hg/shelve* | sort
790 790 .hg/shelved
791 791 .hg/shelved/junk1.patch
792 792 .hg/shelved/junk2.hg
793 793 .hg/shelved/junk3
794 794
795 795 $ cd ..
796 796
797 797 Unshelve respects --keep even if user intervention is needed
798 798 $ hg init unshelvekeep && cd unshelvekeep
799 799 $ echo 1 > file && hg ci -Am 1
800 800 adding file
801 801 $ echo 2 >> file
802 802 $ hg shelve
803 803 shelved as default
804 804 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
805 805 $ echo 3 >> file && hg ci -Am 13
806 806 $ hg shelve --list
807 807 default (*s ago) * changes to: 1 (glob)
808 808 $ hg unshelve --keep
809 809 unshelving change 'default'
810 810 rebasing shelved changes
811 811 merging file
812 812 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
813 813 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
814 814 [240]
815 815 $ hg resolve --mark file
816 816 (no more unresolved files)
817 817 continue: hg unshelve --continue
818 818 $ hg continue
819 819 unshelve of 'default' complete
820 820 $ hg shelve --list
821 821 default (*s ago) * changes to: 1 (glob)
822 822 $ cd ..
823 823
824 824 Unshelving when there are deleted files does not crash (issue4176)
825 825 $ hg init unshelve-deleted-file && cd unshelve-deleted-file
826 826 $ echo a > a && echo b > b && hg ci -Am ab
827 827 adding a
828 828 adding b
829 829 $ echo aa > a && hg shelve
830 830 shelved as default
831 831 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
832 832 $ rm b
833 833 $ hg st
834 834 ! b
835 835 $ hg unshelve
836 836 unshelving change 'default'
837 837 $ hg shelve
838 838 shelved as default
839 839 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
840 840 $ rm a && echo b > b
841 841 $ hg st
842 842 ! a
843 843 $ hg unshelve
844 844 unshelving change 'default'
845 845 abort: shelved change touches missing files
846 846 (run hg status to see which files are missing)
847 847 [255]
848 848 $ hg st
849 849 ! a
850 850 $ cd ..
851 851
852 852 New versions of Mercurial know how to read onld shelvedstate files
853 853 $ hg init oldshelvedstate
854 854 $ cd oldshelvedstate
855 855 $ echo root > root && hg ci -Am root
856 856 adding root
857 857 $ echo 1 > a
858 858 $ hg add a
859 859 $ hg shelve --name ashelve
860 860 shelved as ashelve
861 861 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
862 862 $ echo 2 > a
863 863 $ hg ci -Am a
864 864 adding a
865 865 $ hg unshelve
866 866 unshelving change 'ashelve'
867 867 rebasing shelved changes
868 868 merging a
869 869 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
870 870 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
871 871 [240]
872 872 putting v1 shelvedstate file in place of a created v2
873 873 $ cat << EOF > .hg/shelvedstate
874 874 > 1
875 875 > ashelve
876 876 > 8b058dae057a5a78f393f4535d9e363dd5efac9d
877 877 > 8b058dae057a5a78f393f4535d9e363dd5efac9d
878 878 > 8b058dae057a5a78f393f4535d9e363dd5efac9d f543b27db2cdb41737e2e0008dc524c471da1446
879 879 > f543b27db2cdb41737e2e0008dc524c471da1446
880 880 >
881 881 > nokeep
882 882 > :no-active-bookmark
883 883 > EOF
884 884 $ echo 1 > a
885 885 $ hg resolve --mark a
886 886 (no more unresolved files)
887 887 continue: hg unshelve --continue
888 888 mercurial does not crash
889 889 $ hg continue
890 890 unshelve of 'ashelve' complete
891 891
892 892 #if phasebased
893 893
894 894 Unshelve with some metadata file missing
895 895 ----------------------------------------
896 896
897 897 $ hg shelve
898 898 shelved as default
899 899 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
900 900 $ echo 3 > a
901 901
902 902 Test with the `.shelve` missing, but the changeset still in the repo (non-natural case)
903 903
904 904 $ rm .hg/shelved/default.shelve
905 905 $ hg unshelve
906 906 unshelving change 'default'
907 907 temporarily committing pending changes (restore with 'hg unshelve --abort')
908 908 rebasing shelved changes
909 909 merging a
910 910 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
911 911 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
912 912 [240]
913 913 $ hg abort
914 914 unshelve of 'default' aborted
915 915
916 916 Unshelve without .shelve metadata (can happen when upgrading a repository with old shelve)
917 917
918 918 $ cat .hg/shelved/default.shelve
919 919 node=82e0cb9893247d12667017593ce1e5655860f1ac
920 920 $ hg strip --hidden --rev 82e0cb989324 --no-backup
921 921 $ rm .hg/shelved/default.shelve
922 922 $ hg unshelve
923 923 unshelving change 'default'
924 924 temporarily committing pending changes (restore with 'hg unshelve --abort')
925 925 rebasing shelved changes
926 926 merging a
927 927 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
928 928 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
929 929 [240]
930 930 $ cat .hg/shelved/default.shelve
931 931 node=82e0cb9893247d12667017593ce1e5655860f1ac
932 932 $ hg abort
933 933 unshelve of 'default' aborted
934 934
935 935 #endif
936 936
937 937 $ cd ..
938 938
939 939 Block merge abort when unshelve in progress(issue6160)
940 940 ------------------------------------------------------
941 941
942 942 $ hg init a
943 943 $ cd a
944 944 $ echo foo > a ; hg commit -qAm "initial commit"
945 945 $ echo bar > a
946 946 $ hg shelve
947 947 shelved as default
948 948 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
949 949 $ echo foobar > a
950 950 $ hg unshelve
951 951 unshelving change 'default'
952 952 temporarily committing pending changes (restore with 'hg unshelve --abort')
953 953 rebasing shelved changes
954 954 merging a
955 955 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
956 956 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
957 957 [240]
958 958
959 959 $ hg log --template '{desc|firstline} {author} {date|isodate} \n' -r .
960 960 pending changes temporary commit shelve@localhost 1970-01-01 00:00 +0000
961 961 $ hg merge --abort
962 962 abort: cannot abort merge with unshelve in progress
963 963 (use 'hg unshelve --continue' or 'hg unshelve --abort')
964 964 [20]
965 965
966 966 $ hg unshelve --abort
967 967 unshelve of 'default' aborted
968 968
969 969 $ hg log -G --template '{desc|firstline} {author} {date|isodate} \n' -r .
970 970 @ initial commit test 1970-01-01 00:00 +0000
971 971
972 972 $ cd ..
973 973
974 974 Demonstrate that the labels are correct in the merge conflict
975 975 -------------------------------------------------------------
976 976 $ hg init labels
977 977 $ cd labels
978 978 $ echo r0 > foo
979 979 $ hg ci -qAm r0
980 980 $ echo "this will be shelved" >> foo
981 981 $ hg shelve -q
982 982 $ echo "this is in wdir, conflicts with shelve" >> foo
983 983 $ hg unshelve -q
984 984 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
985 985 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
986 986 [240]
987 987 $ cat foo
988 988 r0
989 989 <<<<<<< working-copy: 0b2fcf2a90e9 - shelve: pending changes temporary commit
990 990 this is in wdir, conflicts with shelve
991 991 =======
992 992 this will be shelved
993 993 >>>>>>> shelve: 9c072a2163db - shelve: changes to: r0
994 994 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now