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