##// END OF EJS Templates
shelve: allow --patch and --stat without --list for a single shelf...
Tony Tung -
r25104:d6453f6f default
parent child Browse files
Show More
@@ -1,731 +1,742
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
24 24 from mercurial.i18n import _
25 25 from mercurial.node import nullid, nullrev, bin, hex
26 26 from mercurial import changegroup, cmdutil, scmutil, phases, commands
27 27 from mercurial import error, hg, mdiff, merge, patch, repair, util
28 28 from mercurial import templatefilters, exchange, bundlerepo
29 29 from mercurial import lock as lockmod
30 30 from hgext import rebase
31 31 import errno
32 32
33 33 cmdtable = {}
34 34 command = cmdutil.command(cmdtable)
35 35 testedwith = 'internal'
36 36
37 37 class shelvedfile(object):
38 38 """Helper for the file storing a single shelve
39 39
40 40 Handles common functions on shelve files (.hg/.patch) using
41 41 the vfs layer"""
42 42 def __init__(self, repo, name, filetype=None):
43 43 self.repo = repo
44 44 self.name = name
45 45 self.vfs = scmutil.vfs(repo.join('shelved'))
46 46 self.ui = self.repo.ui
47 47 if filetype:
48 48 self.fname = name + '.' + filetype
49 49 else:
50 50 self.fname = name
51 51
52 52 def exists(self):
53 53 return self.vfs.exists(self.fname)
54 54
55 55 def filename(self):
56 56 return self.vfs.join(self.fname)
57 57
58 58 def unlink(self):
59 59 util.unlink(self.filename())
60 60
61 61 def stat(self):
62 62 return self.vfs.stat(self.fname)
63 63
64 64 def opener(self, mode='rb'):
65 65 try:
66 66 return self.vfs(self.fname, mode)
67 67 except IOError, err:
68 68 if err.errno != errno.ENOENT:
69 69 raise
70 70 raise util.Abort(_("shelved change '%s' not found") % self.name)
71 71
72 72 def applybundle(self):
73 73 fp = self.opener()
74 74 try:
75 75 gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs)
76 76 changegroup.addchangegroup(self.repo, gen, 'unshelve',
77 77 'bundle:' + self.vfs.join(self.fname),
78 78 targetphase=phases.secret)
79 79 finally:
80 80 fp.close()
81 81
82 82 def bundlerepo(self):
83 83 return bundlerepo.bundlerepository(self.repo.baseui, self.repo.root,
84 84 self.vfs.join(self.fname))
85 85 def writebundle(self, cg):
86 86 changegroup.writebundle(self.ui, cg, self.fname, 'HG10UN', self.vfs)
87 87
88 88 class shelvedstate(object):
89 89 """Handle persistence during unshelving operations.
90 90
91 91 Handles saving and restoring a shelved state. Ensures that different
92 92 versions of a shelved state are possible and handles them appropriately.
93 93 """
94 94 _version = 1
95 95 _filename = 'shelvedstate'
96 96
97 97 @classmethod
98 98 def load(cls, repo):
99 99 fp = repo.vfs(cls._filename)
100 100 try:
101 101 version = int(fp.readline().strip())
102 102
103 103 if version != cls._version:
104 104 raise util.Abort(_('this version of shelve is incompatible '
105 105 'with the version used in this repo'))
106 106 name = fp.readline().strip()
107 107 wctx = fp.readline().strip()
108 108 pendingctx = fp.readline().strip()
109 109 parents = [bin(h) for h in fp.readline().split()]
110 110 stripnodes = [bin(h) for h in fp.readline().split()]
111 111 finally:
112 112 fp.close()
113 113
114 114 obj = cls()
115 115 obj.name = name
116 116 obj.wctx = repo[bin(wctx)]
117 117 obj.pendingctx = repo[bin(pendingctx)]
118 118 obj.parents = parents
119 119 obj.stripnodes = stripnodes
120 120
121 121 return obj
122 122
123 123 @classmethod
124 124 def save(cls, repo, name, originalwctx, pendingctx, stripnodes):
125 125 fp = repo.vfs(cls._filename, 'wb')
126 126 fp.write('%i\n' % cls._version)
127 127 fp.write('%s\n' % name)
128 128 fp.write('%s\n' % hex(originalwctx.node()))
129 129 fp.write('%s\n' % hex(pendingctx.node()))
130 130 fp.write('%s\n' % ' '.join([hex(p) for p in repo.dirstate.parents()]))
131 131 fp.write('%s\n' % ' '.join([hex(n) for n in stripnodes]))
132 132 fp.close()
133 133
134 134 @classmethod
135 135 def clear(cls, repo):
136 136 util.unlinkpath(repo.join(cls._filename), ignoremissing=True)
137 137
138 138 def createcmd(ui, repo, pats, opts):
139 139 """subcommand that creates a new shelve"""
140 140
141 141 def publicancestors(ctx):
142 142 """Compute the public ancestors of a commit.
143 143
144 144 Much faster than the revset ancestors(ctx) & draft()"""
145 145 seen = set([nullrev])
146 146 visit = util.deque()
147 147 visit.append(ctx)
148 148 while visit:
149 149 ctx = visit.popleft()
150 150 yield ctx.node()
151 151 for parent in ctx.parents():
152 152 rev = parent.rev()
153 153 if rev not in seen:
154 154 seen.add(rev)
155 155 if parent.mutable():
156 156 visit.append(parent)
157 157
158 158 wctx = repo[None]
159 159 parents = wctx.parents()
160 160 if len(parents) > 1:
161 161 raise util.Abort(_('cannot shelve while merging'))
162 162 parent = parents[0]
163 163
164 164 # we never need the user, so we use a generic user for all shelve operations
165 165 user = 'shelve@localhost'
166 166 label = repo._activebookmark or parent.branch() or 'default'
167 167
168 168 # slashes aren't allowed in filenames, therefore we rename it
169 169 label = label.replace('/', '_')
170 170
171 171 def gennames():
172 172 yield label
173 173 for i in xrange(1, 100):
174 174 yield '%s-%02d' % (label, i)
175 175
176 176 def commitfunc(ui, repo, message, match, opts):
177 177 hasmq = util.safehasattr(repo, 'mq')
178 178 if hasmq:
179 179 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
180 180 backup = repo.ui.backupconfig('phases', 'new-commit')
181 181 try:
182 182 repo.ui. setconfig('phases', 'new-commit', phases.secret)
183 183 editor = cmdutil.getcommiteditor(editform='shelve.shelve', **opts)
184 184 return repo.commit(message, user, opts.get('date'), match,
185 185 editor=editor)
186 186 finally:
187 187 repo.ui.restoreconfig(backup)
188 188 if hasmq:
189 189 repo.mq.checkapplied = saved
190 190
191 191 if parent.node() != nullid:
192 192 desc = "changes to '%s'" % parent.description().split('\n', 1)[0]
193 193 else:
194 194 desc = '(changes in empty repository)'
195 195
196 196 if not opts['message']:
197 197 opts['message'] = desc
198 198
199 199 name = opts['name']
200 200
201 201 wlock = lock = tr = bms = None
202 202 try:
203 203 wlock = repo.wlock()
204 204 lock = repo.lock()
205 205
206 206 bms = repo._bookmarks.copy()
207 207 # use an uncommitted transaction to generate the bundle to avoid
208 208 # pull races. ensure we don't print the abort message to stderr.
209 209 tr = repo.transaction('commit', report=lambda x: None)
210 210
211 211 if name:
212 212 if shelvedfile(repo, name, 'hg').exists():
213 213 raise util.Abort(_("a shelved change named '%s' already exists")
214 214 % name)
215 215 else:
216 216 for n in gennames():
217 217 if not shelvedfile(repo, n, 'hg').exists():
218 218 name = n
219 219 break
220 220 else:
221 221 raise util.Abort(_("too many shelved changes named '%s'") %
222 222 label)
223 223
224 224 # ensure we are not creating a subdirectory or a hidden file
225 225 if '/' in name or '\\' in name:
226 226 raise util.Abort(_('shelved change names may not contain slashes'))
227 227 if name.startswith('.'):
228 228 raise util.Abort(_("shelved change names may not start with '.'"))
229 229 interactive = opts.get('interactive', False)
230 230
231 231 def interactivecommitfunc(ui, repo, *pats, **opts):
232 232 match = scmutil.match(repo['.'], pats, {})
233 233 message = opts['message']
234 234 return commitfunc(ui, repo, message, match, opts)
235 235 if not interactive:
236 236 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
237 237 else:
238 238 node = cmdutil.dorecord(ui, repo, interactivecommitfunc, 'commit',
239 239 False, cmdutil.recordfilter, *pats, **opts)
240 240 if not node:
241 241 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
242 242 if stat.deleted:
243 243 ui.status(_("nothing changed (%d missing files, see "
244 244 "'hg status')\n") % len(stat.deleted))
245 245 else:
246 246 ui.status(_("nothing changed\n"))
247 247 return 1
248 248
249 249 bases = list(publicancestors(repo[node]))
250 250 cg = changegroup.changegroupsubset(repo, bases, [node], 'shelve')
251 251 shelvedfile(repo, name, 'hg').writebundle(cg)
252 252 cmdutil.export(repo, [node],
253 253 fp=shelvedfile(repo, name, 'patch').opener('wb'),
254 254 opts=mdiff.diffopts(git=True))
255 255
256 256
257 257 if ui.formatted():
258 258 desc = util.ellipsis(desc, ui.termwidth())
259 259 ui.status(_('shelved as %s\n') % name)
260 260 hg.update(repo, parent.node())
261 261 finally:
262 262 if bms:
263 263 # restore old bookmarks
264 264 repo._bookmarks.update(bms)
265 265 repo._bookmarks.write()
266 266 if tr:
267 267 tr.abort()
268 268 lockmod.release(lock, wlock)
269 269
270 270 def cleanupcmd(ui, repo):
271 271 """subcommand that deletes all shelves"""
272 272
273 273 wlock = None
274 274 try:
275 275 wlock = repo.wlock()
276 276 for (name, _type) in repo.vfs.readdir('shelved'):
277 277 suffix = name.rsplit('.', 1)[-1]
278 278 if suffix in ('hg', 'patch'):
279 279 shelvedfile(repo, name).unlink()
280 280 finally:
281 281 lockmod.release(wlock)
282 282
283 283 def deletecmd(ui, repo, pats):
284 284 """subcommand that deletes a specific shelve"""
285 285 if not pats:
286 286 raise util.Abort(_('no shelved changes specified!'))
287 287 wlock = repo.wlock()
288 288 try:
289 289 for name in pats:
290 290 for suffix in 'hg patch'.split():
291 291 shelvedfile(repo, name, suffix).unlink()
292 292 except OSError, err:
293 293 if err.errno != errno.ENOENT:
294 294 raise
295 295 raise util.Abort(_("shelved change '%s' not found") % name)
296 296 finally:
297 297 lockmod.release(wlock)
298 298
299 299 def listshelves(repo):
300 300 """return all shelves in repo as list of (time, filename)"""
301 301 try:
302 302 names = repo.vfs.readdir('shelved')
303 303 except OSError, err:
304 304 if err.errno != errno.ENOENT:
305 305 raise
306 306 return []
307 307 info = []
308 308 for (name, _type) in names:
309 309 pfx, sfx = name.rsplit('.', 1)
310 310 if not pfx or sfx != 'patch':
311 311 continue
312 312 st = shelvedfile(repo, name).stat()
313 313 info.append((st.st_mtime, shelvedfile(repo, pfx).filename()))
314 314 return sorted(info, reverse=True)
315 315
316 316 def listcmd(ui, repo, pats, opts):
317 317 """subcommand that displays the list of shelves"""
318 318 pats = set(pats)
319 319 width = 80
320 320 if not ui.plain():
321 321 width = ui.termwidth()
322 322 namelabel = 'shelve.newest'
323 323 for mtime, name in listshelves(repo):
324 324 sname = util.split(name)[1]
325 325 if pats and sname not in pats:
326 326 continue
327 327 ui.write(sname, label=namelabel)
328 328 namelabel = 'shelve.name'
329 329 if ui.quiet:
330 330 ui.write('\n')
331 331 continue
332 332 ui.write(' ' * (16 - len(sname)))
333 333 used = 16
334 334 age = '(%s)' % templatefilters.age(util.makedate(mtime), abbrev=True)
335 335 ui.write(age, label='shelve.age')
336 336 ui.write(' ' * (12 - len(age)))
337 337 used += 12
338 338 fp = open(name + '.patch', 'rb')
339 339 try:
340 340 while True:
341 341 line = fp.readline()
342 342 if not line:
343 343 break
344 344 if not line.startswith('#'):
345 345 desc = line.rstrip()
346 346 if ui.formatted():
347 347 desc = util.ellipsis(desc, width - used)
348 348 ui.write(desc)
349 349 break
350 350 ui.write('\n')
351 351 if not (opts['patch'] or opts['stat']):
352 352 continue
353 353 difflines = fp.readlines()
354 354 if opts['patch']:
355 355 for chunk, label in patch.difflabel(iter, difflines):
356 356 ui.write(chunk, label=label)
357 357 if opts['stat']:
358 358 for chunk, label in patch.diffstatui(difflines, width=width,
359 359 git=True):
360 360 ui.write(chunk, label=label)
361 361 finally:
362 362 fp.close()
363 363
364 def singlepatchcmds(ui, repo, pats, opts, subcommand):
365 """subcommand that displays a single shelf"""
366 if len(pats) != 1:
367 raise util.Abort(_("--%s expects a single shelf") % subcommand)
368 shelfname = pats[0]
369
370 if not shelvedfile(repo, shelfname, 'patch').exists():
371 raise util.Abort(_("cannot find shelf %s") % shelfname)
372
373 listcmd(ui, repo, pats, opts)
374
364 375 def checkparents(repo, state):
365 376 """check parent while resuming an unshelve"""
366 377 if state.parents != repo.dirstate.parents():
367 378 raise util.Abort(_('working directory parents do not match unshelve '
368 379 'state'))
369 380
370 381 def pathtofiles(repo, files):
371 382 cwd = repo.getcwd()
372 383 return [repo.pathto(f, cwd) for f in files]
373 384
374 385 def unshelveabort(ui, repo, state, opts):
375 386 """subcommand that abort an in-progress unshelve"""
376 387 wlock = repo.wlock()
377 388 lock = None
378 389 try:
379 390 checkparents(repo, state)
380 391
381 392 util.rename(repo.join('unshelverebasestate'),
382 393 repo.join('rebasestate'))
383 394 try:
384 395 rebase.rebase(ui, repo, **{
385 396 'abort' : True
386 397 })
387 398 except Exception:
388 399 util.rename(repo.join('rebasestate'),
389 400 repo.join('unshelverebasestate'))
390 401 raise
391 402
392 403 lock = repo.lock()
393 404
394 405 mergefiles(ui, repo, state.wctx, state.pendingctx)
395 406
396 407 repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve')
397 408 shelvedstate.clear(repo)
398 409 ui.warn(_("unshelve of '%s' aborted\n") % state.name)
399 410 finally:
400 411 lockmod.release(lock, wlock)
401 412
402 413 def mergefiles(ui, repo, wctx, shelvectx):
403 414 """updates to wctx and merges the changes from shelvectx into the
404 415 dirstate."""
405 416 oldquiet = ui.quiet
406 417 try:
407 418 ui.quiet = True
408 419 hg.update(repo, wctx.node())
409 420 files = []
410 421 files.extend(shelvectx.files())
411 422 files.extend(shelvectx.parents()[0].files())
412 423
413 424 # revert will overwrite unknown files, so move them out of the way
414 425 for file in repo.status(unknown=True).unknown:
415 426 if file in files:
416 427 util.rename(file, file + ".orig")
417 428 ui.pushbuffer(True)
418 429 cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(),
419 430 *pathtofiles(repo, files),
420 431 **{'no_backup': True})
421 432 ui.popbuffer()
422 433 finally:
423 434 ui.quiet = oldquiet
424 435
425 436 def unshelvecleanup(ui, repo, name, opts):
426 437 """remove related files after an unshelve"""
427 438 if not opts['keep']:
428 439 for filetype in 'hg patch'.split():
429 440 shelvedfile(repo, name, filetype).unlink()
430 441
431 442 def unshelvecontinue(ui, repo, state, opts):
432 443 """subcommand to continue an in-progress unshelve"""
433 444 # We're finishing off a merge. First parent is our original
434 445 # parent, second is the temporary "fake" commit we're unshelving.
435 446 wlock = repo.wlock()
436 447 lock = None
437 448 try:
438 449 checkparents(repo, state)
439 450 ms = merge.mergestate(repo)
440 451 if [f for f in ms if ms[f] == 'u']:
441 452 raise util.Abort(
442 453 _("unresolved conflicts, can't continue"),
443 454 hint=_("see 'hg resolve', then 'hg unshelve --continue'"))
444 455
445 456 lock = repo.lock()
446 457
447 458 util.rename(repo.join('unshelverebasestate'),
448 459 repo.join('rebasestate'))
449 460 try:
450 461 rebase.rebase(ui, repo, **{
451 462 'continue' : True
452 463 })
453 464 except Exception:
454 465 util.rename(repo.join('rebasestate'),
455 466 repo.join('unshelverebasestate'))
456 467 raise
457 468
458 469 shelvectx = repo['tip']
459 470 if not shelvectx in state.pendingctx.children():
460 471 # rebase was a no-op, so it produced no child commit
461 472 shelvectx = state.pendingctx
462 473 else:
463 474 # only strip the shelvectx if the rebase produced it
464 475 state.stripnodes.append(shelvectx.node())
465 476
466 477 mergefiles(ui, repo, state.wctx, shelvectx)
467 478
468 479 repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve')
469 480 shelvedstate.clear(repo)
470 481 unshelvecleanup(ui, repo, state.name, opts)
471 482 ui.status(_("unshelve of '%s' complete\n") % state.name)
472 483 finally:
473 484 lockmod.release(lock, wlock)
474 485
475 486 @command('unshelve',
476 487 [('a', 'abort', None,
477 488 _('abort an incomplete unshelve operation')),
478 489 ('c', 'continue', None,
479 490 _('continue an incomplete unshelve operation')),
480 491 ('', 'keep', None,
481 492 _('keep shelve after unshelving')),
482 493 ('', 'date', '',
483 494 _('set date for temporary commits (DEPRECATED)'), _('DATE'))],
484 495 _('hg unshelve [SHELVED]'))
485 496 def unshelve(ui, repo, *shelved, **opts):
486 497 """restore a shelved change to the working directory
487 498
488 499 This command accepts an optional name of a shelved change to
489 500 restore. If none is given, the most recent shelved change is used.
490 501
491 502 If a shelved change is applied successfully, the bundle that
492 503 contains the shelved changes is deleted afterwards.
493 504
494 505 Since you can restore a shelved change on top of an arbitrary
495 506 commit, it is possible that unshelving will result in a conflict
496 507 between your changes and the commits you are unshelving onto. If
497 508 this occurs, you must resolve the conflict, then use
498 509 ``--continue`` to complete the unshelve operation. (The bundle
499 510 will not be deleted until you successfully complete the unshelve.)
500 511
501 512 (Alternatively, you can use ``--abort`` to abandon an unshelve
502 513 that causes a conflict. This reverts the unshelved changes, and
503 514 does not delete the bundle.)
504 515 """
505 516 abortf = opts['abort']
506 517 continuef = opts['continue']
507 518 if not abortf and not continuef:
508 519 cmdutil.checkunfinished(repo)
509 520
510 521 if abortf or continuef:
511 522 if abortf and continuef:
512 523 raise util.Abort(_('cannot use both abort and continue'))
513 524 if shelved:
514 525 raise util.Abort(_('cannot combine abort/continue with '
515 526 'naming a shelved change'))
516 527
517 528 try:
518 529 state = shelvedstate.load(repo)
519 530 except IOError, err:
520 531 if err.errno != errno.ENOENT:
521 532 raise
522 533 raise util.Abort(_('no unshelve operation underway'))
523 534
524 535 if abortf:
525 536 return unshelveabort(ui, repo, state, opts)
526 537 elif continuef:
527 538 return unshelvecontinue(ui, repo, state, opts)
528 539 elif len(shelved) > 1:
529 540 raise util.Abort(_('can only unshelve one change at a time'))
530 541 elif not shelved:
531 542 shelved = listshelves(repo)
532 543 if not shelved:
533 544 raise util.Abort(_('no shelved changes to apply!'))
534 545 basename = util.split(shelved[0][1])[1]
535 546 ui.status(_("unshelving change '%s'\n") % basename)
536 547 else:
537 548 basename = shelved[0]
538 549
539 550 if not shelvedfile(repo, basename, 'patch').exists():
540 551 raise util.Abort(_("shelved change '%s' not found") % basename)
541 552
542 553 oldquiet = ui.quiet
543 554 wlock = lock = tr = None
544 555 try:
545 556 wlock = repo.wlock()
546 557 lock = repo.lock()
547 558
548 559 tr = repo.transaction('unshelve', report=lambda x: None)
549 560 oldtiprev = len(repo)
550 561
551 562 pctx = repo['.']
552 563 tmpwctx = pctx
553 564 # The goal is to have a commit structure like so:
554 565 # ...-> pctx -> tmpwctx -> shelvectx
555 566 # where tmpwctx is an optional commit with the user's pending changes
556 567 # and shelvectx is the unshelved changes. Then we merge it all down
557 568 # to the original pctx.
558 569
559 570 # Store pending changes in a commit
560 571 s = repo.status()
561 572 if s.modified or s.added or s.removed or s.deleted:
562 573 ui.status(_("temporarily committing pending changes "
563 574 "(restore with 'hg unshelve --abort')\n"))
564 575 def commitfunc(ui, repo, message, match, opts):
565 576 hasmq = util.safehasattr(repo, 'mq')
566 577 if hasmq:
567 578 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
568 579
569 580 backup = repo.ui.backupconfig('phases', 'new-commit')
570 581 try:
571 582 repo.ui. setconfig('phases', 'new-commit', phases.secret)
572 583 return repo.commit(message, 'shelve@localhost',
573 584 opts.get('date'), match)
574 585 finally:
575 586 repo.ui.restoreconfig(backup)
576 587 if hasmq:
577 588 repo.mq.checkapplied = saved
578 589
579 590 tempopts = {}
580 591 tempopts['message'] = "pending changes temporary commit"
581 592 tempopts['date'] = opts.get('date')
582 593 ui.quiet = True
583 594 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
584 595 tmpwctx = repo[node]
585 596
586 597 ui.quiet = True
587 598 shelvedfile(repo, basename, 'hg').applybundle()
588 599
589 600 ui.quiet = oldquiet
590 601
591 602 shelvectx = repo['tip']
592 603
593 604 # If the shelve is not immediately on top of the commit
594 605 # we'll be merging with, rebase it to be on top.
595 606 if tmpwctx.node() != shelvectx.parents()[0].node():
596 607 ui.status(_('rebasing shelved changes\n'))
597 608 try:
598 609 rebase.rebase(ui, repo, **{
599 610 'rev' : [shelvectx.rev()],
600 611 'dest' : str(tmpwctx.rev()),
601 612 'keep' : True,
602 613 })
603 614 except error.InterventionRequired:
604 615 tr.close()
605 616
606 617 stripnodes = [repo.changelog.node(rev)
607 618 for rev in xrange(oldtiprev, len(repo))]
608 619 shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes)
609 620
610 621 util.rename(repo.join('rebasestate'),
611 622 repo.join('unshelverebasestate'))
612 623 raise error.InterventionRequired(
613 624 _("unresolved conflicts (see 'hg resolve', then "
614 625 "'hg unshelve --continue')"))
615 626
616 627 # refresh ctx after rebase completes
617 628 shelvectx = repo['tip']
618 629
619 630 if not shelvectx in tmpwctx.children():
620 631 # rebase was a no-op, so it produced no child commit
621 632 shelvectx = tmpwctx
622 633
623 634 mergefiles(ui, repo, pctx, shelvectx)
624 635 shelvedstate.clear(repo)
625 636
626 637 # The transaction aborting will strip all the commits for us,
627 638 # but it doesn't update the inmemory structures, so addchangegroup
628 639 # hooks still fire and try to operate on the missing commits.
629 640 # Clean up manually to prevent this.
630 641 repo.unfiltered().changelog.strip(oldtiprev, tr)
631 642
632 643 unshelvecleanup(ui, repo, basename, opts)
633 644 finally:
634 645 ui.quiet = oldquiet
635 646 if tr:
636 647 tr.release()
637 648 lockmod.release(lock, wlock)
638 649
639 650 @command('shelve',
640 651 [('A', 'addremove', None,
641 652 _('mark new/missing files as added/removed before shelving')),
642 653 ('', 'cleanup', None,
643 654 _('delete all shelved changes')),
644 655 ('', 'date', '',
645 656 _('shelve with the specified commit date'), _('DATE')),
646 657 ('d', 'delete', None,
647 658 _('delete the named shelved change(s)')),
648 659 ('e', 'edit', False,
649 660 _('invoke editor on commit messages')),
650 661 ('l', 'list', None,
651 662 _('list current shelves')),
652 663 ('m', 'message', '',
653 664 _('use text as shelve message'), _('TEXT')),
654 665 ('n', 'name', '',
655 666 _('use the given name for the shelved commit'), _('NAME')),
656 667 ('p', 'patch', None,
657 668 _('show patch')),
658 669 ('i', 'interactive', None,
659 670 _('interactive mode, only works while creating a shelve'
660 671 '(EXPERIMENTAL)')),
661 672 ('', 'stat', None,
662 673 _('output diffstat-style summary of changes'))] + commands.walkopts,
663 674 _('hg shelve [OPTION]... [FILE]...'))
664 675 def shelvecmd(ui, repo, *pats, **opts):
665 676 '''save and set aside changes from the working directory
666 677
667 678 Shelving takes files that "hg status" reports as not clean, saves
668 679 the modifications to a bundle (a shelved change), and reverts the
669 680 files so that their state in the working directory becomes clean.
670 681
671 682 To restore these changes to the working directory, using "hg
672 683 unshelve"; this will work even if you switch to a different
673 684 commit.
674 685
675 686 When no files are specified, "hg shelve" saves all not-clean
676 687 files. If specific files or directories are named, only changes to
677 688 those files are shelved.
678 689
679 690 Each shelved change has a name that makes it easier to find later.
680 691 The name of a shelved change defaults to being based on the active
681 692 bookmark, or if there is no active bookmark, the current named
682 693 branch. To specify a different name, use ``--name``.
683 694
684 695 To see a list of existing shelved changes, use the ``--list``
685 696 option. For each shelved change, this will print its name, age,
686 697 and description; use ``--patch`` or ``--stat`` for more details.
687 698
688 699 To delete specific shelved changes, use ``--delete``. To delete
689 700 all shelved changes, use ``--cleanup``.
690 701 '''
691 702 cmdutil.checkunfinished(repo)
692 703
693 704 allowables = [
694 705 ('addremove', set(['create'])), # 'create' is pseudo action
695 706 ('cleanup', set(['cleanup'])),
696 707 # ('date', set(['create'])), # ignored for passing '--date "0 0"' in tests
697 708 ('delete', set(['delete'])),
698 709 ('edit', set(['create'])),
699 710 ('list', set(['list'])),
700 711 ('message', set(['create'])),
701 712 ('name', set(['create'])),
702 ('patch', set(['list'])),
703 ('stat', set(['list'])),
713 ('patch', set(['patch', 'list'])),
714 ('stat', set(['stat', 'list'])),
704 715 ]
705 716 def checkopt(opt):
706 717 if opts[opt]:
707 718 for i, allowable in allowables:
708 719 if opts[i] and opt not in allowable:
709 720 raise util.Abort(_("options '--%s' and '--%s' may not be "
710 721 "used together") % (opt, i))
711 722 return True
712 723 if checkopt('cleanup'):
713 724 if pats:
714 725 raise util.Abort(_("cannot specify names when using '--cleanup'"))
715 726 return cleanupcmd(ui, repo)
716 727 elif checkopt('delete'):
717 728 return deletecmd(ui, repo, pats)
718 729 elif checkopt('list'):
719 730 return listcmd(ui, repo, pats, opts)
731 elif checkopt('patch'):
732 return singlepatchcmds(ui, repo, pats, opts, subcommand='patch')
733 elif checkopt('stat'):
734 return singlepatchcmds(ui, repo, pats, opts, subcommand='stat')
720 735 else:
721 for i in ('patch', 'stat'):
722 if opts[i]:
723 raise util.Abort(_("option '--%s' may not be "
724 "used when shelving a change") % (i,))
725 736 return createcmd(ui, repo, pats, opts)
726 737
727 738 def extsetup(ui):
728 739 cmdutil.unfinishedstates.append(
729 740 [shelvedstate._filename, False, False,
730 741 _('unshelve already in progress'),
731 742 _("use 'hg unshelve --continue' or 'hg unshelve --abort'")])
@@ -1,865 +1,906
1 1 $ cat <<EOF >> $HGRCPATH
2 2 > [extensions]
3 3 > mq =
4 4 > shelve =
5 5 > [defaults]
6 6 > diff = --nodates --git
7 7 > qnew = --date '0 0'
8 8 > EOF
9 9
10 10 $ hg init repo
11 11 $ cd repo
12 12 $ mkdir a b
13 13 $ echo a > a/a
14 14 $ echo b > b/b
15 15 $ echo c > c
16 16 $ echo d > d
17 17 $ echo x > x
18 18 $ hg addremove -q
19 19
20 20 shelve has a help message
21 21 $ hg shelve -h
22 22 hg shelve [OPTION]... [FILE]...
23 23
24 24 save and set aside changes from the working directory
25 25
26 26 Shelving takes files that "hg status" reports as not clean, saves the
27 27 modifications to a bundle (a shelved change), and reverts the files so
28 28 that their state in the working directory becomes clean.
29 29
30 30 To restore these changes to the working directory, using "hg unshelve";
31 31 this will work even if you switch to a different commit.
32 32
33 33 When no files are specified, "hg shelve" saves all not-clean files. If
34 34 specific files or directories are named, only changes to those files are
35 35 shelved.
36 36
37 37 Each shelved change has a name that makes it easier to find later. The
38 38 name of a shelved change defaults to being based on the active bookmark,
39 39 or if there is no active bookmark, the current named branch. To specify a
40 40 different name, use "--name".
41 41
42 42 To see a list of existing shelved changes, use the "--list" option. For
43 43 each shelved change, this will print its name, age, and description; use "
44 44 --patch" or "--stat" for more details.
45 45
46 46 To delete specific shelved changes, use "--delete". To delete all shelved
47 47 changes, use "--cleanup".
48 48
49 49 (use "hg help -e shelve" to show help for the shelve extension)
50 50
51 51 options ([+] can be repeated):
52 52
53 53 -A --addremove mark new/missing files as added/removed before
54 54 shelving
55 55 --cleanup delete all shelved changes
56 56 --date DATE shelve with the specified commit date
57 57 -d --delete delete the named shelved change(s)
58 58 -e --edit invoke editor on commit messages
59 59 -l --list list current shelves
60 60 -m --message TEXT use text as shelve message
61 61 -n --name NAME use the given name for the shelved commit
62 62 -p --patch show patch
63 63 --stat output diffstat-style summary of changes
64 64 -I --include PATTERN [+] include names matching the given patterns
65 65 -X --exclude PATTERN [+] exclude names matching the given patterns
66 66 --mq operate on patch repository
67 67
68 68 (some details hidden, use --verbose to show complete help)
69 69
70 70 shelving in an empty repo should be possible
71 71 (this tests also that editor is not invoked, if '--edit' is not
72 72 specified)
73 73
74 74 $ HGEDITOR=cat hg shelve
75 75 shelved as default
76 76 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
77 77
78 78 $ hg unshelve
79 79 unshelving change 'default'
80 80
81 81 $ hg commit -q -m 'initial commit'
82 82
83 83 $ hg shelve
84 84 nothing changed
85 85 [1]
86 86
87 87 create an mq patch - shelving should work fine with a patch applied
88 88
89 89 $ echo n > n
90 90 $ hg add n
91 91 $ hg commit n -m second
92 92 $ hg qnew second.patch
93 93
94 94 shelve a change that we will delete later
95 95
96 96 $ echo a >> a/a
97 97 $ hg shelve
98 98 shelved as default
99 99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 100
101 101 set up some more complex changes to shelve
102 102
103 103 $ echo a >> a/a
104 104 $ hg mv b b.rename
105 105 moving b/b to b.rename/b (glob)
106 106 $ hg cp c c.copy
107 107 $ hg status -C
108 108 M a/a
109 109 A b.rename/b
110 110 b/b
111 111 A c.copy
112 112 c
113 113 R b/b
114 114
115 115 prevent some foot-shooting
116 116
117 117 $ hg shelve -n foo/bar
118 118 abort: shelved change names may not contain slashes
119 119 [255]
120 120 $ hg shelve -n .baz
121 121 abort: shelved change names may not start with '.'
122 122 [255]
123 123
124 124 the common case - no options or filenames
125 125
126 126 $ hg shelve
127 127 shelved as default-01
128 128 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
129 129 $ hg status -C
130 130
131 131 ensure that our shelved changes exist
132 132
133 133 $ hg shelve -l
134 134 default-01 (*)* changes to '[mq]: second.patch' (glob)
135 135 default (*)* changes to '[mq]: second.patch' (glob)
136 136
137 137 $ hg shelve -l -p default
138 138 default (*)* changes to '[mq]: second.patch' (glob)
139 139
140 140 diff --git a/a/a b/a/a
141 141 --- a/a/a
142 142 +++ b/a/a
143 143 @@ -1,1 +1,2 @@
144 144 a
145 145 +a
146 146
147 147 $ hg shelve --list --addremove
148 148 abort: options '--list' and '--addremove' may not be used together
149 149 [255]
150 150
151 151 delete our older shelved change
152 152
153 153 $ hg shelve -d default
154 154 $ hg qfinish -a -q
155 155
156 156 local edits should not prevent a shelved change from applying
157 157
158 158 $ printf "z\na\n" > a/a
159 159 $ hg unshelve --keep
160 160 unshelving change 'default-01'
161 161 temporarily committing pending changes (restore with 'hg unshelve --abort')
162 162 rebasing shelved changes
163 163 rebasing 4:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
164 164 merging a/a
165 165
166 166 $ hg revert --all -q
167 167 $ rm a/a.orig b.rename/b c.copy
168 168
169 169 apply it and make sure our state is as expected
170 170
171 171 $ hg unshelve
172 172 unshelving change 'default-01'
173 173 $ hg status -C
174 174 M a/a
175 175 A b.rename/b
176 176 b/b
177 177 A c.copy
178 178 c
179 179 R b/b
180 180 $ hg shelve -l
181 181
182 182 $ hg unshelve
183 183 abort: no shelved changes to apply!
184 184 [255]
185 185 $ hg unshelve foo
186 186 abort: shelved change 'foo' not found
187 187 [255]
188 188
189 189 named shelves, specific filenames, and "commit messages" should all work
190 190 (this tests also that editor is invoked, if '--edit' is specified)
191 191
192 192 $ hg status -C
193 193 M a/a
194 194 A b.rename/b
195 195 b/b
196 196 A c.copy
197 197 c
198 198 R b/b
199 199 $ HGEDITOR=cat hg shelve -q -n wibble -m wat -e a
200 200 wat
201 201
202 202
203 203 HG: Enter commit message. Lines beginning with 'HG:' are removed.
204 204 HG: Leave message empty to abort commit.
205 205 HG: --
206 206 HG: user: shelve@localhost
207 207 HG: branch 'default'
208 208 HG: changed a/a
209 209
210 210 expect "a" to no longer be present, but status otherwise unchanged
211 211
212 212 $ hg status -C
213 213 A b.rename/b
214 214 b/b
215 215 A c.copy
216 216 c
217 217 R b/b
218 218 $ hg shelve -l --stat
219 219 wibble (*) wat (glob)
220 220 a/a | 1 +
221 221 1 files changed, 1 insertions(+), 0 deletions(-)
222 222
223 223 and now "a/a" should reappear
224 224
225 225 $ cd a
226 226 $ hg unshelve -q wibble
227 227 $ cd ..
228 228 $ hg status -C
229 229 M a/a
230 230 A b.rename/b
231 231 b/b
232 232 A c.copy
233 233 c
234 234 R b/b
235 235
236 236 cause unshelving to result in a merge with 'a' conflicting
237 237
238 238 $ hg shelve -q
239 239 $ echo c>>a/a
240 240 $ hg commit -m second
241 241 $ hg tip --template '{files}\n'
242 242 a/a
243 243
244 244 add an unrelated change that should be preserved
245 245
246 246 $ mkdir foo
247 247 $ echo foo > foo/foo
248 248 $ hg add foo/foo
249 249
250 250 force a conflicted merge to occur
251 251
252 252 $ hg unshelve
253 253 unshelving change 'default'
254 254 temporarily committing pending changes (restore with 'hg unshelve --abort')
255 255 rebasing shelved changes
256 256 rebasing 5:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
257 257 merging a/a
258 258 warning: conflicts during merge.
259 259 merging a/a incomplete! (edit conflicts, then use 'hg resolve --mark')
260 260 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
261 261 [1]
262 262
263 263 ensure that we have a merge with unresolved conflicts
264 264
265 265 $ hg heads -q --template '{rev}\n'
266 266 5
267 267 4
268 268 $ hg parents -q --template '{rev}\n'
269 269 4
270 270 5
271 271 $ hg status
272 272 M a/a
273 273 M b.rename/b
274 274 M c.copy
275 275 R b/b
276 276 ? a/a.orig
277 277 $ hg diff
278 278 diff --git a/a/a b/a/a
279 279 --- a/a/a
280 280 +++ b/a/a
281 281 @@ -1,2 +1,6 @@
282 282 a
283 283 +<<<<<<< dest: * - shelve: pending changes temporary commit (glob)
284 284 c
285 285 +=======
286 286 +a
287 287 +>>>>>>> source: 4702e8911fe0 - shelve: changes to '[mq]: second.patch'
288 288 diff --git a/b/b b/b.rename/b
289 289 rename from b/b
290 290 rename to b.rename/b
291 291 diff --git a/c b/c.copy
292 292 copy from c
293 293 copy to c.copy
294 294 $ hg resolve -l
295 295 U a/a
296 296
297 297 $ hg shelve
298 298 abort: unshelve already in progress
299 299 (use 'hg unshelve --continue' or 'hg unshelve --abort')
300 300 [255]
301 301
302 302 abort the unshelve and be happy
303 303
304 304 $ hg status
305 305 M a/a
306 306 M b.rename/b
307 307 M c.copy
308 308 R b/b
309 309 ? a/a.orig
310 310 $ hg unshelve -a
311 311 rebase aborted
312 312 unshelve of 'default' aborted
313 313 $ hg heads -q
314 314 3:2e69b451d1ea
315 315 $ hg parents
316 316 changeset: 3:2e69b451d1ea
317 317 tag: tip
318 318 user: test
319 319 date: Thu Jan 01 00:00:00 1970 +0000
320 320 summary: second
321 321
322 322 $ hg resolve -l
323 323 $ hg status
324 324 A foo/foo
325 325 ? a/a.orig
326 326
327 327 try to continue with no unshelve underway
328 328
329 329 $ hg unshelve -c
330 330 abort: no unshelve operation underway
331 331 [255]
332 332 $ hg status
333 333 A foo/foo
334 334 ? a/a.orig
335 335
336 336 redo the unshelve to get a conflict
337 337
338 338 $ hg unshelve -q
339 339 warning: conflicts during merge.
340 340 merging a/a incomplete! (edit conflicts, then use 'hg resolve --mark')
341 341 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
342 342 [1]
343 343
344 344 attempt to continue
345 345
346 346 $ hg unshelve -c
347 347 abort: unresolved conflicts, can't continue
348 348 (see 'hg resolve', then 'hg unshelve --continue')
349 349 [255]
350 350
351 351 $ hg revert -r . a/a
352 352 $ hg resolve -m a/a
353 353 (no more unresolved files)
354 354
355 355 $ hg commit -m 'commit while unshelve in progress'
356 356 abort: unshelve already in progress
357 357 (use 'hg unshelve --continue' or 'hg unshelve --abort')
358 358 [255]
359 359
360 360 $ hg unshelve -c
361 361 rebasing 5:4702e8911fe0 "changes to '[mq]: second.patch'" (tip)
362 362 unshelve of 'default' complete
363 363
364 364 ensure the repo is as we hope
365 365
366 366 $ hg parents
367 367 changeset: 3:2e69b451d1ea
368 368 tag: tip
369 369 user: test
370 370 date: Thu Jan 01 00:00:00 1970 +0000
371 371 summary: second
372 372
373 373 $ hg heads -q
374 374 3:2e69b451d1ea
375 375
376 376 $ hg status -C
377 377 A b.rename/b
378 378 b/b
379 379 A c.copy
380 380 c
381 381 A foo/foo
382 382 R b/b
383 383 ? a/a.orig
384 384
385 385 there should be no shelves left
386 386
387 387 $ hg shelve -l
388 388
389 389 #if execbit
390 390
391 391 ensure that metadata-only changes are shelved
392 392
393 393 $ chmod +x a/a
394 394 $ hg shelve -q -n execbit a/a
395 395 $ hg status a/a
396 396 $ hg unshelve -q execbit
397 397 $ hg status a/a
398 398 M a/a
399 399 $ hg revert a/a
400 400
401 401 #endif
402 402
403 403 #if symlink
404 404
405 405 $ rm a/a
406 406 $ ln -s foo a/a
407 407 $ hg shelve -q -n symlink a/a
408 408 $ hg status a/a
409 409 $ hg unshelve -q symlink
410 410 $ hg status a/a
411 411 M a/a
412 412 $ hg revert a/a
413 413
414 414 #endif
415 415
416 416 set up another conflict between a commit and a shelved change
417 417
418 418 $ hg revert -q -C -a
419 419 $ rm a/a.orig b.rename/b c.copy
420 420 $ echo a >> a/a
421 421 $ hg shelve -q
422 422 $ echo x >> a/a
423 423 $ hg ci -m 'create conflict'
424 424 $ hg add foo/foo
425 425
426 426 if we resolve a conflict while unshelving, the unshelve should succeed
427 427
428 428 $ HGMERGE=true hg unshelve
429 429 unshelving change 'default'
430 430 temporarily committing pending changes (restore with 'hg unshelve --abort')
431 431 rebasing shelved changes
432 432 rebasing 6:c5e6910e7601 "changes to 'second'" (tip)
433 433 merging a/a
434 434 note: rebase of 6:c5e6910e7601 created no changes to commit
435 435 $ hg parents -q
436 436 4:33f7f61e6c5e
437 437 $ hg shelve -l
438 438 $ hg status
439 439 A foo/foo
440 440 $ cat a/a
441 441 a
442 442 c
443 443 x
444 444
445 445 test keep and cleanup
446 446
447 447 $ hg shelve
448 448 shelved as default
449 449 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
450 450 $ hg shelve --list
451 451 default (*) changes to 'create conflict' (glob)
452 452 $ hg unshelve --keep
453 453 unshelving change 'default'
454 454 $ hg shelve --list
455 455 default (*) changes to 'create conflict' (glob)
456 456 $ hg shelve --cleanup
457 457 $ hg shelve --list
458 458
459 459 $ hg shelve --cleanup --delete
460 460 abort: options '--cleanup' and '--delete' may not be used together
461 461 [255]
462 462 $ hg shelve --cleanup --patch
463 463 abort: options '--cleanup' and '--patch' may not be used together
464 464 [255]
465 465 $ hg shelve --cleanup --message MESSAGE
466 466 abort: options '--cleanup' and '--message' may not be used together
467 467 [255]
468 468
469 469 test bookmarks
470 470
471 471 $ hg bookmark test
472 472 $ hg bookmark
473 473 * test 4:33f7f61e6c5e
474 474 $ hg shelve
475 475 shelved as test
476 476 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
477 477 $ hg bookmark
478 478 * test 4:33f7f61e6c5e
479 479 $ hg unshelve
480 480 unshelving change 'test'
481 481 $ hg bookmark
482 482 * test 4:33f7f61e6c5e
483 483
484 484 shelve should still work even if mq is disabled
485 485
486 486 $ hg --config extensions.mq=! shelve
487 487 shelved as test
488 488 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
489 489 $ hg --config extensions.mq=! shelve --list
490 490 test (*) changes to 'create conflict' (glob)
491 491 $ hg --config extensions.mq=! unshelve
492 492 unshelving change 'test'
493 493
494 494 shelve should leave dirstate clean (issue4055)
495 495
496 496 $ cd ..
497 497 $ hg init shelverebase
498 498 $ cd shelverebase
499 499 $ printf 'x\ny\n' > x
500 500 $ echo z > z
501 501 $ hg commit -Aqm xy
502 502 $ echo z >> x
503 503 $ hg commit -Aqm z
504 504 $ hg up 0
505 505 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
506 506 $ printf 'a\nx\ny\nz\n' > x
507 507 $ hg commit -Aqm xyz
508 508 $ echo c >> z
509 509 $ hg shelve
510 510 shelved as default
511 511 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 512 $ hg rebase -d 1 --config extensions.rebase=
513 513 rebasing 2:323bfa07f744 "xyz" (tip)
514 514 merging x
515 515 saved backup bundle to $TESTTMP/shelverebase/.hg/strip-backup/323bfa07f744-78114325-backup.hg (glob)
516 516 $ hg unshelve
517 517 unshelving change 'default'
518 518 rebasing shelved changes
519 519 rebasing 4:b8fefe789ed0 "changes to 'xyz'" (tip)
520 520 $ hg status
521 521 M z
522 522
523 523 $ cd ..
524 524
525 525 shelve should only unshelve pending changes (issue4068)
526 526
527 527 $ hg init onlypendingchanges
528 528 $ cd onlypendingchanges
529 529 $ touch a
530 530 $ hg ci -Aqm a
531 531 $ touch b
532 532 $ hg ci -Aqm b
533 533 $ hg up -q 0
534 534 $ touch c
535 535 $ hg ci -Aqm c
536 536
537 537 $ touch d
538 538 $ hg add d
539 539 $ hg shelve
540 540 shelved as default
541 541 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
542 542 $ hg up -q 1
543 543 $ hg unshelve
544 544 unshelving change 'default'
545 545 rebasing shelved changes
546 546 rebasing 3:0cae6656c016 "changes to 'c'" (tip)
547 547 $ hg status
548 548 A d
549 549
550 550 unshelve should work on an ancestor of the original commit
551 551
552 552 $ hg shelve
553 553 shelved as default
554 554 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
555 555 $ hg up 0
556 556 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
557 557 $ hg unshelve
558 558 unshelving change 'default'
559 559 rebasing shelved changes
560 560 rebasing 3:be58f65f55fb "changes to 'b'" (tip)
561 561 $ hg status
562 562 A d
563 563
564 564 test bug 4073 we need to enable obsolete markers for it
565 565
566 566 $ cat >> $HGRCPATH << EOF
567 567 > [experimental]
568 568 > evolution=createmarkers
569 569 > EOF
570 570 $ hg shelve
571 571 shelved as default
572 572 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
573 573 $ hg debugobsolete `hg --debug id -i -r 1`
574 574 $ hg unshelve
575 575 unshelving change 'default'
576 576
577 577 unshelve should leave unknown files alone (issue4113)
578 578
579 579 $ echo e > e
580 580 $ hg shelve
581 581 shelved as default
582 582 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
583 583 $ hg status
584 584 ? e
585 585 $ hg unshelve
586 586 unshelving change 'default'
587 587 $ hg status
588 588 A d
589 589 ? e
590 590 $ cat e
591 591 e
592 592
593 593 unshelve should keep a copy of unknown files
594 594
595 595 $ hg add e
596 596 $ hg shelve
597 597 shelved as default
598 598 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
599 599 $ echo z > e
600 600 $ hg unshelve
601 601 unshelving change 'default'
602 602 $ cat e
603 603 e
604 604 $ cat e.orig
605 605 z
606 606
607 607
608 608 unshelve and conflicts with tracked and untracked files
609 609
610 610 preparing:
611 611
612 612 $ rm *.orig
613 613 $ hg ci -qm 'commit stuff'
614 614 $ hg phase -p null:
615 615
616 616 no other changes - no merge:
617 617
618 618 $ echo f > f
619 619 $ hg add f
620 620 $ hg shelve
621 621 shelved as default
622 622 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
623 623 $ echo g > f
624 624 $ hg unshelve
625 625 unshelving change 'default'
626 626 $ hg st
627 627 A f
628 628 ? f.orig
629 629 $ cat f
630 630 f
631 631 $ cat f.orig
632 632 g
633 633
634 634 other uncommitted changes - merge:
635 635
636 636 $ hg st
637 637 A f
638 638 ? f.orig
639 639 $ hg shelve
640 640 shelved as default
641 641 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
642 642 $ hg log -G --template '{rev} {desc|firstline} {author}' -R bundle://.hg/shelved/default.hg -r 'bundle()'
643 643 o 4 changes to 'commit stuff' shelve@localhost
644 644 |
645 645 $ hg log -G --template '{rev} {desc|firstline} {author}'
646 646 @ 3 commit stuff test
647 647 |
648 648 | o 2 c test
649 649 |/
650 650 o 0 a test
651 651
652 652 $ mv f.orig f
653 653 $ echo 1 > a
654 654 $ hg unshelve --date '1073741824 0'
655 655 unshelving change 'default'
656 656 temporarily committing pending changes (restore with 'hg unshelve --abort')
657 657 rebasing shelved changes
658 658 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
659 659 merging f
660 660 warning: conflicts during merge.
661 661 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
662 662 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
663 663 [1]
664 664 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
665 665 @ 5 changes to 'commit stuff' shelve@localhost 1970-01-01 00:00 +0000
666 666 |
667 667 | @ 4 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
668 668 |/
669 669 o 3 commit stuff test 1970-01-01 00:00 +0000
670 670 |
671 671 | o 2 c test 1970-01-01 00:00 +0000
672 672 |/
673 673 o 0 a test 1970-01-01 00:00 +0000
674 674
675 675 $ hg st
676 676 M f
677 677 ? f.orig
678 678 $ cat f
679 679 <<<<<<< dest: 5f6b880e719b - shelve: pending changes temporary commit
680 680 g
681 681 =======
682 682 f
683 683 >>>>>>> source: 23b29cada8ba - shelve: changes to 'commit stuff'
684 684 $ cat f.orig
685 685 g
686 686 $ hg unshelve --abort
687 687 rebase aborted
688 688 unshelve of 'default' aborted
689 689 $ hg st
690 690 M a
691 691 ? f.orig
692 692 $ cat f.orig
693 693 g
694 694 $ hg unshelve
695 695 unshelving change 'default'
696 696 temporarily committing pending changes (restore with 'hg unshelve --abort')
697 697 rebasing shelved changes
698 698 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
699 699 $ hg st
700 700 M a
701 701 A f
702 702 ? f.orig
703 703
704 704 other committed changes - merge:
705 705
706 706 $ hg shelve f
707 707 shelved as default
708 708 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
709 709 $ hg ci a -m 'intermediate other change'
710 710 $ mv f.orig f
711 711 $ hg unshelve
712 712 unshelving change 'default'
713 713 rebasing shelved changes
714 714 rebasing 5:23b29cada8ba "changes to 'commit stuff'" (tip)
715 715 merging f
716 716 warning: conflicts during merge.
717 717 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
718 718 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
719 719 [1]
720 720 $ hg st
721 721 M f
722 722 ? f.orig
723 723 $ cat f
724 724 <<<<<<< dest: * - test: intermediate other change (glob)
725 725 g
726 726 =======
727 727 f
728 728 >>>>>>> source: 23b29cada8ba - shelve: changes to 'commit stuff'
729 729 $ cat f.orig
730 730 g
731 731 $ hg unshelve --abort
732 732 rebase aborted
733 733 unshelve of 'default' aborted
734 734 $ hg st
735 735 ? f.orig
736 736 $ cat f.orig
737 737 g
738 738 $ hg shelve --delete default
739 739
740 740 Recreate some conflict again
741 741
742 742 $ cd ../repo
743 743 $ hg up -C -r 3
744 744 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
745 745 (leaving bookmark test)
746 746 $ echo y >> a/a
747 747 $ hg shelve
748 748 shelved as default
749 749 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
750 750 $ hg up test
751 751 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
752 752 (activating bookmark test)
753 753 $ hg unshelve
754 754 unshelving change 'default'
755 755 rebasing shelved changes
756 756 rebasing 5:4b555fdb4e96 "changes to 'second'" (tip)
757 757 merging a/a
758 758 warning: conflicts during merge.
759 759 merging a/a incomplete! (edit conflicts, then use 'hg resolve --mark')
760 760 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
761 761 [1]
762 762
763 763 Test that resolving all conflicts in one direction (so that the rebase
764 764 is a no-op), works (issue4398)
765 765
766 766 $ hg revert -a -r .
767 767 reverting a/a (glob)
768 768 $ hg resolve -m a/a
769 769 (no more unresolved files)
770 770 $ hg unshelve -c
771 771 rebasing 5:4b555fdb4e96 "changes to 'second'" (tip)
772 772 note: rebase of 5:4b555fdb4e96 created no changes to commit
773 773 unshelve of 'default' complete
774 774 $ hg diff
775 775 $ hg status
776 776 ? a/a.orig
777 777 ? foo/foo
778 778 $ hg summary
779 779 parent: 4:33f7f61e6c5e tip
780 780 create conflict
781 781 branch: default
782 782 bookmarks: *test
783 783 commit: 2 unknown (clean)
784 784 update: (current)
785 785
786 786 $ hg shelve --delete --stat
787 787 abort: options '--delete' and '--stat' may not be used together
788 788 [255]
789 789 $ hg shelve --delete --name NAME
790 790 abort: options '--delete' and '--name' may not be used together
791 791 [255]
792 792
793 793 Test interactive shelve
794 794 $ cat <<EOF >> $HGRCPATH
795 795 > [ui]
796 796 > interactive = true
797 797 > EOF
798 798 $ echo 'a' >> a/b
799 799 $ cat a/a >> a/b
800 800 $ echo 'x' >> a/b
801 801 $ mv a/b a/a
802 802 $ echo 'a' >> foo/foo
803 803 $ hg st
804 804 M a/a
805 805 ? a/a.orig
806 806 ? foo/foo
807 807 $ cat a/a
808 808 a
809 809 a
810 810 c
811 811 x
812 812 x
813 813 $ cat foo/foo
814 814 foo
815 815 a
816 816 $ hg shelve --interactive << EOF
817 817 > y
818 818 > y
819 819 > n
820 820 > EOF
821 821 diff --git a/a/a b/a/a
822 822 2 hunks, 2 lines changed
823 823 examine changes to 'a/a'? [Ynesfdaq?] y
824 824
825 825 @@ -1,3 +1,4 @@
826 826 +a
827 827 a
828 828 c
829 829 x
830 830 record change 1/2 to 'a/a'? [Ynesfdaq?] y
831 831
832 832 @@ -1,3 +2,4 @@
833 833 a
834 834 c
835 835 x
836 836 +x
837 837 record change 2/2 to 'a/a'? [Ynesfdaq?] n
838 838
839 839 shelved as test
840 840 merging a/a
841 841 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
842 842 $ cat a/a
843 843 a
844 844 c
845 845 x
846 846 x
847 847 $ cat foo/foo
848 848 foo
849 849 a
850 850 $ hg st
851 851 M a/a
852 852 ? foo/foo
853 853 $ hg unshelve
854 854 unshelving change 'test'
855 855 temporarily committing pending changes (restore with 'hg unshelve --abort')
856 856 rebasing shelved changes
857 857 rebasing 6:65b5d1c34c34 "changes to 'create conflict'" (tip)
858 858 merging a/a
859 859 $ cat a/a
860 860 a
861 861 a
862 862 c
863 863 x
864 864 x
865 $ cd ..
865
866 shelve --patch and shelve --stat should work with a single valid shelfname
867
868 $ hg up --clean .
869 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
870 $ hg shelve --list
871 $ echo 'patch a' > shelf-patch-a
872 $ hg add shelf-patch-a
873 $ hg shelve
874 shelved as default
875 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
876 $ echo 'patch b' > shelf-patch-b
877 $ hg add shelf-patch-b
878 $ hg shelve
879 shelved as default-01
880 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
881 $ hg shelve --patch default default-01
882 abort: --patch expects a single shelf
883 [255]
884 $ hg shelve --stat default default-01
885 abort: --stat expects a single shelf
886 [255]
887 $ hg shelve --patch default
888 default (* ago) changes to 'create conflict' (glob)
889
890 diff --git a/shelf-patch-a b/shelf-patch-a
891 new file mode 100644
892 --- /dev/null
893 +++ b/shelf-patch-a
894 @@ -0,0 +1,1 @@
895 +patch a
896 $ hg shelve --stat default
897 default (* ago) changes to 'create conflict' (glob)
898 shelf-patch-a | 1 +
899 1 files changed, 1 insertions(+), 0 deletions(-)
900 $ hg shelve --patch nonexistentshelf
901 abort: cannot find shelf nonexistentshelf
902 [255]
903 $ hg shelve --stat nonexistentshelf
904 abort: cannot find shelf nonexistentshelf
905 [255]
906
General Comments 0
You need to be logged in to leave comments. Login now