##// END OF EJS Templates
shelve: remove unused variable caught by pyflakes
Sean Farley -
r20937:c0bf8bea stable
parent child Browse files
Show More
@@ -1,692 +1,692 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, bin, hex
26 26 from mercurial import changegroup, cmdutil, scmutil, phases
27 27 from mercurial import error, hg, mdiff, merge, patch, repair, util
28 28 from mercurial import templatefilters
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/.files/.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 if filetype:
47 47 self.fname = name + '.' + filetype
48 48 else:
49 49 self.fname = name
50 50
51 51 def exists(self):
52 52 return self.vfs.exists(self.fname)
53 53
54 54 def filename(self):
55 55 return self.vfs.join(self.fname)
56 56
57 57 def unlink(self):
58 58 util.unlink(self.filename())
59 59
60 60 def stat(self):
61 61 return self.vfs.stat(self.fname)
62 62
63 63 def opener(self, mode='rb'):
64 64 try:
65 65 return self.vfs(self.fname, mode)
66 66 except IOError, err:
67 67 if err.errno != errno.ENOENT:
68 68 raise
69 69 raise util.Abort(_("shelved change '%s' not found") % self.name)
70 70
71 71 class shelvedstate(object):
72 72 """Handle persistence during unshelving operations.
73 73
74 74 Handles saving and restoring a shelved state. Ensures that different
75 75 versions of a shelved state are possible and handles them appropriately.
76 76 """
77 77 _version = 1
78 78 _filename = 'shelvedstate'
79 79
80 80 @classmethod
81 81 def load(cls, repo):
82 82 fp = repo.opener(cls._filename)
83 83 try:
84 84 version = int(fp.readline().strip())
85 85
86 86 if version != cls._version:
87 87 raise util.Abort(_('this version of shelve is incompatible '
88 88 'with the version used in this repo'))
89 89 name = fp.readline().strip()
90 90 wctx = fp.readline().strip()
91 91 pendingctx = fp.readline().strip()
92 92 parents = [bin(h) for h in fp.readline().split()]
93 93 stripnodes = [bin(h) for h in fp.readline().split()]
94 94 finally:
95 95 fp.close()
96 96
97 97 obj = cls()
98 98 obj.name = name
99 99 obj.wctx = repo[bin(wctx)]
100 100 obj.pendingctx = repo[bin(pendingctx)]
101 101 obj.parents = parents
102 102 obj.stripnodes = stripnodes
103 103
104 104 return obj
105 105
106 106 @classmethod
107 107 def save(cls, repo, name, originalwctx, pendingctx, stripnodes):
108 108 fp = repo.opener(cls._filename, 'wb')
109 109 fp.write('%i\n' % cls._version)
110 110 fp.write('%s\n' % name)
111 111 fp.write('%s\n' % hex(originalwctx.node()))
112 112 fp.write('%s\n' % hex(pendingctx.node()))
113 113 fp.write('%s\n' % ' '.join([hex(p) for p in repo.dirstate.parents()]))
114 114 fp.write('%s\n' % ' '.join([hex(n) for n in stripnodes]))
115 115 fp.close()
116 116
117 117 @classmethod
118 118 def clear(cls, repo):
119 119 util.unlinkpath(repo.join(cls._filename), ignoremissing=True)
120 120
121 121 def createcmd(ui, repo, pats, opts):
122 122 """subcommand that creates a new shelve"""
123 123
124 124 def publicancestors(ctx):
125 125 """Compute the heads of the public ancestors of a commit.
126 126
127 127 Much faster than the revset heads(ancestors(ctx) - draft())"""
128 128 seen = set()
129 129 visit = util.deque()
130 130 visit.append(ctx)
131 131 while visit:
132 132 ctx = visit.popleft()
133 133 for parent in ctx.parents():
134 134 rev = parent.rev()
135 135 if rev not in seen:
136 136 seen.add(rev)
137 137 if parent.mutable():
138 138 visit.append(parent)
139 139 else:
140 140 yield parent.node()
141 141
142 142 wctx = repo[None]
143 143 parents = wctx.parents()
144 144 if len(parents) > 1:
145 145 raise util.Abort(_('cannot shelve while merging'))
146 146 parent = parents[0]
147 147
148 148 # we never need the user, so we use a generic user for all shelve operations
149 149 user = 'shelve@localhost'
150 150 label = repo._bookmarkcurrent or parent.branch() or 'default'
151 151
152 152 # slashes aren't allowed in filenames, therefore we rename it
153 origlabel, label = label, label.replace('/', '_')
153 label = label.replace('/', '_')
154 154
155 155 def gennames():
156 156 yield label
157 157 for i in xrange(1, 100):
158 158 yield '%s-%02d' % (label, i)
159 159
160 160 shelvedfiles = []
161 161
162 162 def commitfunc(ui, repo, message, match, opts):
163 163 # check modified, added, removed, deleted only
164 164 for flist in repo.status(match=match)[:4]:
165 165 shelvedfiles.extend(flist)
166 166 hasmq = util.safehasattr(repo, 'mq')
167 167 if hasmq:
168 168 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
169 169 try:
170 170 return repo.commit(message, user, opts.get('date'), match)
171 171 finally:
172 172 if hasmq:
173 173 repo.mq.checkapplied = saved
174 174
175 175 if parent.node() != nullid:
176 176 desc = parent.description().split('\n', 1)[0]
177 177 else:
178 178 desc = '(empty repository)'
179 179
180 180 if not opts['message']:
181 181 opts['message'] = desc
182 182
183 183 name = opts['name']
184 184
185 185 wlock = lock = tr = bms = None
186 186 try:
187 187 wlock = repo.wlock()
188 188 lock = repo.lock()
189 189
190 190 bms = repo._bookmarks.copy()
191 191 # use an uncommitted transaction to generate the bundle to avoid
192 192 # pull races. ensure we don't print the abort message to stderr.
193 193 tr = repo.transaction('commit', report=lambda x: None)
194 194
195 195 if name:
196 196 if shelvedfile(repo, name, 'hg').exists():
197 197 raise util.Abort(_("a shelved change named '%s' already exists")
198 198 % name)
199 199 else:
200 200 for n in gennames():
201 201 if not shelvedfile(repo, n, 'hg').exists():
202 202 name = n
203 203 break
204 204 else:
205 205 raise util.Abort(_("too many shelved changes named '%s'") %
206 206 label)
207 207
208 208 # ensure we are not creating a subdirectory or a hidden file
209 209 if '/' in name or '\\' in name:
210 210 raise util.Abort(_('shelved change names may not contain slashes'))
211 211 if name.startswith('.'):
212 212 raise util.Abort(_("shelved change names may not start with '.'"))
213 213
214 214 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
215 215
216 216 if not node:
217 217 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
218 218 if stat[3]:
219 219 ui.status(_("nothing changed (%d missing files, see "
220 220 "'hg status')\n") % len(stat[3]))
221 221 else:
222 222 ui.status(_("nothing changed\n"))
223 223 return 1
224 224
225 225 phases.retractboundary(repo, phases.secret, [node])
226 226
227 227 fp = shelvedfile(repo, name, 'files').opener('wb')
228 228 fp.write('\0'.join(shelvedfiles))
229 229
230 230 bases = list(publicancestors(repo[node]))
231 231 cg = repo.changegroupsubset(bases, [node], 'shelve')
232 232 changegroup.writebundle(cg, shelvedfile(repo, name, 'hg').filename(),
233 233 'HG10UN')
234 234 cmdutil.export(repo, [node],
235 235 fp=shelvedfile(repo, name, 'patch').opener('wb'),
236 236 opts=mdiff.diffopts(git=True))
237 237
238 238
239 239 if ui.formatted():
240 240 desc = util.ellipsis(desc, ui.termwidth())
241 241 ui.status(_('shelved as %s\n') % name)
242 242 hg.update(repo, parent.node())
243 243 finally:
244 244 if bms:
245 245 # restore old bookmarks
246 246 repo._bookmarks.update(bms)
247 247 repo._bookmarks.write()
248 248 if tr:
249 249 tr.abort()
250 250 lockmod.release(lock, wlock)
251 251
252 252 def cleanupcmd(ui, repo):
253 253 """subcommand that deletes all shelves"""
254 254
255 255 wlock = None
256 256 try:
257 257 wlock = repo.wlock()
258 258 for (name, _) in repo.vfs.readdir('shelved'):
259 259 suffix = name.rsplit('.', 1)[-1]
260 260 if suffix in ('hg', 'files', 'patch'):
261 261 shelvedfile(repo, name).unlink()
262 262 finally:
263 263 lockmod.release(wlock)
264 264
265 265 def deletecmd(ui, repo, pats):
266 266 """subcommand that deletes a specific shelve"""
267 267 if not pats:
268 268 raise util.Abort(_('no shelved changes specified!'))
269 269 wlock = None
270 270 try:
271 271 wlock = repo.wlock()
272 272 try:
273 273 for name in pats:
274 274 for suffix in 'hg files patch'.split():
275 275 shelvedfile(repo, name, suffix).unlink()
276 276 except OSError, err:
277 277 if err.errno != errno.ENOENT:
278 278 raise
279 279 raise util.Abort(_("shelved change '%s' not found") % name)
280 280 finally:
281 281 lockmod.release(wlock)
282 282
283 283 def listshelves(repo):
284 284 """return all shelves in repo as list of (time, filename)"""
285 285 try:
286 286 names = repo.vfs.readdir('shelved')
287 287 except OSError, err:
288 288 if err.errno != errno.ENOENT:
289 289 raise
290 290 return []
291 291 info = []
292 292 for (name, _) in names:
293 293 pfx, sfx = name.rsplit('.', 1)
294 294 if not pfx or sfx != 'patch':
295 295 continue
296 296 st = shelvedfile(repo, name).stat()
297 297 info.append((st.st_mtime, shelvedfile(repo, pfx).filename()))
298 298 return sorted(info, reverse=True)
299 299
300 300 def listcmd(ui, repo, pats, opts):
301 301 """subcommand that displays the list of shelves"""
302 302 pats = set(pats)
303 303 width = 80
304 304 if not ui.plain():
305 305 width = ui.termwidth()
306 306 namelabel = 'shelve.newest'
307 307 for mtime, name in listshelves(repo):
308 308 sname = util.split(name)[1]
309 309 if pats and sname not in pats:
310 310 continue
311 311 ui.write(sname, label=namelabel)
312 312 namelabel = 'shelve.name'
313 313 if ui.quiet:
314 314 ui.write('\n')
315 315 continue
316 316 ui.write(' ' * (16 - len(sname)))
317 317 used = 16
318 318 age = '(%s)' % templatefilters.age(util.makedate(mtime), abbrev=True)
319 319 ui.write(age, label='shelve.age')
320 320 ui.write(' ' * (12 - len(age)))
321 321 used += 12
322 322 fp = open(name + '.patch', 'rb')
323 323 try:
324 324 while True:
325 325 line = fp.readline()
326 326 if not line:
327 327 break
328 328 if not line.startswith('#'):
329 329 desc = line.rstrip()
330 330 if ui.formatted():
331 331 desc = util.ellipsis(desc, width - used)
332 332 ui.write(desc)
333 333 break
334 334 ui.write('\n')
335 335 if not (opts['patch'] or opts['stat']):
336 336 continue
337 337 difflines = fp.readlines()
338 338 if opts['patch']:
339 339 for chunk, label in patch.difflabel(iter, difflines):
340 340 ui.write(chunk, label=label)
341 341 if opts['stat']:
342 342 for chunk, label in patch.diffstatui(difflines, width=width,
343 343 git=True):
344 344 ui.write(chunk, label=label)
345 345 finally:
346 346 fp.close()
347 347
348 348 def checkparents(repo, state):
349 349 """check parent while resuming an unshelve"""
350 350 if state.parents != repo.dirstate.parents():
351 351 raise util.Abort(_('working directory parents do not match unshelve '
352 352 'state'))
353 353
354 354 def pathtofiles(repo, files):
355 355 cwd = repo.getcwd()
356 356 return [repo.pathto(f, cwd) for f in files]
357 357
358 358 def unshelveabort(ui, repo, state, opts):
359 359 """subcommand that abort an in-progress unshelve"""
360 360 wlock = repo.wlock()
361 361 lock = None
362 362 try:
363 363 checkparents(repo, state)
364 364
365 365 util.rename(repo.join('unshelverebasestate'),
366 366 repo.join('rebasestate'))
367 367 try:
368 368 rebase.rebase(ui, repo, **{
369 369 'abort' : True
370 370 })
371 371 except Exception:
372 372 util.rename(repo.join('rebasestate'),
373 373 repo.join('unshelverebasestate'))
374 374 raise
375 375
376 376 lock = repo.lock()
377 377
378 378 mergefiles(ui, repo, state.wctx, state.pendingctx)
379 379
380 380 repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve')
381 381 shelvedstate.clear(repo)
382 382 ui.warn(_("unshelve of '%s' aborted\n") % state.name)
383 383 finally:
384 384 lockmod.release(lock, wlock)
385 385
386 386 def mergefiles(ui, repo, wctx, shelvectx):
387 387 """updates to wctx and merges the changes from shelvectx into the
388 388 dirstate."""
389 389 oldquiet = ui.quiet
390 390 try:
391 391 ui.quiet = True
392 392 hg.update(repo, wctx.node())
393 393 files = []
394 394 files.extend(shelvectx.files())
395 395 files.extend(shelvectx.parents()[0].files())
396 396
397 397 # revert will overwrite unknown files, so move them out of the way
398 398 m, a, r, d, u = repo.status(unknown=True)[:5]
399 399 for file in u:
400 400 if file in files:
401 401 util.rename(file, file + ".orig")
402 402 cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(),
403 403 *pathtofiles(repo, files),
404 404 **{'no_backup': True})
405 405 finally:
406 406 ui.quiet = oldquiet
407 407
408 408 def unshelvecleanup(ui, repo, name, opts):
409 409 """remove related files after an unshelve"""
410 410 if not opts['keep']:
411 411 for filetype in 'hg files patch'.split():
412 412 shelvedfile(repo, name, filetype).unlink()
413 413
414 414 def unshelvecontinue(ui, repo, state, opts):
415 415 """subcommand to continue an in-progress unshelve"""
416 416 # We're finishing off a merge. First parent is our original
417 417 # parent, second is the temporary "fake" commit we're unshelving.
418 418 wlock = repo.wlock()
419 419 lock = None
420 420 try:
421 421 checkparents(repo, state)
422 422 ms = merge.mergestate(repo)
423 423 if [f for f in ms if ms[f] == 'u']:
424 424 raise util.Abort(
425 425 _("unresolved conflicts, can't continue"),
426 426 hint=_("see 'hg resolve', then 'hg unshelve --continue'"))
427 427
428 428 lock = repo.lock()
429 429
430 430 util.rename(repo.join('unshelverebasestate'),
431 431 repo.join('rebasestate'))
432 432 try:
433 433 rebase.rebase(ui, repo, **{
434 434 'continue' : True
435 435 })
436 436 except Exception:
437 437 util.rename(repo.join('rebasestate'),
438 438 repo.join('unshelverebasestate'))
439 439 raise
440 440
441 441 shelvectx = repo['tip']
442 442 if not shelvectx in state.pendingctx.children():
443 443 # rebase was a no-op, so it produced no child commit
444 444 shelvectx = state.pendingctx
445 445
446 446 mergefiles(ui, repo, state.wctx, shelvectx)
447 447
448 448 state.stripnodes.append(shelvectx.node())
449 449 repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve')
450 450 shelvedstate.clear(repo)
451 451 unshelvecleanup(ui, repo, state.name, opts)
452 452 ui.status(_("unshelve of '%s' complete\n") % state.name)
453 453 finally:
454 454 lockmod.release(lock, wlock)
455 455
456 456 @command('unshelve',
457 457 [('a', 'abort', None,
458 458 _('abort an incomplete unshelve operation')),
459 459 ('c', 'continue', None,
460 460 _('continue an incomplete unshelve operation')),
461 461 ('', 'keep', None,
462 462 _('keep shelve after unshelving'))],
463 463 _('hg unshelve [SHELVED]'))
464 464 def unshelve(ui, repo, *shelved, **opts):
465 465 """restore a shelved change to the working directory
466 466
467 467 This command accepts an optional name of a shelved change to
468 468 restore. If none is given, the most recent shelved change is used.
469 469
470 470 If a shelved change is applied successfully, the bundle that
471 471 contains the shelved changes is deleted afterwards.
472 472
473 473 Since you can restore a shelved change on top of an arbitrary
474 474 commit, it is possible that unshelving will result in a conflict
475 475 between your changes and the commits you are unshelving onto. If
476 476 this occurs, you must resolve the conflict, then use
477 477 ``--continue`` to complete the unshelve operation. (The bundle
478 478 will not be deleted until you successfully complete the unshelve.)
479 479
480 480 (Alternatively, you can use ``--abort`` to abandon an unshelve
481 481 that causes a conflict. This reverts the unshelved changes, and
482 482 does not delete the bundle.)
483 483 """
484 484 abortf = opts['abort']
485 485 continuef = opts['continue']
486 486 if not abortf and not continuef:
487 487 cmdutil.checkunfinished(repo)
488 488
489 489 if abortf or continuef:
490 490 if abortf and continuef:
491 491 raise util.Abort(_('cannot use both abort and continue'))
492 492 if shelved:
493 493 raise util.Abort(_('cannot combine abort/continue with '
494 494 'naming a shelved change'))
495 495
496 496 try:
497 497 state = shelvedstate.load(repo)
498 498 except IOError, err:
499 499 if err.errno != errno.ENOENT:
500 500 raise
501 501 raise util.Abort(_('no unshelve operation underway'))
502 502
503 503 if abortf:
504 504 return unshelveabort(ui, repo, state, opts)
505 505 elif continuef:
506 506 return unshelvecontinue(ui, repo, state, opts)
507 507 elif len(shelved) > 1:
508 508 raise util.Abort(_('can only unshelve one change at a time'))
509 509 elif not shelved:
510 510 shelved = listshelves(repo)
511 511 if not shelved:
512 512 raise util.Abort(_('no shelved changes to apply!'))
513 513 basename = util.split(shelved[0][1])[1]
514 514 ui.status(_("unshelving change '%s'\n") % basename)
515 515 else:
516 516 basename = shelved[0]
517 517
518 518 if not shelvedfile(repo, basename, 'files').exists():
519 519 raise util.Abort(_("shelved change '%s' not found") % basename)
520 520
521 521 wlock = lock = tr = None
522 522 try:
523 523 lock = repo.lock()
524 524 wlock = repo.wlock()
525 525
526 526 tr = repo.transaction('unshelve', report=lambda x: None)
527 527 oldtiprev = len(repo)
528 528
529 529 wctx = repo['.']
530 530 tmpwctx = wctx
531 531 # The goal is to have a commit structure like so:
532 532 # ...-> wctx -> tmpwctx -> shelvectx
533 533 # where tmpwctx is an optional commit with the user's pending changes
534 534 # and shelvectx is the unshelved changes. Then we merge it all down
535 535 # to the original wctx.
536 536
537 537 # Store pending changes in a commit
538 538 m, a, r, d = repo.status()[:4]
539 539 if m or a or r or d:
540 540 def commitfunc(ui, repo, message, match, opts):
541 541 hasmq = util.safehasattr(repo, 'mq')
542 542 if hasmq:
543 543 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
544 544
545 545 try:
546 546 return repo.commit(message, 'shelve@localhost',
547 547 opts.get('date'), match)
548 548 finally:
549 549 if hasmq:
550 550 repo.mq.checkapplied = saved
551 551
552 552 tempopts = {}
553 553 tempopts['message'] = "pending changes temporary commit"
554 554 oldquiet = ui.quiet
555 555 try:
556 556 ui.quiet = True
557 557 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
558 558 finally:
559 559 ui.quiet = oldquiet
560 560 tmpwctx = repo[node]
561 561
562 562 try:
563 563 fp = shelvedfile(repo, basename, 'hg').opener()
564 564 gen = changegroup.readbundle(fp, fp.name)
565 565 repo.addchangegroup(gen, 'unshelve', 'bundle:' + fp.name)
566 566 nodes = [ctx.node() for ctx in repo.set('%d:', oldtiprev)]
567 567 phases.retractboundary(repo, phases.secret, nodes)
568 568 finally:
569 569 fp.close()
570 570
571 571 shelvectx = repo['tip']
572 572
573 573 # If the shelve is not immediately on top of the commit
574 574 # we'll be merging with, rebase it to be on top.
575 575 if tmpwctx.node() != shelvectx.parents()[0].node():
576 576 try:
577 577 rebase.rebase(ui, repo, **{
578 578 'rev' : [shelvectx.rev()],
579 579 'dest' : str(tmpwctx.rev()),
580 580 'keep' : True,
581 581 })
582 582 except error.InterventionRequired:
583 583 tr.close()
584 584
585 585 stripnodes = [repo.changelog.node(rev)
586 586 for rev in xrange(oldtiprev, len(repo))]
587 587 shelvedstate.save(repo, basename, wctx, tmpwctx, stripnodes)
588 588
589 589 util.rename(repo.join('rebasestate'),
590 590 repo.join('unshelverebasestate'))
591 591 raise error.InterventionRequired(
592 592 _("unresolved conflicts (see 'hg resolve', then "
593 593 "'hg unshelve --continue')"))
594 594
595 595 # refresh ctx after rebase completes
596 596 shelvectx = repo['tip']
597 597
598 598 if not shelvectx in tmpwctx.children():
599 599 # rebase was a no-op, so it produced no child commit
600 600 shelvectx = tmpwctx
601 601
602 602 mergefiles(ui, repo, wctx, shelvectx)
603 603 shelvedstate.clear(repo)
604 604
605 605 # The transaction aborting will strip all the commits for us,
606 606 # but it doesn't update the inmemory structures, so addchangegroup
607 607 # hooks still fire and try to operate on the missing commits.
608 608 # Clean up manually to prevent this.
609 609 repo.unfiltered().changelog.strip(oldtiprev, tr)
610 610
611 611 unshelvecleanup(ui, repo, basename, opts)
612 612 finally:
613 613 if tr:
614 614 tr.release()
615 615 lockmod.release(lock, wlock)
616 616
617 617 @command('shelve',
618 618 [('A', 'addremove', None,
619 619 _('mark new/missing files as added/removed before shelving')),
620 620 ('', 'cleanup', None,
621 621 _('delete all shelved changes')),
622 622 ('', 'date', '',
623 623 _('shelve with the specified commit date'), _('DATE')),
624 624 ('d', 'delete', None,
625 625 _('delete the named shelved change(s)')),
626 626 ('l', 'list', None,
627 627 _('list current shelves')),
628 628 ('m', 'message', '',
629 629 _('use text as shelve message'), _('TEXT')),
630 630 ('n', 'name', '',
631 631 _('use the given name for the shelved commit'), _('NAME')),
632 632 ('p', 'patch', None,
633 633 _('show patch')),
634 634 ('', 'stat', None,
635 635 _('output diffstat-style summary of changes'))],
636 636 _('hg shelve'))
637 637 def shelvecmd(ui, repo, *pats, **opts):
638 638 '''save and set aside changes from the working directory
639 639
640 640 Shelving takes files that "hg status" reports as not clean, saves
641 641 the modifications to a bundle (a shelved change), and reverts the
642 642 files so that their state in the working directory becomes clean.
643 643
644 644 To restore these changes to the working directory, using "hg
645 645 unshelve"; this will work even if you switch to a different
646 646 commit.
647 647
648 648 When no files are specified, "hg shelve" saves all not-clean
649 649 files. If specific files or directories are named, only changes to
650 650 those files are shelved.
651 651
652 652 Each shelved change has a name that makes it easier to find later.
653 653 The name of a shelved change defaults to being based on the active
654 654 bookmark, or if there is no active bookmark, the current named
655 655 branch. To specify a different name, use ``--name``.
656 656
657 657 To see a list of existing shelved changes, use the ``--list``
658 658 option. For each shelved change, this will print its name, age,
659 659 and description; use ``--patch`` or ``--stat`` for more details.
660 660
661 661 To delete specific shelved changes, use ``--delete``. To delete
662 662 all shelved changes, use ``--cleanup``.
663 663 '''
664 664 cmdutil.checkunfinished(repo)
665 665
666 666 def checkopt(opt, incompatible):
667 667 if opts[opt]:
668 668 for i in incompatible.split():
669 669 if opts[i]:
670 670 raise util.Abort(_("options '--%s' and '--%s' may not be "
671 671 "used together") % (opt, i))
672 672 return True
673 673 if checkopt('cleanup', 'addremove delete list message name patch stat'):
674 674 if pats:
675 675 raise util.Abort(_("cannot specify names when using '--cleanup'"))
676 676 return cleanupcmd(ui, repo)
677 677 elif checkopt('delete', 'addremove cleanup list message name patch stat'):
678 678 return deletecmd(ui, repo, pats)
679 679 elif checkopt('list', 'addremove cleanup delete message name'):
680 680 return listcmd(ui, repo, pats, opts)
681 681 else:
682 682 for i in ('patch', 'stat'):
683 683 if opts[i]:
684 684 raise util.Abort(_("option '--%s' may not be "
685 685 "used when shelving a change") % (i,))
686 686 return createcmd(ui, repo, pats, opts)
687 687
688 688 def extsetup(ui):
689 689 cmdutil.unfinishedstates.append(
690 690 [shelvedstate._filename, False, False,
691 691 _('unshelve already in progress'),
692 692 _("use 'hg unshelve --continue' or 'hg unshelve --abort'")])
General Comments 0
You need to be logged in to leave comments. Login now