##// END OF EJS Templates
shelve: trust caller of shelvedfile.opener() to check that the file exists...
Martin von Zweigbergk -
r46989:b2a8ff73 default
parent child Browse files
Show More
@@ -1,1163 +1,1158 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 from __future__ import absolute_import
23 from __future__ import absolute_import
24
24
25 import collections
25 import collections
26 import errno
26 import errno
27 import itertools
27 import itertools
28 import stat
28 import stat
29
29
30 from .i18n import _
30 from .i18n import _
31 from .pycompat import open
31 from .pycompat import open
32 from .node import (
32 from .node import (
33 bin,
33 bin,
34 hex,
34 hex,
35 nullid,
35 nullid,
36 nullrev,
36 nullrev,
37 )
37 )
38 from . import (
38 from . import (
39 bookmarks,
39 bookmarks,
40 bundle2,
40 bundle2,
41 changegroup,
41 changegroup,
42 cmdutil,
42 cmdutil,
43 discovery,
43 discovery,
44 error,
44 error,
45 exchange,
45 exchange,
46 hg,
46 hg,
47 lock as lockmod,
47 lock as lockmod,
48 mdiff,
48 mdiff,
49 merge,
49 merge,
50 mergestate as mergestatemod,
50 mergestate as mergestatemod,
51 patch,
51 patch,
52 phases,
52 phases,
53 pycompat,
53 pycompat,
54 repair,
54 repair,
55 scmutil,
55 scmutil,
56 templatefilters,
56 templatefilters,
57 util,
57 util,
58 vfs as vfsmod,
58 vfs as vfsmod,
59 )
59 )
60 from .utils import (
60 from .utils import (
61 dateutil,
61 dateutil,
62 stringutil,
62 stringutil,
63 )
63 )
64
64
65 backupdir = b'shelve-backup'
65 backupdir = b'shelve-backup'
66 shelvedir = b'shelved'
66 shelvedir = b'shelved'
67 shelvefileextensions = [b'hg', b'patch', b'shelve']
67 shelvefileextensions = [b'hg', b'patch', b'shelve']
68 # universal extension is present in all types of shelves
68 # universal extension is present in all types of shelves
69 patchextension = b'patch'
69 patchextension = b'patch'
70
70
71 # we never need the user, so we use a
71 # we never need the user, so we use a
72 # generic user for all shelve operations
72 # generic user for all shelve operations
73 shelveuser = b'shelve@localhost'
73 shelveuser = b'shelve@localhost'
74
74
75
75
76 class shelvedfile(object):
76 class shelvedfile(object):
77 """Helper for the file storing a single shelve
77 """Helper for the file storing a single shelve
78
78
79 Handles common functions on shelve files (.hg/.patch) using
79 Handles common functions on shelve files (.hg/.patch) using
80 the vfs layer"""
80 the vfs layer"""
81
81
82 def __init__(self, repo, name, filetype=None):
82 def __init__(self, repo, name, filetype=None):
83 self.repo = repo
83 self.repo = repo
84 self.name = name
84 self.name = name
85 self.vfs = vfsmod.vfs(repo.vfs.join(shelvedir))
85 self.vfs = vfsmod.vfs(repo.vfs.join(shelvedir))
86 self.backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
86 self.backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
87 self.ui = self.repo.ui
87 self.ui = self.repo.ui
88 if filetype:
88 if filetype:
89 self.fname = name + b'.' + filetype
89 self.fname = name + b'.' + filetype
90 else:
90 else:
91 self.fname = name
91 self.fname = name
92
92
93 def exists(self):
93 def exists(self):
94 return self.vfs.exists(self.fname)
94 return self.vfs.exists(self.fname)
95
95
96 def filename(self):
96 def filename(self):
97 return self.vfs.join(self.fname)
97 return self.vfs.join(self.fname)
98
98
99 def backupfilename(self):
99 def backupfilename(self):
100 def gennames(base):
100 def gennames(base):
101 yield base
101 yield base
102 base, ext = base.rsplit(b'.', 1)
102 base, ext = base.rsplit(b'.', 1)
103 for i in itertools.count(1):
103 for i in itertools.count(1):
104 yield b'%s-%d.%s' % (base, i, ext)
104 yield b'%s-%d.%s' % (base, i, ext)
105
105
106 name = self.backupvfs.join(self.fname)
106 name = self.backupvfs.join(self.fname)
107 for n in gennames(name):
107 for n in gennames(name):
108 if not self.backupvfs.exists(n):
108 if not self.backupvfs.exists(n):
109 return n
109 return n
110
110
111 def movetobackup(self):
111 def movetobackup(self):
112 if not self.backupvfs.isdir():
112 if not self.backupvfs.isdir():
113 self.backupvfs.makedir()
113 self.backupvfs.makedir()
114 util.rename(self.filename(), self.backupfilename())
114 util.rename(self.filename(), self.backupfilename())
115
115
116 def stat(self):
116 def stat(self):
117 return self.vfs.stat(self.fname)
117 return self.vfs.stat(self.fname)
118
118
119 def opener(self, mode=b'rb'):
119 def opener(self, mode=b'rb'):
120 try:
120 return self.vfs(self.fname, mode)
121 return self.vfs(self.fname, mode)
122 except IOError as err:
123 if err.errno != errno.ENOENT:
124 raise
125 raise error.Abort(_(b"shelved change '%s' not found") % self.name)
126
121
127 def applybundle(self, tr):
122 def applybundle(self, tr):
128 fp = self.opener()
123 fp = self.opener()
129 try:
124 try:
130 targetphase = phases.internal
125 targetphase = phases.internal
131 if not phases.supportinternal(self.repo):
126 if not phases.supportinternal(self.repo):
132 targetphase = phases.secret
127 targetphase = phases.secret
133 gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs)
128 gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs)
134 pretip = self.repo[b'tip']
129 pretip = self.repo[b'tip']
135 bundle2.applybundle(
130 bundle2.applybundle(
136 self.repo,
131 self.repo,
137 gen,
132 gen,
138 tr,
133 tr,
139 source=b'unshelve',
134 source=b'unshelve',
140 url=b'bundle:' + self.vfs.join(self.fname),
135 url=b'bundle:' + self.vfs.join(self.fname),
141 targetphase=targetphase,
136 targetphase=targetphase,
142 )
137 )
143 shelvectx = self.repo[b'tip']
138 shelvectx = self.repo[b'tip']
144 if pretip == shelvectx:
139 if pretip == shelvectx:
145 shelverev = tr.changes[b'revduplicates'][-1]
140 shelverev = tr.changes[b'revduplicates'][-1]
146 shelvectx = self.repo[shelverev]
141 shelvectx = self.repo[shelverev]
147 return shelvectx
142 return shelvectx
148 finally:
143 finally:
149 fp.close()
144 fp.close()
150
145
151 def writebundle(self, bases, node):
146 def writebundle(self, bases, node):
152 cgversion = changegroup.safeversion(self.repo)
147 cgversion = changegroup.safeversion(self.repo)
153 if cgversion == b'01':
148 if cgversion == b'01':
154 btype = b'HG10BZ'
149 btype = b'HG10BZ'
155 compression = None
150 compression = None
156 else:
151 else:
157 btype = b'HG20'
152 btype = b'HG20'
158 compression = b'BZ'
153 compression = b'BZ'
159
154
160 repo = self.repo.unfiltered()
155 repo = self.repo.unfiltered()
161
156
162 outgoing = discovery.outgoing(
157 outgoing = discovery.outgoing(
163 repo, missingroots=bases, ancestorsof=[node]
158 repo, missingroots=bases, ancestorsof=[node]
164 )
159 )
165 cg = changegroup.makechangegroup(repo, outgoing, cgversion, b'shelve')
160 cg = changegroup.makechangegroup(repo, outgoing, cgversion, b'shelve')
166
161
167 bundle2.writebundle(
162 bundle2.writebundle(
168 self.ui, cg, self.fname, btype, self.vfs, compression=compression
163 self.ui, cg, self.fname, btype, self.vfs, compression=compression
169 )
164 )
170
165
171 def writeinfo(self, info):
166 def writeinfo(self, info):
172 scmutil.simplekeyvaluefile(self.vfs, self.fname).write(info)
167 scmutil.simplekeyvaluefile(self.vfs, self.fname).write(info)
173
168
174 def readinfo(self):
169 def readinfo(self):
175 return scmutil.simplekeyvaluefile(self.vfs, self.fname).read()
170 return scmutil.simplekeyvaluefile(self.vfs, self.fname).read()
176
171
177
172
178 class shelvedstate(object):
173 class shelvedstate(object):
179 """Handle persistence during unshelving operations.
174 """Handle persistence during unshelving operations.
180
175
181 Handles saving and restoring a shelved state. Ensures that different
176 Handles saving and restoring a shelved state. Ensures that different
182 versions of a shelved state are possible and handles them appropriately.
177 versions of a shelved state are possible and handles them appropriately.
183 """
178 """
184
179
185 _version = 2
180 _version = 2
186 _filename = b'shelvedstate'
181 _filename = b'shelvedstate'
187 _keep = b'keep'
182 _keep = b'keep'
188 _nokeep = b'nokeep'
183 _nokeep = b'nokeep'
189 # colon is essential to differentiate from a real bookmark name
184 # colon is essential to differentiate from a real bookmark name
190 _noactivebook = b':no-active-bookmark'
185 _noactivebook = b':no-active-bookmark'
191 _interactive = b'interactive'
186 _interactive = b'interactive'
192
187
193 @classmethod
188 @classmethod
194 def _verifyandtransform(cls, d):
189 def _verifyandtransform(cls, d):
195 """Some basic shelvestate syntactic verification and transformation"""
190 """Some basic shelvestate syntactic verification and transformation"""
196 try:
191 try:
197 d[b'originalwctx'] = bin(d[b'originalwctx'])
192 d[b'originalwctx'] = bin(d[b'originalwctx'])
198 d[b'pendingctx'] = bin(d[b'pendingctx'])
193 d[b'pendingctx'] = bin(d[b'pendingctx'])
199 d[b'parents'] = [bin(h) for h in d[b'parents'].split(b' ')]
194 d[b'parents'] = [bin(h) for h in d[b'parents'].split(b' ')]
200 d[b'nodestoremove'] = [
195 d[b'nodestoremove'] = [
201 bin(h) for h in d[b'nodestoremove'].split(b' ')
196 bin(h) for h in d[b'nodestoremove'].split(b' ')
202 ]
197 ]
203 except (ValueError, TypeError, KeyError) as err:
198 except (ValueError, TypeError, KeyError) as err:
204 raise error.CorruptedState(pycompat.bytestr(err))
199 raise error.CorruptedState(pycompat.bytestr(err))
205
200
206 @classmethod
201 @classmethod
207 def _getversion(cls, repo):
202 def _getversion(cls, repo):
208 """Read version information from shelvestate file"""
203 """Read version information from shelvestate file"""
209 fp = repo.vfs(cls._filename)
204 fp = repo.vfs(cls._filename)
210 try:
205 try:
211 version = int(fp.readline().strip())
206 version = int(fp.readline().strip())
212 except ValueError as err:
207 except ValueError as err:
213 raise error.CorruptedState(pycompat.bytestr(err))
208 raise error.CorruptedState(pycompat.bytestr(err))
214 finally:
209 finally:
215 fp.close()
210 fp.close()
216 return version
211 return version
217
212
218 @classmethod
213 @classmethod
219 def _readold(cls, repo):
214 def _readold(cls, repo):
220 """Read the old position-based version of a shelvestate file"""
215 """Read the old position-based version of a shelvestate file"""
221 # Order is important, because old shelvestate file uses it
216 # Order is important, because old shelvestate file uses it
222 # to detemine values of fields (i.g. name is on the second line,
217 # to detemine values of fields (i.g. name is on the second line,
223 # originalwctx is on the third and so forth). Please do not change.
218 # originalwctx is on the third and so forth). Please do not change.
224 keys = [
219 keys = [
225 b'version',
220 b'version',
226 b'name',
221 b'name',
227 b'originalwctx',
222 b'originalwctx',
228 b'pendingctx',
223 b'pendingctx',
229 b'parents',
224 b'parents',
230 b'nodestoremove',
225 b'nodestoremove',
231 b'branchtorestore',
226 b'branchtorestore',
232 b'keep',
227 b'keep',
233 b'activebook',
228 b'activebook',
234 ]
229 ]
235 # this is executed only seldomly, so it is not a big deal
230 # this is executed only seldomly, so it is not a big deal
236 # that we open this file twice
231 # that we open this file twice
237 fp = repo.vfs(cls._filename)
232 fp = repo.vfs(cls._filename)
238 d = {}
233 d = {}
239 try:
234 try:
240 for key in keys:
235 for key in keys:
241 d[key] = fp.readline().strip()
236 d[key] = fp.readline().strip()
242 finally:
237 finally:
243 fp.close()
238 fp.close()
244 return d
239 return d
245
240
246 @classmethod
241 @classmethod
247 def load(cls, repo):
242 def load(cls, repo):
248 version = cls._getversion(repo)
243 version = cls._getversion(repo)
249 if version < cls._version:
244 if version < cls._version:
250 d = cls._readold(repo)
245 d = cls._readold(repo)
251 elif version == cls._version:
246 elif version == cls._version:
252 d = scmutil.simplekeyvaluefile(repo.vfs, cls._filename).read(
247 d = scmutil.simplekeyvaluefile(repo.vfs, cls._filename).read(
253 firstlinenonkeyval=True
248 firstlinenonkeyval=True
254 )
249 )
255 else:
250 else:
256 raise error.Abort(
251 raise error.Abort(
257 _(
252 _(
258 b'this version of shelve is incompatible '
253 b'this version of shelve is incompatible '
259 b'with the version used in this repo'
254 b'with the version used in this repo'
260 )
255 )
261 )
256 )
262
257
263 cls._verifyandtransform(d)
258 cls._verifyandtransform(d)
264 try:
259 try:
265 obj = cls()
260 obj = cls()
266 obj.name = d[b'name']
261 obj.name = d[b'name']
267 obj.wctx = repo[d[b'originalwctx']]
262 obj.wctx = repo[d[b'originalwctx']]
268 obj.pendingctx = repo[d[b'pendingctx']]
263 obj.pendingctx = repo[d[b'pendingctx']]
269 obj.parents = d[b'parents']
264 obj.parents = d[b'parents']
270 obj.nodestoremove = d[b'nodestoremove']
265 obj.nodestoremove = d[b'nodestoremove']
271 obj.branchtorestore = d.get(b'branchtorestore', b'')
266 obj.branchtorestore = d.get(b'branchtorestore', b'')
272 obj.keep = d.get(b'keep') == cls._keep
267 obj.keep = d.get(b'keep') == cls._keep
273 obj.activebookmark = b''
268 obj.activebookmark = b''
274 if d.get(b'activebook', b'') != cls._noactivebook:
269 if d.get(b'activebook', b'') != cls._noactivebook:
275 obj.activebookmark = d.get(b'activebook', b'')
270 obj.activebookmark = d.get(b'activebook', b'')
276 obj.interactive = d.get(b'interactive') == cls._interactive
271 obj.interactive = d.get(b'interactive') == cls._interactive
277 except (error.RepoLookupError, KeyError) as err:
272 except (error.RepoLookupError, KeyError) as err:
278 raise error.CorruptedState(pycompat.bytestr(err))
273 raise error.CorruptedState(pycompat.bytestr(err))
279
274
280 return obj
275 return obj
281
276
282 @classmethod
277 @classmethod
283 def save(
278 def save(
284 cls,
279 cls,
285 repo,
280 repo,
286 name,
281 name,
287 originalwctx,
282 originalwctx,
288 pendingctx,
283 pendingctx,
289 nodestoremove,
284 nodestoremove,
290 branchtorestore,
285 branchtorestore,
291 keep=False,
286 keep=False,
292 activebook=b'',
287 activebook=b'',
293 interactive=False,
288 interactive=False,
294 ):
289 ):
295 info = {
290 info = {
296 b"name": name,
291 b"name": name,
297 b"originalwctx": hex(originalwctx.node()),
292 b"originalwctx": hex(originalwctx.node()),
298 b"pendingctx": hex(pendingctx.node()),
293 b"pendingctx": hex(pendingctx.node()),
299 b"parents": b' '.join([hex(p) for p in repo.dirstate.parents()]),
294 b"parents": b' '.join([hex(p) for p in repo.dirstate.parents()]),
300 b"nodestoremove": b' '.join([hex(n) for n in nodestoremove]),
295 b"nodestoremove": b' '.join([hex(n) for n in nodestoremove]),
301 b"branchtorestore": branchtorestore,
296 b"branchtorestore": branchtorestore,
302 b"keep": cls._keep if keep else cls._nokeep,
297 b"keep": cls._keep if keep else cls._nokeep,
303 b"activebook": activebook or cls._noactivebook,
298 b"activebook": activebook or cls._noactivebook,
304 }
299 }
305 if interactive:
300 if interactive:
306 info[b'interactive'] = cls._interactive
301 info[b'interactive'] = cls._interactive
307 scmutil.simplekeyvaluefile(repo.vfs, cls._filename).write(
302 scmutil.simplekeyvaluefile(repo.vfs, cls._filename).write(
308 info, firstline=(b"%d" % cls._version)
303 info, firstline=(b"%d" % cls._version)
309 )
304 )
310
305
311 @classmethod
306 @classmethod
312 def clear(cls, repo):
307 def clear(cls, repo):
313 repo.vfs.unlinkpath(cls._filename, ignoremissing=True)
308 repo.vfs.unlinkpath(cls._filename, ignoremissing=True)
314
309
315
310
316 def cleanupoldbackups(repo):
311 def cleanupoldbackups(repo):
317 vfs = vfsmod.vfs(repo.vfs.join(backupdir))
312 vfs = vfsmod.vfs(repo.vfs.join(backupdir))
318 maxbackups = repo.ui.configint(b'shelve', b'maxbackups')
313 maxbackups = repo.ui.configint(b'shelve', b'maxbackups')
319 hgfiles = [f for f in vfs.listdir() if f.endswith(b'.' + patchextension)]
314 hgfiles = [f for f in vfs.listdir() if f.endswith(b'.' + patchextension)]
320 hgfiles = sorted([(vfs.stat(f)[stat.ST_MTIME], f) for f in hgfiles])
315 hgfiles = sorted([(vfs.stat(f)[stat.ST_MTIME], f) for f in hgfiles])
321 if maxbackups > 0 and maxbackups < len(hgfiles):
316 if maxbackups > 0 and maxbackups < len(hgfiles):
322 bordermtime = hgfiles[-maxbackups][0]
317 bordermtime = hgfiles[-maxbackups][0]
323 else:
318 else:
324 bordermtime = None
319 bordermtime = None
325 for mtime, f in hgfiles[: len(hgfiles) - maxbackups]:
320 for mtime, f in hgfiles[: len(hgfiles) - maxbackups]:
326 if mtime == bordermtime:
321 if mtime == bordermtime:
327 # keep it, because timestamp can't decide exact order of backups
322 # keep it, because timestamp can't decide exact order of backups
328 continue
323 continue
329 base = f[: -(1 + len(patchextension))]
324 base = f[: -(1 + len(patchextension))]
330 for ext in shelvefileextensions:
325 for ext in shelvefileextensions:
331 vfs.tryunlink(base + b'.' + ext)
326 vfs.tryunlink(base + b'.' + ext)
332
327
333
328
334 def _backupactivebookmark(repo):
329 def _backupactivebookmark(repo):
335 activebookmark = repo._activebookmark
330 activebookmark = repo._activebookmark
336 if activebookmark:
331 if activebookmark:
337 bookmarks.deactivate(repo)
332 bookmarks.deactivate(repo)
338 return activebookmark
333 return activebookmark
339
334
340
335
341 def _restoreactivebookmark(repo, mark):
336 def _restoreactivebookmark(repo, mark):
342 if mark:
337 if mark:
343 bookmarks.activate(repo, mark)
338 bookmarks.activate(repo, mark)
344
339
345
340
346 def _aborttransaction(repo, tr):
341 def _aborttransaction(repo, tr):
347 """Abort current transaction for shelve/unshelve, but keep dirstate"""
342 """Abort current transaction for shelve/unshelve, but keep dirstate"""
348 dirstatebackupname = b'dirstate.shelve'
343 dirstatebackupname = b'dirstate.shelve'
349 repo.dirstate.savebackup(tr, dirstatebackupname)
344 repo.dirstate.savebackup(tr, dirstatebackupname)
350 tr.abort()
345 tr.abort()
351 repo.dirstate.restorebackup(None, dirstatebackupname)
346 repo.dirstate.restorebackup(None, dirstatebackupname)
352
347
353
348
354 def getshelvename(repo, parent, opts):
349 def getshelvename(repo, parent, opts):
355 """Decide on the name this shelve is going to have"""
350 """Decide on the name this shelve is going to have"""
356
351
357 def gennames():
352 def gennames():
358 yield label
353 yield label
359 for i in itertools.count(1):
354 for i in itertools.count(1):
360 yield b'%s-%02d' % (label, i)
355 yield b'%s-%02d' % (label, i)
361
356
362 name = opts.get(b'name')
357 name = opts.get(b'name')
363 label = repo._activebookmark or parent.branch() or b'default'
358 label = repo._activebookmark or parent.branch() or b'default'
364 # slashes aren't allowed in filenames, therefore we rename it
359 # slashes aren't allowed in filenames, therefore we rename it
365 label = label.replace(b'/', b'_')
360 label = label.replace(b'/', b'_')
366 label = label.replace(b'\\', b'_')
361 label = label.replace(b'\\', b'_')
367 # filenames must not start with '.' as it should not be hidden
362 # filenames must not start with '.' as it should not be hidden
368 if label.startswith(b'.'):
363 if label.startswith(b'.'):
369 label = label.replace(b'.', b'_', 1)
364 label = label.replace(b'.', b'_', 1)
370
365
371 if name:
366 if name:
372 if shelvedfile(repo, name, patchextension).exists():
367 if shelvedfile(repo, name, patchextension).exists():
373 e = _(b"a shelved change named '%s' already exists") % name
368 e = _(b"a shelved change named '%s' already exists") % name
374 raise error.Abort(e)
369 raise error.Abort(e)
375
370
376 # ensure we are not creating a subdirectory or a hidden file
371 # ensure we are not creating a subdirectory or a hidden file
377 if b'/' in name or b'\\' in name:
372 if b'/' in name or b'\\' in name:
378 raise error.Abort(
373 raise error.Abort(
379 _(b'shelved change names can not contain slashes')
374 _(b'shelved change names can not contain slashes')
380 )
375 )
381 if name.startswith(b'.'):
376 if name.startswith(b'.'):
382 raise error.Abort(_(b"shelved change names can not start with '.'"))
377 raise error.Abort(_(b"shelved change names can not start with '.'"))
383
378
384 else:
379 else:
385 for n in gennames():
380 for n in gennames():
386 if not shelvedfile(repo, n, patchextension).exists():
381 if not shelvedfile(repo, n, patchextension).exists():
387 name = n
382 name = n
388 break
383 break
389
384
390 return name
385 return name
391
386
392
387
393 def mutableancestors(ctx):
388 def mutableancestors(ctx):
394 """return all mutable ancestors for ctx (included)
389 """return all mutable ancestors for ctx (included)
395
390
396 Much faster than the revset ancestors(ctx) & draft()"""
391 Much faster than the revset ancestors(ctx) & draft()"""
397 seen = {nullrev}
392 seen = {nullrev}
398 visit = collections.deque()
393 visit = collections.deque()
399 visit.append(ctx)
394 visit.append(ctx)
400 while visit:
395 while visit:
401 ctx = visit.popleft()
396 ctx = visit.popleft()
402 yield ctx.node()
397 yield ctx.node()
403 for parent in ctx.parents():
398 for parent in ctx.parents():
404 rev = parent.rev()
399 rev = parent.rev()
405 if rev not in seen:
400 if rev not in seen:
406 seen.add(rev)
401 seen.add(rev)
407 if parent.mutable():
402 if parent.mutable():
408 visit.append(parent)
403 visit.append(parent)
409
404
410
405
411 def getcommitfunc(extra, interactive, editor=False):
406 def getcommitfunc(extra, interactive, editor=False):
412 def commitfunc(ui, repo, message, match, opts):
407 def commitfunc(ui, repo, message, match, opts):
413 hasmq = util.safehasattr(repo, b'mq')
408 hasmq = util.safehasattr(repo, b'mq')
414 if hasmq:
409 if hasmq:
415 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
410 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
416
411
417 targetphase = phases.internal
412 targetphase = phases.internal
418 if not phases.supportinternal(repo):
413 if not phases.supportinternal(repo):
419 targetphase = phases.secret
414 targetphase = phases.secret
420 overrides = {(b'phases', b'new-commit'): targetphase}
415 overrides = {(b'phases', b'new-commit'): targetphase}
421 try:
416 try:
422 editor_ = False
417 editor_ = False
423 if editor:
418 if editor:
424 editor_ = cmdutil.getcommiteditor(
419 editor_ = cmdutil.getcommiteditor(
425 editform=b'shelve.shelve', **pycompat.strkwargs(opts)
420 editform=b'shelve.shelve', **pycompat.strkwargs(opts)
426 )
421 )
427 with repo.ui.configoverride(overrides):
422 with repo.ui.configoverride(overrides):
428 return repo.commit(
423 return repo.commit(
429 message,
424 message,
430 shelveuser,
425 shelveuser,
431 opts.get(b'date'),
426 opts.get(b'date'),
432 match,
427 match,
433 editor=editor_,
428 editor=editor_,
434 extra=extra,
429 extra=extra,
435 )
430 )
436 finally:
431 finally:
437 if hasmq:
432 if hasmq:
438 repo.mq.checkapplied = saved
433 repo.mq.checkapplied = saved
439
434
440 def interactivecommitfunc(ui, repo, *pats, **opts):
435 def interactivecommitfunc(ui, repo, *pats, **opts):
441 opts = pycompat.byteskwargs(opts)
436 opts = pycompat.byteskwargs(opts)
442 match = scmutil.match(repo[b'.'], pats, {})
437 match = scmutil.match(repo[b'.'], pats, {})
443 message = opts[b'message']
438 message = opts[b'message']
444 return commitfunc(ui, repo, message, match, opts)
439 return commitfunc(ui, repo, message, match, opts)
445
440
446 return interactivecommitfunc if interactive else commitfunc
441 return interactivecommitfunc if interactive else commitfunc
447
442
448
443
449 def _nothingtoshelvemessaging(ui, repo, pats, opts):
444 def _nothingtoshelvemessaging(ui, repo, pats, opts):
450 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
445 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
451 if stat.deleted:
446 if stat.deleted:
452 ui.status(
447 ui.status(
453 _(b"nothing changed (%d missing files, see 'hg status')\n")
448 _(b"nothing changed (%d missing files, see 'hg status')\n")
454 % len(stat.deleted)
449 % len(stat.deleted)
455 )
450 )
456 else:
451 else:
457 ui.status(_(b"nothing changed\n"))
452 ui.status(_(b"nothing changed\n"))
458
453
459
454
460 def _shelvecreatedcommit(repo, node, name, match):
455 def _shelvecreatedcommit(repo, node, name, match):
461 info = {b'node': hex(node)}
456 info = {b'node': hex(node)}
462 shelvedfile(repo, name, b'shelve').writeinfo(info)
457 shelvedfile(repo, name, b'shelve').writeinfo(info)
463 bases = list(mutableancestors(repo[node]))
458 bases = list(mutableancestors(repo[node]))
464 shelvedfile(repo, name, b'hg').writebundle(bases, node)
459 shelvedfile(repo, name, b'hg').writebundle(bases, node)
465 with shelvedfile(repo, name, patchextension).opener(b'wb') as fp:
460 with shelvedfile(repo, name, patchextension).opener(b'wb') as fp:
466 cmdutil.exportfile(
461 cmdutil.exportfile(
467 repo, [node], fp, opts=mdiff.diffopts(git=True), match=match
462 repo, [node], fp, opts=mdiff.diffopts(git=True), match=match
468 )
463 )
469
464
470
465
471 def _includeunknownfiles(repo, pats, opts, extra):
466 def _includeunknownfiles(repo, pats, opts, extra):
472 s = repo.status(match=scmutil.match(repo[None], pats, opts), unknown=True)
467 s = repo.status(match=scmutil.match(repo[None], pats, opts), unknown=True)
473 if s.unknown:
468 if s.unknown:
474 extra[b'shelve_unknown'] = b'\0'.join(s.unknown)
469 extra[b'shelve_unknown'] = b'\0'.join(s.unknown)
475 repo[None].add(s.unknown)
470 repo[None].add(s.unknown)
476
471
477
472
478 def _finishshelve(repo, tr):
473 def _finishshelve(repo, tr):
479 if phases.supportinternal(repo):
474 if phases.supportinternal(repo):
480 tr.close()
475 tr.close()
481 else:
476 else:
482 _aborttransaction(repo, tr)
477 _aborttransaction(repo, tr)
483
478
484
479
485 def createcmd(ui, repo, pats, opts):
480 def createcmd(ui, repo, pats, opts):
486 """subcommand that creates a new shelve"""
481 """subcommand that creates a new shelve"""
487 with repo.wlock():
482 with repo.wlock():
488 cmdutil.checkunfinished(repo)
483 cmdutil.checkunfinished(repo)
489 return _docreatecmd(ui, repo, pats, opts)
484 return _docreatecmd(ui, repo, pats, opts)
490
485
491
486
492 def _docreatecmd(ui, repo, pats, opts):
487 def _docreatecmd(ui, repo, pats, opts):
493 wctx = repo[None]
488 wctx = repo[None]
494 parents = wctx.parents()
489 parents = wctx.parents()
495 parent = parents[0]
490 parent = parents[0]
496 origbranch = wctx.branch()
491 origbranch = wctx.branch()
497
492
498 if parent.node() != nullid:
493 if parent.node() != nullid:
499 desc = b"changes to: %s" % parent.description().split(b'\n', 1)[0]
494 desc = b"changes to: %s" % parent.description().split(b'\n', 1)[0]
500 else:
495 else:
501 desc = b'(changes in empty repository)'
496 desc = b'(changes in empty repository)'
502
497
503 if not opts.get(b'message'):
498 if not opts.get(b'message'):
504 opts[b'message'] = desc
499 opts[b'message'] = desc
505
500
506 lock = tr = activebookmark = None
501 lock = tr = activebookmark = None
507 try:
502 try:
508 lock = repo.lock()
503 lock = repo.lock()
509
504
510 # use an uncommitted transaction to generate the bundle to avoid
505 # use an uncommitted transaction to generate the bundle to avoid
511 # pull races. ensure we don't print the abort message to stderr.
506 # pull races. ensure we don't print the abort message to stderr.
512 tr = repo.transaction(b'shelve', report=lambda x: None)
507 tr = repo.transaction(b'shelve', report=lambda x: None)
513
508
514 interactive = opts.get(b'interactive', False)
509 interactive = opts.get(b'interactive', False)
515 includeunknown = opts.get(b'unknown', False) and not opts.get(
510 includeunknown = opts.get(b'unknown', False) and not opts.get(
516 b'addremove', False
511 b'addremove', False
517 )
512 )
518
513
519 name = getshelvename(repo, parent, opts)
514 name = getshelvename(repo, parent, opts)
520 activebookmark = _backupactivebookmark(repo)
515 activebookmark = _backupactivebookmark(repo)
521 extra = {b'internal': b'shelve'}
516 extra = {b'internal': b'shelve'}
522 if includeunknown:
517 if includeunknown:
523 _includeunknownfiles(repo, pats, opts, extra)
518 _includeunknownfiles(repo, pats, opts, extra)
524
519
525 if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts):
520 if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts):
526 # In non-bare shelve we don't store newly created branch
521 # In non-bare shelve we don't store newly created branch
527 # at bundled commit
522 # at bundled commit
528 repo.dirstate.setbranch(repo[b'.'].branch())
523 repo.dirstate.setbranch(repo[b'.'].branch())
529
524
530 commitfunc = getcommitfunc(extra, interactive, editor=True)
525 commitfunc = getcommitfunc(extra, interactive, editor=True)
531 if not interactive:
526 if not interactive:
532 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
527 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
533 else:
528 else:
534 node = cmdutil.dorecord(
529 node = cmdutil.dorecord(
535 ui,
530 ui,
536 repo,
531 repo,
537 commitfunc,
532 commitfunc,
538 None,
533 None,
539 False,
534 False,
540 cmdutil.recordfilter,
535 cmdutil.recordfilter,
541 *pats,
536 *pats,
542 **pycompat.strkwargs(opts)
537 **pycompat.strkwargs(opts)
543 )
538 )
544 if not node:
539 if not node:
545 _nothingtoshelvemessaging(ui, repo, pats, opts)
540 _nothingtoshelvemessaging(ui, repo, pats, opts)
546 return 1
541 return 1
547
542
548 # Create a matcher so that prefetch doesn't attempt to fetch
543 # Create a matcher so that prefetch doesn't attempt to fetch
549 # the entire repository pointlessly, and as an optimisation
544 # the entire repository pointlessly, and as an optimisation
550 # for movedirstate, if needed.
545 # for movedirstate, if needed.
551 match = scmutil.matchfiles(repo, repo[node].files())
546 match = scmutil.matchfiles(repo, repo[node].files())
552 _shelvecreatedcommit(repo, node, name, match)
547 _shelvecreatedcommit(repo, node, name, match)
553
548
554 ui.status(_(b'shelved as %s\n') % name)
549 ui.status(_(b'shelved as %s\n') % name)
555 if opts[b'keep']:
550 if opts[b'keep']:
556 with repo.dirstate.parentchange():
551 with repo.dirstate.parentchange():
557 scmutil.movedirstate(repo, parent, match)
552 scmutil.movedirstate(repo, parent, match)
558 else:
553 else:
559 hg.update(repo, parent.node())
554 hg.update(repo, parent.node())
560 ms = mergestatemod.mergestate.read(repo)
555 ms = mergestatemod.mergestate.read(repo)
561 if not ms.unresolvedcount():
556 if not ms.unresolvedcount():
562 ms.reset()
557 ms.reset()
563
558
564 if origbranch != repo[b'.'].branch() and not _isbareshelve(pats, opts):
559 if origbranch != repo[b'.'].branch() and not _isbareshelve(pats, opts):
565 repo.dirstate.setbranch(origbranch)
560 repo.dirstate.setbranch(origbranch)
566
561
567 _finishshelve(repo, tr)
562 _finishshelve(repo, tr)
568 finally:
563 finally:
569 _restoreactivebookmark(repo, activebookmark)
564 _restoreactivebookmark(repo, activebookmark)
570 lockmod.release(tr, lock)
565 lockmod.release(tr, lock)
571
566
572
567
573 def _isbareshelve(pats, opts):
568 def _isbareshelve(pats, opts):
574 return (
569 return (
575 not pats
570 not pats
576 and not opts.get(b'interactive', False)
571 and not opts.get(b'interactive', False)
577 and not opts.get(b'include', False)
572 and not opts.get(b'include', False)
578 and not opts.get(b'exclude', False)
573 and not opts.get(b'exclude', False)
579 )
574 )
580
575
581
576
582 def _iswctxonnewbranch(repo):
577 def _iswctxonnewbranch(repo):
583 return repo[None].branch() != repo[b'.'].branch()
578 return repo[None].branch() != repo[b'.'].branch()
584
579
585
580
586 def cleanupcmd(ui, repo):
581 def cleanupcmd(ui, repo):
587 """subcommand that deletes all shelves"""
582 """subcommand that deletes all shelves"""
588
583
589 with repo.wlock():
584 with repo.wlock():
590 for (name, _type) in repo.vfs.readdir(shelvedir):
585 for (name, _type) in repo.vfs.readdir(shelvedir):
591 suffix = name.rsplit(b'.', 1)[-1]
586 suffix = name.rsplit(b'.', 1)[-1]
592 if suffix in shelvefileextensions:
587 if suffix in shelvefileextensions:
593 shelvedfile(repo, name).movetobackup()
588 shelvedfile(repo, name).movetobackup()
594 cleanupoldbackups(repo)
589 cleanupoldbackups(repo)
595
590
596
591
597 def deletecmd(ui, repo, pats):
592 def deletecmd(ui, repo, pats):
598 """subcommand that deletes a specific shelve"""
593 """subcommand that deletes a specific shelve"""
599 if not pats:
594 if not pats:
600 raise error.Abort(_(b'no shelved changes specified!'))
595 raise error.Abort(_(b'no shelved changes specified!'))
601 with repo.wlock():
596 with repo.wlock():
602 for name in pats:
597 for name in pats:
603 if not shelvedfile(repo, name, patchextension).exists():
598 if not shelvedfile(repo, name, patchextension).exists():
604 raise error.Abort(_(b"shelved change '%s' not found") % name)
599 raise error.Abort(_(b"shelved change '%s' not found") % name)
605 for suffix in shelvefileextensions:
600 for suffix in shelvefileextensions:
606 shfile = shelvedfile(repo, name, suffix)
601 shfile = shelvedfile(repo, name, suffix)
607 if shfile.exists():
602 if shfile.exists():
608 shfile.movetobackup()
603 shfile.movetobackup()
609 cleanupoldbackups(repo)
604 cleanupoldbackups(repo)
610
605
611
606
612 def listshelves(repo):
607 def listshelves(repo):
613 """return all shelves in repo as list of (time, filename)"""
608 """return all shelves in repo as list of (time, filename)"""
614 try:
609 try:
615 names = repo.vfs.readdir(shelvedir)
610 names = repo.vfs.readdir(shelvedir)
616 except OSError as err:
611 except OSError as err:
617 if err.errno != errno.ENOENT:
612 if err.errno != errno.ENOENT:
618 raise
613 raise
619 return []
614 return []
620 info = []
615 info = []
621 for (name, _type) in names:
616 for (name, _type) in names:
622 pfx, sfx = name.rsplit(b'.', 1)
617 pfx, sfx = name.rsplit(b'.', 1)
623 if not pfx or sfx != patchextension:
618 if not pfx or sfx != patchextension:
624 continue
619 continue
625 st = shelvedfile(repo, name).stat()
620 st = shelvedfile(repo, name).stat()
626 info.append((st[stat.ST_MTIME], shelvedfile(repo, pfx).filename()))
621 info.append((st[stat.ST_MTIME], shelvedfile(repo, pfx).filename()))
627 return sorted(info, reverse=True)
622 return sorted(info, reverse=True)
628
623
629
624
630 def listcmd(ui, repo, pats, opts):
625 def listcmd(ui, repo, pats, opts):
631 """subcommand that displays the list of shelves"""
626 """subcommand that displays the list of shelves"""
632 pats = set(pats)
627 pats = set(pats)
633 width = 80
628 width = 80
634 if not ui.plain():
629 if not ui.plain():
635 width = ui.termwidth()
630 width = ui.termwidth()
636 namelabel = b'shelve.newest'
631 namelabel = b'shelve.newest'
637 ui.pager(b'shelve')
632 ui.pager(b'shelve')
638 for mtime, name in listshelves(repo):
633 for mtime, name in listshelves(repo):
639 sname = util.split(name)[1]
634 sname = util.split(name)[1]
640 if pats and sname not in pats:
635 if pats and sname not in pats:
641 continue
636 continue
642 ui.write(sname, label=namelabel)
637 ui.write(sname, label=namelabel)
643 namelabel = b'shelve.name'
638 namelabel = b'shelve.name'
644 if ui.quiet:
639 if ui.quiet:
645 ui.write(b'\n')
640 ui.write(b'\n')
646 continue
641 continue
647 ui.write(b' ' * (16 - len(sname)))
642 ui.write(b' ' * (16 - len(sname)))
648 used = 16
643 used = 16
649 date = dateutil.makedate(mtime)
644 date = dateutil.makedate(mtime)
650 age = b'(%s)' % templatefilters.age(date, abbrev=True)
645 age = b'(%s)' % templatefilters.age(date, abbrev=True)
651 ui.write(age, label=b'shelve.age')
646 ui.write(age, label=b'shelve.age')
652 ui.write(b' ' * (12 - len(age)))
647 ui.write(b' ' * (12 - len(age)))
653 used += 12
648 used += 12
654 with open(name + b'.' + patchextension, b'rb') as fp:
649 with open(name + b'.' + patchextension, b'rb') as fp:
655 while True:
650 while True:
656 line = fp.readline()
651 line = fp.readline()
657 if not line:
652 if not line:
658 break
653 break
659 if not line.startswith(b'#'):
654 if not line.startswith(b'#'):
660 desc = line.rstrip()
655 desc = line.rstrip()
661 if ui.formatted():
656 if ui.formatted():
662 desc = stringutil.ellipsis(desc, width - used)
657 desc = stringutil.ellipsis(desc, width - used)
663 ui.write(desc)
658 ui.write(desc)
664 break
659 break
665 ui.write(b'\n')
660 ui.write(b'\n')
666 if not (opts[b'patch'] or opts[b'stat']):
661 if not (opts[b'patch'] or opts[b'stat']):
667 continue
662 continue
668 difflines = fp.readlines()
663 difflines = fp.readlines()
669 if opts[b'patch']:
664 if opts[b'patch']:
670 for chunk, label in patch.difflabel(iter, difflines):
665 for chunk, label in patch.difflabel(iter, difflines):
671 ui.write(chunk, label=label)
666 ui.write(chunk, label=label)
672 if opts[b'stat']:
667 if opts[b'stat']:
673 for chunk, label in patch.diffstatui(difflines, width=width):
668 for chunk, label in patch.diffstatui(difflines, width=width):
674 ui.write(chunk, label=label)
669 ui.write(chunk, label=label)
675
670
676
671
677 def patchcmds(ui, repo, pats, opts):
672 def patchcmds(ui, repo, pats, opts):
678 """subcommand that displays shelves"""
673 """subcommand that displays shelves"""
679 if len(pats) == 0:
674 if len(pats) == 0:
680 shelves = listshelves(repo)
675 shelves = listshelves(repo)
681 if not shelves:
676 if not shelves:
682 raise error.Abort(_(b"there are no shelves to show"))
677 raise error.Abort(_(b"there are no shelves to show"))
683 mtime, name = shelves[0]
678 mtime, name = shelves[0]
684 sname = util.split(name)[1]
679 sname = util.split(name)[1]
685 pats = [sname]
680 pats = [sname]
686
681
687 for shelfname in pats:
682 for shelfname in pats:
688 if not shelvedfile(repo, shelfname, patchextension).exists():
683 if not shelvedfile(repo, shelfname, patchextension).exists():
689 raise error.Abort(_(b"cannot find shelf %s") % shelfname)
684 raise error.Abort(_(b"cannot find shelf %s") % shelfname)
690
685
691 listcmd(ui, repo, pats, opts)
686 listcmd(ui, repo, pats, opts)
692
687
693
688
694 def checkparents(repo, state):
689 def checkparents(repo, state):
695 """check parent while resuming an unshelve"""
690 """check parent while resuming an unshelve"""
696 if state.parents != repo.dirstate.parents():
691 if state.parents != repo.dirstate.parents():
697 raise error.Abort(
692 raise error.Abort(
698 _(b'working directory parents do not match unshelve state')
693 _(b'working directory parents do not match unshelve state')
699 )
694 )
700
695
701
696
702 def _loadshelvedstate(ui, repo, opts):
697 def _loadshelvedstate(ui, repo, opts):
703 try:
698 try:
704 state = shelvedstate.load(repo)
699 state = shelvedstate.load(repo)
705 if opts.get(b'keep') is None:
700 if opts.get(b'keep') is None:
706 opts[b'keep'] = state.keep
701 opts[b'keep'] = state.keep
707 except IOError as err:
702 except IOError as err:
708 if err.errno != errno.ENOENT:
703 if err.errno != errno.ENOENT:
709 raise
704 raise
710 cmdutil.wrongtooltocontinue(repo, _(b'unshelve'))
705 cmdutil.wrongtooltocontinue(repo, _(b'unshelve'))
711 except error.CorruptedState as err:
706 except error.CorruptedState as err:
712 ui.debug(pycompat.bytestr(err) + b'\n')
707 ui.debug(pycompat.bytestr(err) + b'\n')
713 if opts.get(b'continue'):
708 if opts.get(b'continue'):
714 msg = _(b'corrupted shelved state file')
709 msg = _(b'corrupted shelved state file')
715 hint = _(
710 hint = _(
716 b'please run hg unshelve --abort to abort unshelve '
711 b'please run hg unshelve --abort to abort unshelve '
717 b'operation'
712 b'operation'
718 )
713 )
719 raise error.Abort(msg, hint=hint)
714 raise error.Abort(msg, hint=hint)
720 elif opts.get(b'abort'):
715 elif opts.get(b'abort'):
721 shelvedstate.clear(repo)
716 shelvedstate.clear(repo)
722 raise error.Abort(
717 raise error.Abort(
723 _(
718 _(
724 b'could not read shelved state file, your '
719 b'could not read shelved state file, your '
725 b'working copy may be in an unexpected state\n'
720 b'working copy may be in an unexpected state\n'
726 b'please update to some commit\n'
721 b'please update to some commit\n'
727 )
722 )
728 )
723 )
729 return state
724 return state
730
725
731
726
732 def unshelveabort(ui, repo, state):
727 def unshelveabort(ui, repo, state):
733 """subcommand that abort an in-progress unshelve"""
728 """subcommand that abort an in-progress unshelve"""
734 with repo.lock():
729 with repo.lock():
735 try:
730 try:
736 checkparents(repo, state)
731 checkparents(repo, state)
737
732
738 merge.clean_update(state.pendingctx)
733 merge.clean_update(state.pendingctx)
739 if state.activebookmark and state.activebookmark in repo._bookmarks:
734 if state.activebookmark and state.activebookmark in repo._bookmarks:
740 bookmarks.activate(repo, state.activebookmark)
735 bookmarks.activate(repo, state.activebookmark)
741 mergefiles(ui, repo, state.wctx, state.pendingctx)
736 mergefiles(ui, repo, state.wctx, state.pendingctx)
742 if not phases.supportinternal(repo):
737 if not phases.supportinternal(repo):
743 repair.strip(
738 repair.strip(
744 ui, repo, state.nodestoremove, backup=False, topic=b'shelve'
739 ui, repo, state.nodestoremove, backup=False, topic=b'shelve'
745 )
740 )
746 finally:
741 finally:
747 shelvedstate.clear(repo)
742 shelvedstate.clear(repo)
748 ui.warn(_(b"unshelve of '%s' aborted\n") % state.name)
743 ui.warn(_(b"unshelve of '%s' aborted\n") % state.name)
749
744
750
745
751 def hgabortunshelve(ui, repo):
746 def hgabortunshelve(ui, repo):
752 """logic to abort unshelve using 'hg abort"""
747 """logic to abort unshelve using 'hg abort"""
753 with repo.wlock():
748 with repo.wlock():
754 state = _loadshelvedstate(ui, repo, {b'abort': True})
749 state = _loadshelvedstate(ui, repo, {b'abort': True})
755 return unshelveabort(ui, repo, state)
750 return unshelveabort(ui, repo, state)
756
751
757
752
758 def mergefiles(ui, repo, wctx, shelvectx):
753 def mergefiles(ui, repo, wctx, shelvectx):
759 """updates to wctx and merges the changes from shelvectx into the
754 """updates to wctx and merges the changes from shelvectx into the
760 dirstate."""
755 dirstate."""
761 with ui.configoverride({(b'ui', b'quiet'): True}):
756 with ui.configoverride({(b'ui', b'quiet'): True}):
762 hg.update(repo, wctx.node())
757 hg.update(repo, wctx.node())
763 ui.pushbuffer(True)
758 ui.pushbuffer(True)
764 cmdutil.revert(ui, repo, shelvectx)
759 cmdutil.revert(ui, repo, shelvectx)
765 ui.popbuffer()
760 ui.popbuffer()
766
761
767
762
768 def restorebranch(ui, repo, branchtorestore):
763 def restorebranch(ui, repo, branchtorestore):
769 if branchtorestore and branchtorestore != repo.dirstate.branch():
764 if branchtorestore and branchtorestore != repo.dirstate.branch():
770 repo.dirstate.setbranch(branchtorestore)
765 repo.dirstate.setbranch(branchtorestore)
771 ui.status(
766 ui.status(
772 _(b'marked working directory as branch %s\n') % branchtorestore
767 _(b'marked working directory as branch %s\n') % branchtorestore
773 )
768 )
774
769
775
770
776 def unshelvecleanup(ui, repo, name, opts):
771 def unshelvecleanup(ui, repo, name, opts):
777 """remove related files after an unshelve"""
772 """remove related files after an unshelve"""
778 if not opts.get(b'keep'):
773 if not opts.get(b'keep'):
779 for filetype in shelvefileextensions:
774 for filetype in shelvefileextensions:
780 shfile = shelvedfile(repo, name, filetype)
775 shfile = shelvedfile(repo, name, filetype)
781 if shfile.exists():
776 if shfile.exists():
782 shfile.movetobackup()
777 shfile.movetobackup()
783 cleanupoldbackups(repo)
778 cleanupoldbackups(repo)
784
779
785
780
786 def unshelvecontinue(ui, repo, state, opts):
781 def unshelvecontinue(ui, repo, state, opts):
787 """subcommand to continue an in-progress unshelve"""
782 """subcommand to continue an in-progress unshelve"""
788 # We're finishing off a merge. First parent is our original
783 # We're finishing off a merge. First parent is our original
789 # parent, second is the temporary "fake" commit we're unshelving.
784 # parent, second is the temporary "fake" commit we're unshelving.
790 interactive = state.interactive
785 interactive = state.interactive
791 basename = state.name
786 basename = state.name
792 with repo.lock():
787 with repo.lock():
793 checkparents(repo, state)
788 checkparents(repo, state)
794 ms = mergestatemod.mergestate.read(repo)
789 ms = mergestatemod.mergestate.read(repo)
795 if list(ms.unresolved()):
790 if list(ms.unresolved()):
796 raise error.Abort(
791 raise error.Abort(
797 _(b"unresolved conflicts, can't continue"),
792 _(b"unresolved conflicts, can't continue"),
798 hint=_(b"see 'hg resolve', then 'hg unshelve --continue'"),
793 hint=_(b"see 'hg resolve', then 'hg unshelve --continue'"),
799 )
794 )
800
795
801 shelvectx = repo[state.parents[1]]
796 shelvectx = repo[state.parents[1]]
802 pendingctx = state.pendingctx
797 pendingctx = state.pendingctx
803
798
804 with repo.dirstate.parentchange():
799 with repo.dirstate.parentchange():
805 repo.setparents(state.pendingctx.node(), nullid)
800 repo.setparents(state.pendingctx.node(), nullid)
806 repo.dirstate.write(repo.currenttransaction())
801 repo.dirstate.write(repo.currenttransaction())
807
802
808 targetphase = phases.internal
803 targetphase = phases.internal
809 if not phases.supportinternal(repo):
804 if not phases.supportinternal(repo):
810 targetphase = phases.secret
805 targetphase = phases.secret
811 overrides = {(b'phases', b'new-commit'): targetphase}
806 overrides = {(b'phases', b'new-commit'): targetphase}
812 with repo.ui.configoverride(overrides, b'unshelve'):
807 with repo.ui.configoverride(overrides, b'unshelve'):
813 with repo.dirstate.parentchange():
808 with repo.dirstate.parentchange():
814 repo.setparents(state.parents[0], nullid)
809 repo.setparents(state.parents[0], nullid)
815 newnode, ispartialunshelve = _createunshelvectx(
810 newnode, ispartialunshelve = _createunshelvectx(
816 ui, repo, shelvectx, basename, interactive, opts
811 ui, repo, shelvectx, basename, interactive, opts
817 )
812 )
818
813
819 if newnode is None:
814 if newnode is None:
820 shelvectx = state.pendingctx
815 shelvectx = state.pendingctx
821 msg = _(
816 msg = _(
822 b'note: unshelved changes already existed '
817 b'note: unshelved changes already existed '
823 b'in the working copy\n'
818 b'in the working copy\n'
824 )
819 )
825 ui.status(msg)
820 ui.status(msg)
826 else:
821 else:
827 # only strip the shelvectx if we produced one
822 # only strip the shelvectx if we produced one
828 state.nodestoremove.append(newnode)
823 state.nodestoremove.append(newnode)
829 shelvectx = repo[newnode]
824 shelvectx = repo[newnode]
830
825
831 merge.update(pendingctx)
826 merge.update(pendingctx)
832 mergefiles(ui, repo, state.wctx, shelvectx)
827 mergefiles(ui, repo, state.wctx, shelvectx)
833 restorebranch(ui, repo, state.branchtorestore)
828 restorebranch(ui, repo, state.branchtorestore)
834
829
835 if not phases.supportinternal(repo):
830 if not phases.supportinternal(repo):
836 repair.strip(
831 repair.strip(
837 ui, repo, state.nodestoremove, backup=False, topic=b'shelve'
832 ui, repo, state.nodestoremove, backup=False, topic=b'shelve'
838 )
833 )
839 shelvedstate.clear(repo)
834 shelvedstate.clear(repo)
840 if not ispartialunshelve:
835 if not ispartialunshelve:
841 unshelvecleanup(ui, repo, state.name, opts)
836 unshelvecleanup(ui, repo, state.name, opts)
842 _restoreactivebookmark(repo, state.activebookmark)
837 _restoreactivebookmark(repo, state.activebookmark)
843 ui.status(_(b"unshelve of '%s' complete\n") % state.name)
838 ui.status(_(b"unshelve of '%s' complete\n") % state.name)
844
839
845
840
846 def hgcontinueunshelve(ui, repo):
841 def hgcontinueunshelve(ui, repo):
847 """logic to resume unshelve using 'hg continue'"""
842 """logic to resume unshelve using 'hg continue'"""
848 with repo.wlock():
843 with repo.wlock():
849 state = _loadshelvedstate(ui, repo, {b'continue': True})
844 state = _loadshelvedstate(ui, repo, {b'continue': True})
850 return unshelvecontinue(ui, repo, state, {b'keep': state.keep})
845 return unshelvecontinue(ui, repo, state, {b'keep': state.keep})
851
846
852
847
853 def _commitworkingcopychanges(ui, repo, opts, tmpwctx):
848 def _commitworkingcopychanges(ui, repo, opts, tmpwctx):
854 """Temporarily commit working copy changes before moving unshelve commit"""
849 """Temporarily commit working copy changes before moving unshelve commit"""
855 # Store pending changes in a commit and remember added in case a shelve
850 # Store pending changes in a commit and remember added in case a shelve
856 # contains unknown files that are part of the pending change
851 # contains unknown files that are part of the pending change
857 s = repo.status()
852 s = repo.status()
858 addedbefore = frozenset(s.added)
853 addedbefore = frozenset(s.added)
859 if not (s.modified or s.added or s.removed):
854 if not (s.modified or s.added or s.removed):
860 return tmpwctx, addedbefore
855 return tmpwctx, addedbefore
861 ui.status(
856 ui.status(
862 _(
857 _(
863 b"temporarily committing pending changes "
858 b"temporarily committing pending changes "
864 b"(restore with 'hg unshelve --abort')\n"
859 b"(restore with 'hg unshelve --abort')\n"
865 )
860 )
866 )
861 )
867 extra = {b'internal': b'shelve'}
862 extra = {b'internal': b'shelve'}
868 commitfunc = getcommitfunc(extra=extra, interactive=False, editor=False)
863 commitfunc = getcommitfunc(extra=extra, interactive=False, editor=False)
869 tempopts = {}
864 tempopts = {}
870 tempopts[b'message'] = b"pending changes temporary commit"
865 tempopts[b'message'] = b"pending changes temporary commit"
871 tempopts[b'date'] = opts.get(b'date')
866 tempopts[b'date'] = opts.get(b'date')
872 with ui.configoverride({(b'ui', b'quiet'): True}):
867 with ui.configoverride({(b'ui', b'quiet'): True}):
873 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
868 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
874 tmpwctx = repo[node]
869 tmpwctx = repo[node]
875 return tmpwctx, addedbefore
870 return tmpwctx, addedbefore
876
871
877
872
878 def _unshelverestorecommit(ui, repo, tr, basename):
873 def _unshelverestorecommit(ui, repo, tr, basename):
879 """Recreate commit in the repository during the unshelve"""
874 """Recreate commit in the repository during the unshelve"""
880 repo = repo.unfiltered()
875 repo = repo.unfiltered()
881 node = None
876 node = None
882 if shelvedfile(repo, basename, b'shelve').exists():
877 if shelvedfile(repo, basename, b'shelve').exists():
883 node = shelvedfile(repo, basename, b'shelve').readinfo()[b'node']
878 node = shelvedfile(repo, basename, b'shelve').readinfo()[b'node']
884 if node is None or node not in repo:
879 if node is None or node not in repo:
885 with ui.configoverride({(b'ui', b'quiet'): True}):
880 with ui.configoverride({(b'ui', b'quiet'): True}):
886 shelvectx = shelvedfile(repo, basename, b'hg').applybundle(tr)
881 shelvectx = shelvedfile(repo, basename, b'hg').applybundle(tr)
887 # We might not strip the unbundled changeset, so we should keep track of
882 # We might not strip the unbundled changeset, so we should keep track of
888 # the unshelve node in case we need to reuse it (eg: unshelve --keep)
883 # the unshelve node in case we need to reuse it (eg: unshelve --keep)
889 if node is None:
884 if node is None:
890 info = {b'node': hex(shelvectx.node())}
885 info = {b'node': hex(shelvectx.node())}
891 shelvedfile(repo, basename, b'shelve').writeinfo(info)
886 shelvedfile(repo, basename, b'shelve').writeinfo(info)
892 else:
887 else:
893 shelvectx = repo[node]
888 shelvectx = repo[node]
894
889
895 return repo, shelvectx
890 return repo, shelvectx
896
891
897
892
898 def _createunshelvectx(ui, repo, shelvectx, basename, interactive, opts):
893 def _createunshelvectx(ui, repo, shelvectx, basename, interactive, opts):
899 """Handles the creation of unshelve commit and updates the shelve if it
894 """Handles the creation of unshelve commit and updates the shelve if it
900 was partially unshelved.
895 was partially unshelved.
901
896
902 If interactive is:
897 If interactive is:
903
898
904 * False: Commits all the changes in the working directory.
899 * False: Commits all the changes in the working directory.
905 * True: Prompts the user to select changes to unshelve and commit them.
900 * True: Prompts the user to select changes to unshelve and commit them.
906 Update the shelve with remaining changes.
901 Update the shelve with remaining changes.
907
902
908 Returns the node of the new commit formed and a bool indicating whether
903 Returns the node of the new commit formed and a bool indicating whether
909 the shelve was partially unshelved.Creates a commit ctx to unshelve
904 the shelve was partially unshelved.Creates a commit ctx to unshelve
910 interactively or non-interactively.
905 interactively or non-interactively.
911
906
912 The user might want to unshelve certain changes only from the stored
907 The user might want to unshelve certain changes only from the stored
913 shelve in interactive. So, we would create two commits. One with requested
908 shelve in interactive. So, we would create two commits. One with requested
914 changes to unshelve at that time and the latter is shelved for future.
909 changes to unshelve at that time and the latter is shelved for future.
915
910
916 Here, we return both the newnode which is created interactively and a
911 Here, we return both the newnode which is created interactively and a
917 bool to know whether the shelve is partly done or completely done.
912 bool to know whether the shelve is partly done or completely done.
918 """
913 """
919 opts[b'message'] = shelvectx.description()
914 opts[b'message'] = shelvectx.description()
920 opts[b'interactive-unshelve'] = True
915 opts[b'interactive-unshelve'] = True
921 pats = []
916 pats = []
922 if not interactive:
917 if not interactive:
923 newnode = repo.commit(
918 newnode = repo.commit(
924 text=shelvectx.description(),
919 text=shelvectx.description(),
925 extra=shelvectx.extra(),
920 extra=shelvectx.extra(),
926 user=shelvectx.user(),
921 user=shelvectx.user(),
927 date=shelvectx.date(),
922 date=shelvectx.date(),
928 )
923 )
929 return newnode, False
924 return newnode, False
930
925
931 commitfunc = getcommitfunc(shelvectx.extra(), interactive=True, editor=True)
926 commitfunc = getcommitfunc(shelvectx.extra(), interactive=True, editor=True)
932 newnode = cmdutil.dorecord(
927 newnode = cmdutil.dorecord(
933 ui,
928 ui,
934 repo,
929 repo,
935 commitfunc,
930 commitfunc,
936 None,
931 None,
937 False,
932 False,
938 cmdutil.recordfilter,
933 cmdutil.recordfilter,
939 *pats,
934 *pats,
940 **pycompat.strkwargs(opts)
935 **pycompat.strkwargs(opts)
941 )
936 )
942 snode = repo.commit(
937 snode = repo.commit(
943 text=shelvectx.description(),
938 text=shelvectx.description(),
944 extra=shelvectx.extra(),
939 extra=shelvectx.extra(),
945 user=shelvectx.user(),
940 user=shelvectx.user(),
946 )
941 )
947 if snode:
942 if snode:
948 m = scmutil.matchfiles(repo, repo[snode].files())
943 m = scmutil.matchfiles(repo, repo[snode].files())
949 _shelvecreatedcommit(repo, snode, basename, m)
944 _shelvecreatedcommit(repo, snode, basename, m)
950
945
951 return newnode, bool(snode)
946 return newnode, bool(snode)
952
947
953
948
954 def _rebaserestoredcommit(
949 def _rebaserestoredcommit(
955 ui,
950 ui,
956 repo,
951 repo,
957 opts,
952 opts,
958 tr,
953 tr,
959 oldtiprev,
954 oldtiprev,
960 basename,
955 basename,
961 pctx,
956 pctx,
962 tmpwctx,
957 tmpwctx,
963 shelvectx,
958 shelvectx,
964 branchtorestore,
959 branchtorestore,
965 activebookmark,
960 activebookmark,
966 ):
961 ):
967 """Rebase restored commit from its original location to a destination"""
962 """Rebase restored commit from its original location to a destination"""
968 # If the shelve is not immediately on top of the commit
963 # If the shelve is not immediately on top of the commit
969 # we'll be merging with, rebase it to be on top.
964 # we'll be merging with, rebase it to be on top.
970 interactive = opts.get(b'interactive')
965 interactive = opts.get(b'interactive')
971 if tmpwctx.node() == shelvectx.p1().node() and not interactive:
966 if tmpwctx.node() == shelvectx.p1().node() and not interactive:
972 # We won't skip on interactive mode because, the user might want to
967 # We won't skip on interactive mode because, the user might want to
973 # unshelve certain changes only.
968 # unshelve certain changes only.
974 return shelvectx, False
969 return shelvectx, False
975
970
976 overrides = {
971 overrides = {
977 (b'ui', b'forcemerge'): opts.get(b'tool', b''),
972 (b'ui', b'forcemerge'): opts.get(b'tool', b''),
978 (b'phases', b'new-commit'): phases.secret,
973 (b'phases', b'new-commit'): phases.secret,
979 }
974 }
980 with repo.ui.configoverride(overrides, b'unshelve'):
975 with repo.ui.configoverride(overrides, b'unshelve'):
981 ui.status(_(b'rebasing shelved changes\n'))
976 ui.status(_(b'rebasing shelved changes\n'))
982 stats = merge.graft(
977 stats = merge.graft(
983 repo,
978 repo,
984 shelvectx,
979 shelvectx,
985 labels=[b'working-copy', b'shelve'],
980 labels=[b'working-copy', b'shelve'],
986 keepconflictparent=True,
981 keepconflictparent=True,
987 )
982 )
988 if stats.unresolvedcount:
983 if stats.unresolvedcount:
989 tr.close()
984 tr.close()
990
985
991 nodestoremove = [
986 nodestoremove = [
992 repo.changelog.node(rev)
987 repo.changelog.node(rev)
993 for rev in pycompat.xrange(oldtiprev, len(repo))
988 for rev in pycompat.xrange(oldtiprev, len(repo))
994 ]
989 ]
995 shelvedstate.save(
990 shelvedstate.save(
996 repo,
991 repo,
997 basename,
992 basename,
998 pctx,
993 pctx,
999 tmpwctx,
994 tmpwctx,
1000 nodestoremove,
995 nodestoremove,
1001 branchtorestore,
996 branchtorestore,
1002 opts.get(b'keep'),
997 opts.get(b'keep'),
1003 activebookmark,
998 activebookmark,
1004 interactive,
999 interactive,
1005 )
1000 )
1006 raise error.ConflictResolutionRequired(b'unshelve')
1001 raise error.ConflictResolutionRequired(b'unshelve')
1007
1002
1008 with repo.dirstate.parentchange():
1003 with repo.dirstate.parentchange():
1009 repo.setparents(tmpwctx.node(), nullid)
1004 repo.setparents(tmpwctx.node(), nullid)
1010 newnode, ispartialunshelve = _createunshelvectx(
1005 newnode, ispartialunshelve = _createunshelvectx(
1011 ui, repo, shelvectx, basename, interactive, opts
1006 ui, repo, shelvectx, basename, interactive, opts
1012 )
1007 )
1013
1008
1014 if newnode is None:
1009 if newnode is None:
1015 shelvectx = tmpwctx
1010 shelvectx = tmpwctx
1016 msg = _(
1011 msg = _(
1017 b'note: unshelved changes already existed '
1012 b'note: unshelved changes already existed '
1018 b'in the working copy\n'
1013 b'in the working copy\n'
1019 )
1014 )
1020 ui.status(msg)
1015 ui.status(msg)
1021 else:
1016 else:
1022 shelvectx = repo[newnode]
1017 shelvectx = repo[newnode]
1023 merge.update(tmpwctx)
1018 merge.update(tmpwctx)
1024
1019
1025 return shelvectx, ispartialunshelve
1020 return shelvectx, ispartialunshelve
1026
1021
1027
1022
1028 def _forgetunknownfiles(repo, shelvectx, addedbefore):
1023 def _forgetunknownfiles(repo, shelvectx, addedbefore):
1029 # Forget any files that were unknown before the shelve, unknown before
1024 # Forget any files that were unknown before the shelve, unknown before
1030 # unshelve started, but are now added.
1025 # unshelve started, but are now added.
1031 shelveunknown = shelvectx.extra().get(b'shelve_unknown')
1026 shelveunknown = shelvectx.extra().get(b'shelve_unknown')
1032 if not shelveunknown:
1027 if not shelveunknown:
1033 return
1028 return
1034 shelveunknown = frozenset(shelveunknown.split(b'\0'))
1029 shelveunknown = frozenset(shelveunknown.split(b'\0'))
1035 addedafter = frozenset(repo.status().added)
1030 addedafter = frozenset(repo.status().added)
1036 toforget = (addedafter & shelveunknown) - addedbefore
1031 toforget = (addedafter & shelveunknown) - addedbefore
1037 repo[None].forget(toforget)
1032 repo[None].forget(toforget)
1038
1033
1039
1034
1040 def _finishunshelve(repo, oldtiprev, tr, activebookmark):
1035 def _finishunshelve(repo, oldtiprev, tr, activebookmark):
1041 _restoreactivebookmark(repo, activebookmark)
1036 _restoreactivebookmark(repo, activebookmark)
1042 # The transaction aborting will strip all the commits for us,
1037 # The transaction aborting will strip all the commits for us,
1043 # but it doesn't update the inmemory structures, so addchangegroup
1038 # but it doesn't update the inmemory structures, so addchangegroup
1044 # hooks still fire and try to operate on the missing commits.
1039 # hooks still fire and try to operate on the missing commits.
1045 # Clean up manually to prevent this.
1040 # Clean up manually to prevent this.
1046 repo.unfiltered().changelog.strip(oldtiprev, tr)
1041 repo.unfiltered().changelog.strip(oldtiprev, tr)
1047 _aborttransaction(repo, tr)
1042 _aborttransaction(repo, tr)
1048
1043
1049
1044
1050 def _checkunshelveuntrackedproblems(ui, repo, shelvectx):
1045 def _checkunshelveuntrackedproblems(ui, repo, shelvectx):
1051 """Check potential problems which may result from working
1046 """Check potential problems which may result from working
1052 copy having untracked changes."""
1047 copy having untracked changes."""
1053 wcdeleted = set(repo.status().deleted)
1048 wcdeleted = set(repo.status().deleted)
1054 shelvetouched = set(shelvectx.files())
1049 shelvetouched = set(shelvectx.files())
1055 intersection = wcdeleted.intersection(shelvetouched)
1050 intersection = wcdeleted.intersection(shelvetouched)
1056 if intersection:
1051 if intersection:
1057 m = _(b"shelved change touches missing files")
1052 m = _(b"shelved change touches missing files")
1058 hint = _(b"run hg status to see which files are missing")
1053 hint = _(b"run hg status to see which files are missing")
1059 raise error.Abort(m, hint=hint)
1054 raise error.Abort(m, hint=hint)
1060
1055
1061
1056
1062 def unshelvecmd(ui, repo, *shelved, **opts):
1057 def unshelvecmd(ui, repo, *shelved, **opts):
1063 opts = pycompat.byteskwargs(opts)
1058 opts = pycompat.byteskwargs(opts)
1064 abortf = opts.get(b'abort')
1059 abortf = opts.get(b'abort')
1065 continuef = opts.get(b'continue')
1060 continuef = opts.get(b'continue')
1066 interactive = opts.get(b'interactive')
1061 interactive = opts.get(b'interactive')
1067 if not abortf and not continuef:
1062 if not abortf and not continuef:
1068 cmdutil.checkunfinished(repo)
1063 cmdutil.checkunfinished(repo)
1069 shelved = list(shelved)
1064 shelved = list(shelved)
1070 if opts.get(b"name"):
1065 if opts.get(b"name"):
1071 shelved.append(opts[b"name"])
1066 shelved.append(opts[b"name"])
1072
1067
1073 if interactive and opts.get(b'keep'):
1068 if interactive and opts.get(b'keep'):
1074 raise error.Abort(_(b'--keep on --interactive is not yet supported'))
1069 raise error.Abort(_(b'--keep on --interactive is not yet supported'))
1075 if abortf or continuef:
1070 if abortf or continuef:
1076 if abortf and continuef:
1071 if abortf and continuef:
1077 raise error.Abort(_(b'cannot use both abort and continue'))
1072 raise error.Abort(_(b'cannot use both abort and continue'))
1078 if shelved:
1073 if shelved:
1079 raise error.Abort(
1074 raise error.Abort(
1080 _(
1075 _(
1081 b'cannot combine abort/continue with '
1076 b'cannot combine abort/continue with '
1082 b'naming a shelved change'
1077 b'naming a shelved change'
1083 )
1078 )
1084 )
1079 )
1085 if abortf and opts.get(b'tool', False):
1080 if abortf and opts.get(b'tool', False):
1086 ui.warn(_(b'tool option will be ignored\n'))
1081 ui.warn(_(b'tool option will be ignored\n'))
1087
1082
1088 state = _loadshelvedstate(ui, repo, opts)
1083 state = _loadshelvedstate(ui, repo, opts)
1089 if abortf:
1084 if abortf:
1090 return unshelveabort(ui, repo, state)
1085 return unshelveabort(ui, repo, state)
1091 elif continuef and interactive:
1086 elif continuef and interactive:
1092 raise error.Abort(_(b'cannot use both continue and interactive'))
1087 raise error.Abort(_(b'cannot use both continue and interactive'))
1093 elif continuef:
1088 elif continuef:
1094 return unshelvecontinue(ui, repo, state, opts)
1089 return unshelvecontinue(ui, repo, state, opts)
1095 elif len(shelved) > 1:
1090 elif len(shelved) > 1:
1096 raise error.Abort(_(b'can only unshelve one change at a time'))
1091 raise error.Abort(_(b'can only unshelve one change at a time'))
1097 elif not shelved:
1092 elif not shelved:
1098 shelved = listshelves(repo)
1093 shelved = listshelves(repo)
1099 if not shelved:
1094 if not shelved:
1100 raise error.Abort(_(b'no shelved changes to apply!'))
1095 raise error.Abort(_(b'no shelved changes to apply!'))
1101 basename = util.split(shelved[0][1])[1]
1096 basename = util.split(shelved[0][1])[1]
1102 ui.status(_(b"unshelving change '%s'\n") % basename)
1097 ui.status(_(b"unshelving change '%s'\n") % basename)
1103 else:
1098 else:
1104 basename = shelved[0]
1099 basename = shelved[0]
1105
1100
1106 if not shelvedfile(repo, basename, patchextension).exists():
1101 if not shelvedfile(repo, basename, patchextension).exists():
1107 raise error.Abort(_(b"shelved change '%s' not found") % basename)
1102 raise error.Abort(_(b"shelved change '%s' not found") % basename)
1108
1103
1109 return _dounshelve(ui, repo, basename, opts)
1104 return _dounshelve(ui, repo, basename, opts)
1110
1105
1111
1106
1112 def _dounshelve(ui, repo, basename, opts):
1107 def _dounshelve(ui, repo, basename, opts):
1113 repo = repo.unfiltered()
1108 repo = repo.unfiltered()
1114 lock = tr = None
1109 lock = tr = None
1115 try:
1110 try:
1116 lock = repo.lock()
1111 lock = repo.lock()
1117 tr = repo.transaction(b'unshelve', report=lambda x: None)
1112 tr = repo.transaction(b'unshelve', report=lambda x: None)
1118 oldtiprev = len(repo)
1113 oldtiprev = len(repo)
1119
1114
1120 pctx = repo[b'.']
1115 pctx = repo[b'.']
1121 tmpwctx = pctx
1116 tmpwctx = pctx
1122 # The goal is to have a commit structure like so:
1117 # The goal is to have a commit structure like so:
1123 # ...-> pctx -> tmpwctx -> shelvectx
1118 # ...-> pctx -> tmpwctx -> shelvectx
1124 # where tmpwctx is an optional commit with the user's pending changes
1119 # where tmpwctx is an optional commit with the user's pending changes
1125 # and shelvectx is the unshelved changes. Then we merge it all down
1120 # and shelvectx is the unshelved changes. Then we merge it all down
1126 # to the original pctx.
1121 # to the original pctx.
1127
1122
1128 activebookmark = _backupactivebookmark(repo)
1123 activebookmark = _backupactivebookmark(repo)
1129 tmpwctx, addedbefore = _commitworkingcopychanges(
1124 tmpwctx, addedbefore = _commitworkingcopychanges(
1130 ui, repo, opts, tmpwctx
1125 ui, repo, opts, tmpwctx
1131 )
1126 )
1132 repo, shelvectx = _unshelverestorecommit(ui, repo, tr, basename)
1127 repo, shelvectx = _unshelverestorecommit(ui, repo, tr, basename)
1133 _checkunshelveuntrackedproblems(ui, repo, shelvectx)
1128 _checkunshelveuntrackedproblems(ui, repo, shelvectx)
1134 branchtorestore = b''
1129 branchtorestore = b''
1135 if shelvectx.branch() != shelvectx.p1().branch():
1130 if shelvectx.branch() != shelvectx.p1().branch():
1136 branchtorestore = shelvectx.branch()
1131 branchtorestore = shelvectx.branch()
1137
1132
1138 shelvectx, ispartialunshelve = _rebaserestoredcommit(
1133 shelvectx, ispartialunshelve = _rebaserestoredcommit(
1139 ui,
1134 ui,
1140 repo,
1135 repo,
1141 opts,
1136 opts,
1142 tr,
1137 tr,
1143 oldtiprev,
1138 oldtiprev,
1144 basename,
1139 basename,
1145 pctx,
1140 pctx,
1146 tmpwctx,
1141 tmpwctx,
1147 shelvectx,
1142 shelvectx,
1148 branchtorestore,
1143 branchtorestore,
1149 activebookmark,
1144 activebookmark,
1150 )
1145 )
1151 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
1146 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
1152 with ui.configoverride(overrides, b'unshelve'):
1147 with ui.configoverride(overrides, b'unshelve'):
1153 mergefiles(ui, repo, pctx, shelvectx)
1148 mergefiles(ui, repo, pctx, shelvectx)
1154 restorebranch(ui, repo, branchtorestore)
1149 restorebranch(ui, repo, branchtorestore)
1155 shelvedstate.clear(repo)
1150 shelvedstate.clear(repo)
1156 _finishunshelve(repo, oldtiprev, tr, activebookmark)
1151 _finishunshelve(repo, oldtiprev, tr, activebookmark)
1157 _forgetunknownfiles(repo, shelvectx, addedbefore)
1152 _forgetunknownfiles(repo, shelvectx, addedbefore)
1158 if not ispartialunshelve:
1153 if not ispartialunshelve:
1159 unshelvecleanup(ui, repo, basename, opts)
1154 unshelvecleanup(ui, repo, basename, opts)
1160 finally:
1155 finally:
1161 if tr:
1156 if tr:
1162 tr.release()
1157 tr.release()
1163 lockmod.release(lock)
1158 lockmod.release(lock)
@@ -1,997 +1,997 b''
1 #testcases stripbased phasebased
1 #testcases stripbased phasebased
2 #testcases abortflag abortcommand
2 #testcases abortflag abortcommand
3 #testcases continueflag continuecommand
3 #testcases continueflag continuecommand
4
4
5 $ cat <<EOF >> $HGRCPATH
5 $ cat <<EOF >> $HGRCPATH
6 > [extensions]
6 > [extensions]
7 > mq =
7 > mq =
8 > [defaults]
8 > [defaults]
9 > diff = --nodates --git
9 > diff = --nodates --git
10 > qnew = --date '0 0'
10 > qnew = --date '0 0'
11 > [shelve]
11 > [shelve]
12 > maxbackups = 2
12 > maxbackups = 2
13 > EOF
13 > EOF
14
14
15 #if phasebased
15 #if phasebased
16
16
17 $ cat <<EOF >> $HGRCPATH
17 $ cat <<EOF >> $HGRCPATH
18 > [format]
18 > [format]
19 > internal-phase = yes
19 > internal-phase = yes
20 > EOF
20 > EOF
21
21
22 #endif
22 #endif
23
23
24 #if abortflag
24 #if abortflag
25 $ cat >> $HGRCPATH <<EOF
25 $ cat >> $HGRCPATH <<EOF
26 > [alias]
26 > [alias]
27 > abort = unshelve --abort
27 > abort = unshelve --abort
28 > EOF
28 > EOF
29 #endif
29 #endif
30
30
31 #if continueflag
31 #if continueflag
32 $ cat >> $HGRCPATH <<EOF
32 $ cat >> $HGRCPATH <<EOF
33 > [alias]
33 > [alias]
34 > continue = unshelve --continue
34 > continue = unshelve --continue
35 > EOF
35 > EOF
36 #endif
36 #endif
37
37
38 shelve should leave dirstate clean (issue4055)
38 shelve should leave dirstate clean (issue4055)
39
39
40 $ hg init shelverebase
40 $ hg init shelverebase
41 $ cd shelverebase
41 $ cd shelverebase
42 $ printf 'x\ny\n' > x
42 $ printf 'x\ny\n' > x
43 $ echo z > z
43 $ echo z > z
44 $ hg commit -Aqm xy
44 $ hg commit -Aqm xy
45 $ echo z >> x
45 $ echo z >> x
46 $ hg commit -Aqm z
46 $ hg commit -Aqm z
47 $ hg up 5c4c67fb7dce
47 $ hg up 5c4c67fb7dce
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 $ printf 'a\nx\ny\nz\n' > x
49 $ printf 'a\nx\ny\nz\n' > x
50 $ hg commit -Aqm xyz
50 $ hg commit -Aqm xyz
51 $ echo c >> z
51 $ echo c >> z
52 $ hg shelve
52 $ hg shelve
53 shelved as default
53 shelved as default
54 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
54 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
55
55
56 $ hg rebase -d 6c103be8f4e4 --config extensions.rebase=
56 $ hg rebase -d 6c103be8f4e4 --config extensions.rebase=
57 rebasing 2:323bfa07f744( tip)? "xyz" (re)
57 rebasing 2:323bfa07f744( tip)? "xyz" (re)
58 merging x
58 merging x
59 saved backup bundle to \$TESTTMP/shelverebase/.hg/strip-backup/323bfa07f744-(78114325|7ae538ef)-rebase.hg (re)
59 saved backup bundle to \$TESTTMP/shelverebase/.hg/strip-backup/323bfa07f744-(78114325|7ae538ef)-rebase.hg (re)
60 $ hg unshelve
60 $ hg unshelve
61 unshelving change 'default'
61 unshelving change 'default'
62 rebasing shelved changes
62 rebasing shelved changes
63 $ hg status
63 $ hg status
64 M z
64 M z
65
65
66 $ cd ..
66 $ cd ..
67
67
68 shelve should only unshelve pending changes (issue4068)
68 shelve should only unshelve pending changes (issue4068)
69
69
70 $ hg init onlypendingchanges
70 $ hg init onlypendingchanges
71 $ cd onlypendingchanges
71 $ cd onlypendingchanges
72 $ touch a
72 $ touch a
73 $ hg ci -Aqm a
73 $ hg ci -Aqm a
74 $ touch b
74 $ touch b
75 $ hg ci -Aqm b
75 $ hg ci -Aqm b
76 $ hg up -q 3903775176ed
76 $ hg up -q 3903775176ed
77 $ touch c
77 $ touch c
78 $ hg ci -Aqm c
78 $ hg ci -Aqm c
79
79
80 $ touch d
80 $ touch d
81 $ hg add d
81 $ hg add d
82 $ hg shelve
82 $ hg shelve
83 shelved as default
83 shelved as default
84 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
84 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
85 $ hg up -q 0e067c57feba
85 $ hg up -q 0e067c57feba
86 $ hg unshelve
86 $ hg unshelve
87 unshelving change 'default'
87 unshelving change 'default'
88 rebasing shelved changes
88 rebasing shelved changes
89 $ hg status
89 $ hg status
90 A d
90 A d
91
91
92 unshelve should work on an ancestor of the original commit
92 unshelve should work on an ancestor of the original commit
93
93
94 $ hg shelve
94 $ hg shelve
95 shelved as default
95 shelved as default
96 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
96 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
97 $ hg up 3903775176ed
97 $ hg up 3903775176ed
98 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
98 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
99 $ hg unshelve
99 $ hg unshelve
100 unshelving change 'default'
100 unshelving change 'default'
101 rebasing shelved changes
101 rebasing shelved changes
102 $ hg status
102 $ hg status
103 A d
103 A d
104
104
105 test bug 4073 we need to enable obsolete markers for it
105 test bug 4073 we need to enable obsolete markers for it
106
106
107 $ cat >> $HGRCPATH << EOF
107 $ cat >> $HGRCPATH << EOF
108 > [experimental]
108 > [experimental]
109 > evolution.createmarkers=True
109 > evolution.createmarkers=True
110 > EOF
110 > EOF
111 $ hg shelve
111 $ hg shelve
112 shelved as default
112 shelved as default
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 $ hg debugobsolete `hg log -r 0e067c57feba -T '{node}'`
114 $ hg debugobsolete `hg log -r 0e067c57feba -T '{node}'`
115 1 new obsolescence markers
115 1 new obsolescence markers
116 obsoleted 1 changesets
116 obsoleted 1 changesets
117 $ hg unshelve
117 $ hg unshelve
118 unshelving change 'default'
118 unshelving change 'default'
119
119
120 unshelve should leave unknown files alone (issue4113)
120 unshelve should leave unknown files alone (issue4113)
121
121
122 $ echo e > e
122 $ echo e > e
123 $ hg shelve
123 $ hg shelve
124 shelved as default
124 shelved as default
125 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
125 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
126 $ hg status
126 $ hg status
127 ? e
127 ? e
128 $ hg unshelve
128 $ hg unshelve
129 unshelving change 'default'
129 unshelving change 'default'
130 $ hg status
130 $ hg status
131 A d
131 A d
132 ? e
132 ? e
133 $ cat e
133 $ cat e
134 e
134 e
135
135
136 unshelve should keep a copy of unknown files
136 unshelve should keep a copy of unknown files
137
137
138 $ hg add e
138 $ hg add e
139 $ hg shelve
139 $ hg shelve
140 shelved as default
140 shelved as default
141 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
141 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
142 $ echo z > e
142 $ echo z > e
143 $ hg unshelve
143 $ hg unshelve
144 unshelving change 'default'
144 unshelving change 'default'
145 $ cat e
145 $ cat e
146 e
146 e
147 $ cat e.orig
147 $ cat e.orig
148 z
148 z
149 $ rm e.orig
149 $ rm e.orig
150
150
151 restores backup of unknown file to right directory
151 restores backup of unknown file to right directory
152
152
153 $ hg shelve
153 $ hg shelve
154 shelved as default
154 shelved as default
155 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
155 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
156 $ echo z > e
156 $ echo z > e
157 $ mkdir dir
157 $ mkdir dir
158 $ hg unshelve --cwd dir
158 $ hg unshelve --cwd dir
159 unshelving change 'default'
159 unshelving change 'default'
160 $ rmdir dir
160 $ rmdir dir
161 $ cat e
161 $ cat e
162 e
162 e
163 $ cat e.orig
163 $ cat e.orig
164 z
164 z
165
165
166 unshelve and conflicts with tracked and untracked files
166 unshelve and conflicts with tracked and untracked files
167
167
168 preparing:
168 preparing:
169
169
170 $ rm -f *.orig
170 $ rm -f *.orig
171 $ hg ci -qm 'commit stuff'
171 $ hg ci -qm 'commit stuff'
172 $ hg phase -p null:
172 $ hg phase -p null:
173
173
174 no other changes - no merge:
174 no other changes - no merge:
175
175
176 $ echo f > f
176 $ echo f > f
177 $ hg add f
177 $ hg add f
178 $ hg shelve
178 $ hg shelve
179 shelved as default
179 shelved as default
180 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
180 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
181 $ echo g > f
181 $ echo g > f
182 $ hg unshelve
182 $ hg unshelve
183 unshelving change 'default'
183 unshelving change 'default'
184 $ hg st
184 $ hg st
185 A f
185 A f
186 ? f.orig
186 ? f.orig
187 $ cat f
187 $ cat f
188 f
188 f
189 $ cat f.orig
189 $ cat f.orig
190 g
190 g
191
191
192 other uncommitted changes - merge:
192 other uncommitted changes - merge:
193
193
194 $ hg st
194 $ hg st
195 A f
195 A f
196 ? f.orig
196 ? f.orig
197 $ hg shelve
197 $ hg shelve
198 shelved as default
198 shelved as default
199 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
199 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
200 #if repobundlerepo
200 #if repobundlerepo
201 $ hg log -G --template '{rev} {desc|firstline} {author}' -R bundle://.hg/shelved/default.hg -r 'bundle()' --hidden
201 $ hg log -G --template '{rev} {desc|firstline} {author}' -R bundle://.hg/shelved/default.hg -r 'bundle()' --hidden
202 o [48] changes to: commit stuff shelve@localhost (re)
202 o [48] changes to: commit stuff shelve@localhost (re)
203 |
203 |
204 ~
204 ~
205 #endif
205 #endif
206 $ hg log -G --template '{rev} {desc|firstline} {author}'
206 $ hg log -G --template '{rev} {desc|firstline} {author}'
207 @ [37] commit stuff test (re)
207 @ [37] commit stuff test (re)
208 |
208 |
209 | o 2 c test
209 | o 2 c test
210 |/
210 |/
211 o 0 a test
211 o 0 a test
212
212
213 $ mv f.orig f
213 $ mv f.orig f
214 $ echo 1 > a
214 $ echo 1 > a
215 $ hg unshelve --date '1073741824 0'
215 $ hg unshelve --date '1073741824 0'
216 unshelving change 'default'
216 unshelving change 'default'
217 temporarily committing pending changes (restore with 'hg unshelve --abort')
217 temporarily committing pending changes (restore with 'hg unshelve --abort')
218 rebasing shelved changes
218 rebasing shelved changes
219 merging f
219 merging f
220 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
220 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
221 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
221 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
222 [240]
222 [240]
223
223
224 #if phasebased
224 #if phasebased
225 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
225 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
226 @ 9 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
226 @ 9 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
227 |
227 |
228 | @ 8 changes to: commit stuff shelve@localhost 1970-01-01 00:00 +0000
228 | @ 8 changes to: commit stuff shelve@localhost 1970-01-01 00:00 +0000
229 |/
229 |/
230 o 7 commit stuff test 1970-01-01 00:00 +0000
230 o 7 commit stuff test 1970-01-01 00:00 +0000
231 |
231 |
232 | o 2 c test 1970-01-01 00:00 +0000
232 | o 2 c test 1970-01-01 00:00 +0000
233 |/
233 |/
234 o 0 a test 1970-01-01 00:00 +0000
234 o 0 a test 1970-01-01 00:00 +0000
235
235
236 #endif
236 #endif
237
237
238 #if stripbased
238 #if stripbased
239 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
239 $ hg log -G --template '{rev} {desc|firstline} {author} {date|isodate}'
240 @ 5 changes to: commit stuff shelve@localhost 1970-01-01 00:00 +0000
240 @ 5 changes to: commit stuff shelve@localhost 1970-01-01 00:00 +0000
241 |
241 |
242 | @ 4 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
242 | @ 4 pending changes temporary commit shelve@localhost 2004-01-10 13:37 +0000
243 |/
243 |/
244 o 3 commit stuff test 1970-01-01 00:00 +0000
244 o 3 commit stuff test 1970-01-01 00:00 +0000
245 |
245 |
246 | o 2 c test 1970-01-01 00:00 +0000
246 | o 2 c test 1970-01-01 00:00 +0000
247 |/
247 |/
248 o 0 a test 1970-01-01 00:00 +0000
248 o 0 a test 1970-01-01 00:00 +0000
249
249
250 #endif
250 #endif
251
251
252 $ hg st
252 $ hg st
253 M f
253 M f
254 ? f.orig
254 ? f.orig
255 $ cat f
255 $ cat f
256 <<<<<<< working-copy: d44eae5c3d33 - shelve: pending changes temporary commit
256 <<<<<<< working-copy: d44eae5c3d33 - shelve: pending changes temporary commit
257 g
257 g
258 =======
258 =======
259 f
259 f
260 >>>>>>> shelve: aef214a5229c - shelve: changes to: commit stuff
260 >>>>>>> shelve: aef214a5229c - shelve: changes to: commit stuff
261 $ cat f.orig
261 $ cat f.orig
262 g
262 g
263 $ hg unshelve --abort -t false
263 $ hg unshelve --abort -t false
264 tool option will be ignored
264 tool option will be ignored
265 unshelve of 'default' aborted
265 unshelve of 'default' aborted
266 $ hg st
266 $ hg st
267 M a
267 M a
268 ? f.orig
268 ? f.orig
269 $ cat f.orig
269 $ cat f.orig
270 g
270 g
271 $ hg unshelve
271 $ hg unshelve
272 unshelving change 'default'
272 unshelving change 'default'
273 temporarily committing pending changes (restore with 'hg unshelve --abort')
273 temporarily committing pending changes (restore with 'hg unshelve --abort')
274 rebasing shelved changes
274 rebasing shelved changes
275 $ hg st
275 $ hg st
276 M a
276 M a
277 A f
277 A f
278 ? f.orig
278 ? f.orig
279
279
280 other committed changes - merge:
280 other committed changes - merge:
281
281
282 $ hg shelve f
282 $ hg shelve f
283 shelved as default
283 shelved as default
284 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
284 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
285 $ hg ci a -m 'intermediate other change'
285 $ hg ci a -m 'intermediate other change'
286 $ mv f.orig f
286 $ mv f.orig f
287 $ hg unshelve
287 $ hg unshelve
288 unshelving change 'default'
288 unshelving change 'default'
289 rebasing shelved changes
289 rebasing shelved changes
290 merging f
290 merging f
291 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
291 warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
292 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
292 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
293 [240]
293 [240]
294 $ hg st
294 $ hg st
295 M f
295 M f
296 ? f.orig
296 ? f.orig
297 $ cat f
297 $ cat f
298 <<<<<<< working-copy: 6b563750f973 - test: intermediate other change
298 <<<<<<< working-copy: 6b563750f973 - test: intermediate other change
299 g
299 g
300 =======
300 =======
301 f
301 f
302 >>>>>>> shelve: aef214a5229c - shelve: changes to: commit stuff
302 >>>>>>> shelve: aef214a5229c - shelve: changes to: commit stuff
303 $ cat f.orig
303 $ cat f.orig
304 g
304 g
305
305
306 #if abortcommand
306 #if abortcommand
307 when in dry-run mode
307 when in dry-run mode
308 $ hg abort --dry-run
308 $ hg abort --dry-run
309 unshelve in progress, will be aborted
309 unshelve in progress, will be aborted
310 #endif
310 #endif
311
311
312 $ hg abort
312 $ hg abort
313 unshelve of 'default' aborted
313 unshelve of 'default' aborted
314 $ hg st
314 $ hg st
315 ? f.orig
315 ? f.orig
316 $ cat f.orig
316 $ cat f.orig
317 g
317 g
318 $ hg shelve --delete default
318 $ hg shelve --delete default
319 $ cd ..
319 $ cd ..
320
320
321 you shouldn't be able to ask for the patch/stats of the most recent shelve if
321 you shouldn't be able to ask for the patch/stats of the most recent shelve if
322 there are no shelves
322 there are no shelves
323
323
324 $ hg init noshelves
324 $ hg init noshelves
325 $ cd noshelves
325 $ cd noshelves
326
326
327 $ hg shelve --patch
327 $ hg shelve --patch
328 abort: there are no shelves to show
328 abort: there are no shelves to show
329 [255]
329 [255]
330 $ hg shelve --stat
330 $ hg shelve --stat
331 abort: there are no shelves to show
331 abort: there are no shelves to show
332 [255]
332 [255]
333
333
334 $ cd ..
334 $ cd ..
335
335
336 test .orig files go where the user wants them to
336 test .orig files go where the user wants them to
337 ---------------------------------------------------------------
337 ---------------------------------------------------------------
338 $ hg init salvage
338 $ hg init salvage
339 $ cd salvage
339 $ cd salvage
340 $ echo 'content' > root
340 $ echo 'content' > root
341 $ hg commit -A -m 'root' -q
341 $ hg commit -A -m 'root' -q
342 $ echo '' > root
342 $ echo '' > root
343 $ hg shelve -q
343 $ hg shelve -q
344 $ echo 'contADDent' > root
344 $ echo 'contADDent' > root
345 $ hg unshelve -q --config 'ui.origbackuppath=.hg/origbackups'
345 $ hg unshelve -q --config 'ui.origbackuppath=.hg/origbackups'
346 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
346 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
347 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
347 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
348 [240]
348 [240]
349 $ ls .hg/origbackups
349 $ ls .hg/origbackups
350 root
350 root
351 $ rm -rf .hg/origbackups
351 $ rm -rf .hg/origbackups
352
352
353 test Abort unshelve always gets user out of the unshelved state
353 test Abort unshelve always gets user out of the unshelved state
354 ---------------------------------------------------------------
354 ---------------------------------------------------------------
355
355
356 with a corrupted shelve state file
356 with a corrupted shelve state file
357 $ sed 's/ae8c668541e8/123456789012/' .hg/shelvedstate > ../corrupt-shelvedstate
357 $ sed 's/ae8c668541e8/123456789012/' .hg/shelvedstate > ../corrupt-shelvedstate
358 $ mv ../corrupt-shelvedstate .hg/shelvestate
358 $ mv ../corrupt-shelvedstate .hg/shelvestate
359 $ hg unshelve --abort 2>&1 | grep 'aborted'
359 $ hg unshelve --abort 2>&1 | grep 'aborted'
360 unshelve of 'default' aborted
360 unshelve of 'default' aborted
361 $ hg summary
361 $ hg summary
362 parent: 0:ae8c668541e8 tip
362 parent: 0:ae8c668541e8 tip
363 root
363 root
364 branch: default
364 branch: default
365 commit: 1 modified
365 commit: 1 modified
366 update: (current)
366 update: (current)
367 phases: 1 draft
367 phases: 1 draft
368 $ hg up -C .
368 $ hg up -C .
369 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
370
370
371 $ cd ..
371 $ cd ..
372
372
373 Shelve and unshelve unknown files. For the purposes of unshelve, a shelved
373 Shelve and unshelve unknown files. For the purposes of unshelve, a shelved
374 unknown file is the same as a shelved added file, except that it will be in
374 unknown file is the same as a shelved added file, except that it will be in
375 unknown state after unshelve if and only if it was either absent or unknown
375 unknown state after unshelve if and only if it was either absent or unknown
376 before the unshelve operation.
376 before the unshelve operation.
377
377
378 $ hg init unknowns
378 $ hg init unknowns
379 $ cd unknowns
379 $ cd unknowns
380
380
381 The simplest case is if I simply have an unknown file that I shelve and unshelve
381 The simplest case is if I simply have an unknown file that I shelve and unshelve
382
382
383 $ echo unknown > unknown
383 $ echo unknown > unknown
384 $ hg status
384 $ hg status
385 ? unknown
385 ? unknown
386 $ hg shelve --unknown
386 $ hg shelve --unknown
387 shelved as default
387 shelved as default
388 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
388 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
389 $ hg status
389 $ hg status
390 $ hg unshelve
390 $ hg unshelve
391 unshelving change 'default'
391 unshelving change 'default'
392 $ hg status
392 $ hg status
393 ? unknown
393 ? unknown
394 $ rm unknown
394 $ rm unknown
395
395
396 If I shelve, add the file, and unshelve, does it stay added?
396 If I shelve, add the file, and unshelve, does it stay added?
397
397
398 $ echo unknown > unknown
398 $ echo unknown > unknown
399 $ hg shelve -u
399 $ hg shelve -u
400 shelved as default
400 shelved as default
401 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
401 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
402 $ hg status
402 $ hg status
403 $ touch unknown
403 $ touch unknown
404 $ hg add unknown
404 $ hg add unknown
405 $ hg status
405 $ hg status
406 A unknown
406 A unknown
407 $ hg unshelve
407 $ hg unshelve
408 unshelving change 'default'
408 unshelving change 'default'
409 temporarily committing pending changes (restore with 'hg unshelve --abort')
409 temporarily committing pending changes (restore with 'hg unshelve --abort')
410 rebasing shelved changes
410 rebasing shelved changes
411 merging unknown
411 merging unknown
412 $ hg status
412 $ hg status
413 A unknown
413 A unknown
414 $ hg forget unknown
414 $ hg forget unknown
415 $ rm unknown
415 $ rm unknown
416
416
417 And if I shelve, commit, then unshelve, does it become modified?
417 And if I shelve, commit, then unshelve, does it become modified?
418
418
419 $ echo unknown > unknown
419 $ echo unknown > unknown
420 $ hg shelve -u
420 $ hg shelve -u
421 shelved as default
421 shelved as default
422 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
422 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
423 $ hg status
423 $ hg status
424 $ touch unknown
424 $ touch unknown
425 $ hg add unknown
425 $ hg add unknown
426 $ hg commit -qm "Add unknown"
426 $ hg commit -qm "Add unknown"
427 $ hg status
427 $ hg status
428 $ hg unshelve
428 $ hg unshelve
429 unshelving change 'default'
429 unshelving change 'default'
430 rebasing shelved changes
430 rebasing shelved changes
431 merging unknown
431 merging unknown
432 $ hg status
432 $ hg status
433 M unknown
433 M unknown
434 $ hg remove --force unknown
434 $ hg remove --force unknown
435 $ hg commit -qm "Remove unknown"
435 $ hg commit -qm "Remove unknown"
436
436
437 $ cd ..
437 $ cd ..
438
438
439 We expects that non-bare shelve keeps newly created branch in
439 We expects that non-bare shelve keeps newly created branch in
440 working directory.
440 working directory.
441
441
442 $ hg init shelve-preserve-new-branch
442 $ hg init shelve-preserve-new-branch
443 $ cd shelve-preserve-new-branch
443 $ cd shelve-preserve-new-branch
444 $ echo "a" >> a
444 $ echo "a" >> a
445 $ hg add a
445 $ hg add a
446 $ echo "b" >> b
446 $ echo "b" >> b
447 $ hg add b
447 $ hg add b
448 $ hg commit -m "ab"
448 $ hg commit -m "ab"
449 $ echo "aa" >> a
449 $ echo "aa" >> a
450 $ echo "bb" >> b
450 $ echo "bb" >> b
451 $ hg branch new-branch
451 $ hg branch new-branch
452 marked working directory as branch new-branch
452 marked working directory as branch new-branch
453 (branches are permanent and global, did you want a bookmark?)
453 (branches are permanent and global, did you want a bookmark?)
454 $ hg status
454 $ hg status
455 M a
455 M a
456 M b
456 M b
457 $ hg branch
457 $ hg branch
458 new-branch
458 new-branch
459 $ hg shelve a
459 $ hg shelve a
460 shelved as default
460 shelved as default
461 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
461 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 $ hg branch
462 $ hg branch
463 new-branch
463 new-branch
464 $ hg status
464 $ hg status
465 M b
465 M b
466 $ touch "c" >> c
466 $ touch "c" >> c
467 $ hg add c
467 $ hg add c
468 $ hg status
468 $ hg status
469 M b
469 M b
470 A c
470 A c
471 $ hg shelve --exclude c
471 $ hg shelve --exclude c
472 shelved as default-01
472 shelved as default-01
473 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
473 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
474 $ hg branch
474 $ hg branch
475 new-branch
475 new-branch
476 $ hg status
476 $ hg status
477 A c
477 A c
478 $ hg shelve --include c
478 $ hg shelve --include c
479 shelved as default-02
479 shelved as default-02
480 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
480 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
481 $ hg branch
481 $ hg branch
482 new-branch
482 new-branch
483 $ hg status
483 $ hg status
484 $ echo "d" >> d
484 $ echo "d" >> d
485 $ hg add d
485 $ hg add d
486 $ hg status
486 $ hg status
487 A d
487 A d
488
488
489 We expect that bare-shelve will not keep branch in current working directory.
489 We expect that bare-shelve will not keep branch in current working directory.
490
490
491 $ hg shelve
491 $ hg shelve
492 shelved as default-03
492 shelved as default-03
493 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
493 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
494 $ hg branch
494 $ hg branch
495 default
495 default
496 $ cd ..
496 $ cd ..
497
497
498 When i shelve commit on newly created branch i expect
498 When i shelve commit on newly created branch i expect
499 that after unshelve newly created branch will be preserved.
499 that after unshelve newly created branch will be preserved.
500
500
501 $ hg init shelve_on_new_branch_simple
501 $ hg init shelve_on_new_branch_simple
502 $ cd shelve_on_new_branch_simple
502 $ cd shelve_on_new_branch_simple
503 $ echo "aaa" >> a
503 $ echo "aaa" >> a
504 $ hg commit -A -m "a"
504 $ hg commit -A -m "a"
505 adding a
505 adding a
506 $ hg branch
506 $ hg branch
507 default
507 default
508 $ hg branch test
508 $ hg branch test
509 marked working directory as branch test
509 marked working directory as branch test
510 (branches are permanent and global, did you want a bookmark?)
510 (branches are permanent and global, did you want a bookmark?)
511 $ echo "bbb" >> a
511 $ echo "bbb" >> a
512 $ hg status
512 $ hg status
513 M a
513 M a
514 $ hg shelve
514 $ hg shelve
515 shelved as default
515 shelved as default
516 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
516 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
517 $ hg branch
517 $ hg branch
518 default
518 default
519 $ echo "bbb" >> b
519 $ echo "bbb" >> b
520 $ hg status
520 $ hg status
521 ? b
521 ? b
522 $ hg unshelve
522 $ hg unshelve
523 unshelving change 'default'
523 unshelving change 'default'
524 marked working directory as branch test
524 marked working directory as branch test
525 $ hg status
525 $ hg status
526 M a
526 M a
527 ? b
527 ? b
528 $ hg branch
528 $ hg branch
529 test
529 test
530 $ cd ..
530 $ cd ..
531
531
532 When i shelve commit on newly created branch, make
532 When i shelve commit on newly created branch, make
533 some changes, unshelve it and running into merge
533 some changes, unshelve it and running into merge
534 conflicts i expect that after fixing them and
534 conflicts i expect that after fixing them and
535 running unshelve --continue newly created branch
535 running unshelve --continue newly created branch
536 will be preserved.
536 will be preserved.
537
537
538 $ hg init shelve_on_new_branch_conflict
538 $ hg init shelve_on_new_branch_conflict
539 $ cd shelve_on_new_branch_conflict
539 $ cd shelve_on_new_branch_conflict
540 $ echo "aaa" >> a
540 $ echo "aaa" >> a
541 $ hg commit -A -m "a"
541 $ hg commit -A -m "a"
542 adding a
542 adding a
543 $ hg branch
543 $ hg branch
544 default
544 default
545 $ hg branch test
545 $ hg branch test
546 marked working directory as branch test
546 marked working directory as branch test
547 (branches are permanent and global, did you want a bookmark?)
547 (branches are permanent and global, did you want a bookmark?)
548 $ echo "bbb" >> a
548 $ echo "bbb" >> a
549 $ hg status
549 $ hg status
550 M a
550 M a
551 $ hg shelve
551 $ hg shelve
552 shelved as default
552 shelved as default
553 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
553 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
554 $ hg branch
554 $ hg branch
555 default
555 default
556 $ echo "ccc" >> a
556 $ echo "ccc" >> a
557 $ hg status
557 $ hg status
558 M a
558 M a
559 $ hg unshelve
559 $ hg unshelve
560 unshelving change 'default'
560 unshelving change 'default'
561 temporarily committing pending changes (restore with 'hg unshelve --abort')
561 temporarily committing pending changes (restore with 'hg unshelve --abort')
562 rebasing shelved changes
562 rebasing shelved changes
563 merging a
563 merging a
564 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
564 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
565 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
565 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
566 [240]
566 [240]
567 $ echo "aaabbbccc" > a
567 $ echo "aaabbbccc" > a
568 $ rm a.orig
568 $ rm a.orig
569 $ hg resolve --mark a
569 $ hg resolve --mark a
570 (no more unresolved files)
570 (no more unresolved files)
571 continue: hg unshelve --continue
571 continue: hg unshelve --continue
572 $ hg continue
572 $ hg continue
573 marked working directory as branch test
573 marked working directory as branch test
574 unshelve of 'default' complete
574 unshelve of 'default' complete
575 $ cat a
575 $ cat a
576 aaabbbccc
576 aaabbbccc
577 $ hg status
577 $ hg status
578 M a
578 M a
579 $ hg branch
579 $ hg branch
580 test
580 test
581 $ hg commit -m "test-commit"
581 $ hg commit -m "test-commit"
582
582
583 When i shelve on test branch, update to default branch
583 When i shelve on test branch, update to default branch
584 and unshelve i expect that it will not preserve previous
584 and unshelve i expect that it will not preserve previous
585 test branch.
585 test branch.
586
586
587 $ echo "xxx" > b
587 $ echo "xxx" > b
588 $ hg add b
588 $ hg add b
589 $ hg shelve
589 $ hg shelve
590 shelved as test
590 shelved as test
591 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
591 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
592 $ hg update -r 7049e48789d7
592 $ hg update -r 7049e48789d7
593 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
593 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
594 $ hg unshelve
594 $ hg unshelve
595 unshelving change 'test'
595 unshelving change 'test'
596 rebasing shelved changes
596 rebasing shelved changes
597 $ hg status
597 $ hg status
598 A b
598 A b
599 $ hg branch
599 $ hg branch
600 default
600 default
601 $ cd ..
601 $ cd ..
602
602
603 When i unshelve resulting in merge conflicts and makes saved
603 When i unshelve resulting in merge conflicts and makes saved
604 file shelvedstate looks like in previous versions in
604 file shelvedstate looks like in previous versions in
605 mercurial(without restore branch information in 7th line) i
605 mercurial(without restore branch information in 7th line) i
606 expect that after resolving conflicts and successfully
606 expect that after resolving conflicts and successfully
607 running 'shelve --continue' the branch information won't be
607 running 'shelve --continue' the branch information won't be
608 restored and branch will be unchanged.
608 restored and branch will be unchanged.
609
609
610 shelve on new branch, conflict with previous shelvedstate
610 shelve on new branch, conflict with previous shelvedstate
611
611
612 $ hg init conflict
612 $ hg init conflict
613 $ cd conflict
613 $ cd conflict
614 $ echo "aaa" >> a
614 $ echo "aaa" >> a
615 $ hg commit -A -m "a"
615 $ hg commit -A -m "a"
616 adding a
616 adding a
617 $ hg branch
617 $ hg branch
618 default
618 default
619 $ hg branch test
619 $ hg branch test
620 marked working directory as branch test
620 marked working directory as branch test
621 (branches are permanent and global, did you want a bookmark?)
621 (branches are permanent and global, did you want a bookmark?)
622 $ echo "bbb" >> a
622 $ echo "bbb" >> a
623 $ hg status
623 $ hg status
624 M a
624 M a
625 $ hg shelve
625 $ hg shelve
626 shelved as default
626 shelved as default
627 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
627 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
628 $ hg branch
628 $ hg branch
629 default
629 default
630 $ echo "ccc" >> a
630 $ echo "ccc" >> a
631 $ hg status
631 $ hg status
632 M a
632 M a
633 $ hg unshelve
633 $ hg unshelve
634 unshelving change 'default'
634 unshelving change 'default'
635 temporarily committing pending changes (restore with 'hg unshelve --abort')
635 temporarily committing pending changes (restore with 'hg unshelve --abort')
636 rebasing shelved changes
636 rebasing shelved changes
637 merging a
637 merging a
638 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
638 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
639 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
639 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
640 [240]
640 [240]
641
641
642 Removing restore branch information from shelvedstate file(making it looks like
642 Removing restore branch information from shelvedstate file(making it looks like
643 in previous versions) and running unshelve --continue
643 in previous versions) and running unshelve --continue
644
644
645 $ cp .hg/shelvedstate .hg/shelvedstate_old
645 $ cp .hg/shelvedstate .hg/shelvedstate_old
646 $ cat .hg/shelvedstate_old | grep -v 'branchtorestore' > .hg/shelvedstate
646 $ cat .hg/shelvedstate_old | grep -v 'branchtorestore' > .hg/shelvedstate
647
647
648 $ echo "aaabbbccc" > a
648 $ echo "aaabbbccc" > a
649 $ rm a.orig
649 $ rm a.orig
650 $ hg resolve --mark a
650 $ hg resolve --mark a
651 (no more unresolved files)
651 (no more unresolved files)
652 continue: hg unshelve --continue
652 continue: hg unshelve --continue
653
653
654 #if continuecommand
654 #if continuecommand
655 $ hg continue --dry-run
655 $ hg continue --dry-run
656 unshelve in progress, will be resumed
656 unshelve in progress, will be resumed
657 #endif
657 #endif
658
658
659 $ hg continue
659 $ hg continue
660 unshelve of 'default' complete
660 unshelve of 'default' complete
661 $ cat a
661 $ cat a
662 aaabbbccc
662 aaabbbccc
663 $ hg status
663 $ hg status
664 M a
664 M a
665 $ hg branch
665 $ hg branch
666 default
666 default
667 $ cd ..
667 $ cd ..
668
668
669 On non bare shelve the branch information shouldn't be restored
669 On non bare shelve the branch information shouldn't be restored
670
670
671 $ hg init bare_shelve_on_new_branch
671 $ hg init bare_shelve_on_new_branch
672 $ cd bare_shelve_on_new_branch
672 $ cd bare_shelve_on_new_branch
673 $ echo "aaa" >> a
673 $ echo "aaa" >> a
674 $ hg commit -A -m "a"
674 $ hg commit -A -m "a"
675 adding a
675 adding a
676 $ hg branch
676 $ hg branch
677 default
677 default
678 $ hg branch test
678 $ hg branch test
679 marked working directory as branch test
679 marked working directory as branch test
680 (branches are permanent and global, did you want a bookmark?)
680 (branches are permanent and global, did you want a bookmark?)
681 $ echo "bbb" >> a
681 $ echo "bbb" >> a
682 $ hg status
682 $ hg status
683 M a
683 M a
684 $ hg shelve a
684 $ hg shelve a
685 shelved as default
685 shelved as default
686 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
686 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
687 $ hg branch
687 $ hg branch
688 test
688 test
689 $ hg branch default
689 $ hg branch default
690 marked working directory as branch default
690 marked working directory as branch default
691 (branches are permanent and global, did you want a bookmark?)
691 (branches are permanent and global, did you want a bookmark?)
692 $ echo "bbb" >> b
692 $ echo "bbb" >> b
693 $ hg status
693 $ hg status
694 ? b
694 ? b
695 $ hg unshelve
695 $ hg unshelve
696 unshelving change 'default'
696 unshelving change 'default'
697 $ hg status
697 $ hg status
698 M a
698 M a
699 ? b
699 ? b
700 $ hg branch
700 $ hg branch
701 default
701 default
702 $ cd ..
702 $ cd ..
703
703
704 Prepare unshelve with a corrupted shelvedstate
704 Prepare unshelve with a corrupted shelvedstate
705 $ hg init r1 && cd r1
705 $ hg init r1 && cd r1
706 $ echo text1 > file && hg add file
706 $ echo text1 > file && hg add file
707 $ hg shelve
707 $ hg shelve
708 shelved as default
708 shelved as default
709 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
710 $ echo text2 > file && hg ci -Am text1
710 $ echo text2 > file && hg ci -Am text1
711 adding file
711 adding file
712 $ hg unshelve
712 $ hg unshelve
713 unshelving change 'default'
713 unshelving change 'default'
714 rebasing shelved changes
714 rebasing shelved changes
715 merging file
715 merging file
716 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
716 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
717 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
717 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
718 [240]
718 [240]
719 $ echo somethingsomething > .hg/shelvedstate
719 $ echo somethingsomething > .hg/shelvedstate
720
720
721 Unshelve --continue fails with appropriate message if shelvedstate is corrupted
721 Unshelve --continue fails with appropriate message if shelvedstate is corrupted
722 $ hg continue
722 $ hg continue
723 abort: corrupted shelved state file
723 abort: corrupted shelved state file
724 (please run hg unshelve --abort to abort unshelve operation)
724 (please run hg unshelve --abort to abort unshelve operation)
725 [255]
725 [255]
726
726
727 Unshelve --abort works with a corrupted shelvedstate
727 Unshelve --abort works with a corrupted shelvedstate
728 $ hg abort
728 $ hg abort
729 abort: could not read shelved state file, your working copy may be in an unexpected state
729 abort: could not read shelved state file, your working copy may be in an unexpected state
730 please update to some commit
730 please update to some commit
731
731
732 [255]
732 [255]
733
733
734 Unshelve --abort fails with appropriate message if there's no unshelve in
734 Unshelve --abort fails with appropriate message if there's no unshelve in
735 progress
735 progress
736
736
737 #if abortflag
737 #if abortflag
738 $ hg unshelve --abort
738 $ hg unshelve --abort
739 abort: no unshelve in progress
739 abort: no unshelve in progress
740 [20]
740 [20]
741 #else
741 #else
742 $ hg abort
742 $ hg abort
743 aborting the merge, updating back to 9451eaa6eee3
743 aborting the merge, updating back to 9451eaa6eee3
744 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
744 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
745 #endif
745 #endif
746 $ cd ..
746 $ cd ..
747
747
748 Test corrupt shelves (in .hg/shelved/, not .hg/shelvestate)
748 Test corrupt shelves (in .hg/shelved/, not .hg/shelvestate)
749 $ hg init corrupt-shelves
749 $ hg init corrupt-shelves
750 $ cd corrupt-shelves
750 $ cd corrupt-shelves
751 $ mkdir .hg/shelved
751 $ mkdir .hg/shelved
752
752
753 # A (corrupt) .patch file without a .hg file
753 # A (corrupt) .patch file without a .hg file
754 $ touch .hg/shelved/junk1.patch
754 $ touch .hg/shelved/junk1.patch
755 $ hg shelve -l
755 $ hg shelve -l
756 junk1 (* ago) (glob)
756 junk1 (* ago) (glob)
757 $ hg unshelve
757 $ hg unshelve
758 unshelving change 'junk1'
758 unshelving change 'junk1'
759 abort: shelved change 'junk1' not found
759 abort: $ENOENT$: '$TESTTMP/corrupt-shelves/.hg/shelved/junk1.hg'
760 [255]
760 [255]
761 $ hg shelve -d junk1
761 $ hg shelve -d junk1
762 $ find .hg/shelve* | sort
762 $ find .hg/shelve* | sort
763 .hg/shelve-backup
763 .hg/shelve-backup
764 .hg/shelve-backup/junk1.patch
764 .hg/shelve-backup/junk1.patch
765 .hg/shelved
765 .hg/shelved
766
766
767 # A .hg file without a .patch file
767 # A .hg file without a .patch file
768 $ touch .hg/shelved/junk2.hg
768 $ touch .hg/shelved/junk2.hg
769 $ hg shelve -l
769 $ hg shelve -l
770 $ hg unshelve
770 $ hg unshelve
771 abort: no shelved changes to apply!
771 abort: no shelved changes to apply!
772 [255]
772 [255]
773 $ hg shelve -d junk2
773 $ hg shelve -d junk2
774 abort: shelved change 'junk2' not found
774 abort: shelved change 'junk2' not found
775 [255]
775 [255]
776 $ find .hg/shelve* | sort
776 $ find .hg/shelve* | sort
777 .hg/shelve-backup
777 .hg/shelve-backup
778 .hg/shelve-backup/junk1.patch
778 .hg/shelve-backup/junk1.patch
779 .hg/shelved
779 .hg/shelved
780 .hg/shelved/junk2.hg
780 .hg/shelved/junk2.hg
781
781
782 # A file with an unexpected extension
782 # A file with an unexpected extension
783 $ touch .hg/shelved/junk3
783 $ touch .hg/shelved/junk3
784 $ hg shelve -l 2>&1 | grep ValueError
784 $ hg shelve -l 2>&1 | grep ValueError
785 ValueError: * (glob)
785 ValueError: * (glob)
786 $ hg unshelve 2>&1 | grep ValueError
786 $ hg unshelve 2>&1 | grep ValueError
787 ValueError: * (glob)
787 ValueError: * (glob)
788 $ hg shelve -d junk3
788 $ hg shelve -d junk3
789 abort: shelved change 'junk3' not found
789 abort: shelved change 'junk3' not found
790 [255]
790 [255]
791 $ find .hg/shelve* | sort
791 $ find .hg/shelve* | sort
792 .hg/shelve-backup
792 .hg/shelve-backup
793 .hg/shelve-backup/junk1.patch
793 .hg/shelve-backup/junk1.patch
794 .hg/shelved
794 .hg/shelved
795 .hg/shelved/junk2.hg
795 .hg/shelved/junk2.hg
796 .hg/shelved/junk3
796 .hg/shelved/junk3
797
797
798 $ cd ..
798 $ cd ..
799
799
800 Unshelve respects --keep even if user intervention is needed
800 Unshelve respects --keep even if user intervention is needed
801 $ hg init unshelvekeep && cd unshelvekeep
801 $ hg init unshelvekeep && cd unshelvekeep
802 $ echo 1 > file && hg ci -Am 1
802 $ echo 1 > file && hg ci -Am 1
803 adding file
803 adding file
804 $ echo 2 >> file
804 $ echo 2 >> file
805 $ hg shelve
805 $ hg shelve
806 shelved as default
806 shelved as default
807 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
807 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
808 $ echo 3 >> file && hg ci -Am 13
808 $ echo 3 >> file && hg ci -Am 13
809 $ hg shelve --list
809 $ hg shelve --list
810 default (*s ago) * changes to: 1 (glob)
810 default (*s ago) * changes to: 1 (glob)
811 $ hg unshelve --keep
811 $ hg unshelve --keep
812 unshelving change 'default'
812 unshelving change 'default'
813 rebasing shelved changes
813 rebasing shelved changes
814 merging file
814 merging file
815 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
815 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
816 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
816 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
817 [240]
817 [240]
818 $ hg resolve --mark file
818 $ hg resolve --mark file
819 (no more unresolved files)
819 (no more unresolved files)
820 continue: hg unshelve --continue
820 continue: hg unshelve --continue
821 $ hg continue
821 $ hg continue
822 unshelve of 'default' complete
822 unshelve of 'default' complete
823 $ hg shelve --list
823 $ hg shelve --list
824 default (*s ago) * changes to: 1 (glob)
824 default (*s ago) * changes to: 1 (glob)
825 $ cd ..
825 $ cd ..
826
826
827 Unshelving when there are deleted files does not crash (issue4176)
827 Unshelving when there are deleted files does not crash (issue4176)
828 $ hg init unshelve-deleted-file && cd unshelve-deleted-file
828 $ hg init unshelve-deleted-file && cd unshelve-deleted-file
829 $ echo a > a && echo b > b && hg ci -Am ab
829 $ echo a > a && echo b > b && hg ci -Am ab
830 adding a
830 adding a
831 adding b
831 adding b
832 $ echo aa > a && hg shelve
832 $ echo aa > a && hg shelve
833 shelved as default
833 shelved as default
834 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
834 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
835 $ rm b
835 $ rm b
836 $ hg st
836 $ hg st
837 ! b
837 ! b
838 $ hg unshelve
838 $ hg unshelve
839 unshelving change 'default'
839 unshelving change 'default'
840 $ hg shelve
840 $ hg shelve
841 shelved as default
841 shelved as default
842 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
842 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
843 $ rm a && echo b > b
843 $ rm a && echo b > b
844 $ hg st
844 $ hg st
845 ! a
845 ! a
846 $ hg unshelve
846 $ hg unshelve
847 unshelving change 'default'
847 unshelving change 'default'
848 abort: shelved change touches missing files
848 abort: shelved change touches missing files
849 (run hg status to see which files are missing)
849 (run hg status to see which files are missing)
850 [255]
850 [255]
851 $ hg st
851 $ hg st
852 ! a
852 ! a
853 $ cd ..
853 $ cd ..
854
854
855 New versions of Mercurial know how to read onld shelvedstate files
855 New versions of Mercurial know how to read onld shelvedstate files
856 $ hg init oldshelvedstate
856 $ hg init oldshelvedstate
857 $ cd oldshelvedstate
857 $ cd oldshelvedstate
858 $ echo root > root && hg ci -Am root
858 $ echo root > root && hg ci -Am root
859 adding root
859 adding root
860 $ echo 1 > a
860 $ echo 1 > a
861 $ hg add a
861 $ hg add a
862 $ hg shelve --name ashelve
862 $ hg shelve --name ashelve
863 shelved as ashelve
863 shelved as ashelve
864 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
864 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
865 $ echo 2 > a
865 $ echo 2 > a
866 $ hg ci -Am a
866 $ hg ci -Am a
867 adding a
867 adding a
868 $ hg unshelve
868 $ hg unshelve
869 unshelving change 'ashelve'
869 unshelving change 'ashelve'
870 rebasing shelved changes
870 rebasing shelved changes
871 merging a
871 merging a
872 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
872 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
873 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
873 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
874 [240]
874 [240]
875 putting v1 shelvedstate file in place of a created v2
875 putting v1 shelvedstate file in place of a created v2
876 $ cat << EOF > .hg/shelvedstate
876 $ cat << EOF > .hg/shelvedstate
877 > 1
877 > 1
878 > ashelve
878 > ashelve
879 > 8b058dae057a5a78f393f4535d9e363dd5efac9d
879 > 8b058dae057a5a78f393f4535d9e363dd5efac9d
880 > 8b058dae057a5a78f393f4535d9e363dd5efac9d
880 > 8b058dae057a5a78f393f4535d9e363dd5efac9d
881 > 8b058dae057a5a78f393f4535d9e363dd5efac9d f543b27db2cdb41737e2e0008dc524c471da1446
881 > 8b058dae057a5a78f393f4535d9e363dd5efac9d f543b27db2cdb41737e2e0008dc524c471da1446
882 > f543b27db2cdb41737e2e0008dc524c471da1446
882 > f543b27db2cdb41737e2e0008dc524c471da1446
883 >
883 >
884 > nokeep
884 > nokeep
885 > :no-active-bookmark
885 > :no-active-bookmark
886 > EOF
886 > EOF
887 $ echo 1 > a
887 $ echo 1 > a
888 $ hg resolve --mark a
888 $ hg resolve --mark a
889 (no more unresolved files)
889 (no more unresolved files)
890 continue: hg unshelve --continue
890 continue: hg unshelve --continue
891 mercurial does not crash
891 mercurial does not crash
892 $ hg continue
892 $ hg continue
893 unshelve of 'ashelve' complete
893 unshelve of 'ashelve' complete
894
894
895 #if phasebased
895 #if phasebased
896
896
897 Unshelve with some metadata file missing
897 Unshelve with some metadata file missing
898 ----------------------------------------
898 ----------------------------------------
899
899
900 $ hg shelve
900 $ hg shelve
901 shelved as default
901 shelved as default
902 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
902 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
903 $ echo 3 > a
903 $ echo 3 > a
904
904
905 Test with the `.shelve` missing, but the changeset still in the repo (non-natural case)
905 Test with the `.shelve` missing, but the changeset still in the repo (non-natural case)
906
906
907 $ rm .hg/shelved/default.shelve
907 $ rm .hg/shelved/default.shelve
908 $ hg unshelve
908 $ hg unshelve
909 unshelving change 'default'
909 unshelving change 'default'
910 temporarily committing pending changes (restore with 'hg unshelve --abort')
910 temporarily committing pending changes (restore with 'hg unshelve --abort')
911 rebasing shelved changes
911 rebasing shelved changes
912 merging a
912 merging a
913 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
913 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
914 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
914 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
915 [240]
915 [240]
916 $ hg abort
916 $ hg abort
917 unshelve of 'default' aborted
917 unshelve of 'default' aborted
918
918
919 Unshelve without .shelve metadata (can happen when upgrading a repository with old shelve)
919 Unshelve without .shelve metadata (can happen when upgrading a repository with old shelve)
920
920
921 $ cat .hg/shelved/default.shelve
921 $ cat .hg/shelved/default.shelve
922 node=82e0cb9893247d12667017593ce1e5655860f1ac
922 node=82e0cb9893247d12667017593ce1e5655860f1ac
923 $ hg strip --hidden --rev 82e0cb989324 --no-backup
923 $ hg strip --hidden --rev 82e0cb989324 --no-backup
924 $ rm .hg/shelved/default.shelve
924 $ rm .hg/shelved/default.shelve
925 $ hg unshelve
925 $ hg unshelve
926 unshelving change 'default'
926 unshelving change 'default'
927 temporarily committing pending changes (restore with 'hg unshelve --abort')
927 temporarily committing pending changes (restore with 'hg unshelve --abort')
928 rebasing shelved changes
928 rebasing shelved changes
929 merging a
929 merging a
930 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
930 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
931 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
931 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
932 [240]
932 [240]
933 $ cat .hg/shelved/default.shelve
933 $ cat .hg/shelved/default.shelve
934 node=82e0cb9893247d12667017593ce1e5655860f1ac
934 node=82e0cb9893247d12667017593ce1e5655860f1ac
935 $ hg abort
935 $ hg abort
936 unshelve of 'default' aborted
936 unshelve of 'default' aborted
937
937
938 #endif
938 #endif
939
939
940 $ cd ..
940 $ cd ..
941
941
942 Block merge abort when unshelve in progress(issue6160)
942 Block merge abort when unshelve in progress(issue6160)
943 ------------------------------------------------------
943 ------------------------------------------------------
944
944
945 $ hg init a
945 $ hg init a
946 $ cd a
946 $ cd a
947 $ echo foo > a ; hg commit -qAm "initial commit"
947 $ echo foo > a ; hg commit -qAm "initial commit"
948 $ echo bar > a
948 $ echo bar > a
949 $ hg shelve
949 $ hg shelve
950 shelved as default
950 shelved as default
951 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
951 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
952 $ echo foobar > a
952 $ echo foobar > a
953 $ hg unshelve
953 $ hg unshelve
954 unshelving change 'default'
954 unshelving change 'default'
955 temporarily committing pending changes (restore with 'hg unshelve --abort')
955 temporarily committing pending changes (restore with 'hg unshelve --abort')
956 rebasing shelved changes
956 rebasing shelved changes
957 merging a
957 merging a
958 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
958 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
959 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
959 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
960 [240]
960 [240]
961
961
962 $ hg log --template '{desc|firstline} {author} {date|isodate} \n' -r .
962 $ hg log --template '{desc|firstline} {author} {date|isodate} \n' -r .
963 pending changes temporary commit shelve@localhost 1970-01-01 00:00 +0000
963 pending changes temporary commit shelve@localhost 1970-01-01 00:00 +0000
964 $ hg merge --abort
964 $ hg merge --abort
965 abort: cannot abort merge with unshelve in progress
965 abort: cannot abort merge with unshelve in progress
966 (use 'hg unshelve --continue' or 'hg unshelve --abort')
966 (use 'hg unshelve --continue' or 'hg unshelve --abort')
967 [20]
967 [20]
968
968
969 $ hg unshelve --abort
969 $ hg unshelve --abort
970 unshelve of 'default' aborted
970 unshelve of 'default' aborted
971
971
972 $ hg log -G --template '{desc|firstline} {author} {date|isodate} \n' -r .
972 $ hg log -G --template '{desc|firstline} {author} {date|isodate} \n' -r .
973 @ initial commit test 1970-01-01 00:00 +0000
973 @ initial commit test 1970-01-01 00:00 +0000
974
974
975 $ cd ..
975 $ cd ..
976
976
977 Demonstrate that the labels are correct in the merge conflict
977 Demonstrate that the labels are correct in the merge conflict
978 -------------------------------------------------------------
978 -------------------------------------------------------------
979 $ hg init labels
979 $ hg init labels
980 $ cd labels
980 $ cd labels
981 $ echo r0 > foo
981 $ echo r0 > foo
982 $ hg ci -qAm r0
982 $ hg ci -qAm r0
983 $ echo "this will be shelved" >> foo
983 $ echo "this will be shelved" >> foo
984 $ hg shelve -q
984 $ hg shelve -q
985 $ echo "this is in wdir, conflicts with shelve" >> foo
985 $ echo "this is in wdir, conflicts with shelve" >> foo
986 $ hg unshelve -q
986 $ hg unshelve -q
987 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
987 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
988 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
988 unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
989 [240]
989 [240]
990 $ cat foo
990 $ cat foo
991 r0
991 r0
992 <<<<<<< working-copy: 0b2fcf2a90e9 - shelve: pending changes temporary commit
992 <<<<<<< working-copy: 0b2fcf2a90e9 - shelve: pending changes temporary commit
993 this is in wdir, conflicts with shelve
993 this is in wdir, conflicts with shelve
994 =======
994 =======
995 this will be shelved
995 this will be shelved
996 >>>>>>> shelve: 9c072a2163db - shelve: changes to: r0
996 >>>>>>> shelve: 9c072a2163db - shelve: changes to: r0
997 $ cd ..
997 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now