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