|
@@
-1,973
+1,973
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
|
|
|
28
|
|
|
29
|
from mercurial.i18n import _
|
|
29
|
from mercurial.i18n import _
|
|
30
|
from mercurial import (
|
|
30
|
from mercurial import (
|
|
31
|
bundle2,
|
|
31
|
bundle2,
|
|
32
|
bundlerepo,
|
|
32
|
bundlerepo,
|
|
33
|
changegroup,
|
|
33
|
changegroup,
|
|
34
|
cmdutil,
|
|
34
|
cmdutil,
|
|
35
|
commands,
|
|
35
|
commands,
|
|
36
|
error,
|
|
36
|
error,
|
|
37
|
exchange,
|
|
37
|
exchange,
|
|
38
|
hg,
|
|
38
|
hg,
|
|
39
|
lock as lockmod,
|
|
39
|
lock as lockmod,
|
|
40
|
mdiff,
|
|
40
|
mdiff,
|
|
41
|
merge,
|
|
41
|
merge,
|
|
42
|
node as nodemod,
|
|
42
|
node as nodemod,
|
|
43
|
patch,
|
|
43
|
patch,
|
|
44
|
phases,
|
|
44
|
phases,
|
|
45
|
repair,
|
|
45
|
repair,
|
|
46
|
scmutil,
|
|
46
|
scmutil,
|
|
47
|
templatefilters,
|
|
47
|
templatefilters,
|
|
48
|
util,
|
|
48
|
util,
|
|
49
|
)
|
|
49
|
)
|
|
50
|
|
|
50
|
|
|
51
|
from . import (
|
|
51
|
from . import (
|
|
52
|
rebase,
|
|
52
|
rebase,
|
|
53
|
)
|
|
53
|
)
|
|
54
|
|
|
54
|
|
|
55
|
cmdtable = {}
|
|
55
|
cmdtable = {}
|
|
56
|
command = cmdutil.command(cmdtable)
|
|
56
|
command = cmdutil.command(cmdtable)
|
|
57
|
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
|
|
57
|
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
|
|
58
|
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
|
|
58
|
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
|
|
59
|
# be specifying the version(s) of Mercurial they are tested with, or
|
|
59
|
# be specifying the version(s) of Mercurial they are tested with, or
|
|
60
|
# leave the attribute unspecified.
|
|
60
|
# leave the attribute unspecified.
|
|
61
|
testedwith = 'ships-with-hg-core'
|
|
61
|
testedwith = 'ships-with-hg-core'
|
|
62
|
|
|
62
|
|
|
63
|
backupdir = 'shelve-backup'
|
|
63
|
backupdir = 'shelve-backup'
|
|
64
|
shelvedir = 'shelved'
|
|
64
|
shelvedir = 'shelved'
|
|
65
|
shelvefileextensions = ['hg', 'patch']
|
|
65
|
shelvefileextensions = ['hg', 'patch']
|
|
66
|
|
|
66
|
|
|
67
|
# we never need the user, so we use a
|
|
67
|
# we never need the user, so we use a
|
|
68
|
# generic user for all shelve operations
|
|
68
|
# generic user for all shelve operations
|
|
69
|
shelveuser = 'shelve@localhost'
|
|
69
|
shelveuser = 'shelve@localhost'
|
|
70
|
|
|
70
|
|
|
71
|
class shelvedfile(object):
|
|
71
|
class shelvedfile(object):
|
|
72
|
"""Helper for the file storing a single shelve
|
|
72
|
"""Helper for the file storing a single shelve
|
|
73
|
|
|
73
|
|
|
74
|
Handles common functions on shelve files (.hg/.patch) using
|
|
74
|
Handles common functions on shelve files (.hg/.patch) using
|
|
75
|
the vfs layer"""
|
|
75
|
the vfs layer"""
|
|
76
|
def __init__(self, repo, name, filetype=None):
|
|
76
|
def __init__(self, repo, name, filetype=None):
|
|
77
|
self.repo = repo
|
|
77
|
self.repo = repo
|
|
78
|
self.name = name
|
|
78
|
self.name = name
|
|
79
|
self.vfs = scmutil.vfs(repo.join(shelvedir))
|
|
79
|
self.vfs = scmutil.vfs(repo.join(shelvedir))
|
|
80
|
self.backupvfs = scmutil.vfs(repo.join(backupdir))
|
|
80
|
self.backupvfs = scmutil.vfs(repo.join(backupdir))
|
|
81
|
self.ui = self.repo.ui
|
|
81
|
self.ui = self.repo.ui
|
|
82
|
if filetype:
|
|
82
|
if filetype:
|
|
83
|
self.fname = name + '.' + filetype
|
|
83
|
self.fname = name + '.' + filetype
|
|
84
|
else:
|
|
84
|
else:
|
|
85
|
self.fname = name
|
|
85
|
self.fname = name
|
|
86
|
|
|
86
|
|
|
87
|
def exists(self):
|
|
87
|
def exists(self):
|
|
88
|
return self.vfs.exists(self.fname)
|
|
88
|
return self.vfs.exists(self.fname)
|
|
89
|
|
|
89
|
|
|
90
|
def filename(self):
|
|
90
|
def filename(self):
|
|
91
|
return self.vfs.join(self.fname)
|
|
91
|
return self.vfs.join(self.fname)
|
|
92
|
|
|
92
|
|
|
93
|
def backupfilename(self):
|
|
93
|
def backupfilename(self):
|
|
94
|
def gennames(base):
|
|
94
|
def gennames(base):
|
|
95
|
yield base
|
|
95
|
yield base
|
|
96
|
base, ext = base.rsplit('.', 1)
|
|
96
|
base, ext = base.rsplit('.', 1)
|
|
97
|
for i in itertools.count(1):
|
|
97
|
for i in itertools.count(1):
|
|
98
|
yield '%s-%d.%s' % (base, i, ext)
|
|
98
|
yield '%s-%d.%s' % (base, i, ext)
|
|
99
|
|
|
99
|
|
|
100
|
name = self.backupvfs.join(self.fname)
|
|
100
|
name = self.backupvfs.join(self.fname)
|
|
101
|
for n in gennames(name):
|
|
101
|
for n in gennames(name):
|
|
102
|
if not self.backupvfs.exists(n):
|
|
102
|
if not self.backupvfs.exists(n):
|
|
103
|
return n
|
|
103
|
return n
|
|
104
|
|
|
104
|
|
|
105
|
def movetobackup(self):
|
|
105
|
def movetobackup(self):
|
|
106
|
if not self.backupvfs.isdir():
|
|
106
|
if not self.backupvfs.isdir():
|
|
107
|
self.backupvfs.makedir()
|
|
107
|
self.backupvfs.makedir()
|
|
108
|
util.rename(self.filename(), self.backupfilename())
|
|
108
|
util.rename(self.filename(), self.backupfilename())
|
|
109
|
|
|
109
|
|
|
110
|
def stat(self):
|
|
110
|
def stat(self):
|
|
111
|
return self.vfs.stat(self.fname)
|
|
111
|
return self.vfs.stat(self.fname)
|
|
112
|
|
|
112
|
|
|
113
|
def opener(self, mode='rb'):
|
|
113
|
def opener(self, mode='rb'):
|
|
114
|
try:
|
|
114
|
try:
|
|
115
|
return self.vfs(self.fname, mode)
|
|
115
|
return self.vfs(self.fname, mode)
|
|
116
|
except IOError as err:
|
|
116
|
except IOError as err:
|
|
117
|
if err.errno != errno.ENOENT:
|
|
117
|
if err.errno != errno.ENOENT:
|
|
118
|
raise
|
|
118
|
raise
|
|
119
|
raise error.Abort(_("shelved change '%s' not found") % self.name)
|
|
119
|
raise error.Abort(_("shelved change '%s' not found") % self.name)
|
|
120
|
|
|
120
|
|
|
121
|
def applybundle(self):
|
|
121
|
def applybundle(self):
|
|
122
|
fp = self.opener()
|
|
122
|
fp = self.opener()
|
|
123
|
try:
|
|
123
|
try:
|
|
124
|
gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs)
|
|
124
|
gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs)
|
|
125
|
if not isinstance(gen, bundle2.unbundle20):
|
|
125
|
if not isinstance(gen, bundle2.unbundle20):
|
|
126
|
gen.apply(self.repo, 'unshelve',
|
|
126
|
gen.apply(self.repo, 'unshelve',
|
|
127
|
'bundle:' + self.vfs.join(self.fname),
|
|
127
|
'bundle:' + self.vfs.join(self.fname),
|
|
128
|
targetphase=phases.secret)
|
|
128
|
targetphase=phases.secret)
|
|
129
|
if isinstance(gen, bundle2.unbundle20):
|
|
129
|
if isinstance(gen, bundle2.unbundle20):
|
|
130
|
bundle2.applybundle(self.repo, gen,
|
|
130
|
bundle2.applybundle(self.repo, gen,
|
|
131
|
self.repo.currenttransaction(),
|
|
131
|
self.repo.currenttransaction(),
|
|
132
|
source='unshelve',
|
|
132
|
source='unshelve',
|
|
133
|
url='bundle:' + self.vfs.join(self.fname))
|
|
133
|
url='bundle:' + self.vfs.join(self.fname))
|
|
134
|
finally:
|
|
134
|
finally:
|
|
135
|
fp.close()
|
|
135
|
fp.close()
|
|
136
|
|
|
136
|
|
|
137
|
def bundlerepo(self):
|
|
137
|
def bundlerepo(self):
|
|
138
|
return bundlerepo.bundlerepository(self.repo.baseui, self.repo.root,
|
|
138
|
return bundlerepo.bundlerepository(self.repo.baseui, self.repo.root,
|
|
139
|
self.vfs.join(self.fname))
|
|
139
|
self.vfs.join(self.fname))
|
|
140
|
def writebundle(self, bases, node):
|
|
140
|
def writebundle(self, bases, node):
|
|
141
|
cgversion = changegroup.safeversion(self.repo)
|
|
141
|
cgversion = changegroup.safeversion(self.repo)
|
|
142
|
if cgversion == '01':
|
|
142
|
if cgversion == '01':
|
|
143
|
btype = 'HG10BZ'
|
|
143
|
btype = 'HG10BZ'
|
|
144
|
compression = None
|
|
144
|
compression = None
|
|
145
|
else:
|
|
145
|
else:
|
|
146
|
btype = 'HG20'
|
|
146
|
btype = 'HG20'
|
|
147
|
compression = 'BZ'
|
|
147
|
compression = 'BZ'
|
|
148
|
|
|
148
|
|
|
149
|
cg = changegroup.changegroupsubset(self.repo, bases, [node], 'shelve',
|
|
149
|
cg = changegroup.changegroupsubset(self.repo, bases, [node], 'shelve',
|
|
150
|
version=cgversion)
|
|
150
|
version=cgversion)
|
|
151
|
bundle2.writebundle(self.ui, cg, self.fname, btype, self.vfs,
|
|
151
|
bundle2.writebundle(self.ui, cg, self.fname, btype, self.vfs,
|
|
152
|
compression=compression)
|
|
152
|
compression=compression)
|
|
153
|
|
|
153
|
|
|
154
|
class shelvedstate(object):
|
|
154
|
class shelvedstate(object):
|
|
155
|
"""Handle persistence during unshelving operations.
|
|
155
|
"""Handle persistence during unshelving operations.
|
|
156
|
|
|
156
|
|
|
157
|
Handles saving and restoring a shelved state. Ensures that different
|
|
157
|
Handles saving and restoring a shelved state. Ensures that different
|
|
158
|
versions of a shelved state are possible and handles them appropriately.
|
|
158
|
versions of a shelved state are possible and handles them appropriately.
|
|
159
|
"""
|
|
159
|
"""
|
|
160
|
_version = 1
|
|
160
|
_version = 1
|
|
161
|
_filename = 'shelvedstate'
|
|
161
|
_filename = 'shelvedstate'
|
|
162
|
_keep = 'keep'
|
|
162
|
_keep = 'keep'
|
|
163
|
_nokeep = 'nokeep'
|
|
163
|
_nokeep = 'nokeep'
|
|
164
|
|
|
164
|
|
|
165
|
@classmethod
|
|
165
|
@classmethod
|
|
166
|
def load(cls, repo):
|
|
166
|
def load(cls, repo):
|
|
167
|
fp = repo.vfs(cls._filename)
|
|
167
|
fp = repo.vfs(cls._filename)
|
|
168
|
try:
|
|
168
|
try:
|
|
169
|
version = int(fp.readline().strip())
|
|
169
|
version = int(fp.readline().strip())
|
|
170
|
|
|
170
|
|
|
171
|
if version != cls._version:
|
|
171
|
if version != cls._version:
|
|
172
|
raise error.Abort(_('this version of shelve is incompatible '
|
|
172
|
raise error.Abort(_('this version of shelve is incompatible '
|
|
173
|
'with the version used in this repo'))
|
|
173
|
'with the version used in this repo'))
|
|
174
|
name = fp.readline().strip()
|
|
174
|
name = fp.readline().strip()
|
|
175
|
wctx = nodemod.bin(fp.readline().strip())
|
|
175
|
wctx = nodemod.bin(fp.readline().strip())
|
|
176
|
pendingctx = nodemod.bin(fp.readline().strip())
|
|
176
|
pendingctx = nodemod.bin(fp.readline().strip())
|
|
177
|
parents = [nodemod.bin(h) for h in fp.readline().split()]
|
|
177
|
parents = [nodemod.bin(h) for h in fp.readline().split()]
|
|
178
|
stripnodes = [nodemod.bin(h) for h in fp.readline().split()]
|
|
178
|
stripnodes = [nodemod.bin(h) for h in fp.readline().split()]
|
|
179
|
branchtorestore = fp.readline().strip()
|
|
179
|
branchtorestore = fp.readline().strip()
|
|
180
|
keep = fp.readline().strip() == cls._keep
|
|
180
|
keep = fp.readline().strip() == cls._keep
|
|
181
|
except (ValueError, TypeError) as err:
|
|
181
|
except (ValueError, TypeError) as err:
|
|
182
|
raise error.CorruptedState(str(err))
|
|
182
|
raise error.CorruptedState(str(err))
|
|
183
|
finally:
|
|
183
|
finally:
|
|
184
|
fp.close()
|
|
184
|
fp.close()
|
|
185
|
|
|
185
|
|
|
186
|
try:
|
|
186
|
try:
|
|
187
|
obj = cls()
|
|
187
|
obj = cls()
|
|
188
|
obj.name = name
|
|
188
|
obj.name = name
|
|
189
|
obj.wctx = repo[wctx]
|
|
189
|
obj.wctx = repo[wctx]
|
|
190
|
obj.pendingctx = repo[pendingctx]
|
|
190
|
obj.pendingctx = repo[pendingctx]
|
|
191
|
obj.parents = parents
|
|
191
|
obj.parents = parents
|
|
192
|
obj.stripnodes = stripnodes
|
|
192
|
obj.stripnodes = stripnodes
|
|
193
|
obj.branchtorestore = branchtorestore
|
|
193
|
obj.branchtorestore = branchtorestore
|
|
194
|
obj.keep = keep
|
|
194
|
obj.keep = keep
|
|
195
|
except error.RepoLookupError as err:
|
|
195
|
except error.RepoLookupError as err:
|
|
196
|
raise error.CorruptedState(str(err))
|
|
196
|
raise error.CorruptedState(str(err))
|
|
197
|
|
|
197
|
|
|
198
|
return obj
|
|
198
|
return obj
|
|
199
|
|
|
199
|
|
|
200
|
@classmethod
|
|
200
|
@classmethod
|
|
201
|
def save(cls, repo, name, originalwctx, pendingctx, stripnodes,
|
|
201
|
def save(cls, repo, name, originalwctx, pendingctx, stripnodes,
|
|
202
|
branchtorestore, keep=False):
|
|
202
|
branchtorestore, keep=False):
|
|
203
|
fp = repo.vfs(cls._filename, 'wb')
|
|
203
|
fp = repo.vfs(cls._filename, 'wb')
|
|
204
|
fp.write('%i\n' % cls._version)
|
|
204
|
fp.write('%i\n' % cls._version)
|
|
205
|
fp.write('%s\n' % name)
|
|
205
|
fp.write('%s\n' % name)
|
|
206
|
fp.write('%s\n' % nodemod.hex(originalwctx.node()))
|
|
206
|
fp.write('%s\n' % nodemod.hex(originalwctx.node()))
|
|
207
|
fp.write('%s\n' % nodemod.hex(pendingctx.node()))
|
|
207
|
fp.write('%s\n' % nodemod.hex(pendingctx.node()))
|
|
208
|
fp.write('%s\n' %
|
|
208
|
fp.write('%s\n' %
|
|
209
|
' '.join([nodemod.hex(p) for p in repo.dirstate.parents()]))
|
|
209
|
' '.join([nodemod.hex(p) for p in repo.dirstate.parents()]))
|
|
210
|
fp.write('%s\n' %
|
|
210
|
fp.write('%s\n' %
|
|
211
|
' '.join([nodemod.hex(n) for n in stripnodes]))
|
|
211
|
' '.join([nodemod.hex(n) for n in stripnodes]))
|
|
212
|
fp.write('%s\n' % branchtorestore)
|
|
212
|
fp.write('%s\n' % branchtorestore)
|
|
213
|
fp.write('%s\n' % (cls._keep if keep else cls._nokeep))
|
|
213
|
fp.write('%s\n' % (cls._keep if keep else cls._nokeep))
|
|
214
|
fp.close()
|
|
214
|
fp.close()
|
|
215
|
|
|
215
|
|
|
216
|
@classmethod
|
|
216
|
@classmethod
|
|
217
|
def clear(cls, repo):
|
|
217
|
def clear(cls, repo):
|
|
218
|
util.unlinkpath(repo.join(cls._filename), ignoremissing=True)
|
|
218
|
util.unlinkpath(repo.join(cls._filename), ignoremissing=True)
|
|
219
|
|
|
219
|
|
|
220
|
def cleanupoldbackups(repo):
|
|
220
|
def cleanupoldbackups(repo):
|
|
221
|
vfs = scmutil.vfs(repo.join(backupdir))
|
|
221
|
vfs = scmutil.vfs(repo.join(backupdir))
|
|
222
|
maxbackups = repo.ui.configint('shelve', 'maxbackups', 10)
|
|
222
|
maxbackups = repo.ui.configint('shelve', 'maxbackups', 10)
|
|
223
|
hgfiles = [f for f in vfs.listdir() if f.endswith('.hg')]
|
|
223
|
hgfiles = [f for f in vfs.listdir() if f.endswith('.hg')]
|
|
224
|
hgfiles = sorted([(vfs.stat(f).st_mtime, f) for f in hgfiles])
|
|
224
|
hgfiles = sorted([(vfs.stat(f).st_mtime, f) for f in hgfiles])
|
|
225
|
if 0 < maxbackups and maxbackups < len(hgfiles):
|
|
225
|
if 0 < maxbackups and maxbackups < len(hgfiles):
|
|
226
|
bordermtime = hgfiles[-maxbackups][0]
|
|
226
|
bordermtime = hgfiles[-maxbackups][0]
|
|
227
|
else:
|
|
227
|
else:
|
|
228
|
bordermtime = None
|
|
228
|
bordermtime = None
|
|
229
|
for mtime, f in hgfiles[:len(hgfiles) - maxbackups]:
|
|
229
|
for mtime, f in hgfiles[:len(hgfiles) - maxbackups]:
|
|
230
|
if mtime == bordermtime:
|
|
230
|
if mtime == bordermtime:
|
|
231
|
# keep it, because timestamp can't decide exact order of backups
|
|
231
|
# keep it, because timestamp can't decide exact order of backups
|
|
232
|
continue
|
|
232
|
continue
|
|
233
|
base = f[:-3]
|
|
233
|
base = f[:-3]
|
|
234
|
for ext in shelvefileextensions:
|
|
234
|
for ext in shelvefileextensions:
|
|
235
|
try:
|
|
235
|
try:
|
|
236
|
vfs.unlink(base + '.' + ext)
|
|
236
|
vfs.unlink(base + '.' + ext)
|
|
237
|
except OSError as err:
|
|
237
|
except OSError as err:
|
|
238
|
if err.errno != errno.ENOENT:
|
|
238
|
if err.errno != errno.ENOENT:
|
|
239
|
raise
|
|
239
|
raise
|
|
240
|
|
|
240
|
|
|
241
|
def _aborttransaction(repo):
|
|
241
|
def _aborttransaction(repo):
|
|
242
|
'''Abort current transaction for shelve/unshelve, but keep dirstate
|
|
242
|
'''Abort current transaction for shelve/unshelve, but keep dirstate
|
|
243
|
'''
|
|
243
|
'''
|
|
244
|
tr = repo.currenttransaction()
|
|
244
|
tr = repo.currenttransaction()
|
|
245
|
repo.dirstate.savebackup(tr, suffix='.shelve')
|
|
245
|
repo.dirstate.savebackup(tr, suffix='.shelve')
|
|
246
|
tr.abort()
|
|
246
|
tr.abort()
|
|
247
|
repo.dirstate.restorebackup(None, suffix='.shelve')
|
|
247
|
repo.dirstate.restorebackup(None, suffix='.shelve')
|
|
248
|
|
|
248
|
|
|
249
|
def createcmd(ui, repo, pats, opts):
|
|
249
|
def createcmd(ui, repo, pats, opts):
|
|
250
|
"""subcommand that creates a new shelve"""
|
|
250
|
"""subcommand that creates a new shelve"""
|
|
251
|
with repo.wlock():
|
|
251
|
with repo.wlock():
|
|
252
|
cmdutil.checkunfinished(repo)
|
|
252
|
cmdutil.checkunfinished(repo)
|
|
253
|
return _docreatecmd(ui, repo, pats, opts)
|
|
253
|
return _docreatecmd(ui, repo, pats, opts)
|
|
254
|
|
|
254
|
|
|
255
|
def getshelvename(repo, parent, opts):
|
|
255
|
def getshelvename(repo, parent, opts):
|
|
256
|
"""Decide on the name this shelve is going to have"""
|
|
256
|
"""Decide on the name this shelve is going to have"""
|
|
257
|
def gennames():
|
|
257
|
def gennames():
|
|
258
|
yield label
|
|
258
|
yield label
|
|
259
|
for i in xrange(1, 100):
|
|
259
|
for i in xrange(1, 100):
|
|
260
|
yield '%s-%02d' % (label, i)
|
|
260
|
yield '%s-%02d' % (label, i)
|
|
261
|
name = opts.get('name')
|
|
261
|
name = opts.get('name')
|
|
262
|
label = repo._activebookmark or parent.branch() or 'default'
|
|
262
|
label = repo._activebookmark or parent.branch() or 'default'
|
|
263
|
# slashes aren't allowed in filenames, therefore we rename it
|
|
263
|
# slashes aren't allowed in filenames, therefore we rename it
|
|
264
|
label = label.replace('/', '_')
|
|
264
|
label = label.replace('/', '_')
|
|
265
|
|
|
265
|
|
|
266
|
if name:
|
|
266
|
if name:
|
|
267
|
if shelvedfile(repo, name, 'hg').exists():
|
|
267
|
if shelvedfile(repo, name, 'hg').exists():
|
|
268
|
e = _("a shelved change named '%s' already exists") % name
|
|
268
|
e = _("a shelved change named '%s' already exists") % name
|
|
269
|
raise error.Abort(e)
|
|
269
|
raise error.Abort(e)
|
|
270
|
else:
|
|
270
|
else:
|
|
271
|
for n in gennames():
|
|
271
|
for n in gennames():
|
|
272
|
if not shelvedfile(repo, n, 'hg').exists():
|
|
272
|
if not shelvedfile(repo, n, 'hg').exists():
|
|
273
|
name = n
|
|
273
|
name = n
|
|
274
|
break
|
|
274
|
break
|
|
275
|
else:
|
|
275
|
else:
|
|
276
|
raise error.Abort(_("too many shelved changes named '%s'") % label)
|
|
276
|
raise error.Abort(_("too many shelved changes named '%s'") % label)
|
|
277
|
|
|
277
|
|
|
278
|
# ensure we are not creating a subdirectory or a hidden file
|
|
278
|
# ensure we are not creating a subdirectory or a hidden file
|
|
279
|
if '/' in name or '\\' in name:
|
|
279
|
if '/' in name or '\\' in name:
|
|
280
|
raise error.Abort(_('shelved change names may not contain slashes'))
|
|
280
|
raise error.Abort(_('shelved change names may not contain slashes'))
|
|
281
|
if name.startswith('.'):
|
|
281
|
if name.startswith('.'):
|
|
282
|
raise error.Abort(_("shelved change names may not start with '.'"))
|
|
282
|
raise error.Abort(_("shelved change names may not start with '.'"))
|
|
283
|
return name
|
|
283
|
return name
|
|
284
|
|
|
284
|
|
|
285
|
def mutableancestors(ctx):
|
|
285
|
def mutableancestors(ctx):
|
|
286
|
"""return all mutable ancestors for ctx (included)
|
|
286
|
"""return all mutable ancestors for ctx (included)
|
|
287
|
|
|
287
|
|
|
288
|
Much faster than the revset ancestors(ctx) & draft()"""
|
|
288
|
Much faster than the revset ancestors(ctx) & draft()"""
|
|
289
|
seen = set([nodemod.nullrev])
|
|
289
|
seen = set([nodemod.nullrev])
|
|
290
|
visit = collections.deque()
|
|
290
|
visit = collections.deque()
|
|
291
|
visit.append(ctx)
|
|
291
|
visit.append(ctx)
|
|
292
|
while visit:
|
|
292
|
while visit:
|
|
293
|
ctx = visit.popleft()
|
|
293
|
ctx = visit.popleft()
|
|
294
|
yield ctx.node()
|
|
294
|
yield ctx.node()
|
|
295
|
for parent in ctx.parents():
|
|
295
|
for parent in ctx.parents():
|
|
296
|
rev = parent.rev()
|
|
296
|
rev = parent.rev()
|
|
297
|
if rev not in seen:
|
|
297
|
if rev not in seen:
|
|
298
|
seen.add(rev)
|
|
298
|
seen.add(rev)
|
|
299
|
if parent.mutable():
|
|
299
|
if parent.mutable():
|
|
300
|
visit.append(parent)
|
|
300
|
visit.append(parent)
|
|
301
|
|
|
301
|
|
|
302
|
def getcommitfunc(extra, interactive, editor=False):
|
|
302
|
def getcommitfunc(extra, interactive, editor=False):
|
|
303
|
def commitfunc(ui, repo, message, match, opts):
|
|
303
|
def commitfunc(ui, repo, message, match, opts):
|
|
304
|
hasmq = util.safehasattr(repo, 'mq')
|
|
304
|
hasmq = util.safehasattr(repo, 'mq')
|
|
305
|
if hasmq:
|
|
305
|
if hasmq:
|
|
306
|
saved, repo.mq.checkapplied = repo.mq.checkapplied, False
|
|
306
|
saved, repo.mq.checkapplied = repo.mq.checkapplied, False
|
|
307
|
backup = repo.ui.backupconfig('phases', 'new-commit')
|
|
307
|
backup = repo.ui.backupconfig('phases', 'new-commit')
|
|
308
|
try:
|
|
308
|
try:
|
|
309
|
repo.ui.setconfig('phases', 'new-commit', phases.secret)
|
|
309
|
repo.ui.setconfig('phases', 'new-commit', phases.secret)
|
|
310
|
editor_ = False
|
|
310
|
editor_ = False
|
|
311
|
if editor:
|
|
311
|
if editor:
|
|
312
|
editor_ = cmdutil.getcommiteditor(editform='shelve.shelve',
|
|
312
|
editor_ = cmdutil.getcommiteditor(editform='shelve.shelve',
|
|
313
|
**opts)
|
|
313
|
**opts)
|
|
314
|
return repo.commit(message, shelveuser, opts.get('date'), match,
|
|
314
|
return repo.commit(message, shelveuser, opts.get('date'), match,
|
|
315
|
editor=editor_, extra=extra)
|
|
315
|
editor=editor_, extra=extra)
|
|
316
|
finally:
|
|
316
|
finally:
|
|
317
|
repo.ui.restoreconfig(backup)
|
|
317
|
repo.ui.restoreconfig(backup)
|
|
318
|
if hasmq:
|
|
318
|
if hasmq:
|
|
319
|
repo.mq.checkapplied = saved
|
|
319
|
repo.mq.checkapplied = saved
|
|
320
|
|
|
320
|
|
|
321
|
def interactivecommitfunc(ui, repo, *pats, **opts):
|
|
321
|
def interactivecommitfunc(ui, repo, *pats, **opts):
|
|
322
|
match = scmutil.match(repo['.'], pats, {})
|
|
322
|
match = scmutil.match(repo['.'], pats, {})
|
|
323
|
message = opts['message']
|
|
323
|
message = opts['message']
|
|
324
|
return commitfunc(ui, repo, message, match, opts)
|
|
324
|
return commitfunc(ui, repo, message, match, opts)
|
|
325
|
|
|
325
|
|
|
326
|
return interactivecommitfunc if interactive else commitfunc
|
|
326
|
return interactivecommitfunc if interactive else commitfunc
|
|
327
|
|
|
327
|
|
|
328
|
def _nothingtoshelvemessaging(ui, repo, pats, opts):
|
|
328
|
def _nothingtoshelvemessaging(ui, repo, pats, opts):
|
|
329
|
stat = repo.status(match=scmutil.match(repo[None], pats, opts))
|
|
329
|
stat = repo.status(match=scmutil.match(repo[None], pats, opts))
|
|
330
|
if stat.deleted:
|
|
330
|
if stat.deleted:
|
|
331
|
ui.status(_("nothing changed (%d missing files, see "
|
|
331
|
ui.status(_("nothing changed (%d missing files, see "
|
|
332
|
"'hg status')\n") % len(stat.deleted))
|
|
332
|
"'hg status')\n") % len(stat.deleted))
|
|
333
|
else:
|
|
333
|
else:
|
|
334
|
ui.status(_("nothing changed\n"))
|
|
334
|
ui.status(_("nothing changed\n"))
|
|
335
|
|
|
335
|
|
|
336
|
def _shelvecreatedcommit(repo, node, name):
|
|
336
|
def _shelvecreatedcommit(repo, node, name):
|
|
337
|
bases = list(mutableancestors(repo[node]))
|
|
337
|
bases = list(mutableancestors(repo[node]))
|
|
338
|
shelvedfile(repo, name, 'hg').writebundle(bases, node)
|
|
338
|
shelvedfile(repo, name, 'hg').writebundle(bases, node)
|
|
339
|
cmdutil.export(repo, [node],
|
|
339
|
cmdutil.export(repo, [node],
|
|
340
|
fp=shelvedfile(repo, name, 'patch').opener('wb'),
|
|
340
|
fp=shelvedfile(repo, name, 'patch').opener('wb'),
|
|
341
|
opts=mdiff.diffopts(git=True))
|
|
341
|
opts=mdiff.diffopts(git=True))
|
|
342
|
|
|
342
|
|
|
343
|
def _includeunknownfiles(repo, pats, opts, extra):
|
|
343
|
def _includeunknownfiles(repo, pats, opts, extra):
|
|
344
|
s = repo.status(match=scmutil.match(repo[None], pats, opts),
|
|
344
|
s = repo.status(match=scmutil.match(repo[None], pats, opts),
|
|
345
|
unknown=True)
|
|
345
|
unknown=True)
|
|
346
|
if s.unknown:
|
|
346
|
if s.unknown:
|
|
347
|
extra['shelve_unknown'] = '\0'.join(s.unknown)
|
|
347
|
extra['shelve_unknown'] = '\0'.join(s.unknown)
|
|
348
|
repo[None].add(s.unknown)
|
|
348
|
repo[None].add(s.unknown)
|
|
349
|
|
|
349
|
|
|
350
|
def _finishshelve(repo):
|
|
350
|
def _finishshelve(repo):
|
|
351
|
_aborttransaction(repo)
|
|
351
|
_aborttransaction(repo)
|
|
352
|
|
|
352
|
|
|
353
|
def _docreatecmd(ui, repo, pats, opts):
|
|
353
|
def _docreatecmd(ui, repo, pats, opts):
|
|
354
|
wctx = repo[None]
|
|
354
|
wctx = repo[None]
|
|
355
|
parents = wctx.parents()
|
|
355
|
parents = wctx.parents()
|
|
356
|
if len(parents) > 1:
|
|
356
|
if len(parents) > 1:
|
|
357
|
raise error.Abort(_('cannot shelve while merging'))
|
|
357
|
raise error.Abort(_('cannot shelve while merging'))
|
|
358
|
parent = parents[0]
|
|
358
|
parent = parents[0]
|
|
359
|
origbranch = wctx.branch()
|
|
359
|
origbranch = wctx.branch()
|
|
360
|
|
|
360
|
|
|
361
|
if parent.node() != nodemod.nullid:
|
|
361
|
if parent.node() != nodemod.nullid:
|
|
362
|
desc = "changes to: %s" % parent.description().split('\n', 1)[0]
|
|
362
|
desc = "changes to: %s" % parent.description().split('\n', 1)[0]
|
|
363
|
else:
|
|
363
|
else:
|
|
364
|
desc = '(changes in empty repository)'
|
|
364
|
desc = '(changes in empty repository)'
|
|
365
|
|
|
365
|
|
|
366
|
if not opts.get('message'):
|
|
366
|
if not opts.get('message'):
|
|
367
|
opts['message'] = desc
|
|
367
|
opts['message'] = desc
|
|
368
|
|
|
368
|
|
|
369
|
lock = tr = None
|
|
369
|
lock = tr = None
|
|
370
|
try:
|
|
370
|
try:
|
|
371
|
lock = repo.lock()
|
|
371
|
lock = repo.lock()
|
|
372
|
|
|
372
|
|
|
373
|
# use an uncommitted transaction to generate the bundle to avoid
|
|
373
|
# use an uncommitted transaction to generate the bundle to avoid
|
|
374
|
# pull races. ensure we don't print the abort message to stderr.
|
|
374
|
# pull races. ensure we don't print the abort message to stderr.
|
|
375
|
tr = repo.transaction('commit', report=lambda x: None)
|
|
375
|
tr = repo.transaction('commit', report=lambda x: None)
|
|
376
|
|
|
376
|
|
|
377
|
interactive = opts.get('interactive', False)
|
|
377
|
interactive = opts.get('interactive', False)
|
|
378
|
includeunknown = (opts.get('unknown', False) and
|
|
378
|
includeunknown = (opts.get('unknown', False) and
|
|
379
|
not opts.get('addremove', False))
|
|
379
|
not opts.get('addremove', False))
|
|
380
|
|
|
380
|
|
|
381
|
name = getshelvename(repo, parent, opts)
|
|
381
|
name = getshelvename(repo, parent, opts)
|
|
382
|
extra = {}
|
|
382
|
extra = {}
|
|
383
|
if includeunknown:
|
|
383
|
if includeunknown:
|
|
384
|
_includeunknownfiles(repo, pats, opts, extra)
|
|
384
|
_includeunknownfiles(repo, pats, opts, extra)
|
|
385
|
|
|
385
|
|
|
386
|
if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts):
|
|
386
|
if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts):
|
|
387
|
# In non-bare shelve we don't store newly created branch
|
|
387
|
# In non-bare shelve we don't store newly created branch
|
|
388
|
# at bundled commit
|
|
388
|
# at bundled commit
|
|
389
|
repo.dirstate.setbranch(repo['.'].branch())
|
|
389
|
repo.dirstate.setbranch(repo['.'].branch())
|
|
390
|
|
|
390
|
|
|
391
|
commitfunc = getcommitfunc(extra, interactive, editor=True)
|
|
391
|
commitfunc = getcommitfunc(extra, interactive, editor=True)
|
|
392
|
if not interactive:
|
|
392
|
if not interactive:
|
|
393
|
node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
|
|
393
|
node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
|
|
394
|
else:
|
|
394
|
else:
|
|
395
|
node = cmdutil.dorecord(ui, repo, commitfunc, None,
|
|
395
|
node = cmdutil.dorecord(ui, repo, commitfunc, None,
|
|
396
|
False, cmdutil.recordfilter, *pats, **opts)
|
|
396
|
False, cmdutil.recordfilter, *pats, **opts)
|
|
397
|
if not node:
|
|
397
|
if not node:
|
|
398
|
_nothingtoshelvemessaging(ui, repo, pats, opts)
|
|
398
|
_nothingtoshelvemessaging(ui, repo, pats, opts)
|
|
399
|
return 1
|
|
399
|
return 1
|
|
400
|
|
|
400
|
|
|
401
|
_shelvecreatedcommit(repo, node, name)
|
|
401
|
_shelvecreatedcommit(repo, node, name)
|
|
402
|
|
|
402
|
|
|
403
|
if ui.formatted():
|
|
403
|
if ui.formatted():
|
|
404
|
desc = util.ellipsis(desc, ui.termwidth())
|
|
404
|
desc = util.ellipsis(desc, ui.termwidth())
|
|
405
|
ui.status(_('shelved as %s\n') % name)
|
|
405
|
ui.status(_('shelved as %s\n') % name)
|
|
406
|
hg.update(repo, parent.node())
|
|
406
|
hg.update(repo, parent.node())
|
|
407
|
if origbranch != repo['.'].branch() and not _isbareshelve(pats, opts):
|
|
407
|
if origbranch != repo['.'].branch() and not _isbareshelve(pats, opts):
|
|
408
|
repo.dirstate.setbranch(origbranch)
|
|
408
|
repo.dirstate.setbranch(origbranch)
|
|
409
|
|
|
409
|
|
|
410
|
_finishshelve(repo)
|
|
410
|
_finishshelve(repo)
|
|
411
|
finally:
|
|
411
|
finally:
|
|
412
|
lockmod.release(tr, lock)
|
|
412
|
lockmod.release(tr, lock)
|
|
413
|
|
|
413
|
|
|
414
|
def _isbareshelve(pats, opts):
|
|
414
|
def _isbareshelve(pats, opts):
|
|
415
|
return (not pats
|
|
415
|
return (not pats
|
|
416
|
and not opts.get('interactive', False)
|
|
416
|
and not opts.get('interactive', False)
|
|
417
|
and not opts.get('include', False)
|
|
417
|
and not opts.get('include', False)
|
|
418
|
and not opts.get('exclude', False))
|
|
418
|
and not opts.get('exclude', False))
|
|
419
|
|
|
419
|
|
|
420
|
def _iswctxonnewbranch(repo):
|
|
420
|
def _iswctxonnewbranch(repo):
|
|
421
|
return repo[None].branch() != repo['.'].branch()
|
|
421
|
return repo[None].branch() != repo['.'].branch()
|
|
422
|
|
|
422
|
|
|
423
|
def cleanupcmd(ui, repo):
|
|
423
|
def cleanupcmd(ui, repo):
|
|
424
|
"""subcommand that deletes all shelves"""
|
|
424
|
"""subcommand that deletes all shelves"""
|
|
425
|
|
|
425
|
|
|
426
|
with repo.wlock():
|
|
426
|
with repo.wlock():
|
|
427
|
for (name, _type) in repo.vfs.readdir(shelvedir):
|
|
427
|
for (name, _type) in repo.vfs.readdir(shelvedir):
|
|
428
|
suffix = name.rsplit('.', 1)[-1]
|
|
428
|
suffix = name.rsplit('.', 1)[-1]
|
|
429
|
if suffix in shelvefileextensions:
|
|
429
|
if suffix in shelvefileextensions:
|
|
430
|
shelvedfile(repo, name).movetobackup()
|
|
430
|
shelvedfile(repo, name).movetobackup()
|
|
431
|
cleanupoldbackups(repo)
|
|
431
|
cleanupoldbackups(repo)
|
|
432
|
|
|
432
|
|
|
433
|
def deletecmd(ui, repo, pats):
|
|
433
|
def deletecmd(ui, repo, pats):
|
|
434
|
"""subcommand that deletes a specific shelve"""
|
|
434
|
"""subcommand that deletes a specific shelve"""
|
|
435
|
if not pats:
|
|
435
|
if not pats:
|
|
436
|
raise error.Abort(_('no shelved changes specified!'))
|
|
436
|
raise error.Abort(_('no shelved changes specified!'))
|
|
437
|
with repo.wlock():
|
|
437
|
with repo.wlock():
|
|
438
|
try:
|
|
438
|
try:
|
|
439
|
for name in pats:
|
|
439
|
for name in pats:
|
|
440
|
for suffix in shelvefileextensions:
|
|
440
|
for suffix in shelvefileextensions:
|
|
441
|
shfile = shelvedfile(repo, name, suffix)
|
|
441
|
shfile = shelvedfile(repo, name, suffix)
|
|
442
|
# patch file is necessary, as it should
|
|
442
|
# patch file is necessary, as it should
|
|
443
|
# be present for any kind of shelve,
|
|
443
|
# be present for any kind of shelve,
|
|
444
|
# but the .hg file is optional as in future we
|
|
444
|
# but the .hg file is optional as in future we
|
|
445
|
# will add obsolete shelve with does not create a
|
|
445
|
# will add obsolete shelve with does not create a
|
|
446
|
# bundle
|
|
446
|
# bundle
|
|
447
|
if shfile.exists() or suffix == 'patch':
|
|
447
|
if shfile.exists() or suffix == 'patch':
|
|
448
|
shfile.movetobackup()
|
|
448
|
shfile.movetobackup()
|
|
449
|
cleanupoldbackups(repo)
|
|
449
|
cleanupoldbackups(repo)
|
|
450
|
except OSError as err:
|
|
450
|
except OSError as err:
|
|
451
|
if err.errno != errno.ENOENT:
|
|
451
|
if err.errno != errno.ENOENT:
|
|
452
|
raise
|
|
452
|
raise
|
|
453
|
raise error.Abort(_("shelved change '%s' not found") % name)
|
|
453
|
raise error.Abort(_("shelved change '%s' not found") % name)
|
|
454
|
|
|
454
|
|
|
455
|
def listshelves(repo):
|
|
455
|
def listshelves(repo):
|
|
456
|
"""return all shelves in repo as list of (time, filename)"""
|
|
456
|
"""return all shelves in repo as list of (time, filename)"""
|
|
457
|
try:
|
|
457
|
try:
|
|
458
|
names = repo.vfs.readdir(shelvedir)
|
|
458
|
names = repo.vfs.readdir(shelvedir)
|
|
459
|
except OSError as err:
|
|
459
|
except OSError as err:
|
|
460
|
if err.errno != errno.ENOENT:
|
|
460
|
if err.errno != errno.ENOENT:
|
|
461
|
raise
|
|
461
|
raise
|
|
462
|
return []
|
|
462
|
return []
|
|
463
|
info = []
|
|
463
|
info = []
|
|
464
|
for (name, _type) in names:
|
|
464
|
for (name, _type) in names:
|
|
465
|
pfx, sfx = name.rsplit('.', 1)
|
|
465
|
pfx, sfx = name.rsplit('.', 1)
|
|
466
|
if not pfx or sfx != 'patch':
|
|
466
|
if not pfx or sfx != 'patch':
|
|
467
|
continue
|
|
467
|
continue
|
|
468
|
st = shelvedfile(repo, name).stat()
|
|
468
|
st = shelvedfile(repo, name).stat()
|
|
469
|
info.append((st.st_mtime, shelvedfile(repo, pfx).filename()))
|
|
469
|
info.append((st.st_mtime, shelvedfile(repo, pfx).filename()))
|
|
470
|
return sorted(info, reverse=True)
|
|
470
|
return sorted(info, reverse=True)
|
|
471
|
|
|
471
|
|
|
472
|
def listcmd(ui, repo, pats, opts):
|
|
472
|
def listcmd(ui, repo, pats, opts):
|
|
473
|
"""subcommand that displays the list of shelves"""
|
|
473
|
"""subcommand that displays the list of shelves"""
|
|
474
|
pats = set(pats)
|
|
474
|
pats = set(pats)
|
|
475
|
width = 80
|
|
475
|
width = 80
|
|
476
|
if not ui.plain():
|
|
476
|
if not ui.plain():
|
|
477
|
width = ui.termwidth()
|
|
477
|
width = ui.termwidth()
|
|
478
|
namelabel = 'shelve.newest'
|
|
478
|
namelabel = 'shelve.newest'
|
|
479
|
for mtime, name in listshelves(repo):
|
|
479
|
for mtime, name in listshelves(repo):
|
|
480
|
sname = util.split(name)[1]
|
|
480
|
sname = util.split(name)[1]
|
|
481
|
if pats and sname not in pats:
|
|
481
|
if pats and sname not in pats:
|
|
482
|
continue
|
|
482
|
continue
|
|
483
|
ui.write(sname, label=namelabel)
|
|
483
|
ui.write(sname, label=namelabel)
|
|
484
|
namelabel = 'shelve.name'
|
|
484
|
namelabel = 'shelve.name'
|
|
485
|
if ui.quiet:
|
|
485
|
if ui.quiet:
|
|
486
|
ui.write('\n')
|
|
486
|
ui.write('\n')
|
|
487
|
continue
|
|
487
|
continue
|
|
488
|
ui.write(' ' * (16 - len(sname)))
|
|
488
|
ui.write(' ' * (16 - len(sname)))
|
|
489
|
used = 16
|
|
489
|
used = 16
|
|
490
|
age = '(%s)' % templatefilters.age(util.makedate(mtime), abbrev=True)
|
|
490
|
age = '(%s)' % templatefilters.age(util.makedate(mtime), abbrev=True)
|
|
491
|
ui.write(age, label='shelve.age')
|
|
491
|
ui.write(age, label='shelve.age')
|
|
492
|
ui.write(' ' * (12 - len(age)))
|
|
492
|
ui.write(' ' * (12 - len(age)))
|
|
493
|
used += 12
|
|
493
|
used += 12
|
|
494
|
with open(name + '.patch', 'rb') as fp:
|
|
494
|
with open(name + '.patch', 'rb') as fp:
|
|
495
|
while True:
|
|
495
|
while True:
|
|
496
|
line = fp.readline()
|
|
496
|
line = fp.readline()
|
|
497
|
if not line:
|
|
497
|
if not line:
|
|
498
|
break
|
|
498
|
break
|
|
499
|
if not line.startswith('#'):
|
|
499
|
if not line.startswith('#'):
|
|
500
|
desc = line.rstrip()
|
|
500
|
desc = line.rstrip()
|
|
501
|
if ui.formatted():
|
|
501
|
if ui.formatted():
|
|
502
|
desc = util.ellipsis(desc, width - used)
|
|
502
|
desc = util.ellipsis(desc, width - used)
|
|
503
|
ui.write(desc)
|
|
503
|
ui.write(desc)
|
|
504
|
break
|
|
504
|
break
|
|
505
|
ui.write('\n')
|
|
505
|
ui.write('\n')
|
|
506
|
if not (opts['patch'] or opts['stat']):
|
|
506
|
if not (opts['patch'] or opts['stat']):
|
|
507
|
continue
|
|
507
|
continue
|
|
508
|
difflines = fp.readlines()
|
|
508
|
difflines = fp.readlines()
|
|
509
|
if opts['patch']:
|
|
509
|
if opts['patch']:
|
|
510
|
for chunk, label in patch.difflabel(iter, difflines):
|
|
510
|
for chunk, label in patch.difflabel(iter, difflines):
|
|
511
|
ui.write(chunk, label=label)
|
|
511
|
ui.write(chunk, label=label)
|
|
512
|
if opts['stat']:
|
|
512
|
if opts['stat']:
|
|
513
|
for chunk, label in patch.diffstatui(difflines, width=width):
|
|
513
|
for chunk, label in patch.diffstatui(difflines, width=width):
|
|
514
|
ui.write(chunk, label=label)
|
|
514
|
ui.write(chunk, label=label)
|
|
515
|
|
|
515
|
|
|
516
|
def singlepatchcmds(ui, repo, pats, opts, subcommand):
|
|
516
|
def singlepatchcmds(ui, repo, pats, opts, subcommand):
|
|
517
|
"""subcommand that displays a single shelf"""
|
|
517
|
"""subcommand that displays a single shelf"""
|
|
518
|
if len(pats) != 1:
|
|
518
|
if len(pats) != 1:
|
|
519
|
raise error.Abort(_("--%s expects a single shelf") % subcommand)
|
|
519
|
raise error.Abort(_("--%s expects a single shelf") % subcommand)
|
|
520
|
shelfname = pats[0]
|
|
520
|
shelfname = pats[0]
|
|
521
|
|
|
521
|
|
|
522
|
if not shelvedfile(repo, shelfname, 'patch').exists():
|
|
522
|
if not shelvedfile(repo, shelfname, 'patch').exists():
|
|
523
|
raise error.Abort(_("cannot find shelf %s") % shelfname)
|
|
523
|
raise error.Abort(_("cannot find shelf %s") % shelfname)
|
|
524
|
|
|
524
|
|
|
525
|
listcmd(ui, repo, pats, opts)
|
|
525
|
listcmd(ui, repo, pats, opts)
|
|
526
|
|
|
526
|
|
|
527
|
def checkparents(repo, state):
|
|
527
|
def checkparents(repo, state):
|
|
528
|
"""check parent while resuming an unshelve"""
|
|
528
|
"""check parent while resuming an unshelve"""
|
|
529
|
if state.parents != repo.dirstate.parents():
|
|
529
|
if state.parents != repo.dirstate.parents():
|
|
530
|
raise error.Abort(_('working directory parents do not match unshelve '
|
|
530
|
raise error.Abort(_('working directory parents do not match unshelve '
|
|
531
|
'state'))
|
|
531
|
'state'))
|
|
532
|
|
|
532
|
|
|
533
|
def pathtofiles(repo, files):
|
|
533
|
def pathtofiles(repo, files):
|
|
534
|
cwd = repo.getcwd()
|
|
534
|
cwd = repo.getcwd()
|
|
535
|
return [repo.pathto(f, cwd) for f in files]
|
|
535
|
return [repo.pathto(f, cwd) for f in files]
|
|
536
|
|
|
536
|
|
|
537
|
def unshelveabort(ui, repo, state, opts):
|
|
537
|
def unshelveabort(ui, repo, state, opts):
|
|
538
|
"""subcommand that abort an in-progress unshelve"""
|
|
538
|
"""subcommand that abort an in-progress unshelve"""
|
|
539
|
with repo.lock():
|
|
539
|
with repo.lock():
|
|
540
|
try:
|
|
540
|
try:
|
|
541
|
checkparents(repo, state)
|
|
541
|
checkparents(repo, state)
|
|
542
|
|
|
542
|
|
|
543
|
util.rename(repo.join('unshelverebasestate'),
|
|
543
|
util.rename(repo.join('unshelverebasestate'),
|
|
544
|
repo.join('rebasestate'))
|
|
544
|
repo.join('rebasestate'))
|
|
545
|
try:
|
|
545
|
try:
|
|
546
|
rebase.rebase(ui, repo, **{
|
|
546
|
rebase.rebase(ui, repo, **{
|
|
547
|
'abort' : True
|
|
547
|
'abort' : True
|
|
548
|
})
|
|
548
|
})
|
|
549
|
except Exception:
|
|
549
|
except Exception:
|
|
550
|
util.rename(repo.join('rebasestate'),
|
|
550
|
util.rename(repo.join('rebasestate'),
|
|
551
|
repo.join('unshelverebasestate'))
|
|
551
|
repo.join('unshelverebasestate'))
|
|
552
|
raise
|
|
552
|
raise
|
|
553
|
|
|
553
|
|
|
554
|
mergefiles(ui, repo, state.wctx, state.pendingctx)
|
|
554
|
mergefiles(ui, repo, state.wctx, state.pendingctx)
|
|
555
|
repair.strip(ui, repo, state.stripnodes, backup=False,
|
|
555
|
repair.strip(ui, repo, state.stripnodes, backup=False,
|
|
556
|
topic='shelve')
|
|
556
|
topic='shelve')
|
|
557
|
finally:
|
|
557
|
finally:
|
|
558
|
shelvedstate.clear(repo)
|
|
558
|
shelvedstate.clear(repo)
|
|
559
|
ui.warn(_("unshelve of '%s' aborted\n") % state.name)
|
|
559
|
ui.warn(_("unshelve of '%s' aborted\n") % state.name)
|
|
560
|
|
|
560
|
|
|
561
|
def mergefiles(ui, repo, wctx, shelvectx):
|
|
561
|
def mergefiles(ui, repo, wctx, shelvectx):
|
|
562
|
"""updates to wctx and merges the changes from shelvectx into the
|
|
562
|
"""updates to wctx and merges the changes from shelvectx into the
|
|
563
|
dirstate."""
|
|
563
|
dirstate."""
|
|
564
|
oldquiet = ui.quiet
|
|
564
|
oldquiet = ui.quiet
|
|
565
|
try:
|
|
565
|
try:
|
|
566
|
ui.quiet = True
|
|
566
|
ui.quiet = True
|
|
567
|
hg.update(repo, wctx.node())
|
|
567
|
hg.update(repo, wctx.node())
|
|
568
|
files = []
|
|
568
|
files = []
|
|
569
|
files.extend(shelvectx.files())
|
|
569
|
files.extend(shelvectx.files())
|
|
570
|
files.extend(shelvectx.parents()[0].files())
|
|
570
|
files.extend(shelvectx.parents()[0].files())
|
|
571
|
|
|
571
|
|
|
572
|
# revert will overwrite unknown files, so move them out of the way
|
|
572
|
# revert will overwrite unknown files, so move them out of the way
|
|
573
|
for file in repo.status(unknown=True).unknown:
|
|
573
|
for file in repo.status(unknown=True).unknown:
|
|
574
|
if file in files:
|
|
574
|
if file in files:
|
|
575
|
util.rename(file, scmutil.origpath(ui, repo, file))
|
|
575
|
util.rename(file, scmutil.origpath(ui, repo, file))
|
|
576
|
ui.pushbuffer(True)
|
|
576
|
ui.pushbuffer(True)
|
|
577
|
cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(),
|
|
577
|
cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(),
|
|
578
|
*pathtofiles(repo, files),
|
|
578
|
*pathtofiles(repo, files),
|
|
579
|
**{'no_backup': True})
|
|
579
|
**{'no_backup': True})
|
|
580
|
ui.popbuffer()
|
|
580
|
ui.popbuffer()
|
|
581
|
finally:
|
|
581
|
finally:
|
|
582
|
ui.quiet = oldquiet
|
|
582
|
ui.quiet = oldquiet
|
|
583
|
|
|
583
|
|
|
584
|
def restorebranch(ui, repo, branchtorestore):
|
|
584
|
def restorebranch(ui, repo, branchtorestore):
|
|
585
|
if branchtorestore and branchtorestore != repo.dirstate.branch():
|
|
585
|
if branchtorestore and branchtorestore != repo.dirstate.branch():
|
|
586
|
repo.dirstate.setbranch(branchtorestore)
|
|
586
|
repo.dirstate.setbranch(branchtorestore)
|
|
587
|
ui.status(_('marked working directory as branch %s\n')
|
|
587
|
ui.status(_('marked working directory as branch %s\n')
|
|
588
|
% branchtorestore)
|
|
588
|
% branchtorestore)
|
|
589
|
|
|
589
|
|
|
590
|
def unshelvecleanup(ui, repo, name, opts):
|
|
590
|
def unshelvecleanup(ui, repo, name, opts):
|
|
591
|
"""remove related files after an unshelve"""
|
|
591
|
"""remove related files after an unshelve"""
|
|
592
|
if not opts.get('keep'):
|
|
592
|
if not opts.get('keep'):
|
|
593
|
for filetype in shelvefileextensions:
|
|
593
|
for filetype in shelvefileextensions:
|
|
594
|
shfile = shelvedfile(repo, name, filetype)
|
|
594
|
shfile = shelvedfile(repo, name, filetype)
|
|
595
|
if shfile.exists():
|
|
595
|
if shfile.exists():
|
|
596
|
shfile.movetobackup()
|
|
596
|
shfile.movetobackup()
|
|
597
|
cleanupoldbackups(repo)
|
|
597
|
cleanupoldbackups(repo)
|
|
598
|
|
|
598
|
|
|
599
|
def unshelvecontinue(ui, repo, state, opts):
|
|
599
|
def unshelvecontinue(ui, repo, state, opts):
|
|
600
|
"""subcommand to continue an in-progress unshelve"""
|
|
600
|
"""subcommand to continue an in-progress unshelve"""
|
|
601
|
# We're finishing off a merge. First parent is our original
|
|
601
|
# We're finishing off a merge. First parent is our original
|
|
602
|
# parent, second is the temporary "fake" commit we're unshelving.
|
|
602
|
# parent, second is the temporary "fake" commit we're unshelving.
|
|
603
|
with repo.lock():
|
|
603
|
with repo.lock():
|
|
604
|
checkparents(repo, state)
|
|
604
|
checkparents(repo, state)
|
|
605
|
ms = merge.mergestate.read(repo)
|
|
605
|
ms = merge.mergestate.read(repo)
|
|
606
|
if [f for f in ms if ms[f] == 'u']:
|
|
606
|
if [f for f in ms if ms[f] == 'u']:
|
|
607
|
raise error.Abort(
|
|
607
|
raise error.Abort(
|
|
608
|
_("unresolved conflicts, can't continue"),
|
|
608
|
_("unresolved conflicts, can't continue"),
|
|
609
|
hint=_("see 'hg resolve', then 'hg unshelve --continue'"))
|
|
609
|
hint=_("see 'hg resolve', then 'hg unshelve --continue'"))
|
|
610
|
|
|
610
|
|
|
611
|
util.rename(repo.join('unshelverebasestate'),
|
|
611
|
util.rename(repo.join('unshelverebasestate'),
|
|
612
|
repo.join('rebasestate'))
|
|
612
|
repo.join('rebasestate'))
|
|
613
|
try:
|
|
613
|
try:
|
|
614
|
rebase.rebase(ui, repo, **{
|
|
614
|
rebase.rebase(ui, repo, **{
|
|
615
|
'continue' : True
|
|
615
|
'continue' : True
|
|
616
|
})
|
|
616
|
})
|
|
617
|
except Exception:
|
|
617
|
except Exception:
|
|
618
|
util.rename(repo.join('rebasestate'),
|
|
618
|
util.rename(repo.join('rebasestate'),
|
|
619
|
repo.join('unshelverebasestate'))
|
|
619
|
repo.join('unshelverebasestate'))
|
|
620
|
raise
|
|
620
|
raise
|
|
621
|
|
|
621
|
|
|
622
|
shelvectx = repo['tip']
|
|
622
|
shelvectx = repo['tip']
|
|
623
|
if not shelvectx in state.pendingctx.children():
|
|
623
|
if not shelvectx in state.pendingctx.children():
|
|
624
|
# rebase was a no-op, so it produced no child commit
|
|
624
|
# rebase was a no-op, so it produced no child commit
|
|
625
|
shelvectx = state.pendingctx
|
|
625
|
shelvectx = state.pendingctx
|
|
626
|
else:
|
|
626
|
else:
|
|
627
|
# only strip the shelvectx if the rebase produced it
|
|
627
|
# only strip the shelvectx if the rebase produced it
|
|
628
|
state.stripnodes.append(shelvectx.node())
|
|
628
|
state.stripnodes.append(shelvectx.node())
|
|
629
|
|
|
629
|
|
|
630
|
mergefiles(ui, repo, state.wctx, shelvectx)
|
|
630
|
mergefiles(ui, repo, state.wctx, shelvectx)
|
|
631
|
restorebranch(ui, repo, state.branchtorestore)
|
|
631
|
restorebranch(ui, repo, state.branchtorestore)
|
|
632
|
|
|
632
|
|
|
633
|
repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve')
|
|
633
|
repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve')
|
|
634
|
shelvedstate.clear(repo)
|
|
634
|
shelvedstate.clear(repo)
|
|
635
|
unshelvecleanup(ui, repo, state.name, opts)
|
|
635
|
unshelvecleanup(ui, repo, state.name, opts)
|
|
636
|
ui.status(_("unshelve of '%s' complete\n") % state.name)
|
|
636
|
ui.status(_("unshelve of '%s' complete\n") % state.name)
|
|
637
|
|
|
637
|
|
|
638
|
def _commitworkingcopychanges(ui, repo, opts, tmpwctx):
|
|
638
|
def _commitworkingcopychanges(ui, repo, opts, tmpwctx):
|
|
639
|
"""Temporarily commit working copy changes before moving unshelve commit"""
|
|
639
|
"""Temporarily commit working copy changes before moving unshelve commit"""
|
|
640
|
# Store pending changes in a commit and remember added in case a shelve
|
|
640
|
# Store pending changes in a commit and remember added in case a shelve
|
|
641
|
# contains unknown files that are part of the pending change
|
|
641
|
# contains unknown files that are part of the pending change
|
|
642
|
s = repo.status()
|
|
642
|
s = repo.status()
|
|
643
|
addedbefore = frozenset(s.added)
|
|
643
|
addedbefore = frozenset(s.added)
|
|
644
|
if not (s.modified or s.added or s.removed or s.deleted):
|
|
644
|
if not (s.modified or s.added or s.removed or s.deleted):
|
|
645
|
return tmpwctx, addedbefore
|
|
645
|
return tmpwctx, addedbefore
|
|
646
|
ui.status(_("temporarily committing pending changes "
|
|
646
|
ui.status(_("temporarily committing pending changes "
|
|
647
|
"(restore with 'hg unshelve --abort')\n"))
|
|
647
|
"(restore with 'hg unshelve --abort')\n"))
|
|
648
|
commitfunc = getcommitfunc(extra=None, interactive=False,
|
|
648
|
commitfunc = getcommitfunc(extra=None, interactive=False,
|
|
649
|
editor=False)
|
|
649
|
editor=False)
|
|
650
|
tempopts = {}
|
|
650
|
tempopts = {}
|
|
651
|
tempopts['message'] = "pending changes temporary commit"
|
|
651
|
tempopts['message'] = "pending changes temporary commit"
|
|
652
|
tempopts['date'] = opts.get('date')
|
|
652
|
tempopts['date'] = opts.get('date')
|
|
653
|
ui.quiet = True
|
|
653
|
ui.quiet = True
|
|
654
|
node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
|
|
654
|
node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
|
|
655
|
tmpwctx = repo[node]
|
|
655
|
tmpwctx = repo[node]
|
|
656
|
return tmpwctx, addedbefore
|
|
656
|
return tmpwctx, addedbefore
|
|
657
|
|
|
657
|
|
|
658
|
def _unshelverestorecommit(ui, repo, basename, oldquiet):
|
|
658
|
def _unshelverestorecommit(ui, repo, basename, oldquiet):
|
|
659
|
"""Recreate commit in the repository during the unshelve"""
|
|
659
|
"""Recreate commit in the repository during the unshelve"""
|
|
660
|
ui.quiet = True
|
|
660
|
ui.quiet = True
|
|
661
|
shelvedfile(repo, basename, 'hg').applybundle()
|
|
661
|
shelvedfile(repo, basename, 'hg').applybundle()
|
|
662
|
shelvectx = repo['tip']
|
|
662
|
shelvectx = repo['tip']
|
|
663
|
ui.quiet = oldquiet
|
|
663
|
ui.quiet = oldquiet
|
|
664
|
return repo, shelvectx
|
|
664
|
return repo, shelvectx
|
|
665
|
|
|
665
|
|
|
666
|
def _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev, basename, pctx,
|
|
666
|
def _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev, basename, pctx,
|
|
667
|
tmpwctx, shelvectx, branchtorestore):
|
|
667
|
tmpwctx, shelvectx, branchtorestore):
|
|
668
|
"""Rebase restored commit from its original location to a destination"""
|
|
668
|
"""Rebase restored commit from its original location to a destination"""
|
|
669
|
# If the shelve is not immediately on top of the commit
|
|
669
|
# If the shelve is not immediately on top of the commit
|
|
670
|
# we'll be merging with, rebase it to be on top.
|
|
670
|
# we'll be merging with, rebase it to be on top.
|
|
671
|
if tmpwctx.node() == shelvectx.parents()[0].node():
|
|
671
|
if tmpwctx.node() == shelvectx.parents()[0].node():
|
|
672
|
return shelvectx
|
|
672
|
return shelvectx
|
|
673
|
|
|
673
|
|
|
674
|
ui.status(_('rebasing shelved changes\n'))
|
|
674
|
ui.status(_('rebasing shelved changes\n'))
|
|
675
|
try:
|
|
675
|
try:
|
|
676
|
rebase.rebase(ui, repo, **{
|
|
676
|
rebase.rebase(ui, repo, **{
|
|
677
|
'rev': [shelvectx.rev()],
|
|
677
|
'rev': [shelvectx.rev()],
|
|
678
|
'dest': str(tmpwctx.rev()),
|
|
678
|
'dest': str(tmpwctx.rev()),
|
|
679
|
'keep': True,
|
|
679
|
'keep': True,
|
|
680
|
'tool': opts.get('tool', ''),
|
|
680
|
'tool': opts.get('tool', ''),
|
|
681
|
})
|
|
681
|
})
|
|
682
|
except error.InterventionRequired:
|
|
682
|
except error.InterventionRequired:
|
|
683
|
tr.close()
|
|
683
|
tr.close()
|
|
684
|
|
|
684
|
|
|
685
|
stripnodes = [repo.changelog.node(rev)
|
|
685
|
stripnodes = [repo.changelog.node(rev)
|
|
686
|
for rev in xrange(oldtiprev, len(repo))]
|
|
686
|
for rev in xrange(oldtiprev, len(repo))]
|
|
687
|
shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes,
|
|
687
|
shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes,
|
|
688
|
branchtorestore, opts.get('keep'))
|
|
688
|
branchtorestore, opts.get('keep'))
|
|
689
|
|
|
689
|
|
|
690
|
util.rename(repo.join('rebasestate'),
|
|
690
|
util.rename(repo.join('rebasestate'),
|
|
691
|
repo.join('unshelverebasestate'))
|
|
691
|
repo.join('unshelverebasestate'))
|
|
692
|
raise error.InterventionRequired(
|
|
692
|
raise error.InterventionRequired(
|
|
693
|
_("unresolved conflicts (see 'hg resolve', then "
|
|
693
|
_("unresolved conflicts (see 'hg resolve', then "
|
|
694
|
"'hg unshelve --continue')"))
|
|
694
|
"'hg unshelve --continue')"))
|
|
695
|
|
|
695
|
|
|
696
|
# refresh ctx after rebase completes
|
|
696
|
# refresh ctx after rebase completes
|
|
697
|
shelvectx = repo['tip']
|
|
697
|
shelvectx = repo['tip']
|
|
698
|
|
|
698
|
|
|
699
|
if not shelvectx in tmpwctx.children():
|
|
699
|
if not shelvectx in tmpwctx.children():
|
|
700
|
# rebase was a no-op, so it produced no child commit
|
|
700
|
# rebase was a no-op, so it produced no child commit
|
|
701
|
shelvectx = tmpwctx
|
|
701
|
shelvectx = tmpwctx
|
|
702
|
return shelvectx
|
|
702
|
return shelvectx
|
|
703
|
|
|
703
|
|
|
704
|
def _forgetunknownfiles(repo, shelvectx, addedbefore):
|
|
704
|
def _forgetunknownfiles(repo, shelvectx, addedbefore):
|
|
705
|
# Forget any files that were unknown before the shelve, unknown before
|
|
705
|
# Forget any files that were unknown before the shelve, unknown before
|
|
706
|
# unshelve started, but are now added.
|
|
706
|
# unshelve started, but are now added.
|
|
707
|
shelveunknown = shelvectx.extra().get('shelve_unknown')
|
|
707
|
shelveunknown = shelvectx.extra().get('shelve_unknown')
|
|
708
|
if not shelveunknown:
|
|
708
|
if not shelveunknown:
|
|
709
|
return
|
|
709
|
return
|
|
710
|
shelveunknown = frozenset(shelveunknown.split('\0'))
|
|
710
|
shelveunknown = frozenset(shelveunknown.split('\0'))
|
|
711
|
addedafter = frozenset(repo.status().added)
|
|
711
|
addedafter = frozenset(repo.status().added)
|
|
712
|
toforget = (addedafter & shelveunknown) - addedbefore
|
|
712
|
toforget = (addedafter & shelveunknown) - addedbefore
|
|
713
|
repo[None].forget(toforget)
|
|
713
|
repo[None].forget(toforget)
|
|
714
|
|
|
714
|
|
|
715
|
def _finishunshelve(repo, oldtiprev, tr):
|
|
715
|
def _finishunshelve(repo, oldtiprev, tr):
|
|
716
|
# The transaction aborting will strip all the commits for us,
|
|
716
|
# The transaction aborting will strip all the commits for us,
|
|
717
|
# but it doesn't update the inmemory structures, so addchangegroup
|
|
717
|
# but it doesn't update the inmemory structures, so addchangegroup
|
|
718
|
# hooks still fire and try to operate on the missing commits.
|
|
718
|
# hooks still fire and try to operate on the missing commits.
|
|
719
|
# Clean up manually to prevent this.
|
|
719
|
# Clean up manually to prevent this.
|
|
720
|
repo.unfiltered().changelog.strip(oldtiprev, tr)
|
|
720
|
repo.unfiltered().changelog.strip(oldtiprev, tr)
|
|
721
|
_aborttransaction(repo)
|
|
721
|
_aborttransaction(repo)
|
|
722
|
|
|
722
|
|
|
723
|
@command('unshelve',
|
|
723
|
@command('unshelve',
|
|
724
|
[('a', 'abort', None,
|
|
724
|
[('a', 'abort', None,
|
|
725
|
_('abort an incomplete unshelve operation')),
|
|
725
|
_('abort an incomplete unshelve operation')),
|
|
726
|
('c', 'continue', None,
|
|
726
|
('c', 'continue', None,
|
|
727
|
_('continue an incomplete unshelve operation')),
|
|
727
|
_('continue an incomplete unshelve operation')),
|
|
728
|
('k', 'keep', None,
|
|
728
|
('k', 'keep', None,
|
|
729
|
_('keep shelve after unshelving')),
|
|
729
|
_('keep shelve after unshelving')),
|
|
730
|
('t', 'tool', '', _('specify merge tool')),
|
|
730
|
('t', 'tool', '', _('specify merge tool')),
|
|
731
|
('', 'date', '',
|
|
731
|
('', 'date', '',
|
|
732
|
_('set date for temporary commits (DEPRECATED)'), _('DATE'))],
|
|
732
|
_('set date for temporary commits (DEPRECATED)'), _('DATE'))],
|
|
733
|
_('hg unshelve [SHELVED]'))
|
|
733
|
_('hg unshelve [SHELVED]'))
|
|
734
|
def unshelve(ui, repo, *shelved, **opts):
|
|
734
|
def unshelve(ui, repo, *shelved, **opts):
|
|
735
|
"""restore a shelved change to the working directory
|
|
735
|
"""restore a shelved change to the working directory
|
|
736
|
|
|
736
|
|
|
737
|
This command accepts an optional name of a shelved change to
|
|
737
|
This command accepts an optional name of a shelved change to
|
|
738
|
restore. If none is given, the most recent shelved change is used.
|
|
738
|
restore. If none is given, the most recent shelved change is used.
|
|
739
|
|
|
739
|
|
|
740
|
If a shelved change is applied successfully, the bundle that
|
|
740
|
If a shelved change is applied successfully, the bundle that
|
|
741
|
contains the shelved changes is moved to a backup location
|
|
741
|
contains the shelved changes is moved to a backup location
|
|
742
|
(.hg/shelve-backup).
|
|
742
|
(.hg/shelve-backup).
|
|
743
|
|
|
743
|
|
|
744
|
Since you can restore a shelved change on top of an arbitrary
|
|
744
|
Since you can restore a shelved change on top of an arbitrary
|
|
745
|
commit, it is possible that unshelving will result in a conflict
|
|
745
|
commit, it is possible that unshelving will result in a conflict
|
|
746
|
between your changes and the commits you are unshelving onto. If
|
|
746
|
between your changes and the commits you are unshelving onto. If
|
|
747
|
this occurs, you must resolve the conflict, then use
|
|
747
|
this occurs, you must resolve the conflict, then use
|
|
748
|
``--continue`` to complete the unshelve operation. (The bundle
|
|
748
|
``--continue`` to complete the unshelve operation. (The bundle
|
|
749
|
will not be moved until you successfully complete the unshelve.)
|
|
749
|
will not be moved until you successfully complete the unshelve.)
|
|
750
|
|
|
750
|
|
|
751
|
(Alternatively, you can use ``--abort`` to abandon an unshelve
|
|
751
|
(Alternatively, you can use ``--abort`` to abandon an unshelve
|
|
752
|
that causes a conflict. This reverts the unshelved changes, and
|
|
752
|
that causes a conflict. This reverts the unshelved changes, and
|
|
753
|
leaves the bundle in place.)
|
|
753
|
leaves the bundle in place.)
|
|
754
|
|
|
754
|
|
|
755
|
If bare shelved change(when no files are specified, without interactive,
|
|
755
|
If bare shelved change(when no files are specified, without interactive,
|
|
756
|
include and exclude option) was done on newly created branch it would
|
|
756
|
include and exclude option) was done on newly created branch it would
|
|
757
|
restore branch information to the working directory.
|
|
757
|
restore branch information to the working directory.
|
|
758
|
|
|
758
|
|
|
759
|
After a successful unshelve, the shelved changes are stored in a
|
|
759
|
After a successful unshelve, the shelved changes are stored in a
|
|
760
|
backup directory. Only the N most recent backups are kept. N
|
|
760
|
backup directory. Only the N most recent backups are kept. N
|
|
761
|
defaults to 10 but can be overridden using the ``shelve.maxbackups``
|
|
761
|
defaults to 10 but can be overridden using the ``shelve.maxbackups``
|
|
762
|
configuration option.
|
|
762
|
configuration option.
|
|
763
|
|
|
763
|
|
|
764
|
.. container:: verbose
|
|
764
|
.. container:: verbose
|
|
765
|
|
|
765
|
|
|
766
|
Timestamp in seconds is used to decide order of backups. More
|
|
766
|
Timestamp in seconds is used to decide order of backups. More
|
|
767
|
than ``maxbackups`` backups are kept, if same timestamp
|
|
767
|
than ``maxbackups`` backups are kept, if same timestamp
|
|
768
|
prevents from deciding exact order of them, for safety.
|
|
768
|
prevents from deciding exact order of them, for safety.
|
|
769
|
"""
|
|
769
|
"""
|
|
770
|
with repo.wlock():
|
|
770
|
with repo.wlock():
|
|
771
|
return _dounshelve(ui, repo, *shelved, **opts)
|
|
771
|
return _dounshelve(ui, repo, *shelved, **opts)
|
|
772
|
|
|
772
|
|
|
773
|
def _dounshelve(ui, repo, *shelved, **opts):
|
|
773
|
def _dounshelve(ui, repo, *shelved, **opts):
|
|
774
|
abortf = opts.get('abort')
|
|
774
|
abortf = opts.get('abort')
|
|
775
|
continuef = opts.get('continue')
|
|
775
|
continuef = opts.get('continue')
|
|
776
|
if not abortf and not continuef:
|
|
776
|
if not abortf and not continuef:
|
|
777
|
cmdutil.checkunfinished(repo)
|
|
777
|
cmdutil.checkunfinished(repo)
|
|
778
|
|
|
778
|
|
|
779
|
if abortf or continuef:
|
|
779
|
if abortf or continuef:
|
|
780
|
if abortf and continuef:
|
|
780
|
if abortf and continuef:
|
|
781
|
raise error.Abort(_('cannot use both abort and continue'))
|
|
781
|
raise error.Abort(_('cannot use both abort and continue'))
|
|
782
|
if shelved:
|
|
782
|
if shelved:
|
|
783
|
raise error.Abort(_('cannot combine abort/continue with '
|
|
783
|
raise error.Abort(_('cannot combine abort/continue with '
|
|
784
|
'naming a shelved change'))
|
|
784
|
'naming a shelved change'))
|
|
785
|
if abortf and opts.get('tool', False):
|
|
785
|
if abortf and opts.get('tool', False):
|
|
786
|
ui.warn(_('tool option will be ignored\n'))
|
|
786
|
ui.warn(_('tool option will be ignored\n'))
|
|
787
|
|
|
787
|
|
|
788
|
try:
|
|
788
|
try:
|
|
789
|
state = shelvedstate.load(repo)
|
|
789
|
state = shelvedstate.load(repo)
|
|
790
|
if opts.get('keep') is None:
|
|
790
|
if opts.get('keep') is None:
|
|
791
|
opts['keep'] = state.keep
|
|
791
|
opts['keep'] = state.keep
|
|
792
|
except IOError as err:
|
|
792
|
except IOError as err:
|
|
793
|
if err.errno != errno.ENOENT:
|
|
793
|
if err.errno != errno.ENOENT:
|
|
794
|
raise
|
|
794
|
raise
|
|
795
|
cmdutil.wrongtooltocontinue(repo, _('unshelve'))
|
|
795
|
cmdutil.wrongtooltocontinue(repo, _('unshelve'))
|
|
796
|
except error.CorruptedState as err:
|
|
796
|
except error.CorruptedState as err:
|
|
797
|
ui.debug(str(err) + '\n')
|
|
797
|
ui.debug(str(err) + '\n')
|
|
798
|
if continuef:
|
|
798
|
if continuef:
|
|
799
|
msg = _('corrupted shelved state file')
|
|
799
|
msg = _('corrupted shelved state file')
|
|
800
|
hint = _('please run hg unshelve --abort to abort unshelve '
|
|
800
|
hint = _('please run hg unshelve --abort to abort unshelve '
|
|
801
|
'operation')
|
|
801
|
'operation')
|
|
802
|
raise error.Abort(msg, hint=hint)
|
|
802
|
raise error.Abort(msg, hint=hint)
|
|
803
|
elif abortf:
|
|
803
|
elif abortf:
|
|
804
|
msg = _('could not read shelved state file, your working copy '
|
|
804
|
msg = _('could not read shelved state file, your working copy '
|
|
805
|
'may be in an unexpected state\nplease update to some '
|
|
805
|
'may be in an unexpected state\nplease update to some '
|
|
806
|
'commit\n')
|
|
806
|
'commit\n')
|
|
807
|
ui.warn(msg)
|
|
807
|
ui.warn(msg)
|
|
808
|
shelvedstate.clear(repo)
|
|
808
|
shelvedstate.clear(repo)
|
|
809
|
return
|
|
809
|
return
|
|
810
|
|
|
810
|
|
|
811
|
if abortf:
|
|
811
|
if abortf:
|
|
812
|
return unshelveabort(ui, repo, state, opts)
|
|
812
|
return unshelveabort(ui, repo, state, opts)
|
|
813
|
elif continuef:
|
|
813
|
elif continuef:
|
|
814
|
return unshelvecontinue(ui, repo, state, opts)
|
|
814
|
return unshelvecontinue(ui, repo, state, opts)
|
|
815
|
elif len(shelved) > 1:
|
|
815
|
elif len(shelved) > 1:
|
|
816
|
raise error.Abort(_('can only unshelve one change at a time'))
|
|
816
|
raise error.Abort(_('can only unshelve one change at a time'))
|
|
817
|
elif not shelved:
|
|
817
|
elif not shelved:
|
|
818
|
shelved = listshelves(repo)
|
|
818
|
shelved = listshelves(repo)
|
|
819
|
if not shelved:
|
|
819
|
if not shelved:
|
|
820
|
raise error.Abort(_('no shelved changes to apply!'))
|
|
820
|
raise error.Abort(_('no shelved changes to apply!'))
|
|
821
|
basename = util.split(shelved[0][1])[1]
|
|
821
|
basename = util.split(shelved[0][1])[1]
|
|
822
|
ui.status(_("unshelving change '%s'\n") % basename)
|
|
822
|
ui.status(_("unshelving change '%s'\n") % basename)
|
|
823
|
else:
|
|
823
|
else:
|
|
824
|
basename = shelved[0]
|
|
824
|
basename = shelved[0]
|
|
825
|
|
|
825
|
|
|
826
|
if not shelvedfile(repo, basename, 'patch').exists():
|
|
826
|
if not shelvedfile(repo, basename, 'patch').exists():
|
|
827
|
raise error.Abort(_("shelved change '%s' not found") % basename)
|
|
827
|
raise error.Abort(_("shelved change '%s' not found") % basename)
|
|
828
|
|
|
828
|
|
|
829
|
oldquiet = ui.quiet
|
|
829
|
oldquiet = ui.quiet
|
|
830
|
lock = tr = None
|
|
830
|
lock = tr = None
|
|
831
|
forcemerge = ui.backupconfig('ui', 'forcemerge')
|
|
831
|
forcemerge = ui.backupconfig('ui', 'forcemerge')
|
|
832
|
try:
|
|
832
|
try:
|
|
833
|
ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'unshelve')
|
|
833
|
ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'unshelve')
|
|
834
|
lock = repo.lock()
|
|
834
|
lock = repo.lock()
|
|
835
|
|
|
835
|
|
|
836
|
tr = repo.transaction('unshelve', report=lambda x: None)
|
|
836
|
tr = repo.transaction('unshelve', report=lambda x: None)
|
|
837
|
oldtiprev = len(repo)
|
|
837
|
oldtiprev = len(repo)
|
|
838
|
|
|
838
|
|
|
839
|
pctx = repo['.']
|
|
839
|
pctx = repo['.']
|
|
840
|
tmpwctx = pctx
|
|
840
|
tmpwctx = pctx
|
|
841
|
# The goal is to have a commit structure like so:
|
|
841
|
# The goal is to have a commit structure like so:
|
|
842
|
# ...-> pctx -> tmpwctx -> shelvectx
|
|
842
|
# ...-> pctx -> tmpwctx -> shelvectx
|
|
843
|
# where tmpwctx is an optional commit with the user's pending changes
|
|
843
|
# where tmpwctx is an optional commit with the user's pending changes
|
|
844
|
# and shelvectx is the unshelved changes. Then we merge it all down
|
|
844
|
# and shelvectx is the unshelved changes. Then we merge it all down
|
|
845
|
# to the original pctx.
|
|
845
|
# to the original pctx.
|
|
846
|
|
|
846
|
|
|
847
|
tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts,
|
|
847
|
tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts,
|
|
848
|
tmpwctx)
|
|
848
|
tmpwctx)
|
|
849
|
|
|
849
|
|
|
850
|
repo, shelvectx = _unshelverestorecommit(ui, repo, basename, oldquiet)
|
|
850
|
repo, shelvectx = _unshelverestorecommit(ui, repo, basename, oldquiet)
|
|
851
|
|
|
851
|
|
|
852
|
branchtorestore = ''
|
|
852
|
branchtorestore = ''
|
|
853
|
if shelvectx.branch() != shelvectx.p1().branch():
|
|
853
|
if shelvectx.branch() != shelvectx.p1().branch():
|
|
854
|
branchtorestore = shelvectx.branch()
|
|
854
|
branchtorestore = shelvectx.branch()
|
|
855
|
|
|
855
|
|
|
856
|
shelvectx = _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev,
|
|
856
|
shelvectx = _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev,
|
|
857
|
basename, pctx, tmpwctx, shelvectx,
|
|
857
|
basename, pctx, tmpwctx, shelvectx,
|
|
858
|
branchtorestore)
|
|
858
|
branchtorestore)
|
|
859
|
mergefiles(ui, repo, pctx, shelvectx)
|
|
859
|
mergefiles(ui, repo, pctx, shelvectx)
|
|
860
|
restorebranch(ui, repo, branchtorestore)
|
|
860
|
restorebranch(ui, repo, branchtorestore)
|
|
861
|
_forgetunknownfiles(repo, shelvectx, addedbefore)
|
|
861
|
_forgetunknownfiles(repo, shelvectx, addedbefore)
|
|
862
|
|
|
862
|
|
|
863
|
shelvedstate.clear(repo)
|
|
863
|
shelvedstate.clear(repo)
|
|
864
|
_finishunshelve(repo, oldtiprev, tr)
|
|
864
|
_finishunshelve(repo, oldtiprev, tr)
|
|
865
|
unshelvecleanup(ui, repo, basename, opts)
|
|
865
|
unshelvecleanup(ui, repo, basename, opts)
|
|
866
|
finally:
|
|
866
|
finally:
|
|
867
|
ui.quiet = oldquiet
|
|
867
|
ui.quiet = oldquiet
|
|
868
|
if tr:
|
|
868
|
if tr:
|
|
869
|
tr.release()
|
|
869
|
tr.release()
|
|
870
|
lockmod.release(lock)
|
|
870
|
lockmod.release(lock)
|
|
871
|
ui.restoreconfig(forcemerge)
|
|
871
|
ui.restoreconfig(forcemerge)
|
|
872
|
|
|
872
|
|
|
873
|
@command('shelve',
|
|
873
|
@command('shelve',
|
|
874
|
[('A', 'addremove', None,
|
|
874
|
[('A', 'addremove', None,
|
|
875
|
_('mark new/missing files as added/removed before shelving')),
|
|
875
|
_('mark new/missing files as added/removed before shelving')),
|
|
876
|
('u', 'unknown', None,
|
|
876
|
('u', 'unknown', None,
|
|
877
|
_('store unknown files in the shelve')),
|
|
877
|
_('store unknown files in the shelve')),
|
|
878
|
('', 'cleanup', None,
|
|
878
|
('', 'cleanup', None,
|
|
879
|
_('delete all shelved changes')),
|
|
879
|
_('delete all shelved changes')),
|
|
880
|
('', 'date', '',
|
|
880
|
('', 'date', '',
|
|
881
|
_('shelve with the specified commit date'), _('DATE')),
|
|
881
|
_('shelve with the specified commit date'), _('DATE')),
|
|
882
|
('d', 'delete', None,
|
|
882
|
('d', 'delete', None,
|
|
883
|
_('delete the named shelved change(s)')),
|
|
883
|
_('delete the named shelved change(s)')),
|
|
884
|
('e', 'edit', False,
|
|
884
|
('e', 'edit', False,
|
|
885
|
_('invoke editor on commit messages')),
|
|
885
|
_('invoke editor on commit messages')),
|
|
886
|
('l', 'list', None,
|
|
886
|
('l', 'list', None,
|
|
887
|
_('list current shelves')),
|
|
887
|
_('list current shelves')),
|
|
888
|
('m', 'message', '',
|
|
888
|
('m', 'message', '',
|
|
889
|
_('use text as shelve message'), _('TEXT')),
|
|
889
|
_('use text as shelve message'), _('TEXT')),
|
|
890
|
('n', 'name', '',
|
|
890
|
('n', 'name', '',
|
|
891
|
_('use the given name for the shelved commit'), _('NAME')),
|
|
891
|
_('use the given name for the shelved commit'), _('NAME')),
|
|
892
|
('p', 'patch', None,
|
|
892
|
('p', 'patch', None,
|
|
893
|
_('show patch')),
|
|
893
|
_('show patch')),
|
|
894
|
('i', 'interactive', None,
|
|
894
|
('i', 'interactive', None,
|
|
895
|
_('interactive mode, only works while creating a shelve')),
|
|
895
|
_('interactive mode, only works while creating a shelve')),
|
|
896
|
('', 'stat', None,
|
|
896
|
('', 'stat', None,
|
|
897
|
_('output diffstat-style summary of changes'))] + commands.walkopts,
|
|
897
|
_('output diffstat-style summary of changes'))] + commands.walkopts,
|
|
898
|
_('hg shelve [OPTION]... [FILE]...'))
|
|
898
|
_('hg shelve [OPTION]... [FILE]...'))
|
|
899
|
def shelvecmd(ui, repo, *pats, **opts):
|
|
899
|
def shelvecmd(ui, repo, *pats, **opts):
|
|
900
|
'''save and set aside changes from the working directory
|
|
900
|
'''save and set aside changes from the working directory
|
|
901
|
|
|
901
|
|
|
902
|
Shelving takes files that "hg status" reports as not clean, saves
|
|
902
|
Shelving takes files that "hg status" reports as not clean, saves
|
|
903
|
the modifications to a bundle (a shelved change), and reverts the
|
|
903
|
the modifications to a bundle (a shelved change), and reverts the
|
|
904
|
files so that their state in the working directory becomes clean.
|
|
904
|
files so that their state in the working directory becomes clean.
|
|
905
|
|
|
905
|
|
|
906
|
To restore these changes to the working directory, using "hg
|
|
906
|
To restore these changes to the working directory, using "hg
|
|
907
|
unshelve"; this will work even if you switch to a different
|
|
907
|
unshelve"; this will work even if you switch to a different
|
|
908
|
commit.
|
|
908
|
commit.
|
|
909
|
|
|
909
|
|
|
910
|
When no files are specified, "hg shelve" saves all not-clean
|
|
910
|
When no files are specified, "hg shelve" saves all not-clean
|
|
911
|
files. If specific files or directories are named, only changes to
|
|
911
|
files. If specific files or directories are named, only changes to
|
|
912
|
those files are shelved.
|
|
912
|
those files are shelved.
|
|
913
|
|
|
913
|
|
|
914
|
In bare shelve(when no files are specified, without interactive,
|
|
914
|
In bare shelve (when no files are specified, without interactive,
|
|
915
|
include and exclude option), shelving remembers information if the
|
|
915
|
include and exclude option), shelving remembers information if the
|
|
916
|
working directory was on newly created branch, in other words working
|
|
916
|
working directory was on newly created branch, in other words working
|
|
917
|
directory was on different branch than its first parent. In this
|
|
917
|
directory was on different branch than its first parent. In this
|
|
918
|
situation unshelving restores branch information to the working directory.
|
|
918
|
situation unshelving restores branch information to the working directory.
|
|
919
|
|
|
919
|
|
|
920
|
Each shelved change has a name that makes it easier to find later.
|
|
920
|
Each shelved change has a name that makes it easier to find later.
|
|
921
|
The name of a shelved change defaults to being based on the active
|
|
921
|
The name of a shelved change defaults to being based on the active
|
|
922
|
bookmark, or if there is no active bookmark, the current named
|
|
922
|
bookmark, or if there is no active bookmark, the current named
|
|
923
|
branch. To specify a different name, use ``--name``.
|
|
923
|
branch. To specify a different name, use ``--name``.
|
|
924
|
|
|
924
|
|
|
925
|
To see a list of existing shelved changes, use the ``--list``
|
|
925
|
To see a list of existing shelved changes, use the ``--list``
|
|
926
|
option. For each shelved change, this will print its name, age,
|
|
926
|
option. For each shelved change, this will print its name, age,
|
|
927
|
and description; use ``--patch`` or ``--stat`` for more details.
|
|
927
|
and description; use ``--patch`` or ``--stat`` for more details.
|
|
928
|
|
|
928
|
|
|
929
|
To delete specific shelved changes, use ``--delete``. To delete
|
|
929
|
To delete specific shelved changes, use ``--delete``. To delete
|
|
930
|
all shelved changes, use ``--cleanup``.
|
|
930
|
all shelved changes, use ``--cleanup``.
|
|
931
|
'''
|
|
931
|
'''
|
|
932
|
allowables = [
|
|
932
|
allowables = [
|
|
933
|
('addremove', set(['create'])), # 'create' is pseudo action
|
|
933
|
('addremove', set(['create'])), # 'create' is pseudo action
|
|
934
|
('unknown', set(['create'])),
|
|
934
|
('unknown', set(['create'])),
|
|
935
|
('cleanup', set(['cleanup'])),
|
|
935
|
('cleanup', set(['cleanup'])),
|
|
936
|
# ('date', set(['create'])), # ignored for passing '--date "0 0"' in tests
|
|
936
|
# ('date', set(['create'])), # ignored for passing '--date "0 0"' in tests
|
|
937
|
('delete', set(['delete'])),
|
|
937
|
('delete', set(['delete'])),
|
|
938
|
('edit', set(['create'])),
|
|
938
|
('edit', set(['create'])),
|
|
939
|
('list', set(['list'])),
|
|
939
|
('list', set(['list'])),
|
|
940
|
('message', set(['create'])),
|
|
940
|
('message', set(['create'])),
|
|
941
|
('name', set(['create'])),
|
|
941
|
('name', set(['create'])),
|
|
942
|
('patch', set(['patch', 'list'])),
|
|
942
|
('patch', set(['patch', 'list'])),
|
|
943
|
('stat', set(['stat', 'list'])),
|
|
943
|
('stat', set(['stat', 'list'])),
|
|
944
|
]
|
|
944
|
]
|
|
945
|
def checkopt(opt):
|
|
945
|
def checkopt(opt):
|
|
946
|
if opts.get(opt):
|
|
946
|
if opts.get(opt):
|
|
947
|
for i, allowable in allowables:
|
|
947
|
for i, allowable in allowables:
|
|
948
|
if opts[i] and opt not in allowable:
|
|
948
|
if opts[i] and opt not in allowable:
|
|
949
|
raise error.Abort(_("options '--%s' and '--%s' may not be "
|
|
949
|
raise error.Abort(_("options '--%s' and '--%s' may not be "
|
|
950
|
"used together") % (opt, i))
|
|
950
|
"used together") % (opt, i))
|
|
951
|
return True
|
|
951
|
return True
|
|
952
|
if checkopt('cleanup'):
|
|
952
|
if checkopt('cleanup'):
|
|
953
|
if pats:
|
|
953
|
if pats:
|
|
954
|
raise error.Abort(_("cannot specify names when using '--cleanup'"))
|
|
954
|
raise error.Abort(_("cannot specify names when using '--cleanup'"))
|
|
955
|
return cleanupcmd(ui, repo)
|
|
955
|
return cleanupcmd(ui, repo)
|
|
956
|
elif checkopt('delete'):
|
|
956
|
elif checkopt('delete'):
|
|
957
|
return deletecmd(ui, repo, pats)
|
|
957
|
return deletecmd(ui, repo, pats)
|
|
958
|
elif checkopt('list'):
|
|
958
|
elif checkopt('list'):
|
|
959
|
return listcmd(ui, repo, pats, opts)
|
|
959
|
return listcmd(ui, repo, pats, opts)
|
|
960
|
elif checkopt('patch'):
|
|
960
|
elif checkopt('patch'):
|
|
961
|
return singlepatchcmds(ui, repo, pats, opts, subcommand='patch')
|
|
961
|
return singlepatchcmds(ui, repo, pats, opts, subcommand='patch')
|
|
962
|
elif checkopt('stat'):
|
|
962
|
elif checkopt('stat'):
|
|
963
|
return singlepatchcmds(ui, repo, pats, opts, subcommand='stat')
|
|
963
|
return singlepatchcmds(ui, repo, pats, opts, subcommand='stat')
|
|
964
|
else:
|
|
964
|
else:
|
|
965
|
return createcmd(ui, repo, pats, opts)
|
|
965
|
return createcmd(ui, repo, pats, opts)
|
|
966
|
|
|
966
|
|
|
967
|
def extsetup(ui):
|
|
967
|
def extsetup(ui):
|
|
968
|
cmdutil.unfinishedstates.append(
|
|
968
|
cmdutil.unfinishedstates.append(
|
|
969
|
[shelvedstate._filename, False, False,
|
|
969
|
[shelvedstate._filename, False, False,
|
|
970
|
_('unshelve already in progress'),
|
|
970
|
_('unshelve already in progress'),
|
|
971
|
_("use 'hg unshelve --continue' or 'hg unshelve --abort'")])
|
|
971
|
_("use 'hg unshelve --continue' or 'hg unshelve --abort'")])
|
|
972
|
cmdutil.afterresolvedstates.append(
|
|
972
|
cmdutil.afterresolvedstates.append(
|
|
973
|
[shelvedstate._filename, _('hg unshelve --continue')])
|
|
973
|
[shelvedstate._filename, _('hg unshelve --continue')])
|