##// END OF EJS Templates
unshelve: abort on using --keep and --interactive together...
Navaneeth Suresh -
r43029:5c285c8e default
parent child Browse files
Show More
@@ -1,1014 +1,1016 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 . import (
32 32 bookmarks,
33 33 bundle2,
34 34 bundlerepo,
35 35 changegroup,
36 36 cmdutil,
37 37 discovery,
38 38 error,
39 39 exchange,
40 40 hg,
41 41 lock as lockmod,
42 42 mdiff,
43 43 merge,
44 44 node as nodemod,
45 45 patch,
46 46 phases,
47 47 pycompat,
48 48 repair,
49 49 scmutil,
50 50 templatefilters,
51 51 util,
52 52 vfs as vfsmod,
53 53 )
54 54 from .utils import (
55 55 dateutil,
56 56 stringutil,
57 57 )
58 58
59 59 backupdir = 'shelve-backup'
60 60 shelvedir = 'shelved'
61 61 shelvefileextensions = ['hg', 'patch', 'shelve']
62 62 # universal extension is present in all types of shelves
63 63 patchextension = 'patch'
64 64
65 65 # we never need the user, so we use a
66 66 # generic user for all shelve operations
67 67 shelveuser = 'shelve@localhost'
68 68
69 69 class shelvedfile(object):
70 70 """Helper for the file storing a single shelve
71 71
72 72 Handles common functions on shelve files (.hg/.patch) using
73 73 the vfs layer"""
74 74 def __init__(self, repo, name, filetype=None):
75 75 self.repo = repo
76 76 self.name = name
77 77 self.vfs = vfsmod.vfs(repo.vfs.join(shelvedir))
78 78 self.backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
79 79 self.ui = self.repo.ui
80 80 if filetype:
81 81 self.fname = name + '.' + filetype
82 82 else:
83 83 self.fname = name
84 84
85 85 def exists(self):
86 86 return self.vfs.exists(self.fname)
87 87
88 88 def filename(self):
89 89 return self.vfs.join(self.fname)
90 90
91 91 def backupfilename(self):
92 92 def gennames(base):
93 93 yield base
94 94 base, ext = base.rsplit('.', 1)
95 95 for i in itertools.count(1):
96 96 yield '%s-%d.%s' % (base, i, ext)
97 97
98 98 name = self.backupvfs.join(self.fname)
99 99 for n in gennames(name):
100 100 if not self.backupvfs.exists(n):
101 101 return n
102 102
103 103 def movetobackup(self):
104 104 if not self.backupvfs.isdir():
105 105 self.backupvfs.makedir()
106 106 util.rename(self.filename(), self.backupfilename())
107 107
108 108 def stat(self):
109 109 return self.vfs.stat(self.fname)
110 110
111 111 def opener(self, mode='rb'):
112 112 try:
113 113 return self.vfs(self.fname, mode)
114 114 except IOError as err:
115 115 if err.errno != errno.ENOENT:
116 116 raise
117 117 raise error.Abort(_("shelved change '%s' not found") % self.name)
118 118
119 119 def applybundle(self, tr):
120 120 fp = self.opener()
121 121 try:
122 122 targetphase = phases.internal
123 123 if not phases.supportinternal(self.repo):
124 124 targetphase = phases.secret
125 125 gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs)
126 126 pretip = self.repo['tip']
127 127 bundle2.applybundle(self.repo, gen, tr,
128 128 source='unshelve',
129 129 url='bundle:' + self.vfs.join(self.fname),
130 130 targetphase=targetphase)
131 131 shelvectx = self.repo['tip']
132 132 if pretip == shelvectx:
133 133 shelverev = tr.changes['revduplicates'][-1]
134 134 shelvectx = self.repo[shelverev]
135 135 return shelvectx
136 136 finally:
137 137 fp.close()
138 138
139 139 def bundlerepo(self):
140 140 path = self.vfs.join(self.fname)
141 141 return bundlerepo.instance(self.repo.baseui,
142 142 'bundle://%s+%s' % (self.repo.root, path))
143 143
144 144 def writebundle(self, bases, node):
145 145 cgversion = changegroup.safeversion(self.repo)
146 146 if cgversion == '01':
147 147 btype = 'HG10BZ'
148 148 compression = None
149 149 else:
150 150 btype = 'HG20'
151 151 compression = 'BZ'
152 152
153 153 repo = self.repo.unfiltered()
154 154
155 155 outgoing = discovery.outgoing(repo, missingroots=bases,
156 156 missingheads=[node])
157 157 cg = changegroup.makechangegroup(repo, outgoing, cgversion, 'shelve')
158 158
159 159 bundle2.writebundle(self.ui, cg, self.fname, btype, self.vfs,
160 160 compression=compression)
161 161
162 162 def writeinfo(self, info):
163 163 scmutil.simplekeyvaluefile(self.vfs, self.fname).write(info)
164 164
165 165 def readinfo(self):
166 166 return scmutil.simplekeyvaluefile(self.vfs, self.fname).read()
167 167
168 168 class shelvedstate(object):
169 169 """Handle persistence during unshelving operations.
170 170
171 171 Handles saving and restoring a shelved state. Ensures that different
172 172 versions of a shelved state are possible and handles them appropriately.
173 173 """
174 174 _version = 2
175 175 _filename = 'shelvedstate'
176 176 _keep = 'keep'
177 177 _nokeep = 'nokeep'
178 178 # colon is essential to differentiate from a real bookmark name
179 179 _noactivebook = ':no-active-bookmark'
180 180 _interactive = 'interactive'
181 181
182 182 @classmethod
183 183 def _verifyandtransform(cls, d):
184 184 """Some basic shelvestate syntactic verification and transformation"""
185 185 try:
186 186 d['originalwctx'] = nodemod.bin(d['originalwctx'])
187 187 d['pendingctx'] = nodemod.bin(d['pendingctx'])
188 188 d['parents'] = [nodemod.bin(h)
189 189 for h in d['parents'].split(' ')]
190 190 d['nodestoremove'] = [nodemod.bin(h)
191 191 for h in d['nodestoremove'].split(' ')]
192 192 except (ValueError, TypeError, KeyError) as err:
193 193 raise error.CorruptedState(pycompat.bytestr(err))
194 194
195 195 @classmethod
196 196 def _getversion(cls, repo):
197 197 """Read version information from shelvestate file"""
198 198 fp = repo.vfs(cls._filename)
199 199 try:
200 200 version = int(fp.readline().strip())
201 201 except ValueError as err:
202 202 raise error.CorruptedState(pycompat.bytestr(err))
203 203 finally:
204 204 fp.close()
205 205 return version
206 206
207 207 @classmethod
208 208 def _readold(cls, repo):
209 209 """Read the old position-based version of a shelvestate file"""
210 210 # Order is important, because old shelvestate file uses it
211 211 # to detemine values of fields (i.g. name is on the second line,
212 212 # originalwctx is on the third and so forth). Please do not change.
213 213 keys = ['version', 'name', 'originalwctx', 'pendingctx', 'parents',
214 214 'nodestoremove', 'branchtorestore', 'keep', 'activebook']
215 215 # this is executed only seldomly, so it is not a big deal
216 216 # that we open this file twice
217 217 fp = repo.vfs(cls._filename)
218 218 d = {}
219 219 try:
220 220 for key in keys:
221 221 d[key] = fp.readline().strip()
222 222 finally:
223 223 fp.close()
224 224 return d
225 225
226 226 @classmethod
227 227 def load(cls, repo):
228 228 version = cls._getversion(repo)
229 229 if version < cls._version:
230 230 d = cls._readold(repo)
231 231 elif version == cls._version:
232 232 d = scmutil.simplekeyvaluefile(
233 233 repo.vfs, cls._filename).read(firstlinenonkeyval=True)
234 234 else:
235 235 raise error.Abort(_('this version of shelve is incompatible '
236 236 'with the version used in this repo'))
237 237
238 238 cls._verifyandtransform(d)
239 239 try:
240 240 obj = cls()
241 241 obj.name = d['name']
242 242 obj.wctx = repo[d['originalwctx']]
243 243 obj.pendingctx = repo[d['pendingctx']]
244 244 obj.parents = d['parents']
245 245 obj.nodestoremove = d['nodestoremove']
246 246 obj.branchtorestore = d.get('branchtorestore', '')
247 247 obj.keep = d.get('keep') == cls._keep
248 248 obj.activebookmark = ''
249 249 if d.get('activebook', '') != cls._noactivebook:
250 250 obj.activebookmark = d.get('activebook', '')
251 251 obj.interactive = d.get('interactive') == cls._interactive
252 252 except (error.RepoLookupError, KeyError) as err:
253 253 raise error.CorruptedState(pycompat.bytestr(err))
254 254
255 255 return obj
256 256
257 257 @classmethod
258 258 def save(cls, repo, name, originalwctx, pendingctx, nodestoremove,
259 259 branchtorestore, keep=False, activebook='', interactive=False):
260 260 info = {
261 261 "name": name,
262 262 "originalwctx": nodemod.hex(originalwctx.node()),
263 263 "pendingctx": nodemod.hex(pendingctx.node()),
264 264 "parents": ' '.join([nodemod.hex(p)
265 265 for p in repo.dirstate.parents()]),
266 266 "nodestoremove": ' '.join([nodemod.hex(n)
267 267 for n in nodestoremove]),
268 268 "branchtorestore": branchtorestore,
269 269 "keep": cls._keep if keep else cls._nokeep,
270 270 "activebook": activebook or cls._noactivebook
271 271 }
272 272 if interactive:
273 273 info['interactive'] = cls._interactive
274 274 scmutil.simplekeyvaluefile(
275 275 repo.vfs, cls._filename).write(info,
276 276 firstline=("%d" % cls._version))
277 277
278 278 @classmethod
279 279 def clear(cls, repo):
280 280 repo.vfs.unlinkpath(cls._filename, ignoremissing=True)
281 281
282 282 def cleanupoldbackups(repo):
283 283 vfs = vfsmod.vfs(repo.vfs.join(backupdir))
284 284 maxbackups = repo.ui.configint('shelve', 'maxbackups')
285 285 hgfiles = [f for f in vfs.listdir()
286 286 if f.endswith('.' + patchextension)]
287 287 hgfiles = sorted([(vfs.stat(f)[stat.ST_MTIME], f) for f in hgfiles])
288 288 if maxbackups > 0 and maxbackups < len(hgfiles):
289 289 bordermtime = hgfiles[-maxbackups][0]
290 290 else:
291 291 bordermtime = None
292 292 for mtime, f in hgfiles[:len(hgfiles) - maxbackups]:
293 293 if mtime == bordermtime:
294 294 # keep it, because timestamp can't decide exact order of backups
295 295 continue
296 296 base = f[:-(1 + len(patchextension))]
297 297 for ext in shelvefileextensions:
298 298 vfs.tryunlink(base + '.' + ext)
299 299
300 300 def _backupactivebookmark(repo):
301 301 activebookmark = repo._activebookmark
302 302 if activebookmark:
303 303 bookmarks.deactivate(repo)
304 304 return activebookmark
305 305
306 306 def _restoreactivebookmark(repo, mark):
307 307 if mark:
308 308 bookmarks.activate(repo, mark)
309 309
310 310 def _aborttransaction(repo, tr):
311 311 '''Abort current transaction for shelve/unshelve, but keep dirstate
312 312 '''
313 313 dirstatebackupname = 'dirstate.shelve'
314 314 repo.dirstate.savebackup(tr, dirstatebackupname)
315 315 tr.abort()
316 316 repo.dirstate.restorebackup(None, dirstatebackupname)
317 317
318 318 def getshelvename(repo, parent, opts):
319 319 """Decide on the name this shelve is going to have"""
320 320 def gennames():
321 321 yield label
322 322 for i in itertools.count(1):
323 323 yield '%s-%02d' % (label, i)
324 324 name = opts.get('name')
325 325 label = repo._activebookmark or parent.branch() or 'default'
326 326 # slashes aren't allowed in filenames, therefore we rename it
327 327 label = label.replace('/', '_')
328 328 label = label.replace('\\', '_')
329 329 # filenames must not start with '.' as it should not be hidden
330 330 if label.startswith('.'):
331 331 label = label.replace('.', '_', 1)
332 332
333 333 if name:
334 334 if shelvedfile(repo, name, patchextension).exists():
335 335 e = _("a shelved change named '%s' already exists") % name
336 336 raise error.Abort(e)
337 337
338 338 # ensure we are not creating a subdirectory or a hidden file
339 339 if '/' in name or '\\' in name:
340 340 raise error.Abort(_('shelved change names can not contain slashes'))
341 341 if name.startswith('.'):
342 342 raise error.Abort(_("shelved change names can not start with '.'"))
343 343
344 344 else:
345 345 for n in gennames():
346 346 if not shelvedfile(repo, n, patchextension).exists():
347 347 name = n
348 348 break
349 349
350 350 return name
351 351
352 352 def mutableancestors(ctx):
353 353 """return all mutable ancestors for ctx (included)
354 354
355 355 Much faster than the revset ancestors(ctx) & draft()"""
356 356 seen = {nodemod.nullrev}
357 357 visit = collections.deque()
358 358 visit.append(ctx)
359 359 while visit:
360 360 ctx = visit.popleft()
361 361 yield ctx.node()
362 362 for parent in ctx.parents():
363 363 rev = parent.rev()
364 364 if rev not in seen:
365 365 seen.add(rev)
366 366 if parent.mutable():
367 367 visit.append(parent)
368 368
369 369 def getcommitfunc(extra, interactive, editor=False):
370 370 def commitfunc(ui, repo, message, match, opts):
371 371 hasmq = util.safehasattr(repo, 'mq')
372 372 if hasmq:
373 373 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
374 374
375 375 targetphase = phases.internal
376 376 if not phases.supportinternal(repo):
377 377 targetphase = phases.secret
378 378 overrides = {('phases', 'new-commit'): targetphase}
379 379 try:
380 380 editor_ = False
381 381 if editor:
382 382 editor_ = cmdutil.getcommiteditor(editform='shelve.shelve',
383 383 **pycompat.strkwargs(opts))
384 384 with repo.ui.configoverride(overrides):
385 385 return repo.commit(message, shelveuser, opts.get('date'),
386 386 match, editor=editor_, extra=extra)
387 387 finally:
388 388 if hasmq:
389 389 repo.mq.checkapplied = saved
390 390
391 391 def interactivecommitfunc(ui, repo, *pats, **opts):
392 392 opts = pycompat.byteskwargs(opts)
393 393 match = scmutil.match(repo['.'], pats, {})
394 394 message = opts['message']
395 395 return commitfunc(ui, repo, message, match, opts)
396 396
397 397 return interactivecommitfunc if interactive else commitfunc
398 398
399 399 def _nothingtoshelvemessaging(ui, repo, pats, opts):
400 400 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
401 401 if stat.deleted:
402 402 ui.status(_("nothing changed (%d missing files, see "
403 403 "'hg status')\n") % len(stat.deleted))
404 404 else:
405 405 ui.status(_("nothing changed\n"))
406 406
407 407 def _shelvecreatedcommit(repo, node, name, match):
408 408 info = {'node': nodemod.hex(node)}
409 409 shelvedfile(repo, name, 'shelve').writeinfo(info)
410 410 bases = list(mutableancestors(repo[node]))
411 411 shelvedfile(repo, name, 'hg').writebundle(bases, node)
412 412 with shelvedfile(repo, name, patchextension).opener('wb') as fp:
413 413 cmdutil.exportfile(repo, [node], fp, opts=mdiff.diffopts(git=True),
414 414 match=match)
415 415
416 416 def _includeunknownfiles(repo, pats, opts, extra):
417 417 s = repo.status(match=scmutil.match(repo[None], pats, opts),
418 418 unknown=True)
419 419 if s.unknown:
420 420 extra['shelve_unknown'] = '\0'.join(s.unknown)
421 421 repo[None].add(s.unknown)
422 422
423 423 def _finishshelve(repo, tr):
424 424 if phases.supportinternal(repo):
425 425 tr.close()
426 426 else:
427 427 _aborttransaction(repo, tr)
428 428
429 429 def createcmd(ui, repo, pats, opts):
430 430 """subcommand that creates a new shelve"""
431 431 with repo.wlock():
432 432 cmdutil.checkunfinished(repo)
433 433 return _docreatecmd(ui, repo, pats, opts)
434 434
435 435 def _docreatecmd(ui, repo, pats, opts):
436 436 wctx = repo[None]
437 437 parents = wctx.parents()
438 438 parent = parents[0]
439 439 origbranch = wctx.branch()
440 440
441 441 if parent.node() != nodemod.nullid:
442 442 desc = "changes to: %s" % parent.description().split('\n', 1)[0]
443 443 else:
444 444 desc = '(changes in empty repository)'
445 445
446 446 if not opts.get('message'):
447 447 opts['message'] = desc
448 448
449 449 lock = tr = activebookmark = None
450 450 try:
451 451 lock = repo.lock()
452 452
453 453 # use an uncommitted transaction to generate the bundle to avoid
454 454 # pull races. ensure we don't print the abort message to stderr.
455 455 tr = repo.transaction('shelve', report=lambda x: None)
456 456
457 457 interactive = opts.get('interactive', False)
458 458 includeunknown = (opts.get('unknown', False) and
459 459 not opts.get('addremove', False))
460 460
461 461 name = getshelvename(repo, parent, opts)
462 462 activebookmark = _backupactivebookmark(repo)
463 463 extra = {'internal': 'shelve'}
464 464 if includeunknown:
465 465 _includeunknownfiles(repo, pats, opts, extra)
466 466
467 467 if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts):
468 468 # In non-bare shelve we don't store newly created branch
469 469 # at bundled commit
470 470 repo.dirstate.setbranch(repo['.'].branch())
471 471
472 472 commitfunc = getcommitfunc(extra, interactive, editor=True)
473 473 if not interactive:
474 474 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
475 475 else:
476 476 node = cmdutil.dorecord(ui, repo, commitfunc, None,
477 477 False, cmdutil.recordfilter, *pats,
478 478 **pycompat.strkwargs(opts))
479 479 if not node:
480 480 _nothingtoshelvemessaging(ui, repo, pats, opts)
481 481 return 1
482 482
483 483 # Create a matcher so that prefetch doesn't attempt to fetch
484 484 # the entire repository pointlessly, and as an optimisation
485 485 # for movedirstate, if needed.
486 486 match = scmutil.matchfiles(repo, repo[node].files())
487 487 _shelvecreatedcommit(repo, node, name, match)
488 488
489 489 if ui.formatted():
490 490 desc = stringutil.ellipsis(desc, ui.termwidth())
491 491 ui.status(_('shelved as %s\n') % name)
492 492 if opts['keep']:
493 493 with repo.dirstate.parentchange():
494 494 scmutil.movedirstate(repo, parent, match)
495 495 else:
496 496 hg.update(repo, parent.node())
497 497 if origbranch != repo['.'].branch() and not _isbareshelve(pats, opts):
498 498 repo.dirstate.setbranch(origbranch)
499 499
500 500 _finishshelve(repo, tr)
501 501 finally:
502 502 _restoreactivebookmark(repo, activebookmark)
503 503 lockmod.release(tr, lock)
504 504
505 505 def _isbareshelve(pats, opts):
506 506 return (not pats
507 507 and not opts.get('interactive', False)
508 508 and not opts.get('include', False)
509 509 and not opts.get('exclude', False))
510 510
511 511 def _iswctxonnewbranch(repo):
512 512 return repo[None].branch() != repo['.'].branch()
513 513
514 514 def cleanupcmd(ui, repo):
515 515 """subcommand that deletes all shelves"""
516 516
517 517 with repo.wlock():
518 518 for (name, _type) in repo.vfs.readdir(shelvedir):
519 519 suffix = name.rsplit('.', 1)[-1]
520 520 if suffix in shelvefileextensions:
521 521 shelvedfile(repo, name).movetobackup()
522 522 cleanupoldbackups(repo)
523 523
524 524 def deletecmd(ui, repo, pats):
525 525 """subcommand that deletes a specific shelve"""
526 526 if not pats:
527 527 raise error.Abort(_('no shelved changes specified!'))
528 528 with repo.wlock():
529 529 try:
530 530 for name in pats:
531 531 for suffix in shelvefileextensions:
532 532 shfile = shelvedfile(repo, name, suffix)
533 533 # patch file is necessary, as it should
534 534 # be present for any kind of shelve,
535 535 # but the .hg file is optional as in future we
536 536 # will add obsolete shelve with does not create a
537 537 # bundle
538 538 if shfile.exists() or suffix == patchextension:
539 539 shfile.movetobackup()
540 540 cleanupoldbackups(repo)
541 541 except OSError as err:
542 542 if err.errno != errno.ENOENT:
543 543 raise
544 544 raise error.Abort(_("shelved change '%s' not found") % name)
545 545
546 546 def listshelves(repo):
547 547 """return all shelves in repo as list of (time, filename)"""
548 548 try:
549 549 names = repo.vfs.readdir(shelvedir)
550 550 except OSError as err:
551 551 if err.errno != errno.ENOENT:
552 552 raise
553 553 return []
554 554 info = []
555 555 for (name, _type) in names:
556 556 pfx, sfx = name.rsplit('.', 1)
557 557 if not pfx or sfx != patchextension:
558 558 continue
559 559 st = shelvedfile(repo, name).stat()
560 560 info.append((st[stat.ST_MTIME], shelvedfile(repo, pfx).filename()))
561 561 return sorted(info, reverse=True)
562 562
563 563 def listcmd(ui, repo, pats, opts):
564 564 """subcommand that displays the list of shelves"""
565 565 pats = set(pats)
566 566 width = 80
567 567 if not ui.plain():
568 568 width = ui.termwidth()
569 569 namelabel = 'shelve.newest'
570 570 ui.pager('shelve')
571 571 for mtime, name in listshelves(repo):
572 572 sname = util.split(name)[1]
573 573 if pats and sname not in pats:
574 574 continue
575 575 ui.write(sname, label=namelabel)
576 576 namelabel = 'shelve.name'
577 577 if ui.quiet:
578 578 ui.write('\n')
579 579 continue
580 580 ui.write(' ' * (16 - len(sname)))
581 581 used = 16
582 582 date = dateutil.makedate(mtime)
583 583 age = '(%s)' % templatefilters.age(date, abbrev=True)
584 584 ui.write(age, label='shelve.age')
585 585 ui.write(' ' * (12 - len(age)))
586 586 used += 12
587 587 with open(name + '.' + patchextension, 'rb') as fp:
588 588 while True:
589 589 line = fp.readline()
590 590 if not line:
591 591 break
592 592 if not line.startswith('#'):
593 593 desc = line.rstrip()
594 594 if ui.formatted():
595 595 desc = stringutil.ellipsis(desc, width - used)
596 596 ui.write(desc)
597 597 break
598 598 ui.write('\n')
599 599 if not (opts['patch'] or opts['stat']):
600 600 continue
601 601 difflines = fp.readlines()
602 602 if opts['patch']:
603 603 for chunk, label in patch.difflabel(iter, difflines):
604 604 ui.write(chunk, label=label)
605 605 if opts['stat']:
606 606 for chunk, label in patch.diffstatui(difflines, width=width):
607 607 ui.write(chunk, label=label)
608 608
609 609 def patchcmds(ui, repo, pats, opts):
610 610 """subcommand that displays shelves"""
611 611 if len(pats) == 0:
612 612 shelves = listshelves(repo)
613 613 if not shelves:
614 614 raise error.Abort(_("there are no shelves to show"))
615 615 mtime, name = shelves[0]
616 616 sname = util.split(name)[1]
617 617 pats = [sname]
618 618
619 619 for shelfname in pats:
620 620 if not shelvedfile(repo, shelfname, patchextension).exists():
621 621 raise error.Abort(_("cannot find shelf %s") % shelfname)
622 622
623 623 listcmd(ui, repo, pats, opts)
624 624
625 625 def checkparents(repo, state):
626 626 """check parent while resuming an unshelve"""
627 627 if state.parents != repo.dirstate.parents():
628 628 raise error.Abort(_('working directory parents do not match unshelve '
629 629 'state'))
630 630
631 631 def _loadshelvedstate(ui, repo, opts):
632 632 try:
633 633 state = shelvedstate.load(repo)
634 634 if opts.get('keep') is None:
635 635 opts['keep'] = state.keep
636 636 except IOError as err:
637 637 if err.errno != errno.ENOENT:
638 638 raise
639 639 cmdutil.wrongtooltocontinue(repo, _('unshelve'))
640 640 except error.CorruptedState as err:
641 641 ui.debug(pycompat.bytestr(err) + '\n')
642 642 if opts.get('continue'):
643 643 msg = _('corrupted shelved state file')
644 644 hint = _('please run hg unshelve --abort to abort unshelve '
645 645 'operation')
646 646 raise error.Abort(msg, hint=hint)
647 647 elif opts.get('abort'):
648 648 shelvedstate.clear(repo)
649 649 raise error.Abort(_('could not read shelved state file, your '
650 650 'working copy may be in an unexpected state\n'
651 651 'please update to some commit\n'))
652 652 return state
653 653
654 654 def unshelveabort(ui, repo, state):
655 655 """subcommand that abort an in-progress unshelve"""
656 656 with repo.lock():
657 657 try:
658 658 checkparents(repo, state)
659 659
660 660 merge.update(repo, state.pendingctx, branchmerge=False, force=True)
661 661 if (state.activebookmark
662 662 and state.activebookmark in repo._bookmarks):
663 663 bookmarks.activate(repo, state.activebookmark)
664 664 mergefiles(ui, repo, state.wctx, state.pendingctx)
665 665 if not phases.supportinternal(repo):
666 666 repair.strip(ui, repo, state.nodestoremove, backup=False,
667 667 topic='shelve')
668 668 finally:
669 669 shelvedstate.clear(repo)
670 670 ui.warn(_("unshelve of '%s' aborted\n") % state.name)
671 671
672 672 def hgabortunshelve(ui, repo):
673 673 """logic to abort unshelve using 'hg abort"""
674 674 with repo.wlock():
675 675 state = _loadshelvedstate(ui, repo, {'abort' : True})
676 676 return unshelveabort(ui, repo, state)
677 677
678 678 def mergefiles(ui, repo, wctx, shelvectx):
679 679 """updates to wctx and merges the changes from shelvectx into the
680 680 dirstate."""
681 681 with ui.configoverride({('ui', 'quiet'): True}):
682 682 hg.update(repo, wctx.node())
683 683 ui.pushbuffer(True)
684 684 cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents())
685 685 ui.popbuffer()
686 686
687 687 def restorebranch(ui, repo, branchtorestore):
688 688 if branchtorestore and branchtorestore != repo.dirstate.branch():
689 689 repo.dirstate.setbranch(branchtorestore)
690 690 ui.status(_('marked working directory as branch %s\n')
691 691 % branchtorestore)
692 692
693 693 def unshelvecleanup(ui, repo, name, opts):
694 694 """remove related files after an unshelve"""
695 695 if not opts.get('keep'):
696 696 for filetype in shelvefileextensions:
697 697 shfile = shelvedfile(repo, name, filetype)
698 698 if shfile.exists():
699 699 shfile.movetobackup()
700 700 cleanupoldbackups(repo)
701 701 def unshelvecontinue(ui, repo, state, opts):
702 702 """subcommand to continue an in-progress unshelve"""
703 703 # We're finishing off a merge. First parent is our original
704 704 # parent, second is the temporary "fake" commit we're unshelving.
705 705 interactive = state.interactive
706 706 basename = state.name
707 707 with repo.lock():
708 708 checkparents(repo, state)
709 709 ms = merge.mergestate.read(repo)
710 710 if list(ms.unresolved()):
711 711 raise error.Abort(
712 712 _("unresolved conflicts, can't continue"),
713 713 hint=_("see 'hg resolve', then 'hg unshelve --continue'"))
714 714
715 715 shelvectx = repo[state.parents[1]]
716 716 pendingctx = state.pendingctx
717 717
718 718 with repo.dirstate.parentchange():
719 719 repo.setparents(state.pendingctx.node(), nodemod.nullid)
720 720 repo.dirstate.write(repo.currenttransaction())
721 721
722 722 targetphase = phases.internal
723 723 if not phases.supportinternal(repo):
724 724 targetphase = phases.secret
725 725 overrides = {('phases', 'new-commit'): targetphase}
726 726 with repo.ui.configoverride(overrides, 'unshelve'):
727 727 with repo.dirstate.parentchange():
728 728 repo.setparents(state.parents[0], nodemod.nullid)
729 729 newnode, ispartialunshelve = _createunshelvectx(ui,
730 730 repo, shelvectx, basename, interactive, opts)
731 731
732 732 if newnode is None:
733 733 # If it ended up being a no-op commit, then the normal
734 734 # merge state clean-up path doesn't happen, so do it
735 735 # here. Fix issue5494
736 736 merge.mergestate.clean(repo)
737 737 shelvectx = state.pendingctx
738 738 msg = _('note: unshelved changes already existed '
739 739 'in the working copy\n')
740 740 ui.status(msg)
741 741 else:
742 742 # only strip the shelvectx if we produced one
743 743 state.nodestoremove.append(newnode)
744 744 shelvectx = repo[newnode]
745 745
746 746 hg.updaterepo(repo, pendingctx.node(), overwrite=False)
747 747 mergefiles(ui, repo, state.wctx, shelvectx)
748 748 restorebranch(ui, repo, state.branchtorestore)
749 749
750 750 if not phases.supportinternal(repo):
751 751 repair.strip(ui, repo, state.nodestoremove, backup=False,
752 752 topic='shelve')
753 753 shelvedstate.clear(repo)
754 754 if not ispartialunshelve:
755 755 unshelvecleanup(ui, repo, state.name, opts)
756 756 _restoreactivebookmark(repo, state.activebookmark)
757 757 ui.status(_("unshelve of '%s' complete\n") % state.name)
758 758
759 759 def hgcontinueunshelve(ui, repo):
760 760 """logic to resume unshelve using 'hg continue'"""
761 761 with repo.wlock():
762 762 state = _loadshelvedstate(ui, repo, {'continue' : True})
763 763 return unshelvecontinue(ui, repo, state, {'keep' : state.keep})
764 764
765 765 def _commitworkingcopychanges(ui, repo, opts, tmpwctx):
766 766 """Temporarily commit working copy changes before moving unshelve commit"""
767 767 # Store pending changes in a commit and remember added in case a shelve
768 768 # contains unknown files that are part of the pending change
769 769 s = repo.status()
770 770 addedbefore = frozenset(s.added)
771 771 if not (s.modified or s.added or s.removed):
772 772 return tmpwctx, addedbefore
773 773 ui.status(_("temporarily committing pending changes "
774 774 "(restore with 'hg unshelve --abort')\n"))
775 775 extra = {'internal': 'shelve'}
776 776 commitfunc = getcommitfunc(extra=extra, interactive=False,
777 777 editor=False)
778 778 tempopts = {}
779 779 tempopts['message'] = "pending changes temporary commit"
780 780 tempopts['date'] = opts.get('date')
781 781 with ui.configoverride({('ui', 'quiet'): True}):
782 782 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
783 783 tmpwctx = repo[node]
784 784 return tmpwctx, addedbefore
785 785
786 786 def _unshelverestorecommit(ui, repo, tr, basename):
787 787 """Recreate commit in the repository during the unshelve"""
788 788 repo = repo.unfiltered()
789 789 node = None
790 790 if shelvedfile(repo, basename, 'shelve').exists():
791 791 node = shelvedfile(repo, basename, 'shelve').readinfo()['node']
792 792 if node is None or node not in repo:
793 793 with ui.configoverride({('ui', 'quiet'): True}):
794 794 shelvectx = shelvedfile(repo, basename, 'hg').applybundle(tr)
795 795 # We might not strip the unbundled changeset, so we should keep track of
796 796 # the unshelve node in case we need to reuse it (eg: unshelve --keep)
797 797 if node is None:
798 798 info = {'node': nodemod.hex(shelvectx.node())}
799 799 shelvedfile(repo, basename, 'shelve').writeinfo(info)
800 800 else:
801 801 shelvectx = repo[node]
802 802
803 803 return repo, shelvectx
804 804
805 805 def _createunshelvectx(ui, repo, shelvectx, basename, interactive, opts):
806 806 """Handles the creation of unshelve commit and updates the shelve if it
807 807 was partially unshelved.
808 808
809 809 If interactive is:
810 810
811 811 * False: Commits all the changes in the working directory.
812 812 * True: Prompts the user to select changes to unshelve and commit them.
813 813 Update the shelve with remaining changes.
814 814
815 815 Returns the node of the new commit formed and a bool indicating whether
816 816 the shelve was partially unshelved.Creates a commit ctx to unshelve
817 817 interactively or non-interactively.
818 818
819 819 The user might want to unshelve certain changes only from the stored
820 820 shelve in interactive. So, we would create two commits. One with requested
821 821 changes to unshelve at that time and the latter is shelved for future.
822 822
823 823 Here, we return both the newnode which is created interactively and a
824 824 bool to know whether the shelve is partly done or completely done.
825 825 """
826 826 opts['message'] = shelvectx.description()
827 827 opts['interactive-unshelve'] = True
828 828 pats = []
829 829 if not interactive:
830 830 newnode = repo.commit(text=shelvectx.description(),
831 831 extra=shelvectx.extra(),
832 832 user=shelvectx.user(),
833 833 date=shelvectx.date())
834 834 return newnode, False
835 835
836 836 commitfunc = getcommitfunc(shelvectx.extra(), interactive=True,
837 837 editor=True)
838 838 newnode = cmdutil.dorecord(ui, repo, commitfunc, None, False,
839 839 cmdutil.recordfilter, *pats,
840 840 **pycompat.strkwargs(opts))
841 841 snode = repo.commit(text=shelvectx.description(),
842 842 extra=shelvectx.extra(),
843 843 user=shelvectx.user())
844 844 if snode:
845 845 m = scmutil.matchfiles(repo, repo[snode].files())
846 846 _shelvecreatedcommit(repo, snode, basename, m)
847 847
848 848 return newnode, bool(snode)
849 849
850 850 def _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev, basename, pctx,
851 851 tmpwctx, shelvectx, branchtorestore,
852 852 activebookmark):
853 853 """Rebase restored commit from its original location to a destination"""
854 854 # If the shelve is not immediately on top of the commit
855 855 # we'll be merging with, rebase it to be on top.
856 856 interactive = opts.get('interactive')
857 857 if tmpwctx.node() == shelvectx.p1().node() and not interactive:
858 858 # We won't skip on interactive mode because, the user might want to
859 859 # unshelve certain changes only.
860 860 return shelvectx, False
861 861
862 862 overrides = {
863 863 ('ui', 'forcemerge'): opts.get('tool', ''),
864 864 ('phases', 'new-commit'): phases.secret,
865 865 }
866 866 with repo.ui.configoverride(overrides, 'unshelve'):
867 867 ui.status(_('rebasing shelved changes\n'))
868 868 stats = merge.graft(repo, shelvectx, shelvectx.p1(),
869 869 labels=['shelve', 'working-copy'],
870 870 keepconflictparent=True)
871 871 if stats.unresolvedcount:
872 872 tr.close()
873 873
874 874 nodestoremove = [repo.changelog.node(rev)
875 875 for rev in pycompat.xrange(oldtiprev, len(repo))]
876 876 shelvedstate.save(repo, basename, pctx, tmpwctx, nodestoremove,
877 877 branchtorestore, opts.get('keep'), activebookmark,
878 878 interactive)
879 879 raise error.InterventionRequired(
880 880 _("unresolved conflicts (see 'hg resolve', then "
881 881 "'hg unshelve --continue')"))
882 882
883 883 with repo.dirstate.parentchange():
884 884 repo.setparents(tmpwctx.node(), nodemod.nullid)
885 885 newnode, ispartialunshelve = _createunshelvectx(ui, repo,
886 886 shelvectx, basename, interactive, opts)
887 887
888 888 if newnode is None:
889 889 # If it ended up being a no-op commit, then the normal
890 890 # merge state clean-up path doesn't happen, so do it
891 891 # here. Fix issue5494
892 892 merge.mergestate.clean(repo)
893 893 shelvectx = tmpwctx
894 894 msg = _('note: unshelved changes already existed '
895 895 'in the working copy\n')
896 896 ui.status(msg)
897 897 else:
898 898 shelvectx = repo[newnode]
899 899 hg.updaterepo(repo, tmpwctx.node(), False)
900 900
901 901 return shelvectx, ispartialunshelve
902 902
903 903 def _forgetunknownfiles(repo, shelvectx, addedbefore):
904 904 # Forget any files that were unknown before the shelve, unknown before
905 905 # unshelve started, but are now added.
906 906 shelveunknown = shelvectx.extra().get('shelve_unknown')
907 907 if not shelveunknown:
908 908 return
909 909 shelveunknown = frozenset(shelveunknown.split('\0'))
910 910 addedafter = frozenset(repo.status().added)
911 911 toforget = (addedafter & shelveunknown) - addedbefore
912 912 repo[None].forget(toforget)
913 913
914 914 def _finishunshelve(repo, oldtiprev, tr, activebookmark):
915 915 _restoreactivebookmark(repo, activebookmark)
916 916 # The transaction aborting will strip all the commits for us,
917 917 # but it doesn't update the inmemory structures, so addchangegroup
918 918 # hooks still fire and try to operate on the missing commits.
919 919 # Clean up manually to prevent this.
920 920 repo.unfiltered().changelog.strip(oldtiprev, tr)
921 921 _aborttransaction(repo, tr)
922 922
923 923 def _checkunshelveuntrackedproblems(ui, repo, shelvectx):
924 924 """Check potential problems which may result from working
925 925 copy having untracked changes."""
926 926 wcdeleted = set(repo.status().deleted)
927 927 shelvetouched = set(shelvectx.files())
928 928 intersection = wcdeleted.intersection(shelvetouched)
929 929 if intersection:
930 930 m = _("shelved change touches missing files")
931 931 hint = _("run hg status to see which files are missing")
932 932 raise error.Abort(m, hint=hint)
933 933
934 934 def dounshelve(ui, repo, *shelved, **opts):
935 935 opts = pycompat.byteskwargs(opts)
936 936 abortf = opts.get('abort')
937 937 continuef = opts.get('continue')
938 938 interactive = opts.get('interactive')
939 939 if not abortf and not continuef:
940 940 cmdutil.checkunfinished(repo)
941 941 shelved = list(shelved)
942 942 if opts.get("name"):
943 943 shelved.append(opts["name"])
944 944
945 if interactive and opts.get('keep'):
946 raise error.Abort(_('--keep on --interactive is not yet supported'))
945 947 if abortf or continuef:
946 948 if abortf and continuef:
947 949 raise error.Abort(_('cannot use both abort and continue'))
948 950 if shelved:
949 951 raise error.Abort(_('cannot combine abort/continue with '
950 952 'naming a shelved change'))
951 953 if abortf and opts.get('tool', False):
952 954 ui.warn(_('tool option will be ignored\n'))
953 955
954 956 state = _loadshelvedstate(ui, repo, opts)
955 957 if abortf:
956 958 return unshelveabort(ui, repo, state)
957 959 elif continuef and interactive:
958 960 raise error.Abort(_('cannot use both continue and interactive'))
959 961 elif continuef:
960 962 return unshelvecontinue(ui, repo, state, opts)
961 963 elif len(shelved) > 1:
962 964 raise error.Abort(_('can only unshelve one change at a time'))
963 965 elif not shelved:
964 966 shelved = listshelves(repo)
965 967 if not shelved:
966 968 raise error.Abort(_('no shelved changes to apply!'))
967 969 basename = util.split(shelved[0][1])[1]
968 970 ui.status(_("unshelving change '%s'\n") % basename)
969 971 else:
970 972 basename = shelved[0]
971 973
972 974 if not shelvedfile(repo, basename, patchextension).exists():
973 975 raise error.Abort(_("shelved change '%s' not found") % basename)
974 976
975 977 repo = repo.unfiltered()
976 978 lock = tr = None
977 979 try:
978 980 lock = repo.lock()
979 981 tr = repo.transaction('unshelve', report=lambda x: None)
980 982 oldtiprev = len(repo)
981 983
982 984 pctx = repo['.']
983 985 tmpwctx = pctx
984 986 # The goal is to have a commit structure like so:
985 987 # ...-> pctx -> tmpwctx -> shelvectx
986 988 # where tmpwctx is an optional commit with the user's pending changes
987 989 # and shelvectx is the unshelved changes. Then we merge it all down
988 990 # to the original pctx.
989 991
990 992 activebookmark = _backupactivebookmark(repo)
991 993 tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts,
992 994 tmpwctx)
993 995 repo, shelvectx = _unshelverestorecommit(ui, repo, tr, basename)
994 996 _checkunshelveuntrackedproblems(ui, repo, shelvectx)
995 997 branchtorestore = ''
996 998 if shelvectx.branch() != shelvectx.p1().branch():
997 999 branchtorestore = shelvectx.branch()
998 1000
999 1001 shelvectx, ispartialunshelve = _rebaserestoredcommit(ui, repo, opts,
1000 1002 tr, oldtiprev, basename, pctx, tmpwctx, shelvectx,
1001 1003 branchtorestore, activebookmark)
1002 1004 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
1003 1005 with ui.configoverride(overrides, 'unshelve'):
1004 1006 mergefiles(ui, repo, pctx, shelvectx)
1005 1007 restorebranch(ui, repo, branchtorestore)
1006 1008 shelvedstate.clear(repo)
1007 1009 _finishunshelve(repo, oldtiprev, tr, activebookmark)
1008 1010 _forgetunknownfiles(repo, shelvectx, addedbefore)
1009 1011 if not ispartialunshelve:
1010 1012 unshelvecleanup(ui, repo, basename, opts)
1011 1013 finally:
1012 1014 if tr:
1013 1015 tr.release()
1014 1016 lockmod.release(lock)
@@ -1,1477 +1,1481 b''
1 1 #testcases stripbased phasebased
2 2
3 3 $ cat <<EOF >> $HGRCPATH
4 4 > [extensions]
5 5 > mq =
6 6 > [defaults]
7 7 > diff = --nodates --git
8 8 > qnew = --date '0 0'
9 9 > [shelve]
10 10 > maxbackups = 2
11 11 > EOF
12 12
13 13 #if phasebased
14 14
15 15 $ cat <<EOF >> $HGRCPATH
16 16 > [format]
17 17 > internal-phase = yes
18 18 > EOF
19 19
20 20 #endif
21 21
22 22 $ hg init repo
23 23 $ cd repo
24 24 $ mkdir a b
25 25 $ echo a > a/a
26 26 $ echo b > b/b
27 27 $ echo c > c
28 28 $ echo d > d
29 29 $ echo x > x
30 30 $ hg addremove -q
31 31
32 32 shelve has a help message
33 33 $ hg shelve -h
34 34 hg shelve [OPTION]... [FILE]...
35 35
36 36 save and set aside changes from the working directory
37 37
38 38 Shelving takes files that "hg status" reports as not clean, saves the
39 39 modifications to a bundle (a shelved change), and reverts the files so
40 40 that their state in the working directory becomes clean.
41 41
42 42 To restore these changes to the working directory, using "hg unshelve";
43 43 this will work even if you switch to a different commit.
44 44
45 45 When no files are specified, "hg shelve" saves all not-clean files. If
46 46 specific files or directories are named, only changes to those files are
47 47 shelved.
48 48
49 49 In bare shelve (when no files are specified, without interactive, include
50 50 and exclude option), shelving remembers information if the working
51 51 directory was on newly created branch, in other words working directory
52 52 was on different branch than its first parent. In this situation
53 53 unshelving restores branch information to the working directory.
54 54
55 55 Each shelved change has a name that makes it easier to find later. The
56 56 name of a shelved change defaults to being based on the active bookmark,
57 57 or if there is no active bookmark, the current named branch. To specify a
58 58 different name, use "--name".
59 59
60 60 To see a list of existing shelved changes, use the "--list" option. For
61 61 each shelved change, this will print its name, age, and description; use "
62 62 --patch" or "--stat" for more details.
63 63
64 64 To delete specific shelved changes, use "--delete". To delete all shelved
65 65 changes, use "--cleanup".
66 66
67 67 options ([+] can be repeated):
68 68
69 69 -A --addremove mark new/missing files as added/removed before
70 70 shelving
71 71 -u --unknown store unknown files in the shelve
72 72 --cleanup delete all shelved changes
73 73 --date DATE shelve with the specified commit date
74 74 -d --delete delete the named shelved change(s)
75 75 -e --edit invoke editor on commit messages
76 76 -k --keep shelve, but keep changes in the working directory
77 77 -l --list list current shelves
78 78 -m --message TEXT use text as shelve message
79 79 -n --name NAME use the given name for the shelved commit
80 80 -p --patch output patches for changes (provide the names of the
81 81 shelved changes as positional arguments)
82 82 -i --interactive interactive mode
83 83 --stat output diffstat-style summary of changes (provide
84 84 the names of the shelved changes as positional
85 85 arguments)
86 86 -I --include PATTERN [+] include names matching the given patterns
87 87 -X --exclude PATTERN [+] exclude names matching the given patterns
88 88 --mq operate on patch repository
89 89
90 90 (some details hidden, use --verbose to show complete help)
91 91
92 92 shelving in an empty repo should be possible
93 93 (this tests also that editor is not invoked, if '--edit' is not
94 94 specified)
95 95
96 96 $ HGEDITOR=cat hg shelve
97 97 shelved as default
98 98 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
99 99
100 100 $ hg unshelve
101 101 unshelving change 'default'
102 102
103 103 $ hg commit -q -m 'initial commit'
104 104
105 105 $ hg shelve
106 106 nothing changed
107 107 [1]
108 108
109 109 make sure shelve files were backed up
110 110
111 111 $ ls .hg/shelve-backup
112 112 default.hg
113 113 default.patch
114 114 default.shelve
115 115
116 116 checks to make sure we dont create a directory or
117 117 hidden file while choosing a new shelve name
118 118
119 119 when we are given a name
120 120
121 121 $ hg shelve -n foo/bar
122 122 abort: shelved change names can not contain slashes
123 123 [255]
124 124 $ hg shelve -n .baz
125 125 abort: shelved change names can not start with '.'
126 126 [255]
127 127 $ hg shelve -n foo\\bar
128 128 abort: shelved change names can not contain slashes
129 129 [255]
130 130
131 131 when shelve has to choose itself
132 132
133 133 $ hg branch x/y -q
134 134 $ hg commit -q -m "Branch commit 0"
135 135 $ hg shelve
136 136 nothing changed
137 137 [1]
138 138 $ hg branch .x -q
139 139 $ hg commit -q -m "Branch commit 1"
140 140 $ hg shelve
141 141 nothing changed
142 142 [1]
143 143 $ hg branch x\\y -q
144 144 $ hg commit -q -m "Branch commit 2"
145 145 $ hg shelve
146 146 nothing changed
147 147 [1]
148 148
149 149 cleaning the branches made for name checking tests
150 150
151 151 $ hg up default -q
152 152 $ hg strip e9177275307e+6a6d231f43d+882bae7c62c2 -q
153 153
154 154 create an mq patch - shelving should work fine with a patch applied
155 155
156 156 $ echo n > n
157 157 $ hg add n
158 158 $ hg commit n -m second
159 159 $ hg qnew second.patch
160 160
161 161 shelve a change that we will delete later
162 162
163 163 $ echo a >> a/a
164 164 $ hg shelve
165 165 shelved as default
166 166 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
167 167
168 168 set up some more complex changes to shelve
169 169
170 170 $ echo a >> a/a
171 171 $ hg mv b b.rename
172 172 moving b/b to b.rename/b
173 173 $ hg cp c c.copy
174 174 $ hg status -C
175 175 M a/a
176 176 A b.rename/b
177 177 b/b
178 178 A c.copy
179 179 c
180 180 R b/b
181 181
182 182 the common case - no options or filenames
183 183
184 184 $ hg shelve
185 185 shelved as default-01
186 186 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
187 187 $ hg status -C
188 188
189 189 ensure that our shelved changes exist
190 190
191 191 $ hg shelve -l
192 192 default-01 (*)* changes to: [mq]: second.patch (glob)
193 193 default (*)* changes to: [mq]: second.patch (glob)
194 194
195 195 $ hg shelve -l -p default
196 196 default (*)* changes to: [mq]: second.patch (glob)
197 197
198 198 diff --git a/a/a b/a/a
199 199 --- a/a/a
200 200 +++ b/a/a
201 201 @@ -1,1 +1,2 @@
202 202 a
203 203 +a
204 204
205 205 $ hg shelve --list --addremove
206 206 abort: options '--list' and '--addremove' may not be used together
207 207 [255]
208 208
209 209 delete our older shelved change
210 210
211 211 $ hg shelve -d default
212 212 $ hg qfinish -a -q
213 213
214 214 ensure shelve backups aren't overwritten
215 215
216 216 $ ls .hg/shelve-backup/
217 217 default-1.hg
218 218 default-1.patch
219 219 default-1.shelve
220 220 default.hg
221 221 default.patch
222 222 default.shelve
223 223
224 224 local edits should not prevent a shelved change from applying
225 225
226 226 $ printf "z\na\n" > a/a
227 227 $ hg unshelve --keep
228 228 unshelving change 'default-01'
229 229 temporarily committing pending changes (restore with 'hg unshelve --abort')
230 230 rebasing shelved changes
231 231 merging a/a
232 232
233 233 $ hg revert --all -q
234 234 $ rm a/a.orig b.rename/b c.copy
235 235
236 236 apply it and make sure our state is as expected
237 237
238 238 (this also tests that same timestamp prevents backups from being
239 239 removed, even though there are more than 'maxbackups' backups)
240 240
241 241 $ f -t .hg/shelve-backup/default.patch
242 242 .hg/shelve-backup/default.patch: file
243 243 $ touch -t 200001010000 .hg/shelve-backup/default.patch
244 244 $ f -t .hg/shelve-backup/default-1.patch
245 245 .hg/shelve-backup/default-1.patch: file
246 246 $ touch -t 200001010000 .hg/shelve-backup/default-1.patch
247 247
248 248 $ hg unshelve
249 249 unshelving change 'default-01'
250 250 $ hg status -C
251 251 M a/a
252 252 A b.rename/b
253 253 b/b
254 254 A c.copy
255 255 c
256 256 R b/b
257 257 $ hg shelve -l
258 258
259 259 (both of default.hg and default-1.hg should be still kept, because it
260 260 is difficult to decide actual order of them from same timestamp)
261 261
262 262 $ ls .hg/shelve-backup/
263 263 default-01.hg
264 264 default-01.patch
265 265 default-01.shelve
266 266 default-1.hg
267 267 default-1.patch
268 268 default-1.shelve
269 269 default.hg
270 270 default.patch
271 271 default.shelve
272 272
273 273 $ hg unshelve
274 274 abort: no shelved changes to apply!
275 275 [255]
276 276 $ hg unshelve foo
277 277 abort: shelved change 'foo' not found
278 278 [255]
279 279
280 280 named shelves, specific filenames, and "commit messages" should all work
281 281 (this tests also that editor is invoked, if '--edit' is specified)
282 282
283 283 $ hg status -C
284 284 M a/a
285 285 A b.rename/b
286 286 b/b
287 287 A c.copy
288 288 c
289 289 R b/b
290 290 $ HGEDITOR=cat hg shelve -q -n wibble -m wat -e a
291 291 wat
292 292
293 293
294 294 HG: Enter commit message. Lines beginning with 'HG:' are removed.
295 295 HG: Leave message empty to abort commit.
296 296 HG: --
297 297 HG: user: shelve@localhost
298 298 HG: branch 'default'
299 299 HG: changed a/a
300 300
301 301 expect "a" to no longer be present, but status otherwise unchanged
302 302
303 303 $ hg status -C
304 304 A b.rename/b
305 305 b/b
306 306 A c.copy
307 307 c
308 308 R b/b
309 309 $ hg shelve -l --stat
310 310 wibble (*) wat (glob)
311 311 a/a | 1 +
312 312 1 files changed, 1 insertions(+), 0 deletions(-)
313 313
314 314 and now "a/a" should reappear
315 315
316 316 $ cd a
317 317 $ hg unshelve -q wibble
318 318 $ cd ..
319 319 $ hg status -C
320 320 M a/a
321 321 A b.rename/b
322 322 b/b
323 323 A c.copy
324 324 c
325 325 R b/b
326 326
327 327 ensure old shelve backups are being deleted automatically
328 328
329 329 $ ls .hg/shelve-backup/
330 330 default-01.hg
331 331 default-01.patch
332 332 default-01.shelve
333 333 wibble.hg
334 334 wibble.patch
335 335 wibble.shelve
336 336
337 337 cause unshelving to result in a merge with 'a' conflicting
338 338
339 339 $ hg shelve -q
340 340 $ echo c>>a/a
341 341 $ hg commit -m second
342 342 $ hg tip --template '{files}\n'
343 343 a/a
344 344
345 345 add an unrelated change that should be preserved
346 346
347 347 $ mkdir foo
348 348 $ echo foo > foo/foo
349 349 $ hg add foo/foo
350 350
351 351 force a conflicted merge to occur
352 352
353 353 $ hg unshelve
354 354 unshelving change 'default'
355 355 temporarily committing pending changes (restore with 'hg unshelve --abort')
356 356 rebasing shelved changes
357 357 merging a/a
358 358 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
359 359 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
360 360 [1]
361 361 $ hg status -v
362 362 M a/a
363 363 M b.rename/b
364 364 M c.copy
365 365 R b/b
366 366 ? a/a.orig
367 367 # The repository is in an unfinished *unshelve* state.
368 368
369 369 # Unresolved merge conflicts:
370 370 #
371 371 # a/a
372 372 #
373 373 # To mark files as resolved: hg resolve --mark FILE
374 374
375 375 # To continue: hg unshelve --continue
376 376 # To abort: hg unshelve --abort
377 377
378 378
379 379 ensure that we have a merge with unresolved conflicts
380 380
381 381 #if phasebased
382 382 $ hg heads -q --template '{rev}\n'
383 383 8
384 384 5
385 385 $ hg parents -q --template '{rev}\n'
386 386 8
387 387 5
388 388 #endif
389 389
390 390 #if stripbased
391 391 $ hg heads -q --template '{rev}\n'
392 392 5
393 393 4
394 394 $ hg parents -q --template '{rev}\n'
395 395 4
396 396 5
397 397 #endif
398 398
399 399 $ hg status
400 400 M a/a
401 401 M b.rename/b
402 402 M c.copy
403 403 R b/b
404 404 ? a/a.orig
405 405 $ hg diff
406 406 diff --git a/a/a b/a/a
407 407 --- a/a/a
408 408 +++ b/a/a
409 409 @@ -1,2 +1,6 @@
410 410 a
411 411 +<<<<<<< shelve: 2377350b6337 - shelve: pending changes temporary commit
412 412 c
413 413 +=======
414 414 +a
415 415 +>>>>>>> working-copy: a68ec3400638 - shelve: changes to: [mq]: second.patch
416 416 diff --git a/b/b b/b.rename/b
417 417 rename from b/b
418 418 rename to b.rename/b
419 419 diff --git a/c b/c.copy
420 420 copy from c
421 421 copy to c.copy
422 422 $ hg resolve -l
423 423 U a/a
424 424
425 425 $ hg shelve
426 426 abort: unshelve already in progress
427 427 (use 'hg unshelve --continue' or 'hg unshelve --abort')
428 428 [255]
429 429
430 430 abort the unshelve and be happy
431 431
432 432 $ hg status
433 433 M a/a
434 434 M b.rename/b
435 435 M c.copy
436 436 R b/b
437 437 ? a/a.orig
438 438 $ hg unshelve -a
439 439 unshelve of 'default' aborted
440 440 $ hg heads -q
441 441 [37]:2e69b451d1ea (re)
442 442 $ hg parents
443 443 changeset: [37]:2e69b451d1ea (re)
444 444 tag: tip
445 445 parent: 3:509104101065 (?)
446 446 user: test
447 447 date: Thu Jan 01 00:00:00 1970 +0000
448 448 summary: second
449 449
450 450 $ hg resolve -l
451 451 $ hg status
452 452 A foo/foo
453 453 ? a/a.orig
454 454
455 455 try to continue with no unshelve underway
456 456
457 457 $ hg unshelve -c
458 458 abort: no unshelve in progress
459 459 [255]
460 460 $ hg status
461 461 A foo/foo
462 462 ? a/a.orig
463 463
464 464 redo the unshelve to get a conflict
465 465
466 466 $ hg unshelve -q
467 467 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
468 468 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
469 469 [1]
470 470
471 471 attempt to continue
472 472
473 473 $ hg unshelve -c
474 474 abort: unresolved conflicts, can't continue
475 475 (see 'hg resolve', then 'hg unshelve --continue')
476 476 [255]
477 477
478 478 $ hg revert -r . a/a
479 479 $ hg resolve -m a/a
480 480 (no more unresolved files)
481 481 continue: hg unshelve --continue
482 482
483 483 $ hg commit -m 'commit while unshelve in progress'
484 484 abort: unshelve already in progress
485 485 (use 'hg unshelve --continue' or 'hg unshelve --abort')
486 486 [255]
487 487
488 488 $ hg graft --continue
489 489 abort: no graft in progress
490 490 (continue: hg unshelve --continue)
491 491 [255]
492 492 $ hg unshelve -c
493 493 unshelve of 'default' complete
494 494
495 495 ensure the repo is as we hope
496 496
497 497 $ hg parents
498 498 changeset: [37]:2e69b451d1ea (re)
499 499 tag: tip
500 500 parent: 3:509104101065 (?)
501 501 user: test
502 502 date: Thu Jan 01 00:00:00 1970 +0000
503 503 summary: second
504 504
505 505 $ hg heads -q
506 506 [37]:2e69b451d1ea (re)
507 507
508 508 $ hg status -C
509 509 A b.rename/b
510 510 b/b
511 511 A c.copy
512 512 c
513 513 A foo/foo
514 514 R b/b
515 515 ? a/a.orig
516 516
517 517 there should be no shelves left
518 518
519 519 $ hg shelve -l
520 520
521 521 #if execbit
522 522
523 523 ensure that metadata-only changes are shelved
524 524
525 525 $ chmod +x a/a
526 526 $ hg shelve -q -n execbit a/a
527 527 $ hg status a/a
528 528 $ hg unshelve -q execbit
529 529 $ hg status a/a
530 530 M a/a
531 531 $ hg revert a/a
532 532
533 533 #else
534 534
535 535 Dummy shelve op, to keep rev numbers aligned
536 536
537 537 $ echo foo > a/a
538 538 $ hg shelve -q -n dummy a/a
539 539 $ hg unshelve -q dummy
540 540 $ hg revert a/a
541 541
542 542 #endif
543 543
544 544 #if symlink
545 545
546 546 $ rm a/a
547 547 $ ln -s foo a/a
548 548 $ hg shelve -q -n symlink a/a
549 549 $ hg status a/a
550 550 $ hg unshelve -q -n symlink
551 551 $ hg status a/a
552 552 M a/a
553 553 $ hg revert a/a
554 554
555 555 #else
556 556
557 557 Dummy shelve op, to keep rev numbers aligned
558 558
559 559 $ echo bar > a/a
560 560 $ hg shelve -q -n dummy a/a
561 561 $ hg unshelve -q dummy
562 562 $ hg revert a/a
563 563
564 564 #endif
565 565
566 566 set up another conflict between a commit and a shelved change
567 567
568 568 $ hg revert -q -C -a
569 569 $ rm a/a.orig b.rename/b c.copy
570 570 $ echo a >> a/a
571 571 $ hg shelve -q
572 572 $ echo x >> a/a
573 573 $ hg ci -m 'create conflict'
574 574 $ hg add foo/foo
575 575
576 576 if we resolve a conflict while unshelving, the unshelve should succeed
577 577
578 578 $ hg unshelve --tool :merge-other --keep
579 579 unshelving change 'default'
580 580 temporarily committing pending changes (restore with 'hg unshelve --abort')
581 581 rebasing shelved changes
582 582 merging a/a
583 583 $ hg parents -q
584 584 (4|13):33f7f61e6c5e (re)
585 585 $ hg shelve -l
586 586 default (*)* changes to: second (glob)
587 587 $ hg status
588 588 M a/a
589 589 A foo/foo
590 590 $ cat a/a
591 591 a
592 592 c
593 593 a
594 594 $ cat > a/a << EOF
595 595 > a
596 596 > c
597 597 > x
598 598 > EOF
599 599
600 600 $ HGMERGE=true hg unshelve
601 601 unshelving change 'default'
602 602 temporarily committing pending changes (restore with 'hg unshelve --abort')
603 603 rebasing shelved changes
604 604 merging a/a
605 605 note: unshelved changes already existed in the working copy
606 606 $ hg parents -q
607 607 (4|13):33f7f61e6c5e (re)
608 608 $ hg shelve -l
609 609 $ hg status
610 610 A foo/foo
611 611 $ cat a/a
612 612 a
613 613 c
614 614 x
615 615
616 616 test keep and cleanup
617 617
618 618 $ hg shelve
619 619 shelved as default
620 620 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
621 621 $ hg shelve --list
622 622 default (*)* changes to: create conflict (glob)
623 623 $ hg unshelve -k
624 624 unshelving change 'default'
625 625 $ hg shelve --list
626 626 default (*)* changes to: create conflict (glob)
627 627 $ hg shelve --cleanup
628 628 $ hg shelve --list
629 629
630 630 $ hg shelve --cleanup --delete
631 631 abort: options '--cleanup' and '--delete' may not be used together
632 632 [255]
633 633 $ hg shelve --cleanup --patch
634 634 abort: options '--cleanup' and '--patch' may not be used together
635 635 [255]
636 636 $ hg shelve --cleanup --message MESSAGE
637 637 abort: options '--cleanup' and '--message' may not be used together
638 638 [255]
639 639
640 640 test bookmarks
641 641
642 642 $ hg bookmark test
643 643 $ hg bookmark
644 644 \* test (4|13):33f7f61e6c5e (re)
645 645 $ hg shelve
646 646 shelved as test
647 647 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
648 648 $ hg bookmark
649 649 \* test (4|13):33f7f61e6c5e (re)
650 650 $ hg unshelve
651 651 unshelving change 'test'
652 652 $ hg bookmark
653 653 \* test (4|13):33f7f61e6c5e (re)
654 654
655 655 shelve should still work even if mq is disabled
656 656
657 657 $ hg --config extensions.mq=! shelve
658 658 shelved as test
659 659 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
660 660 $ hg --config extensions.mq=! shelve --list
661 661 test (*)* changes to: create conflict (glob)
662 662 $ hg bookmark
663 663 \* test (4|13):33f7f61e6c5e (re)
664 664 $ hg --config extensions.mq=! unshelve
665 665 unshelving change 'test'
666 666 $ hg bookmark
667 667 \* test (4|13):33f7f61e6c5e (re)
668 668
669 669 Recreate some conflict again
670 670
671 671 $ hg up -C -r 2e69b451d1ea
672 672 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
673 673 (leaving bookmark test)
674 674 $ echo y >> a/a
675 675 $ hg shelve
676 676 shelved as default
677 677 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
678 678 $ hg up test
679 679 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
680 680 (activating bookmark test)
681 681 $ hg bookmark
682 682 \* test (4|13):33f7f61e6c5e (re)
683 683 $ hg unshelve
684 684 unshelving change 'default'
685 685 rebasing shelved changes
686 686 merging a/a
687 687 warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark')
688 688 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
689 689 [1]
690 690 $ hg bookmark
691 691 test (4|13):33f7f61e6c5e (re)
692 692
693 693 Test that resolving all conflicts in one direction (so that the rebase
694 694 is a no-op), works (issue4398)
695 695
696 696 $ hg revert -a -r .
697 697 reverting a/a
698 698 $ hg resolve -m a/a
699 699 (no more unresolved files)
700 700 continue: hg unshelve --continue
701 701 $ hg unshelve -c
702 702 note: unshelved changes already existed in the working copy
703 703 unshelve of 'default' complete
704 704 $ hg bookmark
705 705 \* test (4|13):33f7f61e6c5e (re)
706 706 $ hg diff
707 707 $ hg status
708 708 ? a/a.orig
709 709 ? foo/foo
710 710 $ hg summary
711 711 parent: (4|13):33f7f61e6c5e tip (re)
712 712 create conflict
713 713 branch: default
714 714 bookmarks: *test
715 715 commit: 2 unknown (clean)
716 716 update: (current)
717 717 phases: 5 draft
718 718
719 719 $ hg shelve --delete --stat
720 720 abort: options '--delete' and '--stat' may not be used together
721 721 [255]
722 722 $ hg shelve --delete --name NAME
723 723 abort: options '--delete' and '--name' may not be used together
724 724 [255]
725 725
726 726 Test interactive shelve
727 727 $ cat <<EOF >> $HGRCPATH
728 728 > [ui]
729 729 > interactive = true
730 730 > EOF
731 731 $ echo 'a' >> a/b
732 732 $ cat a/a >> a/b
733 733 $ echo 'x' >> a/b
734 734 $ mv a/b a/a
735 735 $ echo 'a' >> foo/foo
736 736 $ hg st
737 737 M a/a
738 738 ? a/a.orig
739 739 ? foo/foo
740 740 $ cat a/a
741 741 a
742 742 a
743 743 c
744 744 x
745 745 x
746 746 $ cat foo/foo
747 747 foo
748 748 a
749 749 $ hg shelve --interactive --config ui.interactive=false
750 750 abort: running non-interactively
751 751 [255]
752 752 $ hg shelve --interactive << EOF
753 753 > y
754 754 > y
755 755 > n
756 756 > EOF
757 757 diff --git a/a/a b/a/a
758 758 2 hunks, 2 lines changed
759 759 examine changes to 'a/a'?
760 760 (enter ? for help) [Ynesfdaq?] y
761 761
762 762 @@ -1,3 +1,4 @@
763 763 +a
764 764 a
765 765 c
766 766 x
767 767 record change 1/2 to 'a/a'?
768 768 (enter ? for help) [Ynesfdaq?] y
769 769
770 770 @@ -1,3 +2,4 @@
771 771 a
772 772 c
773 773 x
774 774 +x
775 775 record change 2/2 to 'a/a'?
776 776 (enter ? for help) [Ynesfdaq?] n
777 777
778 778 shelved as test
779 779 merging a/a
780 780 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
781 781 $ cat a/a
782 782 a
783 783 c
784 784 x
785 785 x
786 786 $ cat foo/foo
787 787 foo
788 788 a
789 789 $ hg st
790 790 M a/a
791 791 ? foo/foo
792 792 $ hg bookmark
793 793 \* test (4|13):33f7f61e6c5e (re)
794 794 $ hg unshelve
795 795 unshelving change 'test'
796 796 temporarily committing pending changes (restore with 'hg unshelve --abort')
797 797 rebasing shelved changes
798 798 merging a/a
799 799 $ hg bookmark
800 800 \* test (4|13):33f7f61e6c5e (re)
801 801 $ cat a/a
802 802 a
803 803 a
804 804 c
805 805 x
806 806 x
807 807
808 808 shelve --patch and shelve --stat should work with valid shelfnames
809 809
810 810 $ hg up --clean .
811 811 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
812 812 (leaving bookmark test)
813 813 $ hg shelve --list
814 814 $ echo 'patch a' > shelf-patch-a
815 815 $ hg add shelf-patch-a
816 816 $ hg shelve
817 817 shelved as default
818 818 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
819 819 $ echo 'patch b' > shelf-patch-b
820 820 $ hg add shelf-patch-b
821 821 $ hg shelve
822 822 shelved as default-01
823 823 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
824 824 $ hg shelve --patch default default-01
825 825 default-01 (*)* changes to: create conflict (glob)
826 826
827 827 diff --git a/shelf-patch-b b/shelf-patch-b
828 828 new file mode 100644
829 829 --- /dev/null
830 830 +++ b/shelf-patch-b
831 831 @@ -0,0 +1,1 @@
832 832 +patch b
833 833 default (*)* changes to: create conflict (glob)
834 834
835 835 diff --git a/shelf-patch-a b/shelf-patch-a
836 836 new file mode 100644
837 837 --- /dev/null
838 838 +++ b/shelf-patch-a
839 839 @@ -0,0 +1,1 @@
840 840 +patch a
841 841 $ hg shelve --stat default default-01
842 842 default-01 (*)* changes to: create conflict (glob)
843 843 shelf-patch-b | 1 +
844 844 1 files changed, 1 insertions(+), 0 deletions(-)
845 845 default (*)* changes to: create conflict (glob)
846 846 shelf-patch-a | 1 +
847 847 1 files changed, 1 insertions(+), 0 deletions(-)
848 848 $ hg shelve --patch default
849 849 default (*)* changes to: create conflict (glob)
850 850
851 851 diff --git a/shelf-patch-a b/shelf-patch-a
852 852 new file mode 100644
853 853 --- /dev/null
854 854 +++ b/shelf-patch-a
855 855 @@ -0,0 +1,1 @@
856 856 +patch a
857 857 $ hg shelve --stat default
858 858 default (*)* changes to: create conflict (glob)
859 859 shelf-patch-a | 1 +
860 860 1 files changed, 1 insertions(+), 0 deletions(-)
861 861 $ hg shelve --patch nonexistentshelf
862 862 abort: cannot find shelf nonexistentshelf
863 863 [255]
864 864 $ hg shelve --stat nonexistentshelf
865 865 abort: cannot find shelf nonexistentshelf
866 866 [255]
867 867 $ hg shelve --patch default nonexistentshelf
868 868 abort: cannot find shelf nonexistentshelf
869 869 [255]
870 870
871 871 when the user asks for a patch, we assume they want the most recent shelve if
872 872 they don't provide a shelve name
873 873
874 874 $ hg shelve --patch
875 875 default-01 (*)* changes to: create conflict (glob)
876 876
877 877 diff --git a/shelf-patch-b b/shelf-patch-b
878 878 new file mode 100644
879 879 --- /dev/null
880 880 +++ b/shelf-patch-b
881 881 @@ -0,0 +1,1 @@
882 882 +patch b
883 883
884 884 $ cd ..
885 885
886 886 Shelve from general delta repo uses bundle2 on disk
887 887 --------------------------------------------------
888 888
889 889 no general delta
890 890
891 891 $ hg clone --pull repo bundle1 --config format.usegeneraldelta=0
892 892 requesting all changes
893 893 adding changesets
894 894 adding manifests
895 895 adding file changes
896 896 added 5 changesets with 8 changes to 6 files
897 897 new changesets cc01e2b0c59f:33f7f61e6c5e
898 898 updating to branch default
899 899 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
900 900 $ cd bundle1
901 901 $ echo babar > jungle
902 902 $ hg add jungle
903 903 $ hg shelve
904 904 shelved as default
905 905 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
906 906 $ hg debugbundle .hg/shelved/*.hg
907 907 330882a04d2ce8487636b1fb292e5beea77fa1e3
908 908 $ cd ..
909 909
910 910 with general delta
911 911
912 912 $ hg clone --pull repo bundle2 --config format.usegeneraldelta=1
913 913 requesting all changes
914 914 adding changesets
915 915 adding manifests
916 916 adding file changes
917 917 added 5 changesets with 8 changes to 6 files
918 918 new changesets cc01e2b0c59f:33f7f61e6c5e
919 919 updating to branch default
920 920 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
921 921 $ cd bundle2
922 922 $ echo babar > jungle
923 923 $ hg add jungle
924 924 $ hg shelve
925 925 shelved as default
926 926 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
927 927 $ hg debugbundle .hg/shelved/*.hg
928 928 Stream params: {Compression: BZ}
929 929 changegroup -- {nbchanges: 1, version: 02} (mandatory: True)
930 930 330882a04d2ce8487636b1fb292e5beea77fa1e3
931 931
932 932 Test shelve --keep
933 933
934 934 $ hg unshelve
935 935 unshelving change 'default'
936 936 $ hg shelve --keep --list
937 937 abort: options '--list' and '--keep' may not be used together
938 938 [255]
939 939 $ hg shelve --keep --patch
940 940 abort: options '--patch' and '--keep' may not be used together
941 941 [255]
942 942 $ hg shelve --keep --delete
943 943 abort: options '--delete' and '--keep' may not be used together
944 944 [255]
945 945 $ hg shelve --keep
946 946 shelved as default
947 947 $ hg diff
948 948 diff --git a/jungle b/jungle
949 949 new file mode 100644
950 950 --- /dev/null
951 951 +++ b/jungle
952 952 @@ -0,0 +1,1 @@
953 953 +babar
954 954 $ cd ..
955 955
956 956 Test visibility of in-memory changes inside transaction to external hook
957 957 ------------------------------------------------------------------------
958 958
959 959 $ cd repo
960 960
961 961 $ echo xxxx >> x
962 962 $ hg commit -m "#5: changes to invoke rebase"
963 963
964 964 $ cat > $TESTTMP/checkvisibility.sh <<EOF
965 965 > echo "==== \$1:"
966 966 > hg parents --template "VISIBLE {rev}:{node|short}\n"
967 967 > # test that pending changes are hidden
968 968 > unset HG_PENDING
969 969 > hg parents --template "ACTUAL {rev}:{node|short}\n"
970 970 > echo "===="
971 971 > EOF
972 972
973 973 $ cat >> .hg/hgrc <<EOF
974 974 > [defaults]
975 975 > # to fix hash id of temporary revisions
976 976 > unshelve = --date '0 0'
977 977 > EOF
978 978
979 979 "hg unshelve" at REV5 implies steps below:
980 980
981 981 (1) commit changes in the working directory (REV6)
982 982 (2) unbundle shelved revision (REV7)
983 983 (3) rebase: merge REV7 into REV6 (REV6 => REV6, REV7)
984 984 (4) rebase: commit merged revision (REV8)
985 985 (5) rebase: update to REV6 (REV8 => REV6)
986 986 (6) update to REV5 (REV6 => REV5)
987 987 (7) abort transaction
988 988
989 989 == test visibility to external preupdate hook
990 990
991 991 $ cat >> .hg/hgrc <<EOF
992 992 > [hooks]
993 993 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
994 994 > EOF
995 995
996 996 $ echo nnnn >> n
997 997
998 998 $ sh $TESTTMP/checkvisibility.sh before-unshelving
999 999 ==== before-unshelving:
1000 1000 VISIBLE (5|19):703117a2acfb (re)
1001 1001 ACTUAL (5|19):703117a2acfb (re)
1002 1002 ====
1003 1003
1004 1004 $ hg unshelve --keep default
1005 1005 temporarily committing pending changes (restore with 'hg unshelve --abort')
1006 1006 rebasing shelved changes
1007 1007 ==== preupdate:
1008 1008 VISIBLE (6|20):54c00d20fb3f (re)
1009 1009 ACTUAL (5|19):703117a2acfb (re)
1010 1010 ====
1011 1011 ==== preupdate:
1012 1012 VISIBLE (8|21):8efe6f7537dc (re)
1013 1013 ACTUAL (5|19):703117a2acfb (re)
1014 1014 ====
1015 1015 ==== preupdate:
1016 1016 VISIBLE (6|20):54c00d20fb3f (re)
1017 1017 ACTUAL (5|19):703117a2acfb (re)
1018 1018 ====
1019 1019
1020 1020 $ cat >> .hg/hgrc <<EOF
1021 1021 > [hooks]
1022 1022 > preupdate.visibility =
1023 1023 > EOF
1024 1024
1025 1025 $ sh $TESTTMP/checkvisibility.sh after-unshelving
1026 1026 ==== after-unshelving:
1027 1027 VISIBLE (5|19):703117a2acfb (re)
1028 1028 ACTUAL (5|19):703117a2acfb (re)
1029 1029 ====
1030 1030
1031 1031 == test visibility to external update hook
1032 1032
1033 1033 $ hg update -q -C 703117a2acfb
1034 1034
1035 1035 $ cat >> .hg/hgrc <<EOF
1036 1036 > [hooks]
1037 1037 > update.visibility = sh $TESTTMP/checkvisibility.sh update
1038 1038 > EOF
1039 1039
1040 1040 $ echo nnnn >> n
1041 1041
1042 1042 $ sh $TESTTMP/checkvisibility.sh before-unshelving
1043 1043 ==== before-unshelving:
1044 1044 VISIBLE (5|19):703117a2acfb (re)
1045 1045 ACTUAL (5|19):703117a2acfb (re)
1046 1046 ====
1047 1047
1048 1048 $ hg unshelve --keep default
1049 1049 temporarily committing pending changes (restore with 'hg unshelve --abort')
1050 1050 rebasing shelved changes
1051 1051 ==== update:
1052 1052 VISIBLE (6|20):54c00d20fb3f (re)
1053 1053 VISIBLE 1?7:492ed9d705e5 (re)
1054 1054 ACTUAL (5|19):703117a2acfb (re)
1055 1055 ====
1056 1056 ==== update:
1057 1057 VISIBLE (6|20):54c00d20fb3f (re)
1058 1058 ACTUAL (5|19):703117a2acfb (re)
1059 1059 ====
1060 1060 ==== update:
1061 1061 VISIBLE (5|19):703117a2acfb (re)
1062 1062 ACTUAL (5|19):703117a2acfb (re)
1063 1063 ====
1064 1064
1065 1065 $ cat >> .hg/hgrc <<EOF
1066 1066 > [hooks]
1067 1067 > update.visibility =
1068 1068 > EOF
1069 1069
1070 1070 $ sh $TESTTMP/checkvisibility.sh after-unshelving
1071 1071 ==== after-unshelving:
1072 1072 VISIBLE (5|19):703117a2acfb (re)
1073 1073 ACTUAL (5|19):703117a2acfb (re)
1074 1074 ====
1075 1075
1076 1076 $ cd ..
1077 1077
1078 1078 Keep active bookmark while (un)shelving even on shared repo (issue4940)
1079 1079 -----------------------------------------------------------------------
1080 1080
1081 1081 $ cat <<EOF >> $HGRCPATH
1082 1082 > [extensions]
1083 1083 > share =
1084 1084 > EOF
1085 1085
1086 1086 $ hg bookmarks -R repo
1087 1087 test (4|13):33f7f61e6c5e (re)
1088 1088 $ hg share -B repo share
1089 1089 updating working directory
1090 1090 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
1091 1091 $ cd share
1092 1092
1093 1093 $ hg bookmarks
1094 1094 test (4|13):33f7f61e6c5e (re)
1095 1095 $ hg bookmarks foo
1096 1096 $ hg bookmarks
1097 1097 \* foo (5|19):703117a2acfb (re)
1098 1098 test (4|13):33f7f61e6c5e (re)
1099 1099 $ echo x >> x
1100 1100 $ hg shelve
1101 1101 shelved as foo
1102 1102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1103 1103 $ hg bookmarks
1104 1104 \* foo (5|19):703117a2acfb (re)
1105 1105 test (4|13):33f7f61e6c5e (re)
1106 1106
1107 1107 $ hg unshelve
1108 1108 unshelving change 'foo'
1109 1109 $ hg bookmarks
1110 1110 \* foo (5|19):703117a2acfb (re)
1111 1111 test (4|13):33f7f61e6c5e (re)
1112 1112
1113 1113 $ cd ..
1114 1114
1115 1115 Abort unshelve while merging (issue5123)
1116 1116 ----------------------------------------
1117 1117
1118 1118 $ hg init issue5123
1119 1119 $ cd issue5123
1120 1120 $ echo > a
1121 1121 $ hg ci -Am a
1122 1122 adding a
1123 1123 $ hg co null
1124 1124 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1125 1125 $ echo > b
1126 1126 $ hg ci -Am b
1127 1127 adding b
1128 1128 created new head
1129 1129 $ echo > c
1130 1130 $ hg add c
1131 1131 $ hg shelve
1132 1132 shelved as default
1133 1133 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1134 1134 $ hg co 1
1135 1135 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1136 1136 $ hg merge 0
1137 1137 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1138 1138 (branch merge, don't forget to commit)
1139 1139 -- successful merge with two parents
1140 1140 $ hg log -G
1141 1141 @ changeset: 1:406bf70c274f
1142 1142 tag: tip
1143 1143 parent: -1:000000000000
1144 1144 user: test
1145 1145 date: Thu Jan 01 00:00:00 1970 +0000
1146 1146 summary: b
1147 1147
1148 1148 @ changeset: 0:ada8c9eb8252
1149 1149 user: test
1150 1150 date: Thu Jan 01 00:00:00 1970 +0000
1151 1151 summary: a
1152 1152
1153 1153 -- trying to pull in the shelve bits
1154 1154 -- unshelve should abort otherwise, it'll eat my second parent.
1155 1155 $ hg unshelve
1156 1156 abort: outstanding uncommitted merge
1157 1157 (use 'hg commit' or 'hg merge --abort')
1158 1158 [255]
1159 1159
1160 1160 $ cd ..
1161 1161
1162 1162 -- test for interactive mode on unshelve
1163 1163
1164 1164 $ hg init a
1165 1165 $ cd a
1166 1166 $ echo > b
1167 1167 $ hg ci -Am b
1168 1168 adding b
1169 1169 $ echo > c
1170 1170 $ echo > d
1171 1171 $ hg add .
1172 1172 adding c
1173 1173 adding d
1174 1174 $ hg shelve
1175 1175 shelved as default
1176 1176 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1177 1177 $ echo > e
1178 1178 $ hg add e
1179 1179 $ hg ci -m e
1180 1180 $ hg shelve --patch
1181 1181 default (*s ago) changes to: b (glob)
1182 1182
1183 1183 diff --git a/c b/c
1184 1184 new file mode 100644
1185 1185 --- /dev/null
1186 1186 +++ b/c
1187 1187 @@ -0,0 +1,1 @@
1188 1188 +
1189 1189 diff --git a/d b/d
1190 1190 new file mode 100644
1191 1191 --- /dev/null
1192 1192 +++ b/d
1193 1193 @@ -0,0 +1,1 @@
1194 1194 +
1195 1195 $ hg unshelve -i <<EOF
1196 1196 > y
1197 1197 > y
1198 1198 > y
1199 1199 > n
1200 1200 > EOF
1201 1201 unshelving change 'default'
1202 1202 rebasing shelved changes
1203 1203 diff --git a/c b/c
1204 1204 new file mode 100644
1205 1205 examine changes to 'c'?
1206 1206 (enter ? for help) [Ynesfdaq?] y
1207 1207
1208 1208 @@ -0,0 +1,1 @@
1209 1209 +
1210 1210 record change 1/2 to 'c'?
1211 1211 (enter ? for help) [Ynesfdaq?] y
1212 1212
1213 1213 diff --git a/d b/d
1214 1214 new file mode 100644
1215 1215 examine changes to 'd'?
1216 1216 (enter ? for help) [Ynesfdaq?] y
1217 1217
1218 1218 @@ -0,0 +1,1 @@
1219 1219 +
1220 1220 record change 2/2 to 'd'?
1221 1221 (enter ? for help) [Ynesfdaq?] n
1222 1222
1223 1223 $ ls
1224 1224 b
1225 1225 c
1226 1226 e
1227 1227 -- shelve should not contain `c` now
1228 1228 $ hg shelve --patch
1229 1229 default (*s ago) changes to: b (glob)
1230 1230
1231 1231 diff --git a/d b/d
1232 1232 new file mode 100644
1233 1233 --- /dev/null
1234 1234 +++ b/d
1235 1235 @@ -0,0 +1,1 @@
1236 1236 +
1237 1237 $ hg unshelve -i <<EOF
1238 1238 > y
1239 1239 > y
1240 1240 > EOF
1241 1241 unshelving change 'default'
1242 1242 temporarily committing pending changes (restore with 'hg unshelve --abort')
1243 1243 rebasing shelved changes
1244 1244 diff --git a/d b/d
1245 1245 new file mode 100644
1246 1246 examine changes to 'd'?
1247 1247 (enter ? for help) [Ynesfdaq?] y
1248 1248
1249 1249 @@ -0,0 +1,1 @@
1250 1250 +
1251 1251 record this change to 'd'?
1252 1252 (enter ? for help) [Ynesfdaq?] y
1253 1253
1254 1254
1255 1255 $ hg status -v
1256 1256 A c
1257 1257 A d
1258 1258 $ ls
1259 1259 b
1260 1260 c
1261 1261 d
1262 1262 e
1263 1263 $ hg shelve --list
1264 1264
1265 1265 -- now, unshelve selected changes from a file
1266 1266
1267 1267 $ echo B > foo
1268 1268 $ hg add foo
1269 1269 $ hg ci -m 'add B to foo'
1270 1270 $ cat > foo <<EOF
1271 1271 > A
1272 1272 > B
1273 1273 > C
1274 1274 > EOF
1275 1275 $ echo > garbage
1276 1276 $ hg st
1277 1277 M foo
1278 1278 ? garbage
1279 1279 $ hg shelve --unknown
1280 1280 shelved as default
1281 1281 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1282 1282 $ cat foo
1283 1283 B
1284 1284 $ hg unshelve -i <<EOF
1285 1285 > y
1286 1286 > y
1287 1287 > n
1288 1288 > y
1289 1289 > y
1290 1290 > EOF
1291 1291 unshelving change 'default'
1292 1292 rebasing shelved changes
1293 1293 diff --git a/foo b/foo
1294 1294 2 hunks, 2 lines changed
1295 1295 examine changes to 'foo'?
1296 1296 (enter ? for help) [Ynesfdaq?] y
1297 1297
1298 1298 @@ -1,1 +1,2 @@
1299 1299 +A
1300 1300 B
1301 1301 record change 1/3 to 'foo'?
1302 1302 (enter ? for help) [Ynesfdaq?] y
1303 1303
1304 1304 @@ -1,1 +2,2 @@
1305 1305 B
1306 1306 +C
1307 1307 record change 2/3 to 'foo'?
1308 1308 (enter ? for help) [Ynesfdaq?] n
1309 1309
1310 1310 diff --git a/garbage b/garbage
1311 1311 new file mode 100644
1312 1312 examine changes to 'garbage'?
1313 1313 (enter ? for help) [Ynesfdaq?] y
1314 1314
1315 1315 @@ -0,0 +1,1 @@
1316 1316 +
1317 1317 record change 3/3 to 'garbage'?
1318 1318 (enter ? for help) [Ynesfdaq?] y
1319 1319
1320 1320 $ hg st
1321 1321 M foo
1322 1322 ? garbage
1323 1323 $ cat foo
1324 1324 A
1325 1325 B
1326 1326 $ hg shelve --patch
1327 1327 default (*s ago) changes to: add B to foo (glob)
1328 1328
1329 1329 diff --git a/foo b/foo
1330 1330 --- a/foo
1331 1331 +++ b/foo
1332 1332 @@ -1,2 +1,3 @@
1333 1333 A
1334 1334 B
1335 1335 +C
1336 1336
1337 1337 -- unshelve interactive on conflicts
1338 1338
1339 1339 $ echo A >> bar1
1340 1340 $ echo A >> bar2
1341 1341 $ hg add bar1 bar2
1342 1342 $ hg ci -m 'add A to bars'
1343 1343 $ echo B >> bar1
1344 1344 $ echo B >> bar2
1345 1345 $ hg shelve
1346 1346 shelved as default-01
1347 1347 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1348 1348 $ echo C >> bar1
1349 1349 $ echo C >> bar2
1350 1350 $ hg ci -m 'add C to bars'
1351 1351 $ hg unshelve -i
1352 1352 unshelving change 'default-01'
1353 1353 rebasing shelved changes
1354 1354 merging bar1
1355 1355 merging bar2
1356 1356 warning: conflicts while merging bar1! (edit, then use 'hg resolve --mark')
1357 1357 warning: conflicts while merging bar2! (edit, then use 'hg resolve --mark')
1358 1358 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
1359 1359 [1]
1360 1360
1361 1361 $ cat > bar1 <<EOF
1362 1362 > A
1363 1363 > B
1364 1364 > C
1365 1365 > EOF
1366 1366 $ cat > bar2 <<EOF
1367 1367 > A
1368 1368 > B
1369 1369 > C
1370 1370 > EOF
1371 1371 $ hg resolve -m bar1 bar2
1372 1372 (no more unresolved files)
1373 1373 continue: hg unshelve --continue
1374 1374
1375 1375 -- using --continue with --interactive should throw an error
1376 1376 $ hg unshelve --continue -i
1377 1377 abort: cannot use both continue and interactive
1378 1378 [255]
1379 1379
1380 1380 $ cat bar1
1381 1381 A
1382 1382 B
1383 1383 C
1384 1384
1385 1385 #if stripbased
1386 1386 $ hg log -r 3:: -G
1387 1387 @ changeset: 5:f1d5f53e397b
1388 1388 | tag: tip
1389 1389 | parent: 3:e28fd7fa7938
1390 1390 | user: shelve@localhost
1391 1391 | date: Thu Jan 01 00:00:00 1970 +0000
1392 1392 | summary: changes to: add A to bars
1393 1393 |
1394 1394 | @ changeset: 4:fe451a778c81
1395 1395 |/ user: test
1396 1396 | date: Thu Jan 01 00:00:00 1970 +0000
1397 1397 | summary: add C to bars
1398 1398 |
1399 1399 o changeset: 3:e28fd7fa7938
1400 1400 | user: test
1401 1401 ~ date: Thu Jan 01 00:00:00 1970 +0000
1402 1402 summary: add A to bars
1403 1403
1404 1404 #endif
1405 1405
1406 1406 $ hg unshelve --continue <<EOF
1407 1407 > y
1408 1408 > y
1409 1409 > y
1410 1410 > n
1411 1411 > EOF
1412 1412 diff --git a/bar1 b/bar1
1413 1413 1 hunks, 1 lines changed
1414 1414 examine changes to 'bar1'?
1415 1415 (enter ? for help) [Ynesfdaq?] y
1416 1416
1417 1417 @@ -1,2 +1,3 @@
1418 1418 A
1419 1419 +B
1420 1420 C
1421 1421 record change 1/2 to 'bar1'?
1422 1422 (enter ? for help) [Ynesfdaq?] y
1423 1423
1424 1424 diff --git a/bar2 b/bar2
1425 1425 1 hunks, 1 lines changed
1426 1426 examine changes to 'bar2'?
1427 1427 (enter ? for help) [Ynesfdaq?] y
1428 1428
1429 1429 @@ -1,2 +1,3 @@
1430 1430 A
1431 1431 +B
1432 1432 C
1433 1433 record change 2/2 to 'bar2'?
1434 1434 (enter ? for help) [Ynesfdaq?] n
1435 1435
1436 1436 unshelve of 'default-01' complete
1437 1437
1438 1438 #if stripbased
1439 1439 $ hg log -r 3:: -G
1440 1440 @ changeset: 4:fe451a778c81
1441 1441 | tag: tip
1442 1442 | user: test
1443 1443 | date: Thu Jan 01 00:00:00 1970 +0000
1444 1444 | summary: add C to bars
1445 1445 |
1446 1446 o changeset: 3:e28fd7fa7938
1447 1447 | user: test
1448 1448 ~ date: Thu Jan 01 00:00:00 1970 +0000
1449 1449 summary: add A to bars
1450 1450
1451 1451 #endif
1452 1452
1453 1453 $ hg unshelve --continue
1454 1454 abort: no unshelve in progress
1455 1455 [255]
1456 1456
1457 1457 $ hg shelve --list
1458 1458 default-01 (*)* changes to: add A to bars (glob)
1459 1459 default (*)* changes to: add B to foo (glob)
1460 1460 $ hg unshelve -n default-01 -i <<EOF
1461 1461 > y
1462 1462 > y
1463 1463 > EOF
1464 1464 temporarily committing pending changes (restore with 'hg unshelve --abort')
1465 1465 rebasing shelved changes
1466 1466 diff --git a/bar2 b/bar2
1467 1467 1 hunks, 1 lines changed
1468 1468 examine changes to 'bar2'?
1469 1469 (enter ? for help) [Ynesfdaq?] y
1470 1470
1471 1471 @@ -1,2 +1,3 @@
1472 1472 A
1473 1473 +B
1474 1474 C
1475 1475 record this change to 'bar2'?
1476 1476 (enter ? for help) [Ynesfdaq?] y
1477 1477
1478 -- test for --interactive --keep
1479 $ hg unshelve -i --keep
1480 abort: --keep on --interactive is not yet supported
1481 [255]
General Comments 0
You need to be logged in to leave comments. Login now