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