##// END OF EJS Templates
mq: upgrade to git patch when necessary (issue767)
Patrick Mezard -
r10190:9c2c9493 default
parent child Browse files
Show More
@@ -0,0 +1,79
1 #!/bin/sh
2
3 # Test the plumbing of mq.git option
4 # Automatic upgrade itself is tested elsewhere.
5
6 echo "[extensions]" >> $HGRCPATH
7 echo "mq=" >> $HGRCPATH
8 echo "[diff]" >> $HGRCPATH
9 echo "nodates=1" >> $HGRCPATH
10
11 hg init repo-auto
12 cd repo-auto
13 echo '% git=auto: regular patch creation'
14 echo a > a
15 hg add a
16 hg qnew -d '0 0' -f adda
17 cat .hg/patches/adda
18 echo '% git=auto: git patch creation with copy'
19 hg cp a b
20 hg qnew -d '0 0' -f copy
21 cat .hg/patches/copy
22 echo '% git=auto: git patch when using --git'
23 echo regular > regular
24 hg add regular
25 hg qnew -d '0 0' --git -f git
26 cat .hg/patches/git
27 echo '% git=auto: regular patch after qrefresh without --git'
28 hg qrefresh -d '0 0'
29 cat .hg/patches/git
30 cd ..
31
32 hg init repo-keep
33 cd repo-keep
34 echo '[mq]' > .hg/hgrc
35 echo 'git = KEEP' >> .hg/hgrc
36 echo '% git=keep: git patch with --git'
37 echo a > a
38 hg add a
39 hg qnew -d '0 0' -f --git git
40 cat .hg/patches/git
41 echo '% git=keep: git patch after qrefresh without --git'
42 echo a >> a
43 hg qrefresh -d '0 0'
44 cat .hg/patches/git
45 cd ..
46
47 hg init repo-yes
48 cd repo-yes
49 echo '[mq]' > .hg/hgrc
50 echo 'git = yes' >> .hg/hgrc
51 echo '% git=yes: git patch'
52 echo a > a
53 hg add a
54 hg qnew -d '0 0' -f git
55 cat .hg/patches/git
56 echo '% git=yes: git patch after qrefresh'
57 echo a >> a
58 hg qrefresh -d '0 0'
59 cat .hg/patches/git
60 cd ..
61
62 hg init repo-no
63 cd repo-no
64 echo '[diff]' > .hg/hgrc
65 echo 'git = True' >> .hg/hgrc
66 echo '[mq]' > .hg/hgrc
67 echo 'git = False' >> .hg/hgrc
68 echo '% git=no: regular patch with copy'
69 echo a > a
70 hg add a
71 hg qnew -d '0 0' -f adda
72 hg cp a b
73 hg qnew -d '0 0' -f regular
74 cat .hg/patches/regular
75 echo '% git=no: regular patch after qrefresh with copy'
76 hg cp a c
77 hg qrefresh -d '0 0'
78 cat .hg/patches/regular
79 cd .. No newline at end of file
@@ -0,0 +1,100
1 % git=auto: regular patch creation
2 # HG changeset patch
3 # Date 0 0
4
5 diff -r 000000000000 -r ef8dafc9fa4c a
6 --- /dev/null
7 +++ b/a
8 @@ -0,0 +1,1 @@
9 +a
10 % git=auto: git patch creation with copy
11 # HG changeset patch
12 # Date 0 0
13
14 diff --git a/a b/b
15 copy from a
16 copy to b
17 % git=auto: git patch when using --git
18 # HG changeset patch
19 # Date 0 0
20
21 diff --git a/regular b/regular
22 new file mode 100644
23 --- /dev/null
24 +++ b/regular
25 @@ -0,0 +1,1 @@
26 +regular
27 % git=auto: regular patch after qrefresh without --git
28 # HG changeset patch
29 # Date 0 0
30
31 diff -r 2962f232b49d regular
32 --- /dev/null
33 +++ b/regular
34 @@ -0,0 +1,1 @@
35 +regular
36 % git=keep: git patch with --git
37 # HG changeset patch
38 # Date 0 0
39
40 diff --git a/a b/a
41 new file mode 100644
42 --- /dev/null
43 +++ b/a
44 @@ -0,0 +1,1 @@
45 +a
46 % git=keep: git patch after qrefresh without --git
47 # HG changeset patch
48 # Date 0 0
49
50 diff --git a/a b/a
51 new file mode 100644
52 --- /dev/null
53 +++ b/a
54 @@ -0,0 +1,2 @@
55 +a
56 +a
57 % git=yes: git patch
58 # HG changeset patch
59 # Date 0 0
60
61 diff --git a/a b/a
62 new file mode 100644
63 --- /dev/null
64 +++ b/a
65 @@ -0,0 +1,1 @@
66 +a
67 % git=yes: git patch after qrefresh
68 # HG changeset patch
69 # Date 0 0
70
71 diff --git a/a b/a
72 new file mode 100644
73 --- /dev/null
74 +++ b/a
75 @@ -0,0 +1,2 @@
76 +a
77 +a
78 % git=no: regular patch with copy
79 # HG changeset patch
80 # Date 0 0
81
82 diff -r ef8dafc9fa4c -r 110cde11d262 b
83 --- /dev/null
84 +++ b/b
85 @@ -0,0 +1,1 @@
86 +a
87 % git=no: regular patch after qrefresh with copy
88 # HG changeset patch
89 # Date 0 0
90
91 diff -r ef8dafc9fa4c b
92 --- /dev/null
93 +++ b/b
94 @@ -0,0 +1,1 @@
95 +a
96 diff -r ef8dafc9fa4c c
97 --- /dev/null
98 +++ b/c
99 @@ -0,0 +1,1 @@
100 +a
@@ -1,2707 +1,2737
1 # mq.py - patch queues for mercurial
1 # mq.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
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, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 '''manage a stack of patches
8 '''manage a stack of patches
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use "hg help command" for more details)::
17 Common tasks (use "hg help command" for more details)::
18
18
19 prepare repository to work with patches qinit
19 prepare repository to work with patches qinit
20 create new patch qnew
20 create new patch qnew
21 import existing patch qimport
21 import existing patch qimport
22
22
23 print patch series qseries
23 print patch series qseries
24 print applied patches qapplied
24 print applied patches qapplied
25
25
26 add known patch to applied stack qpush
26 add known patch to applied stack qpush
27 remove patch from applied stack qpop
27 remove patch from applied stack qpop
28 refresh contents of top applied patch qrefresh
28 refresh contents of top applied patch qrefresh
29
30 By default, mq will automatically use git patches when required to
31 avoid losing file mode changes, copy records, binary files or empty
32 files creations or deletions. This behaviour can be configured with::
33
34 [mq]
35 git = auto/keep/yes/no
36
37 If set to 'keep', mq will obey the [diff] section configuration while
38 preserving existing git patches upon qrefresh. If set to 'yes' or
39 'no', mq will override the [diff] section and always generate git or
40 regular patches, possibly losing data in the second case.
29 '''
41 '''
30
42
31 from mercurial.i18n import _
43 from mercurial.i18n import _
32 from mercurial.node import bin, hex, short, nullid, nullrev
44 from mercurial.node import bin, hex, short, nullid, nullrev
33 from mercurial.lock import release
45 from mercurial.lock import release
34 from mercurial import commands, cmdutil, hg, patch, util
46 from mercurial import commands, cmdutil, hg, patch, util
35 from mercurial import repair, extensions, url, error
47 from mercurial import repair, extensions, url, error
36 import os, sys, re, errno
48 import os, sys, re, errno
37
49
38 commands.norepo += " qclone"
50 commands.norepo += " qclone"
39
51
40 # Patch names looks like unix-file names.
52 # Patch names looks like unix-file names.
41 # They must be joinable with queue directory and result in the patch path.
53 # They must be joinable with queue directory and result in the patch path.
42 normname = util.normpath
54 normname = util.normpath
43
55
44 class statusentry(object):
56 class statusentry(object):
45 def __init__(self, rev, name=None):
57 def __init__(self, rev, name=None):
46 if not name:
58 if not name:
47 fields = rev.split(':', 1)
59 fields = rev.split(':', 1)
48 if len(fields) == 2:
60 if len(fields) == 2:
49 self.rev, self.name = fields
61 self.rev, self.name = fields
50 else:
62 else:
51 self.rev, self.name = None, None
63 self.rev, self.name = None, None
52 else:
64 else:
53 self.rev, self.name = rev, name
65 self.rev, self.name = rev, name
54
66
55 def __str__(self):
67 def __str__(self):
56 return self.rev + ':' + self.name
68 return self.rev + ':' + self.name
57
69
58 class patchheader(object):
70 class patchheader(object):
59 def __init__(self, pf):
71 def __init__(self, pf):
60 def eatdiff(lines):
72 def eatdiff(lines):
61 while lines:
73 while lines:
62 l = lines[-1]
74 l = lines[-1]
63 if (l.startswith("diff -") or
75 if (l.startswith("diff -") or
64 l.startswith("Index:") or
76 l.startswith("Index:") or
65 l.startswith("===========")):
77 l.startswith("===========")):
66 del lines[-1]
78 del lines[-1]
67 else:
79 else:
68 break
80 break
69 def eatempty(lines):
81 def eatempty(lines):
70 while lines:
82 while lines:
71 l = lines[-1]
83 l = lines[-1]
72 if re.match('\s*$', l):
84 if re.match('\s*$', l):
73 del lines[-1]
85 del lines[-1]
74 else:
86 else:
75 break
87 break
76
88
77 message = []
89 message = []
78 comments = []
90 comments = []
79 user = None
91 user = None
80 date = None
92 date = None
81 format = None
93 format = None
82 subject = None
94 subject = None
83 diffstart = 0
95 diffstart = 0
84
96
85 for line in file(pf):
97 for line in file(pf):
86 line = line.rstrip()
98 line = line.rstrip()
87 if line.startswith('diff --git'):
99 if line.startswith('diff --git'):
88 diffstart = 2
100 diffstart = 2
89 break
101 break
90 if diffstart:
102 if diffstart:
91 if line.startswith('+++ '):
103 if line.startswith('+++ '):
92 diffstart = 2
104 diffstart = 2
93 break
105 break
94 if line.startswith("--- "):
106 if line.startswith("--- "):
95 diffstart = 1
107 diffstart = 1
96 continue
108 continue
97 elif format == "hgpatch":
109 elif format == "hgpatch":
98 # parse values when importing the result of an hg export
110 # parse values when importing the result of an hg export
99 if line.startswith("# User "):
111 if line.startswith("# User "):
100 user = line[7:]
112 user = line[7:]
101 elif line.startswith("# Date "):
113 elif line.startswith("# Date "):
102 date = line[7:]
114 date = line[7:]
103 elif not line.startswith("# ") and line:
115 elif not line.startswith("# ") and line:
104 message.append(line)
116 message.append(line)
105 format = None
117 format = None
106 elif line == '# HG changeset patch':
118 elif line == '# HG changeset patch':
107 message = []
119 message = []
108 format = "hgpatch"
120 format = "hgpatch"
109 elif (format != "tagdone" and (line.startswith("Subject: ") or
121 elif (format != "tagdone" and (line.startswith("Subject: ") or
110 line.startswith("subject: "))):
122 line.startswith("subject: "))):
111 subject = line[9:]
123 subject = line[9:]
112 format = "tag"
124 format = "tag"
113 elif (format != "tagdone" and (line.startswith("From: ") or
125 elif (format != "tagdone" and (line.startswith("From: ") or
114 line.startswith("from: "))):
126 line.startswith("from: "))):
115 user = line[6:]
127 user = line[6:]
116 format = "tag"
128 format = "tag"
117 elif format == "tag" and line == "":
129 elif format == "tag" and line == "":
118 # when looking for tags (subject: from: etc) they
130 # when looking for tags (subject: from: etc) they
119 # end once you find a blank line in the source
131 # end once you find a blank line in the source
120 format = "tagdone"
132 format = "tagdone"
121 elif message or line:
133 elif message or line:
122 message.append(line)
134 message.append(line)
123 comments.append(line)
135 comments.append(line)
124
136
125 eatdiff(message)
137 eatdiff(message)
126 eatdiff(comments)
138 eatdiff(comments)
127 eatempty(message)
139 eatempty(message)
128 eatempty(comments)
140 eatempty(comments)
129
141
130 # make sure message isn't empty
142 # make sure message isn't empty
131 if format and format.startswith("tag") and subject:
143 if format and format.startswith("tag") and subject:
132 message.insert(0, "")
144 message.insert(0, "")
133 message.insert(0, subject)
145 message.insert(0, subject)
134
146
135 self.message = message
147 self.message = message
136 self.comments = comments
148 self.comments = comments
137 self.user = user
149 self.user = user
138 self.date = date
150 self.date = date
139 self.haspatch = diffstart > 1
151 self.haspatch = diffstart > 1
140
152
141 def setuser(self, user):
153 def setuser(self, user):
142 if not self.updateheader(['From: ', '# User '], user):
154 if not self.updateheader(['From: ', '# User '], user):
143 try:
155 try:
144 patchheaderat = self.comments.index('# HG changeset patch')
156 patchheaderat = self.comments.index('# HG changeset patch')
145 self.comments.insert(patchheaderat + 1, '# User ' + user)
157 self.comments.insert(patchheaderat + 1, '# User ' + user)
146 except ValueError:
158 except ValueError:
147 if self._hasheader(['Date: ']):
159 if self._hasheader(['Date: ']):
148 self.comments = ['From: ' + user] + self.comments
160 self.comments = ['From: ' + user] + self.comments
149 else:
161 else:
150 tmp = ['# HG changeset patch', '# User ' + user, '']
162 tmp = ['# HG changeset patch', '# User ' + user, '']
151 self.comments = tmp + self.comments
163 self.comments = tmp + self.comments
152 self.user = user
164 self.user = user
153
165
154 def setdate(self, date):
166 def setdate(self, date):
155 if not self.updateheader(['Date: ', '# Date '], date):
167 if not self.updateheader(['Date: ', '# Date '], date):
156 try:
168 try:
157 patchheaderat = self.comments.index('# HG changeset patch')
169 patchheaderat = self.comments.index('# HG changeset patch')
158 self.comments.insert(patchheaderat + 1, '# Date ' + date)
170 self.comments.insert(patchheaderat + 1, '# Date ' + date)
159 except ValueError:
171 except ValueError:
160 if self._hasheader(['From: ']):
172 if self._hasheader(['From: ']):
161 self.comments = ['Date: ' + date] + self.comments
173 self.comments = ['Date: ' + date] + self.comments
162 else:
174 else:
163 tmp = ['# HG changeset patch', '# Date ' + date, '']
175 tmp = ['# HG changeset patch', '# Date ' + date, '']
164 self.comments = tmp + self.comments
176 self.comments = tmp + self.comments
165 self.date = date
177 self.date = date
166
178
167 def setmessage(self, message):
179 def setmessage(self, message):
168 if self.comments:
180 if self.comments:
169 self._delmsg()
181 self._delmsg()
170 self.message = [message]
182 self.message = [message]
171 self.comments += self.message
183 self.comments += self.message
172
184
173 def updateheader(self, prefixes, new):
185 def updateheader(self, prefixes, new):
174 '''Update all references to a field in the patch header.
186 '''Update all references to a field in the patch header.
175 Return whether the field is present.'''
187 Return whether the field is present.'''
176 res = False
188 res = False
177 for prefix in prefixes:
189 for prefix in prefixes:
178 for i in xrange(len(self.comments)):
190 for i in xrange(len(self.comments)):
179 if self.comments[i].startswith(prefix):
191 if self.comments[i].startswith(prefix):
180 self.comments[i] = prefix + new
192 self.comments[i] = prefix + new
181 res = True
193 res = True
182 break
194 break
183 return res
195 return res
184
196
185 def _hasheader(self, prefixes):
197 def _hasheader(self, prefixes):
186 '''Check if a header starts with any of the given prefixes.'''
198 '''Check if a header starts with any of the given prefixes.'''
187 for prefix in prefixes:
199 for prefix in prefixes:
188 for comment in self.comments:
200 for comment in self.comments:
189 if comment.startswith(prefix):
201 if comment.startswith(prefix):
190 return True
202 return True
191 return False
203 return False
192
204
193 def __str__(self):
205 def __str__(self):
194 if not self.comments:
206 if not self.comments:
195 return ''
207 return ''
196 return '\n'.join(self.comments) + '\n\n'
208 return '\n'.join(self.comments) + '\n\n'
197
209
198 def _delmsg(self):
210 def _delmsg(self):
199 '''Remove existing message, keeping the rest of the comments fields.
211 '''Remove existing message, keeping the rest of the comments fields.
200 If comments contains 'subject: ', message will prepend
212 If comments contains 'subject: ', message will prepend
201 the field and a blank line.'''
213 the field and a blank line.'''
202 if self.message:
214 if self.message:
203 subj = 'subject: ' + self.message[0].lower()
215 subj = 'subject: ' + self.message[0].lower()
204 for i in xrange(len(self.comments)):
216 for i in xrange(len(self.comments)):
205 if subj == self.comments[i].lower():
217 if subj == self.comments[i].lower():
206 del self.comments[i]
218 del self.comments[i]
207 self.message = self.message[2:]
219 self.message = self.message[2:]
208 break
220 break
209 ci = 0
221 ci = 0
210 for mi in self.message:
222 for mi in self.message:
211 while mi != self.comments[ci]:
223 while mi != self.comments[ci]:
212 ci += 1
224 ci += 1
213 del self.comments[ci]
225 del self.comments[ci]
214
226
215 class queue(object):
227 class queue(object):
216 def __init__(self, ui, path, patchdir=None):
228 def __init__(self, ui, path, patchdir=None):
217 self.basepath = path
229 self.basepath = path
218 self.path = patchdir or os.path.join(path, "patches")
230 self.path = patchdir or os.path.join(path, "patches")
219 self.opener = util.opener(self.path)
231 self.opener = util.opener(self.path)
220 self.ui = ui
232 self.ui = ui
221 self.applied_dirty = 0
233 self.applied_dirty = 0
222 self.series_dirty = 0
234 self.series_dirty = 0
223 self.series_path = "series"
235 self.series_path = "series"
224 self.status_path = "status"
236 self.status_path = "status"
225 self.guards_path = "guards"
237 self.guards_path = "guards"
226 self.active_guards = None
238 self.active_guards = None
227 self.guards_dirty = False
239 self.guards_dirty = False
240 # Handle mq.git as a bool with extended values
241 try:
242 gitmode = ui.configbool('mq', 'git', None)
243 if gitmode is None:
244 raise error.ConfigError()
245 self.gitmode = gitmode and 'yes' or 'no'
246 except error.ConfigError:
247 self.gitmode = ui.config('mq', 'git', 'auto').lower()
228
248
229 @util.propertycache
249 @util.propertycache
230 def applied(self):
250 def applied(self):
231 if os.path.exists(self.join(self.status_path)):
251 if os.path.exists(self.join(self.status_path)):
232 lines = self.opener(self.status_path).read().splitlines()
252 lines = self.opener(self.status_path).read().splitlines()
233 return [statusentry(l) for l in lines]
253 return [statusentry(l) for l in lines]
234 return []
254 return []
235
255
236 @util.propertycache
256 @util.propertycache
237 def full_series(self):
257 def full_series(self):
238 if os.path.exists(self.join(self.series_path)):
258 if os.path.exists(self.join(self.series_path)):
239 return self.opener(self.series_path).read().splitlines()
259 return self.opener(self.series_path).read().splitlines()
240 return []
260 return []
241
261
242 @util.propertycache
262 @util.propertycache
243 def series(self):
263 def series(self):
244 self.parse_series()
264 self.parse_series()
245 return self.series
265 return self.series
246
266
247 @util.propertycache
267 @util.propertycache
248 def series_guards(self):
268 def series_guards(self):
249 self.parse_series()
269 self.parse_series()
250 return self.series_guards
270 return self.series_guards
251
271
252 def invalidate(self):
272 def invalidate(self):
253 for a in 'applied full_series series series_guards'.split():
273 for a in 'applied full_series series series_guards'.split():
254 if a in self.__dict__:
274 if a in self.__dict__:
255 delattr(self, a)
275 delattr(self, a)
256 self.applied_dirty = 0
276 self.applied_dirty = 0
257 self.series_dirty = 0
277 self.series_dirty = 0
258 self.guards_dirty = False
278 self.guards_dirty = False
259 self.active_guards = None
279 self.active_guards = None
260
280
261 def diffopts(self, opts={}, patchfn=None):
281 def diffopts(self, opts={}, patchfn=None):
262 diffopts = patch.diffopts(self.ui, opts)
282 diffopts = patch.diffopts(self.ui, opts)
283 if self.gitmode == 'auto':
284 diffopts.upgrade = True
285 elif self.gitmode == 'keep':
286 pass
287 elif self.gitmode in ('yes', 'no'):
288 diffopts.git = self.gitmode == 'yes'
289 else:
290 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
291 ' got %s') % self.gitmode)
263 if patchfn:
292 if patchfn:
264 diffopts = self.patchopts(diffopts, patchfn)
293 diffopts = self.patchopts(diffopts, patchfn)
265 return diffopts
294 return diffopts
266
295
267 def patchopts(self, diffopts, *patches):
296 def patchopts(self, diffopts, *patches):
268 """Return a copy of input diff options with git set to true if
297 """Return a copy of input diff options with git set to true if
269 referenced patch is a git patch.
298 referenced patch is a git patch and should be preserved as such.
270 """
299 """
271 diffopts = diffopts.copy()
300 diffopts = diffopts.copy()
272 for patchfn in patches:
301 if not diffopts.git and self.gitmode == 'keep':
273 patchf = self.opener(patchfn, 'r')
302 for patchfn in patches:
274 # if the patch was a git patch, refresh it as a git patch
303 patchf = self.opener(patchfn, 'r')
275 for line in patchf:
304 # if the patch was a git patch, refresh it as a git patch
276 if line.startswith('diff --git'):
305 for line in patchf:
277 diffopts.git = True
306 if line.startswith('diff --git'):
278 break
307 diffopts.git = True
279 patchf.close()
308 break
309 patchf.close()
280 return diffopts
310 return diffopts
281
311
282 def join(self, *p):
312 def join(self, *p):
283 return os.path.join(self.path, *p)
313 return os.path.join(self.path, *p)
284
314
285 def find_series(self, patch):
315 def find_series(self, patch):
286 pre = re.compile("(\s*)([^#]+)")
316 pre = re.compile("(\s*)([^#]+)")
287 index = 0
317 index = 0
288 for l in self.full_series:
318 for l in self.full_series:
289 m = pre.match(l)
319 m = pre.match(l)
290 if m:
320 if m:
291 s = m.group(2)
321 s = m.group(2)
292 s = s.rstrip()
322 s = s.rstrip()
293 if s == patch:
323 if s == patch:
294 return index
324 return index
295 index += 1
325 index += 1
296 return None
326 return None
297
327
298 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
328 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
299
329
300 def parse_series(self):
330 def parse_series(self):
301 self.series = []
331 self.series = []
302 self.series_guards = []
332 self.series_guards = []
303 for l in self.full_series:
333 for l in self.full_series:
304 h = l.find('#')
334 h = l.find('#')
305 if h == -1:
335 if h == -1:
306 patch = l
336 patch = l
307 comment = ''
337 comment = ''
308 elif h == 0:
338 elif h == 0:
309 continue
339 continue
310 else:
340 else:
311 patch = l[:h]
341 patch = l[:h]
312 comment = l[h:]
342 comment = l[h:]
313 patch = patch.strip()
343 patch = patch.strip()
314 if patch:
344 if patch:
315 if patch in self.series:
345 if patch in self.series:
316 raise util.Abort(_('%s appears more than once in %s') %
346 raise util.Abort(_('%s appears more than once in %s') %
317 (patch, self.join(self.series_path)))
347 (patch, self.join(self.series_path)))
318 self.series.append(patch)
348 self.series.append(patch)
319 self.series_guards.append(self.guard_re.findall(comment))
349 self.series_guards.append(self.guard_re.findall(comment))
320
350
321 def check_guard(self, guard):
351 def check_guard(self, guard):
322 if not guard:
352 if not guard:
323 return _('guard cannot be an empty string')
353 return _('guard cannot be an empty string')
324 bad_chars = '# \t\r\n\f'
354 bad_chars = '# \t\r\n\f'
325 first = guard[0]
355 first = guard[0]
326 if first in '-+':
356 if first in '-+':
327 return (_('guard %r starts with invalid character: %r') %
357 return (_('guard %r starts with invalid character: %r') %
328 (guard, first))
358 (guard, first))
329 for c in bad_chars:
359 for c in bad_chars:
330 if c in guard:
360 if c in guard:
331 return _('invalid character in guard %r: %r') % (guard, c)
361 return _('invalid character in guard %r: %r') % (guard, c)
332
362
333 def set_active(self, guards):
363 def set_active(self, guards):
334 for guard in guards:
364 for guard in guards:
335 bad = self.check_guard(guard)
365 bad = self.check_guard(guard)
336 if bad:
366 if bad:
337 raise util.Abort(bad)
367 raise util.Abort(bad)
338 guards = sorted(set(guards))
368 guards = sorted(set(guards))
339 self.ui.debug('active guards: %s\n' % ' '.join(guards))
369 self.ui.debug('active guards: %s\n' % ' '.join(guards))
340 self.active_guards = guards
370 self.active_guards = guards
341 self.guards_dirty = True
371 self.guards_dirty = True
342
372
343 def active(self):
373 def active(self):
344 if self.active_guards is None:
374 if self.active_guards is None:
345 self.active_guards = []
375 self.active_guards = []
346 try:
376 try:
347 guards = self.opener(self.guards_path).read().split()
377 guards = self.opener(self.guards_path).read().split()
348 except IOError, err:
378 except IOError, err:
349 if err.errno != errno.ENOENT: raise
379 if err.errno != errno.ENOENT: raise
350 guards = []
380 guards = []
351 for i, guard in enumerate(guards):
381 for i, guard in enumerate(guards):
352 bad = self.check_guard(guard)
382 bad = self.check_guard(guard)
353 if bad:
383 if bad:
354 self.ui.warn('%s:%d: %s\n' %
384 self.ui.warn('%s:%d: %s\n' %
355 (self.join(self.guards_path), i + 1, bad))
385 (self.join(self.guards_path), i + 1, bad))
356 else:
386 else:
357 self.active_guards.append(guard)
387 self.active_guards.append(guard)
358 return self.active_guards
388 return self.active_guards
359
389
360 def set_guards(self, idx, guards):
390 def set_guards(self, idx, guards):
361 for g in guards:
391 for g in guards:
362 if len(g) < 2:
392 if len(g) < 2:
363 raise util.Abort(_('guard %r too short') % g)
393 raise util.Abort(_('guard %r too short') % g)
364 if g[0] not in '-+':
394 if g[0] not in '-+':
365 raise util.Abort(_('guard %r starts with invalid char') % g)
395 raise util.Abort(_('guard %r starts with invalid char') % g)
366 bad = self.check_guard(g[1:])
396 bad = self.check_guard(g[1:])
367 if bad:
397 if bad:
368 raise util.Abort(bad)
398 raise util.Abort(bad)
369 drop = self.guard_re.sub('', self.full_series[idx])
399 drop = self.guard_re.sub('', self.full_series[idx])
370 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
400 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
371 self.parse_series()
401 self.parse_series()
372 self.series_dirty = True
402 self.series_dirty = True
373
403
374 def pushable(self, idx):
404 def pushable(self, idx):
375 if isinstance(idx, str):
405 if isinstance(idx, str):
376 idx = self.series.index(idx)
406 idx = self.series.index(idx)
377 patchguards = self.series_guards[idx]
407 patchguards = self.series_guards[idx]
378 if not patchguards:
408 if not patchguards:
379 return True, None
409 return True, None
380 guards = self.active()
410 guards = self.active()
381 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
411 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
382 if exactneg:
412 if exactneg:
383 return False, exactneg[0]
413 return False, exactneg[0]
384 pos = [g for g in patchguards if g[0] == '+']
414 pos = [g for g in patchguards if g[0] == '+']
385 exactpos = [g for g in pos if g[1:] in guards]
415 exactpos = [g for g in pos if g[1:] in guards]
386 if pos:
416 if pos:
387 if exactpos:
417 if exactpos:
388 return True, exactpos[0]
418 return True, exactpos[0]
389 return False, pos
419 return False, pos
390 return True, ''
420 return True, ''
391
421
392 def explain_pushable(self, idx, all_patches=False):
422 def explain_pushable(self, idx, all_patches=False):
393 write = all_patches and self.ui.write or self.ui.warn
423 write = all_patches and self.ui.write or self.ui.warn
394 if all_patches or self.ui.verbose:
424 if all_patches or self.ui.verbose:
395 if isinstance(idx, str):
425 if isinstance(idx, str):
396 idx = self.series.index(idx)
426 idx = self.series.index(idx)
397 pushable, why = self.pushable(idx)
427 pushable, why = self.pushable(idx)
398 if all_patches and pushable:
428 if all_patches and pushable:
399 if why is None:
429 if why is None:
400 write(_('allowing %s - no guards in effect\n') %
430 write(_('allowing %s - no guards in effect\n') %
401 self.series[idx])
431 self.series[idx])
402 else:
432 else:
403 if not why:
433 if not why:
404 write(_('allowing %s - no matching negative guards\n') %
434 write(_('allowing %s - no matching negative guards\n') %
405 self.series[idx])
435 self.series[idx])
406 else:
436 else:
407 write(_('allowing %s - guarded by %r\n') %
437 write(_('allowing %s - guarded by %r\n') %
408 (self.series[idx], why))
438 (self.series[idx], why))
409 if not pushable:
439 if not pushable:
410 if why:
440 if why:
411 write(_('skipping %s - guarded by %r\n') %
441 write(_('skipping %s - guarded by %r\n') %
412 (self.series[idx], why))
442 (self.series[idx], why))
413 else:
443 else:
414 write(_('skipping %s - no matching guards\n') %
444 write(_('skipping %s - no matching guards\n') %
415 self.series[idx])
445 self.series[idx])
416
446
417 def save_dirty(self):
447 def save_dirty(self):
418 def write_list(items, path):
448 def write_list(items, path):
419 fp = self.opener(path, 'w')
449 fp = self.opener(path, 'w')
420 for i in items:
450 for i in items:
421 fp.write("%s\n" % i)
451 fp.write("%s\n" % i)
422 fp.close()
452 fp.close()
423 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
453 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
424 if self.series_dirty: write_list(self.full_series, self.series_path)
454 if self.series_dirty: write_list(self.full_series, self.series_path)
425 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
455 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
426
456
427 def removeundo(self, repo):
457 def removeundo(self, repo):
428 undo = repo.sjoin('undo')
458 undo = repo.sjoin('undo')
429 if not os.path.exists(undo):
459 if not os.path.exists(undo):
430 return
460 return
431 try:
461 try:
432 os.unlink(undo)
462 os.unlink(undo)
433 except OSError, inst:
463 except OSError, inst:
434 self.ui.warn(_('error removing undo: %s\n') % str(inst))
464 self.ui.warn(_('error removing undo: %s\n') % str(inst))
435
465
436 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
466 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
437 fp=None, changes=None, opts={}):
467 fp=None, changes=None, opts={}):
438 stat = opts.get('stat')
468 stat = opts.get('stat')
439 if stat:
469 if stat:
440 opts['unified'] = '0'
470 opts['unified'] = '0'
441
471
442 m = cmdutil.match(repo, files, opts)
472 m = cmdutil.match(repo, files, opts)
443 chunks = patch.diff(repo, node1, node2, m, changes, diffopts)
473 chunks = patch.diff(repo, node1, node2, m, changes, diffopts)
444 write = fp is None and repo.ui.write or fp.write
474 write = fp is None and repo.ui.write or fp.write
445 if stat:
475 if stat:
446 width = self.ui.interactive() and util.termwidth() or 80
476 width = self.ui.interactive() and util.termwidth() or 80
447 write(patch.diffstat(util.iterlines(chunks), width=width,
477 write(patch.diffstat(util.iterlines(chunks), width=width,
448 git=diffopts.git))
478 git=diffopts.git))
449 else:
479 else:
450 for chunk in chunks:
480 for chunk in chunks:
451 write(chunk)
481 write(chunk)
452
482
453 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
483 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
454 # first try just applying the patch
484 # first try just applying the patch
455 (err, n) = self.apply(repo, [ patch ], update_status=False,
485 (err, n) = self.apply(repo, [ patch ], update_status=False,
456 strict=True, merge=rev)
486 strict=True, merge=rev)
457
487
458 if err == 0:
488 if err == 0:
459 return (err, n)
489 return (err, n)
460
490
461 if n is None:
491 if n is None:
462 raise util.Abort(_("apply failed for patch %s") % patch)
492 raise util.Abort(_("apply failed for patch %s") % patch)
463
493
464 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
494 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
465
495
466 # apply failed, strip away that rev and merge.
496 # apply failed, strip away that rev and merge.
467 hg.clean(repo, head)
497 hg.clean(repo, head)
468 self.strip(repo, n, update=False, backup='strip')
498 self.strip(repo, n, update=False, backup='strip')
469
499
470 ctx = repo[rev]
500 ctx = repo[rev]
471 ret = hg.merge(repo, rev)
501 ret = hg.merge(repo, rev)
472 if ret:
502 if ret:
473 raise util.Abort(_("update returned %d") % ret)
503 raise util.Abort(_("update returned %d") % ret)
474 n = repo.commit(ctx.description(), ctx.user(), force=True)
504 n = repo.commit(ctx.description(), ctx.user(), force=True)
475 if n is None:
505 if n is None:
476 raise util.Abort(_("repo commit failed"))
506 raise util.Abort(_("repo commit failed"))
477 try:
507 try:
478 ph = patchheader(mergeq.join(patch))
508 ph = patchheader(mergeq.join(patch))
479 except:
509 except:
480 raise util.Abort(_("unable to read %s") % patch)
510 raise util.Abort(_("unable to read %s") % patch)
481
511
482 diffopts = self.patchopts(diffopts, patch)
512 diffopts = self.patchopts(diffopts, patch)
483 patchf = self.opener(patch, "w")
513 patchf = self.opener(patch, "w")
484 comments = str(ph)
514 comments = str(ph)
485 if comments:
515 if comments:
486 patchf.write(comments)
516 patchf.write(comments)
487 self.printdiff(repo, diffopts, head, n, fp=patchf)
517 self.printdiff(repo, diffopts, head, n, fp=patchf)
488 patchf.close()
518 patchf.close()
489 self.removeundo(repo)
519 self.removeundo(repo)
490 return (0, n)
520 return (0, n)
491
521
492 def qparents(self, repo, rev=None):
522 def qparents(self, repo, rev=None):
493 if rev is None:
523 if rev is None:
494 (p1, p2) = repo.dirstate.parents()
524 (p1, p2) = repo.dirstate.parents()
495 if p2 == nullid:
525 if p2 == nullid:
496 return p1
526 return p1
497 if len(self.applied) == 0:
527 if len(self.applied) == 0:
498 return None
528 return None
499 return bin(self.applied[-1].rev)
529 return bin(self.applied[-1].rev)
500 pp = repo.changelog.parents(rev)
530 pp = repo.changelog.parents(rev)
501 if pp[1] != nullid:
531 if pp[1] != nullid:
502 arevs = [ x.rev for x in self.applied ]
532 arevs = [ x.rev for x in self.applied ]
503 p0 = hex(pp[0])
533 p0 = hex(pp[0])
504 p1 = hex(pp[1])
534 p1 = hex(pp[1])
505 if p0 in arevs:
535 if p0 in arevs:
506 return pp[0]
536 return pp[0]
507 if p1 in arevs:
537 if p1 in arevs:
508 return pp[1]
538 return pp[1]
509 return pp[0]
539 return pp[0]
510
540
511 def mergepatch(self, repo, mergeq, series, diffopts):
541 def mergepatch(self, repo, mergeq, series, diffopts):
512 if len(self.applied) == 0:
542 if len(self.applied) == 0:
513 # each of the patches merged in will have two parents. This
543 # each of the patches merged in will have two parents. This
514 # can confuse the qrefresh, qdiff, and strip code because it
544 # can confuse the qrefresh, qdiff, and strip code because it
515 # needs to know which parent is actually in the patch queue.
545 # needs to know which parent is actually in the patch queue.
516 # so, we insert a merge marker with only one parent. This way
546 # so, we insert a merge marker with only one parent. This way
517 # the first patch in the queue is never a merge patch
547 # the first patch in the queue is never a merge patch
518 #
548 #
519 pname = ".hg.patches.merge.marker"
549 pname = ".hg.patches.merge.marker"
520 n = repo.commit('[mq]: merge marker', force=True)
550 n = repo.commit('[mq]: merge marker', force=True)
521 self.removeundo(repo)
551 self.removeundo(repo)
522 self.applied.append(statusentry(hex(n), pname))
552 self.applied.append(statusentry(hex(n), pname))
523 self.applied_dirty = 1
553 self.applied_dirty = 1
524
554
525 head = self.qparents(repo)
555 head = self.qparents(repo)
526
556
527 for patch in series:
557 for patch in series:
528 patch = mergeq.lookup(patch, strict=True)
558 patch = mergeq.lookup(patch, strict=True)
529 if not patch:
559 if not patch:
530 self.ui.warn(_("patch %s does not exist\n") % patch)
560 self.ui.warn(_("patch %s does not exist\n") % patch)
531 return (1, None)
561 return (1, None)
532 pushable, reason = self.pushable(patch)
562 pushable, reason = self.pushable(patch)
533 if not pushable:
563 if not pushable:
534 self.explain_pushable(patch, all_patches=True)
564 self.explain_pushable(patch, all_patches=True)
535 continue
565 continue
536 info = mergeq.isapplied(patch)
566 info = mergeq.isapplied(patch)
537 if not info:
567 if not info:
538 self.ui.warn(_("patch %s is not applied\n") % patch)
568 self.ui.warn(_("patch %s is not applied\n") % patch)
539 return (1, None)
569 return (1, None)
540 rev = bin(info[1])
570 rev = bin(info[1])
541 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
571 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
542 if head:
572 if head:
543 self.applied.append(statusentry(hex(head), patch))
573 self.applied.append(statusentry(hex(head), patch))
544 self.applied_dirty = 1
574 self.applied_dirty = 1
545 if err:
575 if err:
546 return (err, head)
576 return (err, head)
547 self.save_dirty()
577 self.save_dirty()
548 return (0, head)
578 return (0, head)
549
579
550 def patch(self, repo, patchfile):
580 def patch(self, repo, patchfile):
551 '''Apply patchfile to the working directory.
581 '''Apply patchfile to the working directory.
552 patchfile: name of patch file'''
582 patchfile: name of patch file'''
553 files = {}
583 files = {}
554 try:
584 try:
555 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
585 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
556 files=files, eolmode=None)
586 files=files, eolmode=None)
557 except Exception, inst:
587 except Exception, inst:
558 self.ui.note(str(inst) + '\n')
588 self.ui.note(str(inst) + '\n')
559 if not self.ui.verbose:
589 if not self.ui.verbose:
560 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
590 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
561 return (False, files, False)
591 return (False, files, False)
562
592
563 return (True, files, fuzz)
593 return (True, files, fuzz)
564
594
565 def apply(self, repo, series, list=False, update_status=True,
595 def apply(self, repo, series, list=False, update_status=True,
566 strict=False, patchdir=None, merge=None, all_files={}):
596 strict=False, patchdir=None, merge=None, all_files={}):
567 wlock = lock = tr = None
597 wlock = lock = tr = None
568 try:
598 try:
569 wlock = repo.wlock()
599 wlock = repo.wlock()
570 lock = repo.lock()
600 lock = repo.lock()
571 tr = repo.transaction()
601 tr = repo.transaction()
572 try:
602 try:
573 ret = self._apply(repo, series, list, update_status,
603 ret = self._apply(repo, series, list, update_status,
574 strict, patchdir, merge, all_files=all_files)
604 strict, patchdir, merge, all_files=all_files)
575 tr.close()
605 tr.close()
576 self.save_dirty()
606 self.save_dirty()
577 return ret
607 return ret
578 except:
608 except:
579 try:
609 try:
580 tr.abort()
610 tr.abort()
581 finally:
611 finally:
582 repo.invalidate()
612 repo.invalidate()
583 repo.dirstate.invalidate()
613 repo.dirstate.invalidate()
584 raise
614 raise
585 finally:
615 finally:
586 del tr
616 del tr
587 release(lock, wlock)
617 release(lock, wlock)
588 self.removeundo(repo)
618 self.removeundo(repo)
589
619
590 def _apply(self, repo, series, list=False, update_status=True,
620 def _apply(self, repo, series, list=False, update_status=True,
591 strict=False, patchdir=None, merge=None, all_files={}):
621 strict=False, patchdir=None, merge=None, all_files={}):
592 '''returns (error, hash)
622 '''returns (error, hash)
593 error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz'''
623 error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz'''
594 # TODO unify with commands.py
624 # TODO unify with commands.py
595 if not patchdir:
625 if not patchdir:
596 patchdir = self.path
626 patchdir = self.path
597 err = 0
627 err = 0
598 n = None
628 n = None
599 for patchname in series:
629 for patchname in series:
600 pushable, reason = self.pushable(patchname)
630 pushable, reason = self.pushable(patchname)
601 if not pushable:
631 if not pushable:
602 self.explain_pushable(patchname, all_patches=True)
632 self.explain_pushable(patchname, all_patches=True)
603 continue
633 continue
604 self.ui.status(_("applying %s\n") % patchname)
634 self.ui.status(_("applying %s\n") % patchname)
605 pf = os.path.join(patchdir, patchname)
635 pf = os.path.join(patchdir, patchname)
606
636
607 try:
637 try:
608 ph = patchheader(self.join(patchname))
638 ph = patchheader(self.join(patchname))
609 except:
639 except:
610 self.ui.warn(_("unable to read %s\n") % patchname)
640 self.ui.warn(_("unable to read %s\n") % patchname)
611 err = 1
641 err = 1
612 break
642 break
613
643
614 message = ph.message
644 message = ph.message
615 if not message:
645 if not message:
616 message = _("imported patch %s\n") % patchname
646 message = _("imported patch %s\n") % patchname
617 else:
647 else:
618 if list:
648 if list:
619 message.append(_("\nimported patch %s") % patchname)
649 message.append(_("\nimported patch %s") % patchname)
620 message = '\n'.join(message)
650 message = '\n'.join(message)
621
651
622 if ph.haspatch:
652 if ph.haspatch:
623 (patcherr, files, fuzz) = self.patch(repo, pf)
653 (patcherr, files, fuzz) = self.patch(repo, pf)
624 all_files.update(files)
654 all_files.update(files)
625 patcherr = not patcherr
655 patcherr = not patcherr
626 else:
656 else:
627 self.ui.warn(_("patch %s is empty\n") % patchname)
657 self.ui.warn(_("patch %s is empty\n") % patchname)
628 patcherr, files, fuzz = 0, [], 0
658 patcherr, files, fuzz = 0, [], 0
629
659
630 if merge and files:
660 if merge and files:
631 # Mark as removed/merged and update dirstate parent info
661 # Mark as removed/merged and update dirstate parent info
632 removed = []
662 removed = []
633 merged = []
663 merged = []
634 for f in files:
664 for f in files:
635 if os.path.exists(repo.wjoin(f)):
665 if os.path.exists(repo.wjoin(f)):
636 merged.append(f)
666 merged.append(f)
637 else:
667 else:
638 removed.append(f)
668 removed.append(f)
639 for f in removed:
669 for f in removed:
640 repo.dirstate.remove(f)
670 repo.dirstate.remove(f)
641 for f in merged:
671 for f in merged:
642 repo.dirstate.merge(f)
672 repo.dirstate.merge(f)
643 p1, p2 = repo.dirstate.parents()
673 p1, p2 = repo.dirstate.parents()
644 repo.dirstate.setparents(p1, merge)
674 repo.dirstate.setparents(p1, merge)
645
675
646 files = patch.updatedir(self.ui, repo, files)
676 files = patch.updatedir(self.ui, repo, files)
647 match = cmdutil.matchfiles(repo, files or [])
677 match = cmdutil.matchfiles(repo, files or [])
648 n = repo.commit(message, ph.user, ph.date, match=match, force=True)
678 n = repo.commit(message, ph.user, ph.date, match=match, force=True)
649
679
650 if n is None:
680 if n is None:
651 raise util.Abort(_("repo commit failed"))
681 raise util.Abort(_("repo commit failed"))
652
682
653 if update_status:
683 if update_status:
654 self.applied.append(statusentry(hex(n), patchname))
684 self.applied.append(statusentry(hex(n), patchname))
655
685
656 if patcherr:
686 if patcherr:
657 self.ui.warn(_("patch failed, rejects left in working dir\n"))
687 self.ui.warn(_("patch failed, rejects left in working dir\n"))
658 err = 2
688 err = 2
659 break
689 break
660
690
661 if fuzz and strict:
691 if fuzz and strict:
662 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
692 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
663 err = 3
693 err = 3
664 break
694 break
665 return (err, n)
695 return (err, n)
666
696
667 def _cleanup(self, patches, numrevs, keep=False):
697 def _cleanup(self, patches, numrevs, keep=False):
668 if not keep:
698 if not keep:
669 r = self.qrepo()
699 r = self.qrepo()
670 if r:
700 if r:
671 r.remove(patches, True)
701 r.remove(patches, True)
672 else:
702 else:
673 for p in patches:
703 for p in patches:
674 os.unlink(self.join(p))
704 os.unlink(self.join(p))
675
705
676 if numrevs:
706 if numrevs:
677 del self.applied[:numrevs]
707 del self.applied[:numrevs]
678 self.applied_dirty = 1
708 self.applied_dirty = 1
679
709
680 for i in sorted([self.find_series(p) for p in patches], reverse=True):
710 for i in sorted([self.find_series(p) for p in patches], reverse=True):
681 del self.full_series[i]
711 del self.full_series[i]
682 self.parse_series()
712 self.parse_series()
683 self.series_dirty = 1
713 self.series_dirty = 1
684
714
685 def _revpatches(self, repo, revs):
715 def _revpatches(self, repo, revs):
686 firstrev = repo[self.applied[0].rev].rev()
716 firstrev = repo[self.applied[0].rev].rev()
687 patches = []
717 patches = []
688 for i, rev in enumerate(revs):
718 for i, rev in enumerate(revs):
689
719
690 if rev < firstrev:
720 if rev < firstrev:
691 raise util.Abort(_('revision %d is not managed') % rev)
721 raise util.Abort(_('revision %d is not managed') % rev)
692
722
693 ctx = repo[rev]
723 ctx = repo[rev]
694 base = bin(self.applied[i].rev)
724 base = bin(self.applied[i].rev)
695 if ctx.node() != base:
725 if ctx.node() != base:
696 msg = _('cannot delete revision %d above applied patches')
726 msg = _('cannot delete revision %d above applied patches')
697 raise util.Abort(msg % rev)
727 raise util.Abort(msg % rev)
698
728
699 patch = self.applied[i].name
729 patch = self.applied[i].name
700 for fmt in ('[mq]: %s', 'imported patch %s'):
730 for fmt in ('[mq]: %s', 'imported patch %s'):
701 if ctx.description() == fmt % patch:
731 if ctx.description() == fmt % patch:
702 msg = _('patch %s finalized without changeset message\n')
732 msg = _('patch %s finalized without changeset message\n')
703 repo.ui.status(msg % patch)
733 repo.ui.status(msg % patch)
704 break
734 break
705
735
706 patches.append(patch)
736 patches.append(patch)
707 return patches
737 return patches
708
738
709 def finish(self, repo, revs):
739 def finish(self, repo, revs):
710 patches = self._revpatches(repo, sorted(revs))
740 patches = self._revpatches(repo, sorted(revs))
711 self._cleanup(patches, len(patches))
741 self._cleanup(patches, len(patches))
712
742
713 def delete(self, repo, patches, opts):
743 def delete(self, repo, patches, opts):
714 if not patches and not opts.get('rev'):
744 if not patches and not opts.get('rev'):
715 raise util.Abort(_('qdelete requires at least one revision or '
745 raise util.Abort(_('qdelete requires at least one revision or '
716 'patch name'))
746 'patch name'))
717
747
718 realpatches = []
748 realpatches = []
719 for patch in patches:
749 for patch in patches:
720 patch = self.lookup(patch, strict=True)
750 patch = self.lookup(patch, strict=True)
721 info = self.isapplied(patch)
751 info = self.isapplied(patch)
722 if info:
752 if info:
723 raise util.Abort(_("cannot delete applied patch %s") % patch)
753 raise util.Abort(_("cannot delete applied patch %s") % patch)
724 if patch not in self.series:
754 if patch not in self.series:
725 raise util.Abort(_("patch %s not in series file") % patch)
755 raise util.Abort(_("patch %s not in series file") % patch)
726 realpatches.append(patch)
756 realpatches.append(patch)
727
757
728 numrevs = 0
758 numrevs = 0
729 if opts.get('rev'):
759 if opts.get('rev'):
730 if not self.applied:
760 if not self.applied:
731 raise util.Abort(_('no patches applied'))
761 raise util.Abort(_('no patches applied'))
732 revs = cmdutil.revrange(repo, opts['rev'])
762 revs = cmdutil.revrange(repo, opts['rev'])
733 if len(revs) > 1 and revs[0] > revs[1]:
763 if len(revs) > 1 and revs[0] > revs[1]:
734 revs.reverse()
764 revs.reverse()
735 revpatches = self._revpatches(repo, revs)
765 revpatches = self._revpatches(repo, revs)
736 realpatches += revpatches
766 realpatches += revpatches
737 numrevs = len(revpatches)
767 numrevs = len(revpatches)
738
768
739 self._cleanup(realpatches, numrevs, opts.get('keep'))
769 self._cleanup(realpatches, numrevs, opts.get('keep'))
740
770
741 def check_toppatch(self, repo):
771 def check_toppatch(self, repo):
742 if len(self.applied) > 0:
772 if len(self.applied) > 0:
743 top = bin(self.applied[-1].rev)
773 top = bin(self.applied[-1].rev)
744 pp = repo.dirstate.parents()
774 pp = repo.dirstate.parents()
745 if top not in pp:
775 if top not in pp:
746 raise util.Abort(_("working directory revision is not qtip"))
776 raise util.Abort(_("working directory revision is not qtip"))
747 return top
777 return top
748 return None
778 return None
749 def check_localchanges(self, repo, force=False, refresh=True):
779 def check_localchanges(self, repo, force=False, refresh=True):
750 m, a, r, d = repo.status()[:4]
780 m, a, r, d = repo.status()[:4]
751 if m or a or r or d:
781 if m or a or r or d:
752 if not force:
782 if not force:
753 if refresh:
783 if refresh:
754 raise util.Abort(_("local changes found, refresh first"))
784 raise util.Abort(_("local changes found, refresh first"))
755 else:
785 else:
756 raise util.Abort(_("local changes found"))
786 raise util.Abort(_("local changes found"))
757 return m, a, r, d
787 return m, a, r, d
758
788
759 _reserved = ('series', 'status', 'guards')
789 _reserved = ('series', 'status', 'guards')
760 def check_reserved_name(self, name):
790 def check_reserved_name(self, name):
761 if (name in self._reserved or name.startswith('.hg')
791 if (name in self._reserved or name.startswith('.hg')
762 or name.startswith('.mq')):
792 or name.startswith('.mq')):
763 raise util.Abort(_('"%s" cannot be used as the name of a patch')
793 raise util.Abort(_('"%s" cannot be used as the name of a patch')
764 % name)
794 % name)
765
795
766 def new(self, repo, patchfn, *pats, **opts):
796 def new(self, repo, patchfn, *pats, **opts):
767 """options:
797 """options:
768 msg: a string or a no-argument function returning a string
798 msg: a string or a no-argument function returning a string
769 """
799 """
770 msg = opts.get('msg')
800 msg = opts.get('msg')
771 force = opts.get('force')
801 force = opts.get('force')
772 user = opts.get('user')
802 user = opts.get('user')
773 date = opts.get('date')
803 date = opts.get('date')
774 if date:
804 if date:
775 date = util.parsedate(date)
805 date = util.parsedate(date)
776 diffopts = self.diffopts({'git': opts.get('git')})
806 diffopts = self.diffopts({'git': opts.get('git')})
777 self.check_reserved_name(patchfn)
807 self.check_reserved_name(patchfn)
778 if os.path.exists(self.join(patchfn)):
808 if os.path.exists(self.join(patchfn)):
779 raise util.Abort(_('patch "%s" already exists') % patchfn)
809 raise util.Abort(_('patch "%s" already exists') % patchfn)
780 if opts.get('include') or opts.get('exclude') or pats:
810 if opts.get('include') or opts.get('exclude') or pats:
781 match = cmdutil.match(repo, pats, opts)
811 match = cmdutil.match(repo, pats, opts)
782 # detect missing files in pats
812 # detect missing files in pats
783 def badfn(f, msg):
813 def badfn(f, msg):
784 raise util.Abort('%s: %s' % (f, msg))
814 raise util.Abort('%s: %s' % (f, msg))
785 match.bad = badfn
815 match.bad = badfn
786 m, a, r, d = repo.status(match=match)[:4]
816 m, a, r, d = repo.status(match=match)[:4]
787 else:
817 else:
788 m, a, r, d = self.check_localchanges(repo, force)
818 m, a, r, d = self.check_localchanges(repo, force)
789 match = cmdutil.matchfiles(repo, m + a + r)
819 match = cmdutil.matchfiles(repo, m + a + r)
790 if force:
820 if force:
791 p = repo[None].parents()
821 p = repo[None].parents()
792 if len(p) > 1:
822 if len(p) > 1:
793 raise util.Abort(_('cannot manage merge changesets'))
823 raise util.Abort(_('cannot manage merge changesets'))
794 commitfiles = m + a + r
824 commitfiles = m + a + r
795 self.check_toppatch(repo)
825 self.check_toppatch(repo)
796 insert = self.full_series_end()
826 insert = self.full_series_end()
797 wlock = repo.wlock()
827 wlock = repo.wlock()
798 try:
828 try:
799 # if patch file write fails, abort early
829 # if patch file write fails, abort early
800 p = self.opener(patchfn, "w")
830 p = self.opener(patchfn, "w")
801 try:
831 try:
802 if date:
832 if date:
803 p.write("# HG changeset patch\n")
833 p.write("# HG changeset patch\n")
804 if user:
834 if user:
805 p.write("# User " + user + "\n")
835 p.write("# User " + user + "\n")
806 p.write("# Date %d %d\n\n" % date)
836 p.write("# Date %d %d\n\n" % date)
807 elif user:
837 elif user:
808 p.write("From: " + user + "\n\n")
838 p.write("From: " + user + "\n\n")
809
839
810 if hasattr(msg, '__call__'):
840 if hasattr(msg, '__call__'):
811 msg = msg()
841 msg = msg()
812 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
842 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
813 n = repo.commit(commitmsg, user, date, match=match, force=True)
843 n = repo.commit(commitmsg, user, date, match=match, force=True)
814 if n is None:
844 if n is None:
815 raise util.Abort(_("repo commit failed"))
845 raise util.Abort(_("repo commit failed"))
816 try:
846 try:
817 self.full_series[insert:insert] = [patchfn]
847 self.full_series[insert:insert] = [patchfn]
818 self.applied.append(statusentry(hex(n), patchfn))
848 self.applied.append(statusentry(hex(n), patchfn))
819 self.parse_series()
849 self.parse_series()
820 self.series_dirty = 1
850 self.series_dirty = 1
821 self.applied_dirty = 1
851 self.applied_dirty = 1
822 if msg:
852 if msg:
823 msg = msg + "\n\n"
853 msg = msg + "\n\n"
824 p.write(msg)
854 p.write(msg)
825 if commitfiles:
855 if commitfiles:
826 parent = self.qparents(repo, n)
856 parent = self.qparents(repo, n)
827 chunks = patch.diff(repo, node1=parent, node2=n,
857 chunks = patch.diff(repo, node1=parent, node2=n,
828 match=match, opts=diffopts)
858 match=match, opts=diffopts)
829 for chunk in chunks:
859 for chunk in chunks:
830 p.write(chunk)
860 p.write(chunk)
831 p.close()
861 p.close()
832 wlock.release()
862 wlock.release()
833 wlock = None
863 wlock = None
834 r = self.qrepo()
864 r = self.qrepo()
835 if r: r.add([patchfn])
865 if r: r.add([patchfn])
836 except:
866 except:
837 repo.rollback()
867 repo.rollback()
838 raise
868 raise
839 except Exception:
869 except Exception:
840 patchpath = self.join(patchfn)
870 patchpath = self.join(patchfn)
841 try:
871 try:
842 os.unlink(patchpath)
872 os.unlink(patchpath)
843 except:
873 except:
844 self.ui.warn(_('error unlinking %s\n') % patchpath)
874 self.ui.warn(_('error unlinking %s\n') % patchpath)
845 raise
875 raise
846 self.removeundo(repo)
876 self.removeundo(repo)
847 finally:
877 finally:
848 release(wlock)
878 release(wlock)
849
879
850 def strip(self, repo, rev, update=True, backup="all", force=None):
880 def strip(self, repo, rev, update=True, backup="all", force=None):
851 wlock = lock = None
881 wlock = lock = None
852 try:
882 try:
853 wlock = repo.wlock()
883 wlock = repo.wlock()
854 lock = repo.lock()
884 lock = repo.lock()
855
885
856 if update:
886 if update:
857 self.check_localchanges(repo, force=force, refresh=False)
887 self.check_localchanges(repo, force=force, refresh=False)
858 urev = self.qparents(repo, rev)
888 urev = self.qparents(repo, rev)
859 hg.clean(repo, urev)
889 hg.clean(repo, urev)
860 repo.dirstate.write()
890 repo.dirstate.write()
861
891
862 self.removeundo(repo)
892 self.removeundo(repo)
863 repair.strip(self.ui, repo, rev, backup)
893 repair.strip(self.ui, repo, rev, backup)
864 # strip may have unbundled a set of backed up revisions after
894 # strip may have unbundled a set of backed up revisions after
865 # the actual strip
895 # the actual strip
866 self.removeundo(repo)
896 self.removeundo(repo)
867 finally:
897 finally:
868 release(lock, wlock)
898 release(lock, wlock)
869
899
870 def isapplied(self, patch):
900 def isapplied(self, patch):
871 """returns (index, rev, patch)"""
901 """returns (index, rev, patch)"""
872 for i, a in enumerate(self.applied):
902 for i, a in enumerate(self.applied):
873 if a.name == patch:
903 if a.name == patch:
874 return (i, a.rev, a.name)
904 return (i, a.rev, a.name)
875 return None
905 return None
876
906
877 # if the exact patch name does not exist, we try a few
907 # if the exact patch name does not exist, we try a few
878 # variations. If strict is passed, we try only #1
908 # variations. If strict is passed, we try only #1
879 #
909 #
880 # 1) a number to indicate an offset in the series file
910 # 1) a number to indicate an offset in the series file
881 # 2) a unique substring of the patch name was given
911 # 2) a unique substring of the patch name was given
882 # 3) patchname[-+]num to indicate an offset in the series file
912 # 3) patchname[-+]num to indicate an offset in the series file
883 def lookup(self, patch, strict=False):
913 def lookup(self, patch, strict=False):
884 patch = patch and str(patch)
914 patch = patch and str(patch)
885
915
886 def partial_name(s):
916 def partial_name(s):
887 if s in self.series:
917 if s in self.series:
888 return s
918 return s
889 matches = [x for x in self.series if s in x]
919 matches = [x for x in self.series if s in x]
890 if len(matches) > 1:
920 if len(matches) > 1:
891 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
921 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
892 for m in matches:
922 for m in matches:
893 self.ui.warn(' %s\n' % m)
923 self.ui.warn(' %s\n' % m)
894 return None
924 return None
895 if matches:
925 if matches:
896 return matches[0]
926 return matches[0]
897 if len(self.series) > 0 and len(self.applied) > 0:
927 if len(self.series) > 0 and len(self.applied) > 0:
898 if s == 'qtip':
928 if s == 'qtip':
899 return self.series[self.series_end(True)-1]
929 return self.series[self.series_end(True)-1]
900 if s == 'qbase':
930 if s == 'qbase':
901 return self.series[0]
931 return self.series[0]
902 return None
932 return None
903
933
904 if patch is None:
934 if patch is None:
905 return None
935 return None
906 if patch in self.series:
936 if patch in self.series:
907 return patch
937 return patch
908
938
909 if not os.path.isfile(self.join(patch)):
939 if not os.path.isfile(self.join(patch)):
910 try:
940 try:
911 sno = int(patch)
941 sno = int(patch)
912 except(ValueError, OverflowError):
942 except(ValueError, OverflowError):
913 pass
943 pass
914 else:
944 else:
915 if -len(self.series) <= sno < len(self.series):
945 if -len(self.series) <= sno < len(self.series):
916 return self.series[sno]
946 return self.series[sno]
917
947
918 if not strict:
948 if not strict:
919 res = partial_name(patch)
949 res = partial_name(patch)
920 if res:
950 if res:
921 return res
951 return res
922 minus = patch.rfind('-')
952 minus = patch.rfind('-')
923 if minus >= 0:
953 if minus >= 0:
924 res = partial_name(patch[:minus])
954 res = partial_name(patch[:minus])
925 if res:
955 if res:
926 i = self.series.index(res)
956 i = self.series.index(res)
927 try:
957 try:
928 off = int(patch[minus+1:] or 1)
958 off = int(patch[minus+1:] or 1)
929 except(ValueError, OverflowError):
959 except(ValueError, OverflowError):
930 pass
960 pass
931 else:
961 else:
932 if i - off >= 0:
962 if i - off >= 0:
933 return self.series[i - off]
963 return self.series[i - off]
934 plus = patch.rfind('+')
964 plus = patch.rfind('+')
935 if plus >= 0:
965 if plus >= 0:
936 res = partial_name(patch[:plus])
966 res = partial_name(patch[:plus])
937 if res:
967 if res:
938 i = self.series.index(res)
968 i = self.series.index(res)
939 try:
969 try:
940 off = int(patch[plus+1:] or 1)
970 off = int(patch[plus+1:] or 1)
941 except(ValueError, OverflowError):
971 except(ValueError, OverflowError):
942 pass
972 pass
943 else:
973 else:
944 if i + off < len(self.series):
974 if i + off < len(self.series):
945 return self.series[i + off]
975 return self.series[i + off]
946 raise util.Abort(_("patch %s not in series") % patch)
976 raise util.Abort(_("patch %s not in series") % patch)
947
977
948 def push(self, repo, patch=None, force=False, list=False,
978 def push(self, repo, patch=None, force=False, list=False,
949 mergeq=None, all=False):
979 mergeq=None, all=False):
950 diffopts = self.diffopts()
980 diffopts = self.diffopts()
951 wlock = repo.wlock()
981 wlock = repo.wlock()
952 try:
982 try:
953 if repo.dirstate.parents()[0] not in repo.heads():
983 if repo.dirstate.parents()[0] not in repo.heads():
954 self.ui.status(_("(working directory not at a head)\n"))
984 self.ui.status(_("(working directory not at a head)\n"))
955
985
956 if not self.series:
986 if not self.series:
957 self.ui.warn(_('no patches in series\n'))
987 self.ui.warn(_('no patches in series\n'))
958 return 0
988 return 0
959
989
960 patch = self.lookup(patch)
990 patch = self.lookup(patch)
961 # Suppose our series file is: A B C and the current 'top'
991 # Suppose our series file is: A B C and the current 'top'
962 # patch is B. qpush C should be performed (moving forward)
992 # patch is B. qpush C should be performed (moving forward)
963 # qpush B is a NOP (no change) qpush A is an error (can't
993 # qpush B is a NOP (no change) qpush A is an error (can't
964 # go backwards with qpush)
994 # go backwards with qpush)
965 if patch:
995 if patch:
966 info = self.isapplied(patch)
996 info = self.isapplied(patch)
967 if info:
997 if info:
968 if info[0] < len(self.applied) - 1:
998 if info[0] < len(self.applied) - 1:
969 raise util.Abort(
999 raise util.Abort(
970 _("cannot push to a previous patch: %s") % patch)
1000 _("cannot push to a previous patch: %s") % patch)
971 self.ui.warn(
1001 self.ui.warn(
972 _('qpush: %s is already at the top\n') % patch)
1002 _('qpush: %s is already at the top\n') % patch)
973 return
1003 return
974 pushable, reason = self.pushable(patch)
1004 pushable, reason = self.pushable(patch)
975 if not pushable:
1005 if not pushable:
976 if reason:
1006 if reason:
977 reason = _('guarded by %r') % reason
1007 reason = _('guarded by %r') % reason
978 else:
1008 else:
979 reason = _('no matching guards')
1009 reason = _('no matching guards')
980 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1010 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
981 return 1
1011 return 1
982 elif all:
1012 elif all:
983 patch = self.series[-1]
1013 patch = self.series[-1]
984 if self.isapplied(patch):
1014 if self.isapplied(patch):
985 self.ui.warn(_('all patches are currently applied\n'))
1015 self.ui.warn(_('all patches are currently applied\n'))
986 return 0
1016 return 0
987
1017
988 # Following the above example, starting at 'top' of B:
1018 # Following the above example, starting at 'top' of B:
989 # qpush should be performed (pushes C), but a subsequent
1019 # qpush should be performed (pushes C), but a subsequent
990 # qpush without an argument is an error (nothing to
1020 # qpush without an argument is an error (nothing to
991 # apply). This allows a loop of "...while hg qpush..." to
1021 # apply). This allows a loop of "...while hg qpush..." to
992 # work as it detects an error when done
1022 # work as it detects an error when done
993 start = self.series_end()
1023 start = self.series_end()
994 if start == len(self.series):
1024 if start == len(self.series):
995 self.ui.warn(_('patch series already fully applied\n'))
1025 self.ui.warn(_('patch series already fully applied\n'))
996 return 1
1026 return 1
997 if not force:
1027 if not force:
998 self.check_localchanges(repo)
1028 self.check_localchanges(repo)
999
1029
1000 self.applied_dirty = 1
1030 self.applied_dirty = 1
1001 if start > 0:
1031 if start > 0:
1002 self.check_toppatch(repo)
1032 self.check_toppatch(repo)
1003 if not patch:
1033 if not patch:
1004 patch = self.series[start]
1034 patch = self.series[start]
1005 end = start + 1
1035 end = start + 1
1006 else:
1036 else:
1007 end = self.series.index(patch, start) + 1
1037 end = self.series.index(patch, start) + 1
1008
1038
1009 s = self.series[start:end]
1039 s = self.series[start:end]
1010 all_files = {}
1040 all_files = {}
1011 try:
1041 try:
1012 if mergeq:
1042 if mergeq:
1013 ret = self.mergepatch(repo, mergeq, s, diffopts)
1043 ret = self.mergepatch(repo, mergeq, s, diffopts)
1014 else:
1044 else:
1015 ret = self.apply(repo, s, list, all_files=all_files)
1045 ret = self.apply(repo, s, list, all_files=all_files)
1016 except:
1046 except:
1017 self.ui.warn(_('cleaning up working directory...'))
1047 self.ui.warn(_('cleaning up working directory...'))
1018 node = repo.dirstate.parents()[0]
1048 node = repo.dirstate.parents()[0]
1019 hg.revert(repo, node, None)
1049 hg.revert(repo, node, None)
1020 unknown = repo.status(unknown=True)[4]
1050 unknown = repo.status(unknown=True)[4]
1021 # only remove unknown files that we know we touched or
1051 # only remove unknown files that we know we touched or
1022 # created while patching
1052 # created while patching
1023 for f in unknown:
1053 for f in unknown:
1024 if f in all_files:
1054 if f in all_files:
1025 util.unlink(repo.wjoin(f))
1055 util.unlink(repo.wjoin(f))
1026 self.ui.warn(_('done\n'))
1056 self.ui.warn(_('done\n'))
1027 raise
1057 raise
1028
1058
1029 if not self.applied:
1059 if not self.applied:
1030 return ret[0]
1060 return ret[0]
1031 top = self.applied[-1].name
1061 top = self.applied[-1].name
1032 if ret[0] and ret[0] > 1:
1062 if ret[0] and ret[0] > 1:
1033 msg = _("errors during apply, please fix and refresh %s\n")
1063 msg = _("errors during apply, please fix and refresh %s\n")
1034 self.ui.write(msg % top)
1064 self.ui.write(msg % top)
1035 else:
1065 else:
1036 self.ui.write(_("now at: %s\n") % top)
1066 self.ui.write(_("now at: %s\n") % top)
1037 return ret[0]
1067 return ret[0]
1038
1068
1039 finally:
1069 finally:
1040 wlock.release()
1070 wlock.release()
1041
1071
1042 def pop(self, repo, patch=None, force=False, update=True, all=False):
1072 def pop(self, repo, patch=None, force=False, update=True, all=False):
1043 def getfile(f, rev, flags):
1073 def getfile(f, rev, flags):
1044 t = repo.file(f).read(rev)
1074 t = repo.file(f).read(rev)
1045 repo.wwrite(f, t, flags)
1075 repo.wwrite(f, t, flags)
1046
1076
1047 wlock = repo.wlock()
1077 wlock = repo.wlock()
1048 try:
1078 try:
1049 if patch:
1079 if patch:
1050 # index, rev, patch
1080 # index, rev, patch
1051 info = self.isapplied(patch)
1081 info = self.isapplied(patch)
1052 if not info:
1082 if not info:
1053 patch = self.lookup(patch)
1083 patch = self.lookup(patch)
1054 info = self.isapplied(patch)
1084 info = self.isapplied(patch)
1055 if not info:
1085 if not info:
1056 raise util.Abort(_("patch %s is not applied") % patch)
1086 raise util.Abort(_("patch %s is not applied") % patch)
1057
1087
1058 if len(self.applied) == 0:
1088 if len(self.applied) == 0:
1059 # Allow qpop -a to work repeatedly,
1089 # Allow qpop -a to work repeatedly,
1060 # but not qpop without an argument
1090 # but not qpop without an argument
1061 self.ui.warn(_("no patches applied\n"))
1091 self.ui.warn(_("no patches applied\n"))
1062 return not all
1092 return not all
1063
1093
1064 if all:
1094 if all:
1065 start = 0
1095 start = 0
1066 elif patch:
1096 elif patch:
1067 start = info[0] + 1
1097 start = info[0] + 1
1068 else:
1098 else:
1069 start = len(self.applied) - 1
1099 start = len(self.applied) - 1
1070
1100
1071 if start >= len(self.applied):
1101 if start >= len(self.applied):
1072 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1102 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1073 return
1103 return
1074
1104
1075 if not update:
1105 if not update:
1076 parents = repo.dirstate.parents()
1106 parents = repo.dirstate.parents()
1077 rr = [ bin(x.rev) for x in self.applied ]
1107 rr = [ bin(x.rev) for x in self.applied ]
1078 for p in parents:
1108 for p in parents:
1079 if p in rr:
1109 if p in rr:
1080 self.ui.warn(_("qpop: forcing dirstate update\n"))
1110 self.ui.warn(_("qpop: forcing dirstate update\n"))
1081 update = True
1111 update = True
1082 else:
1112 else:
1083 parents = [p.hex() for p in repo[None].parents()]
1113 parents = [p.hex() for p in repo[None].parents()]
1084 needupdate = False
1114 needupdate = False
1085 for entry in self.applied[start:]:
1115 for entry in self.applied[start:]:
1086 if entry.rev in parents:
1116 if entry.rev in parents:
1087 needupdate = True
1117 needupdate = True
1088 break
1118 break
1089 update = needupdate
1119 update = needupdate
1090
1120
1091 if not force and update:
1121 if not force and update:
1092 self.check_localchanges(repo)
1122 self.check_localchanges(repo)
1093
1123
1094 self.applied_dirty = 1
1124 self.applied_dirty = 1
1095 end = len(self.applied)
1125 end = len(self.applied)
1096 rev = bin(self.applied[start].rev)
1126 rev = bin(self.applied[start].rev)
1097 if update:
1127 if update:
1098 top = self.check_toppatch(repo)
1128 top = self.check_toppatch(repo)
1099
1129
1100 try:
1130 try:
1101 heads = repo.changelog.heads(rev)
1131 heads = repo.changelog.heads(rev)
1102 except error.LookupError:
1132 except error.LookupError:
1103 node = short(rev)
1133 node = short(rev)
1104 raise util.Abort(_('trying to pop unknown node %s') % node)
1134 raise util.Abort(_('trying to pop unknown node %s') % node)
1105
1135
1106 if heads != [bin(self.applied[-1].rev)]:
1136 if heads != [bin(self.applied[-1].rev)]:
1107 raise util.Abort(_("popping would remove a revision not "
1137 raise util.Abort(_("popping would remove a revision not "
1108 "managed by this patch queue"))
1138 "managed by this patch queue"))
1109
1139
1110 # we know there are no local changes, so we can make a simplified
1140 # we know there are no local changes, so we can make a simplified
1111 # form of hg.update.
1141 # form of hg.update.
1112 if update:
1142 if update:
1113 qp = self.qparents(repo, rev)
1143 qp = self.qparents(repo, rev)
1114 changes = repo.changelog.read(qp)
1144 changes = repo.changelog.read(qp)
1115 mmap = repo.manifest.read(changes[0])
1145 mmap = repo.manifest.read(changes[0])
1116 m, a, r, d = repo.status(qp, top)[:4]
1146 m, a, r, d = repo.status(qp, top)[:4]
1117 if d:
1147 if d:
1118 raise util.Abort(_("deletions found between repo revs"))
1148 raise util.Abort(_("deletions found between repo revs"))
1119 for f in a:
1149 for f in a:
1120 try:
1150 try:
1121 os.unlink(repo.wjoin(f))
1151 os.unlink(repo.wjoin(f))
1122 except OSError, e:
1152 except OSError, e:
1123 if e.errno != errno.ENOENT:
1153 if e.errno != errno.ENOENT:
1124 raise
1154 raise
1125 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
1155 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
1126 except: pass
1156 except: pass
1127 repo.dirstate.forget(f)
1157 repo.dirstate.forget(f)
1128 for f in m:
1158 for f in m:
1129 getfile(f, mmap[f], mmap.flags(f))
1159 getfile(f, mmap[f], mmap.flags(f))
1130 for f in r:
1160 for f in r:
1131 getfile(f, mmap[f], mmap.flags(f))
1161 getfile(f, mmap[f], mmap.flags(f))
1132 for f in m + r:
1162 for f in m + r:
1133 repo.dirstate.normal(f)
1163 repo.dirstate.normal(f)
1134 repo.dirstate.setparents(qp, nullid)
1164 repo.dirstate.setparents(qp, nullid)
1135 for patch in reversed(self.applied[start:end]):
1165 for patch in reversed(self.applied[start:end]):
1136 self.ui.status(_("popping %s\n") % patch.name)
1166 self.ui.status(_("popping %s\n") % patch.name)
1137 del self.applied[start:end]
1167 del self.applied[start:end]
1138 self.strip(repo, rev, update=False, backup='strip')
1168 self.strip(repo, rev, update=False, backup='strip')
1139 if len(self.applied):
1169 if len(self.applied):
1140 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1170 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1141 else:
1171 else:
1142 self.ui.write(_("patch queue now empty\n"))
1172 self.ui.write(_("patch queue now empty\n"))
1143 finally:
1173 finally:
1144 wlock.release()
1174 wlock.release()
1145
1175
1146 def diff(self, repo, pats, opts):
1176 def diff(self, repo, pats, opts):
1147 top = self.check_toppatch(repo)
1177 top = self.check_toppatch(repo)
1148 if not top:
1178 if not top:
1149 self.ui.write(_("no patches applied\n"))
1179 self.ui.write(_("no patches applied\n"))
1150 return
1180 return
1151 qp = self.qparents(repo, top)
1181 qp = self.qparents(repo, top)
1152 if opts.get('reverse'):
1182 if opts.get('reverse'):
1153 node1, node2 = None, qp
1183 node1, node2 = None, qp
1154 else:
1184 else:
1155 node1, node2 = qp, None
1185 node1, node2 = qp, None
1156 diffopts = self.diffopts(opts)
1186 diffopts = self.diffopts(opts)
1157 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1187 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1158
1188
1159 def refresh(self, repo, pats=None, **opts):
1189 def refresh(self, repo, pats=None, **opts):
1160 if len(self.applied) == 0:
1190 if len(self.applied) == 0:
1161 self.ui.write(_("no patches applied\n"))
1191 self.ui.write(_("no patches applied\n"))
1162 return 1
1192 return 1
1163 msg = opts.get('msg', '').rstrip()
1193 msg = opts.get('msg', '').rstrip()
1164 newuser = opts.get('user')
1194 newuser = opts.get('user')
1165 newdate = opts.get('date')
1195 newdate = opts.get('date')
1166 if newdate:
1196 if newdate:
1167 newdate = '%d %d' % util.parsedate(newdate)
1197 newdate = '%d %d' % util.parsedate(newdate)
1168 wlock = repo.wlock()
1198 wlock = repo.wlock()
1169 try:
1199 try:
1170 self.check_toppatch(repo)
1200 self.check_toppatch(repo)
1171 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
1201 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
1172 top = bin(top)
1202 top = bin(top)
1173 if repo.changelog.heads(top) != [top]:
1203 if repo.changelog.heads(top) != [top]:
1174 raise util.Abort(_("cannot refresh a revision with children"))
1204 raise util.Abort(_("cannot refresh a revision with children"))
1175 cparents = repo.changelog.parents(top)
1205 cparents = repo.changelog.parents(top)
1176 patchparent = self.qparents(repo, top)
1206 patchparent = self.qparents(repo, top)
1177 ph = patchheader(self.join(patchfn))
1207 ph = patchheader(self.join(patchfn))
1178 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1208 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1179 if msg:
1209 if msg:
1180 ph.setmessage(msg)
1210 ph.setmessage(msg)
1181 if newuser:
1211 if newuser:
1182 ph.setuser(newuser)
1212 ph.setuser(newuser)
1183 if newdate:
1213 if newdate:
1184 ph.setdate(newdate)
1214 ph.setdate(newdate)
1185
1215
1186 # only commit new patch when write is complete
1216 # only commit new patch when write is complete
1187 patchf = self.opener(patchfn, 'w', atomictemp=True)
1217 patchf = self.opener(patchfn, 'w', atomictemp=True)
1188
1218
1189 comments = str(ph)
1219 comments = str(ph)
1190 if comments:
1220 if comments:
1191 patchf.write(comments)
1221 patchf.write(comments)
1192
1222
1193 tip = repo.changelog.tip()
1223 tip = repo.changelog.tip()
1194 if top == tip:
1224 if top == tip:
1195 # if the top of our patch queue is also the tip, there is an
1225 # if the top of our patch queue is also the tip, there is an
1196 # optimization here. We update the dirstate in place and strip
1226 # optimization here. We update the dirstate in place and strip
1197 # off the tip commit. Then just commit the current directory
1227 # off the tip commit. Then just commit the current directory
1198 # tree. We can also send repo.commit the list of files
1228 # tree. We can also send repo.commit the list of files
1199 # changed to speed up the diff
1229 # changed to speed up the diff
1200 #
1230 #
1201 # in short mode, we only diff the files included in the
1231 # in short mode, we only diff the files included in the
1202 # patch already plus specified files
1232 # patch already plus specified files
1203 #
1233 #
1204 # this should really read:
1234 # this should really read:
1205 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1235 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1206 # but we do it backwards to take advantage of manifest/chlog
1236 # but we do it backwards to take advantage of manifest/chlog
1207 # caching against the next repo.status call
1237 # caching against the next repo.status call
1208 #
1238 #
1209 mm, aa, dd, aa2 = repo.status(patchparent, tip)[:4]
1239 mm, aa, dd, aa2 = repo.status(patchparent, tip)[:4]
1210 changes = repo.changelog.read(tip)
1240 changes = repo.changelog.read(tip)
1211 man = repo.manifest.read(changes[0])
1241 man = repo.manifest.read(changes[0])
1212 aaa = aa[:]
1242 aaa = aa[:]
1213 matchfn = cmdutil.match(repo, pats, opts)
1243 matchfn = cmdutil.match(repo, pats, opts)
1214 if opts.get('short'):
1244 if opts.get('short'):
1215 # if amending a patch, we start with existing
1245 # if amending a patch, we start with existing
1216 # files plus specified files - unfiltered
1246 # files plus specified files - unfiltered
1217 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1247 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1218 # filter with inc/exl options
1248 # filter with inc/exl options
1219 matchfn = cmdutil.match(repo, opts=opts)
1249 matchfn = cmdutil.match(repo, opts=opts)
1220 else:
1250 else:
1221 match = cmdutil.matchall(repo)
1251 match = cmdutil.matchall(repo)
1222 m, a, r, d = repo.status(match=match)[:4]
1252 m, a, r, d = repo.status(match=match)[:4]
1223
1253
1224 # we might end up with files that were added between
1254 # we might end up with files that were added between
1225 # tip and the dirstate parent, but then changed in the
1255 # tip and the dirstate parent, but then changed in the
1226 # local dirstate. in this case, we want them to only
1256 # local dirstate. in this case, we want them to only
1227 # show up in the added section
1257 # show up in the added section
1228 for x in m:
1258 for x in m:
1229 if x not in aa:
1259 if x not in aa:
1230 mm.append(x)
1260 mm.append(x)
1231 # we might end up with files added by the local dirstate that
1261 # we might end up with files added by the local dirstate that
1232 # were deleted by the patch. In this case, they should only
1262 # were deleted by the patch. In this case, they should only
1233 # show up in the changed section.
1263 # show up in the changed section.
1234 for x in a:
1264 for x in a:
1235 if x in dd:
1265 if x in dd:
1236 del dd[dd.index(x)]
1266 del dd[dd.index(x)]
1237 mm.append(x)
1267 mm.append(x)
1238 else:
1268 else:
1239 aa.append(x)
1269 aa.append(x)
1240 # make sure any files deleted in the local dirstate
1270 # make sure any files deleted in the local dirstate
1241 # are not in the add or change column of the patch
1271 # are not in the add or change column of the patch
1242 forget = []
1272 forget = []
1243 for x in d + r:
1273 for x in d + r:
1244 if x in aa:
1274 if x in aa:
1245 del aa[aa.index(x)]
1275 del aa[aa.index(x)]
1246 forget.append(x)
1276 forget.append(x)
1247 continue
1277 continue
1248 elif x in mm:
1278 elif x in mm:
1249 del mm[mm.index(x)]
1279 del mm[mm.index(x)]
1250 dd.append(x)
1280 dd.append(x)
1251
1281
1252 m = list(set(mm))
1282 m = list(set(mm))
1253 r = list(set(dd))
1283 r = list(set(dd))
1254 a = list(set(aa))
1284 a = list(set(aa))
1255 c = [filter(matchfn, l) for l in (m, a, r)]
1285 c = [filter(matchfn, l) for l in (m, a, r)]
1256 match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
1286 match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
1257 chunks = patch.diff(repo, patchparent, match=match,
1287 chunks = patch.diff(repo, patchparent, match=match,
1258 changes=c, opts=diffopts)
1288 changes=c, opts=diffopts)
1259 for chunk in chunks:
1289 for chunk in chunks:
1260 patchf.write(chunk)
1290 patchf.write(chunk)
1261
1291
1262 try:
1292 try:
1263 if diffopts.git:
1293 if diffopts.git or diffopts.upgrade:
1264 copies = {}
1294 copies = {}
1265 for dst in a:
1295 for dst in a:
1266 src = repo.dirstate.copied(dst)
1296 src = repo.dirstate.copied(dst)
1267 # during qfold, the source file for copies may
1297 # during qfold, the source file for copies may
1268 # be removed. Treat this as a simple add.
1298 # be removed. Treat this as a simple add.
1269 if src is not None and src in repo.dirstate:
1299 if src is not None and src in repo.dirstate:
1270 copies.setdefault(src, []).append(dst)
1300 copies.setdefault(src, []).append(dst)
1271 repo.dirstate.add(dst)
1301 repo.dirstate.add(dst)
1272 # remember the copies between patchparent and tip
1302 # remember the copies between patchparent and tip
1273 for dst in aaa:
1303 for dst in aaa:
1274 f = repo.file(dst)
1304 f = repo.file(dst)
1275 src = f.renamed(man[dst])
1305 src = f.renamed(man[dst])
1276 if src:
1306 if src:
1277 copies.setdefault(src[0], []).extend(copies.get(dst, []))
1307 copies.setdefault(src[0], []).extend(copies.get(dst, []))
1278 if dst in a:
1308 if dst in a:
1279 copies[src[0]].append(dst)
1309 copies[src[0]].append(dst)
1280 # we can't copy a file created by the patch itself
1310 # we can't copy a file created by the patch itself
1281 if dst in copies:
1311 if dst in copies:
1282 del copies[dst]
1312 del copies[dst]
1283 for src, dsts in copies.iteritems():
1313 for src, dsts in copies.iteritems():
1284 for dst in dsts:
1314 for dst in dsts:
1285 repo.dirstate.copy(src, dst)
1315 repo.dirstate.copy(src, dst)
1286 else:
1316 else:
1287 for dst in a:
1317 for dst in a:
1288 repo.dirstate.add(dst)
1318 repo.dirstate.add(dst)
1289 # Drop useless copy information
1319 # Drop useless copy information
1290 for f in list(repo.dirstate.copies()):
1320 for f in list(repo.dirstate.copies()):
1291 repo.dirstate.copy(None, f)
1321 repo.dirstate.copy(None, f)
1292 for f in r:
1322 for f in r:
1293 repo.dirstate.remove(f)
1323 repo.dirstate.remove(f)
1294 # if the patch excludes a modified file, mark that
1324 # if the patch excludes a modified file, mark that
1295 # file with mtime=0 so status can see it.
1325 # file with mtime=0 so status can see it.
1296 mm = []
1326 mm = []
1297 for i in xrange(len(m)-1, -1, -1):
1327 for i in xrange(len(m)-1, -1, -1):
1298 if not matchfn(m[i]):
1328 if not matchfn(m[i]):
1299 mm.append(m[i])
1329 mm.append(m[i])
1300 del m[i]
1330 del m[i]
1301 for f in m:
1331 for f in m:
1302 repo.dirstate.normal(f)
1332 repo.dirstate.normal(f)
1303 for f in mm:
1333 for f in mm:
1304 repo.dirstate.normallookup(f)
1334 repo.dirstate.normallookup(f)
1305 for f in forget:
1335 for f in forget:
1306 repo.dirstate.forget(f)
1336 repo.dirstate.forget(f)
1307
1337
1308 if not msg:
1338 if not msg:
1309 if not ph.message:
1339 if not ph.message:
1310 message = "[mq]: %s\n" % patchfn
1340 message = "[mq]: %s\n" % patchfn
1311 else:
1341 else:
1312 message = "\n".join(ph.message)
1342 message = "\n".join(ph.message)
1313 else:
1343 else:
1314 message = msg
1344 message = msg
1315
1345
1316 user = ph.user or changes[1]
1346 user = ph.user or changes[1]
1317
1347
1318 # assumes strip can roll itself back if interrupted
1348 # assumes strip can roll itself back if interrupted
1319 repo.dirstate.setparents(*cparents)
1349 repo.dirstate.setparents(*cparents)
1320 self.applied.pop()
1350 self.applied.pop()
1321 self.applied_dirty = 1
1351 self.applied_dirty = 1
1322 self.strip(repo, top, update=False,
1352 self.strip(repo, top, update=False,
1323 backup='strip')
1353 backup='strip')
1324 except:
1354 except:
1325 repo.dirstate.invalidate()
1355 repo.dirstate.invalidate()
1326 raise
1356 raise
1327
1357
1328 try:
1358 try:
1329 # might be nice to attempt to roll back strip after this
1359 # might be nice to attempt to roll back strip after this
1330 patchf.rename()
1360 patchf.rename()
1331 n = repo.commit(message, user, ph.date, match=match,
1361 n = repo.commit(message, user, ph.date, match=match,
1332 force=True)
1362 force=True)
1333 self.applied.append(statusentry(hex(n), patchfn))
1363 self.applied.append(statusentry(hex(n), patchfn))
1334 except:
1364 except:
1335 ctx = repo[cparents[0]]
1365 ctx = repo[cparents[0]]
1336 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1366 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1337 self.save_dirty()
1367 self.save_dirty()
1338 self.ui.warn(_('refresh interrupted while patch was popped! '
1368 self.ui.warn(_('refresh interrupted while patch was popped! '
1339 '(revert --all, qpush to recover)\n'))
1369 '(revert --all, qpush to recover)\n'))
1340 raise
1370 raise
1341 else:
1371 else:
1342 self.printdiff(repo, diffopts, patchparent, fp=patchf)
1372 self.printdiff(repo, diffopts, patchparent, fp=patchf)
1343 patchf.rename()
1373 patchf.rename()
1344 added = repo.status()[1]
1374 added = repo.status()[1]
1345 for a in added:
1375 for a in added:
1346 f = repo.wjoin(a)
1376 f = repo.wjoin(a)
1347 try:
1377 try:
1348 os.unlink(f)
1378 os.unlink(f)
1349 except OSError, e:
1379 except OSError, e:
1350 if e.errno != errno.ENOENT:
1380 if e.errno != errno.ENOENT:
1351 raise
1381 raise
1352 try: os.removedirs(os.path.dirname(f))
1382 try: os.removedirs(os.path.dirname(f))
1353 except: pass
1383 except: pass
1354 # forget the file copies in the dirstate
1384 # forget the file copies in the dirstate
1355 # push should readd the files later on
1385 # push should readd the files later on
1356 repo.dirstate.forget(a)
1386 repo.dirstate.forget(a)
1357 self.pop(repo, force=True)
1387 self.pop(repo, force=True)
1358 self.push(repo, force=True)
1388 self.push(repo, force=True)
1359 finally:
1389 finally:
1360 wlock.release()
1390 wlock.release()
1361 self.removeundo(repo)
1391 self.removeundo(repo)
1362
1392
1363 def init(self, repo, create=False):
1393 def init(self, repo, create=False):
1364 if not create and os.path.isdir(self.path):
1394 if not create and os.path.isdir(self.path):
1365 raise util.Abort(_("patch queue directory already exists"))
1395 raise util.Abort(_("patch queue directory already exists"))
1366 try:
1396 try:
1367 os.mkdir(self.path)
1397 os.mkdir(self.path)
1368 except OSError, inst:
1398 except OSError, inst:
1369 if inst.errno != errno.EEXIST or not create:
1399 if inst.errno != errno.EEXIST or not create:
1370 raise
1400 raise
1371 if create:
1401 if create:
1372 return self.qrepo(create=True)
1402 return self.qrepo(create=True)
1373
1403
1374 def unapplied(self, repo, patch=None):
1404 def unapplied(self, repo, patch=None):
1375 if patch and patch not in self.series:
1405 if patch and patch not in self.series:
1376 raise util.Abort(_("patch %s is not in series file") % patch)
1406 raise util.Abort(_("patch %s is not in series file") % patch)
1377 if not patch:
1407 if not patch:
1378 start = self.series_end()
1408 start = self.series_end()
1379 else:
1409 else:
1380 start = self.series.index(patch) + 1
1410 start = self.series.index(patch) + 1
1381 unapplied = []
1411 unapplied = []
1382 for i in xrange(start, len(self.series)):
1412 for i in xrange(start, len(self.series)):
1383 pushable, reason = self.pushable(i)
1413 pushable, reason = self.pushable(i)
1384 if pushable:
1414 if pushable:
1385 unapplied.append((i, self.series[i]))
1415 unapplied.append((i, self.series[i]))
1386 self.explain_pushable(i)
1416 self.explain_pushable(i)
1387 return unapplied
1417 return unapplied
1388
1418
1389 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1419 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1390 summary=False):
1420 summary=False):
1391 def displayname(pfx, patchname):
1421 def displayname(pfx, patchname):
1392 if summary:
1422 if summary:
1393 ph = patchheader(self.join(patchname))
1423 ph = patchheader(self.join(patchname))
1394 msg = ph.message and ph.message[0] or ''
1424 msg = ph.message and ph.message[0] or ''
1395 if self.ui.interactive():
1425 if self.ui.interactive():
1396 width = util.termwidth() - len(pfx) - len(patchname) - 2
1426 width = util.termwidth() - len(pfx) - len(patchname) - 2
1397 if width > 0:
1427 if width > 0:
1398 msg = util.ellipsis(msg, width)
1428 msg = util.ellipsis(msg, width)
1399 else:
1429 else:
1400 msg = ''
1430 msg = ''
1401 msg = "%s%s: %s" % (pfx, patchname, msg)
1431 msg = "%s%s: %s" % (pfx, patchname, msg)
1402 else:
1432 else:
1403 msg = pfx + patchname
1433 msg = pfx + patchname
1404 self.ui.write(msg + '\n')
1434 self.ui.write(msg + '\n')
1405
1435
1406 applied = set([p.name for p in self.applied])
1436 applied = set([p.name for p in self.applied])
1407 if length is None:
1437 if length is None:
1408 length = len(self.series) - start
1438 length = len(self.series) - start
1409 if not missing:
1439 if not missing:
1410 if self.ui.verbose:
1440 if self.ui.verbose:
1411 idxwidth = len(str(start+length - 1))
1441 idxwidth = len(str(start+length - 1))
1412 for i in xrange(start, start+length):
1442 for i in xrange(start, start+length):
1413 patch = self.series[i]
1443 patch = self.series[i]
1414 if patch in applied:
1444 if patch in applied:
1415 stat = 'A'
1445 stat = 'A'
1416 elif self.pushable(i)[0]:
1446 elif self.pushable(i)[0]:
1417 stat = 'U'
1447 stat = 'U'
1418 else:
1448 else:
1419 stat = 'G'
1449 stat = 'G'
1420 pfx = ''
1450 pfx = ''
1421 if self.ui.verbose:
1451 if self.ui.verbose:
1422 pfx = '%*d %s ' % (idxwidth, i, stat)
1452 pfx = '%*d %s ' % (idxwidth, i, stat)
1423 elif status and status != stat:
1453 elif status and status != stat:
1424 continue
1454 continue
1425 displayname(pfx, patch)
1455 displayname(pfx, patch)
1426 else:
1456 else:
1427 msng_list = []
1457 msng_list = []
1428 for root, dirs, files in os.walk(self.path):
1458 for root, dirs, files in os.walk(self.path):
1429 d = root[len(self.path) + 1:]
1459 d = root[len(self.path) + 1:]
1430 for f in files:
1460 for f in files:
1431 fl = os.path.join(d, f)
1461 fl = os.path.join(d, f)
1432 if (fl not in self.series and
1462 if (fl not in self.series and
1433 fl not in (self.status_path, self.series_path,
1463 fl not in (self.status_path, self.series_path,
1434 self.guards_path)
1464 self.guards_path)
1435 and not fl.startswith('.')):
1465 and not fl.startswith('.')):
1436 msng_list.append(fl)
1466 msng_list.append(fl)
1437 for x in sorted(msng_list):
1467 for x in sorted(msng_list):
1438 pfx = self.ui.verbose and ('D ') or ''
1468 pfx = self.ui.verbose and ('D ') or ''
1439 displayname(pfx, x)
1469 displayname(pfx, x)
1440
1470
1441 def issaveline(self, l):
1471 def issaveline(self, l):
1442 if l.name == '.hg.patches.save.line':
1472 if l.name == '.hg.patches.save.line':
1443 return True
1473 return True
1444
1474
1445 def qrepo(self, create=False):
1475 def qrepo(self, create=False):
1446 if create or os.path.isdir(self.join(".hg")):
1476 if create or os.path.isdir(self.join(".hg")):
1447 return hg.repository(self.ui, path=self.path, create=create)
1477 return hg.repository(self.ui, path=self.path, create=create)
1448
1478
1449 def restore(self, repo, rev, delete=None, qupdate=None):
1479 def restore(self, repo, rev, delete=None, qupdate=None):
1450 c = repo.changelog.read(rev)
1480 c = repo.changelog.read(rev)
1451 desc = c[4].strip()
1481 desc = c[4].strip()
1452 lines = desc.splitlines()
1482 lines = desc.splitlines()
1453 i = 0
1483 i = 0
1454 datastart = None
1484 datastart = None
1455 series = []
1485 series = []
1456 applied = []
1486 applied = []
1457 qpp = None
1487 qpp = None
1458 for i, line in enumerate(lines):
1488 for i, line in enumerate(lines):
1459 if line == 'Patch Data:':
1489 if line == 'Patch Data:':
1460 datastart = i + 1
1490 datastart = i + 1
1461 elif line.startswith('Dirstate:'):
1491 elif line.startswith('Dirstate:'):
1462 l = line.rstrip()
1492 l = line.rstrip()
1463 l = l[10:].split(' ')
1493 l = l[10:].split(' ')
1464 qpp = [ bin(x) for x in l ]
1494 qpp = [ bin(x) for x in l ]
1465 elif datastart != None:
1495 elif datastart != None:
1466 l = line.rstrip()
1496 l = line.rstrip()
1467 se = statusentry(l)
1497 se = statusentry(l)
1468 file_ = se.name
1498 file_ = se.name
1469 if se.rev:
1499 if se.rev:
1470 applied.append(se)
1500 applied.append(se)
1471 else:
1501 else:
1472 series.append(file_)
1502 series.append(file_)
1473 if datastart is None:
1503 if datastart is None:
1474 self.ui.warn(_("No saved patch data found\n"))
1504 self.ui.warn(_("No saved patch data found\n"))
1475 return 1
1505 return 1
1476 self.ui.warn(_("restoring status: %s\n") % lines[0])
1506 self.ui.warn(_("restoring status: %s\n") % lines[0])
1477 self.full_series = series
1507 self.full_series = series
1478 self.applied = applied
1508 self.applied = applied
1479 self.parse_series()
1509 self.parse_series()
1480 self.series_dirty = 1
1510 self.series_dirty = 1
1481 self.applied_dirty = 1
1511 self.applied_dirty = 1
1482 heads = repo.changelog.heads()
1512 heads = repo.changelog.heads()
1483 if delete:
1513 if delete:
1484 if rev not in heads:
1514 if rev not in heads:
1485 self.ui.warn(_("save entry has children, leaving it alone\n"))
1515 self.ui.warn(_("save entry has children, leaving it alone\n"))
1486 else:
1516 else:
1487 self.ui.warn(_("removing save entry %s\n") % short(rev))
1517 self.ui.warn(_("removing save entry %s\n") % short(rev))
1488 pp = repo.dirstate.parents()
1518 pp = repo.dirstate.parents()
1489 if rev in pp:
1519 if rev in pp:
1490 update = True
1520 update = True
1491 else:
1521 else:
1492 update = False
1522 update = False
1493 self.strip(repo, rev, update=update, backup='strip')
1523 self.strip(repo, rev, update=update, backup='strip')
1494 if qpp:
1524 if qpp:
1495 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1525 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1496 (short(qpp[0]), short(qpp[1])))
1526 (short(qpp[0]), short(qpp[1])))
1497 if qupdate:
1527 if qupdate:
1498 self.ui.status(_("queue directory updating\n"))
1528 self.ui.status(_("queue directory updating\n"))
1499 r = self.qrepo()
1529 r = self.qrepo()
1500 if not r:
1530 if not r:
1501 self.ui.warn(_("Unable to load queue repository\n"))
1531 self.ui.warn(_("Unable to load queue repository\n"))
1502 return 1
1532 return 1
1503 hg.clean(r, qpp[0])
1533 hg.clean(r, qpp[0])
1504
1534
1505 def save(self, repo, msg=None):
1535 def save(self, repo, msg=None):
1506 if len(self.applied) == 0:
1536 if len(self.applied) == 0:
1507 self.ui.warn(_("save: no patches applied, exiting\n"))
1537 self.ui.warn(_("save: no patches applied, exiting\n"))
1508 return 1
1538 return 1
1509 if self.issaveline(self.applied[-1]):
1539 if self.issaveline(self.applied[-1]):
1510 self.ui.warn(_("status is already saved\n"))
1540 self.ui.warn(_("status is already saved\n"))
1511 return 1
1541 return 1
1512
1542
1513 ar = [ ':' + x for x in self.full_series ]
1543 ar = [ ':' + x for x in self.full_series ]
1514 if not msg:
1544 if not msg:
1515 msg = _("hg patches saved state")
1545 msg = _("hg patches saved state")
1516 else:
1546 else:
1517 msg = "hg patches: " + msg.rstrip('\r\n')
1547 msg = "hg patches: " + msg.rstrip('\r\n')
1518 r = self.qrepo()
1548 r = self.qrepo()
1519 if r:
1549 if r:
1520 pp = r.dirstate.parents()
1550 pp = r.dirstate.parents()
1521 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1551 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1522 msg += "\n\nPatch Data:\n"
1552 msg += "\n\nPatch Data:\n"
1523 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1553 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1524 "\n".join(ar) + '\n' or "")
1554 "\n".join(ar) + '\n' or "")
1525 n = repo.commit(text, force=True)
1555 n = repo.commit(text, force=True)
1526 if not n:
1556 if not n:
1527 self.ui.warn(_("repo commit failed\n"))
1557 self.ui.warn(_("repo commit failed\n"))
1528 return 1
1558 return 1
1529 self.applied.append(statusentry(hex(n),'.hg.patches.save.line'))
1559 self.applied.append(statusentry(hex(n),'.hg.patches.save.line'))
1530 self.applied_dirty = 1
1560 self.applied_dirty = 1
1531 self.removeundo(repo)
1561 self.removeundo(repo)
1532
1562
1533 def full_series_end(self):
1563 def full_series_end(self):
1534 if len(self.applied) > 0:
1564 if len(self.applied) > 0:
1535 p = self.applied[-1].name
1565 p = self.applied[-1].name
1536 end = self.find_series(p)
1566 end = self.find_series(p)
1537 if end is None:
1567 if end is None:
1538 return len(self.full_series)
1568 return len(self.full_series)
1539 return end + 1
1569 return end + 1
1540 return 0
1570 return 0
1541
1571
1542 def series_end(self, all_patches=False):
1572 def series_end(self, all_patches=False):
1543 """If all_patches is False, return the index of the next pushable patch
1573 """If all_patches is False, return the index of the next pushable patch
1544 in the series, or the series length. If all_patches is True, return the
1574 in the series, or the series length. If all_patches is True, return the
1545 index of the first patch past the last applied one.
1575 index of the first patch past the last applied one.
1546 """
1576 """
1547 end = 0
1577 end = 0
1548 def next(start):
1578 def next(start):
1549 if all_patches:
1579 if all_patches:
1550 return start
1580 return start
1551 i = start
1581 i = start
1552 while i < len(self.series):
1582 while i < len(self.series):
1553 p, reason = self.pushable(i)
1583 p, reason = self.pushable(i)
1554 if p:
1584 if p:
1555 break
1585 break
1556 self.explain_pushable(i)
1586 self.explain_pushable(i)
1557 i += 1
1587 i += 1
1558 return i
1588 return i
1559 if len(self.applied) > 0:
1589 if len(self.applied) > 0:
1560 p = self.applied[-1].name
1590 p = self.applied[-1].name
1561 try:
1591 try:
1562 end = self.series.index(p)
1592 end = self.series.index(p)
1563 except ValueError:
1593 except ValueError:
1564 return 0
1594 return 0
1565 return next(end + 1)
1595 return next(end + 1)
1566 return next(end)
1596 return next(end)
1567
1597
1568 def appliedname(self, index):
1598 def appliedname(self, index):
1569 pname = self.applied[index].name
1599 pname = self.applied[index].name
1570 if not self.ui.verbose:
1600 if not self.ui.verbose:
1571 p = pname
1601 p = pname
1572 else:
1602 else:
1573 p = str(self.series.index(pname)) + " " + pname
1603 p = str(self.series.index(pname)) + " " + pname
1574 return p
1604 return p
1575
1605
1576 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1606 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1577 force=None, git=False):
1607 force=None, git=False):
1578 def checkseries(patchname):
1608 def checkseries(patchname):
1579 if patchname in self.series:
1609 if patchname in self.series:
1580 raise util.Abort(_('patch %s is already in the series file')
1610 raise util.Abort(_('patch %s is already in the series file')
1581 % patchname)
1611 % patchname)
1582 def checkfile(patchname):
1612 def checkfile(patchname):
1583 if not force and os.path.exists(self.join(patchname)):
1613 if not force and os.path.exists(self.join(patchname)):
1584 raise util.Abort(_('patch "%s" already exists')
1614 raise util.Abort(_('patch "%s" already exists')
1585 % patchname)
1615 % patchname)
1586
1616
1587 if rev:
1617 if rev:
1588 if files:
1618 if files:
1589 raise util.Abort(_('option "-r" not valid when importing '
1619 raise util.Abort(_('option "-r" not valid when importing '
1590 'files'))
1620 'files'))
1591 rev = cmdutil.revrange(repo, rev)
1621 rev = cmdutil.revrange(repo, rev)
1592 rev.sort(reverse=True)
1622 rev.sort(reverse=True)
1593 if (len(files) > 1 or len(rev) > 1) and patchname:
1623 if (len(files) > 1 or len(rev) > 1) and patchname:
1594 raise util.Abort(_('option "-n" not valid when importing multiple '
1624 raise util.Abort(_('option "-n" not valid when importing multiple '
1595 'patches'))
1625 'patches'))
1596 i = 0
1626 i = 0
1597 added = []
1627 added = []
1598 if rev:
1628 if rev:
1599 # If mq patches are applied, we can only import revisions
1629 # If mq patches are applied, we can only import revisions
1600 # that form a linear path to qbase.
1630 # that form a linear path to qbase.
1601 # Otherwise, they should form a linear path to a head.
1631 # Otherwise, they should form a linear path to a head.
1602 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1632 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1603 if len(heads) > 1:
1633 if len(heads) > 1:
1604 raise util.Abort(_('revision %d is the root of more than one '
1634 raise util.Abort(_('revision %d is the root of more than one '
1605 'branch') % rev[-1])
1635 'branch') % rev[-1])
1606 if self.applied:
1636 if self.applied:
1607 base = hex(repo.changelog.node(rev[0]))
1637 base = hex(repo.changelog.node(rev[0]))
1608 if base in [n.rev for n in self.applied]:
1638 if base in [n.rev for n in self.applied]:
1609 raise util.Abort(_('revision %d is already managed')
1639 raise util.Abort(_('revision %d is already managed')
1610 % rev[0])
1640 % rev[0])
1611 if heads != [bin(self.applied[-1].rev)]:
1641 if heads != [bin(self.applied[-1].rev)]:
1612 raise util.Abort(_('revision %d is not the parent of '
1642 raise util.Abort(_('revision %d is not the parent of '
1613 'the queue') % rev[0])
1643 'the queue') % rev[0])
1614 base = repo.changelog.rev(bin(self.applied[0].rev))
1644 base = repo.changelog.rev(bin(self.applied[0].rev))
1615 lastparent = repo.changelog.parentrevs(base)[0]
1645 lastparent = repo.changelog.parentrevs(base)[0]
1616 else:
1646 else:
1617 if heads != [repo.changelog.node(rev[0])]:
1647 if heads != [repo.changelog.node(rev[0])]:
1618 raise util.Abort(_('revision %d has unmanaged children')
1648 raise util.Abort(_('revision %d has unmanaged children')
1619 % rev[0])
1649 % rev[0])
1620 lastparent = None
1650 lastparent = None
1621
1651
1622 diffopts = self.diffopts({'git': git})
1652 diffopts = self.diffopts({'git': git})
1623 for r in rev:
1653 for r in rev:
1624 p1, p2 = repo.changelog.parentrevs(r)
1654 p1, p2 = repo.changelog.parentrevs(r)
1625 n = repo.changelog.node(r)
1655 n = repo.changelog.node(r)
1626 if p2 != nullrev:
1656 if p2 != nullrev:
1627 raise util.Abort(_('cannot import merge revision %d') % r)
1657 raise util.Abort(_('cannot import merge revision %d') % r)
1628 if lastparent and lastparent != r:
1658 if lastparent and lastparent != r:
1629 raise util.Abort(_('revision %d is not the parent of %d')
1659 raise util.Abort(_('revision %d is not the parent of %d')
1630 % (r, lastparent))
1660 % (r, lastparent))
1631 lastparent = p1
1661 lastparent = p1
1632
1662
1633 if not patchname:
1663 if not patchname:
1634 patchname = normname('%d.diff' % r)
1664 patchname = normname('%d.diff' % r)
1635 self.check_reserved_name(patchname)
1665 self.check_reserved_name(patchname)
1636 checkseries(patchname)
1666 checkseries(patchname)
1637 checkfile(patchname)
1667 checkfile(patchname)
1638 self.full_series.insert(0, patchname)
1668 self.full_series.insert(0, patchname)
1639
1669
1640 patchf = self.opener(patchname, "w")
1670 patchf = self.opener(patchname, "w")
1641 patch.export(repo, [n], fp=patchf, opts=diffopts)
1671 patch.export(repo, [n], fp=patchf, opts=diffopts)
1642 patchf.close()
1672 patchf.close()
1643
1673
1644 se = statusentry(hex(n), patchname)
1674 se = statusentry(hex(n), patchname)
1645 self.applied.insert(0, se)
1675 self.applied.insert(0, se)
1646
1676
1647 added.append(patchname)
1677 added.append(patchname)
1648 patchname = None
1678 patchname = None
1649 self.parse_series()
1679 self.parse_series()
1650 self.applied_dirty = 1
1680 self.applied_dirty = 1
1651
1681
1652 for filename in files:
1682 for filename in files:
1653 if existing:
1683 if existing:
1654 if filename == '-':
1684 if filename == '-':
1655 raise util.Abort(_('-e is incompatible with import from -'))
1685 raise util.Abort(_('-e is incompatible with import from -'))
1656 if not patchname:
1686 if not patchname:
1657 patchname = normname(filename)
1687 patchname = normname(filename)
1658 self.check_reserved_name(patchname)
1688 self.check_reserved_name(patchname)
1659 if not os.path.isfile(self.join(patchname)):
1689 if not os.path.isfile(self.join(patchname)):
1660 raise util.Abort(_("patch %s does not exist") % patchname)
1690 raise util.Abort(_("patch %s does not exist") % patchname)
1661 else:
1691 else:
1662 try:
1692 try:
1663 if filename == '-':
1693 if filename == '-':
1664 if not patchname:
1694 if not patchname:
1665 raise util.Abort(_('need --name to import a patch from -'))
1695 raise util.Abort(_('need --name to import a patch from -'))
1666 text = sys.stdin.read()
1696 text = sys.stdin.read()
1667 else:
1697 else:
1668 text = url.open(self.ui, filename).read()
1698 text = url.open(self.ui, filename).read()
1669 except (OSError, IOError):
1699 except (OSError, IOError):
1670 raise util.Abort(_("unable to read %s") % filename)
1700 raise util.Abort(_("unable to read %s") % filename)
1671 if not patchname:
1701 if not patchname:
1672 patchname = normname(os.path.basename(filename))
1702 patchname = normname(os.path.basename(filename))
1673 self.check_reserved_name(patchname)
1703 self.check_reserved_name(patchname)
1674 checkfile(patchname)
1704 checkfile(patchname)
1675 patchf = self.opener(patchname, "w")
1705 patchf = self.opener(patchname, "w")
1676 patchf.write(text)
1706 patchf.write(text)
1677 if not force:
1707 if not force:
1678 checkseries(patchname)
1708 checkseries(patchname)
1679 if patchname not in self.series:
1709 if patchname not in self.series:
1680 index = self.full_series_end() + i
1710 index = self.full_series_end() + i
1681 self.full_series[index:index] = [patchname]
1711 self.full_series[index:index] = [patchname]
1682 self.parse_series()
1712 self.parse_series()
1683 self.ui.warn(_("adding %s to series file\n") % patchname)
1713 self.ui.warn(_("adding %s to series file\n") % patchname)
1684 i += 1
1714 i += 1
1685 added.append(patchname)
1715 added.append(patchname)
1686 patchname = None
1716 patchname = None
1687 self.series_dirty = 1
1717 self.series_dirty = 1
1688 qrepo = self.qrepo()
1718 qrepo = self.qrepo()
1689 if qrepo:
1719 if qrepo:
1690 qrepo.add(added)
1720 qrepo.add(added)
1691
1721
1692 def delete(ui, repo, *patches, **opts):
1722 def delete(ui, repo, *patches, **opts):
1693 """remove patches from queue
1723 """remove patches from queue
1694
1724
1695 The patches must not be applied, and at least one patch is required. With
1725 The patches must not be applied, and at least one patch is required. With
1696 -k/--keep, the patch files are preserved in the patch directory.
1726 -k/--keep, the patch files are preserved in the patch directory.
1697
1727
1698 To stop managing a patch and move it into permanent history,
1728 To stop managing a patch and move it into permanent history,
1699 use the qfinish command."""
1729 use the qfinish command."""
1700 q = repo.mq
1730 q = repo.mq
1701 q.delete(repo, patches, opts)
1731 q.delete(repo, patches, opts)
1702 q.save_dirty()
1732 q.save_dirty()
1703 return 0
1733 return 0
1704
1734
1705 def applied(ui, repo, patch=None, **opts):
1735 def applied(ui, repo, patch=None, **opts):
1706 """print the patches already applied"""
1736 """print the patches already applied"""
1707
1737
1708 q = repo.mq
1738 q = repo.mq
1709 l = len(q.applied)
1739 l = len(q.applied)
1710
1740
1711 if patch:
1741 if patch:
1712 if patch not in q.series:
1742 if patch not in q.series:
1713 raise util.Abort(_("patch %s is not in series file") % patch)
1743 raise util.Abort(_("patch %s is not in series file") % patch)
1714 end = q.series.index(patch) + 1
1744 end = q.series.index(patch) + 1
1715 else:
1745 else:
1716 end = q.series_end(True)
1746 end = q.series_end(True)
1717
1747
1718 if opts.get('last') and not end:
1748 if opts.get('last') and not end:
1719 ui.write(_("no patches applied\n"))
1749 ui.write(_("no patches applied\n"))
1720 return 1
1750 return 1
1721 elif opts.get('last') and end == 1:
1751 elif opts.get('last') and end == 1:
1722 ui.write(_("only one patch applied\n"))
1752 ui.write(_("only one patch applied\n"))
1723 return 1
1753 return 1
1724 elif opts.get('last'):
1754 elif opts.get('last'):
1725 start = end - 2
1755 start = end - 2
1726 end = 1
1756 end = 1
1727 else:
1757 else:
1728 start = 0
1758 start = 0
1729
1759
1730 return q.qseries(repo, length=end, start=start, status='A',
1760 return q.qseries(repo, length=end, start=start, status='A',
1731 summary=opts.get('summary'))
1761 summary=opts.get('summary'))
1732
1762
1733 def unapplied(ui, repo, patch=None, **opts):
1763 def unapplied(ui, repo, patch=None, **opts):
1734 """print the patches not yet applied"""
1764 """print the patches not yet applied"""
1735
1765
1736 q = repo.mq
1766 q = repo.mq
1737 if patch:
1767 if patch:
1738 if patch not in q.series:
1768 if patch not in q.series:
1739 raise util.Abort(_("patch %s is not in series file") % patch)
1769 raise util.Abort(_("patch %s is not in series file") % patch)
1740 start = q.series.index(patch) + 1
1770 start = q.series.index(patch) + 1
1741 else:
1771 else:
1742 start = q.series_end(True)
1772 start = q.series_end(True)
1743
1773
1744 if start == len(q.series) and opts.get('first'):
1774 if start == len(q.series) and opts.get('first'):
1745 ui.write(_("all patches applied\n"))
1775 ui.write(_("all patches applied\n"))
1746 return 1
1776 return 1
1747
1777
1748 length = opts.get('first') and 1 or None
1778 length = opts.get('first') and 1 or None
1749 return q.qseries(repo, start=start, length=length, status='U',
1779 return q.qseries(repo, start=start, length=length, status='U',
1750 summary=opts.get('summary'))
1780 summary=opts.get('summary'))
1751
1781
1752 def qimport(ui, repo, *filename, **opts):
1782 def qimport(ui, repo, *filename, **opts):
1753 """import a patch
1783 """import a patch
1754
1784
1755 The patch is inserted into the series after the last applied
1785 The patch is inserted into the series after the last applied
1756 patch. If no patches have been applied, qimport prepends the patch
1786 patch. If no patches have been applied, qimport prepends the patch
1757 to the series.
1787 to the series.
1758
1788
1759 The patch will have the same name as its source file unless you
1789 The patch will have the same name as its source file unless you
1760 give it a new one with -n/--name.
1790 give it a new one with -n/--name.
1761
1791
1762 You can register an existing patch inside the patch directory with
1792 You can register an existing patch inside the patch directory with
1763 the -e/--existing flag.
1793 the -e/--existing flag.
1764
1794
1765 With -f/--force, an existing patch of the same name will be
1795 With -f/--force, an existing patch of the same name will be
1766 overwritten.
1796 overwritten.
1767
1797
1768 An existing changeset may be placed under mq control with -r/--rev
1798 An existing changeset may be placed under mq control with -r/--rev
1769 (e.g. qimport --rev tip -n patch will place tip under mq control).
1799 (e.g. qimport --rev tip -n patch will place tip under mq control).
1770 With -g/--git, patches imported with --rev will use the git diff
1800 With -g/--git, patches imported with --rev will use the git diff
1771 format. See the diffs help topic for information on why this is
1801 format. See the diffs help topic for information on why this is
1772 important for preserving rename/copy information and permission
1802 important for preserving rename/copy information and permission
1773 changes.
1803 changes.
1774
1804
1775 To import a patch from standard input, pass - as the patch file.
1805 To import a patch from standard input, pass - as the patch file.
1776 When importing from standard input, a patch name must be specified
1806 When importing from standard input, a patch name must be specified
1777 using the --name flag.
1807 using the --name flag.
1778 """
1808 """
1779 q = repo.mq
1809 q = repo.mq
1780 q.qimport(repo, filename, patchname=opts['name'],
1810 q.qimport(repo, filename, patchname=opts['name'],
1781 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1811 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1782 git=opts['git'])
1812 git=opts['git'])
1783 q.save_dirty()
1813 q.save_dirty()
1784
1814
1785 if opts.get('push') and not opts.get('rev'):
1815 if opts.get('push') and not opts.get('rev'):
1786 return q.push(repo, None)
1816 return q.push(repo, None)
1787 return 0
1817 return 0
1788
1818
1789 def init(ui, repo, **opts):
1819 def init(ui, repo, **opts):
1790 """init a new queue repository
1820 """init a new queue repository
1791
1821
1792 The queue repository is unversioned by default. If
1822 The queue repository is unversioned by default. If
1793 -c/--create-repo is specified, qinit will create a separate nested
1823 -c/--create-repo is specified, qinit will create a separate nested
1794 repository for patches (qinit -c may also be run later to convert
1824 repository for patches (qinit -c may also be run later to convert
1795 an unversioned patch repository into a versioned one). You can use
1825 an unversioned patch repository into a versioned one). You can use
1796 qcommit to commit changes to this queue repository."""
1826 qcommit to commit changes to this queue repository."""
1797 q = repo.mq
1827 q = repo.mq
1798 r = q.init(repo, create=opts['create_repo'])
1828 r = q.init(repo, create=opts['create_repo'])
1799 q.save_dirty()
1829 q.save_dirty()
1800 if r:
1830 if r:
1801 if not os.path.exists(r.wjoin('.hgignore')):
1831 if not os.path.exists(r.wjoin('.hgignore')):
1802 fp = r.wopener('.hgignore', 'w')
1832 fp = r.wopener('.hgignore', 'w')
1803 fp.write('^\\.hg\n')
1833 fp.write('^\\.hg\n')
1804 fp.write('^\\.mq\n')
1834 fp.write('^\\.mq\n')
1805 fp.write('syntax: glob\n')
1835 fp.write('syntax: glob\n')
1806 fp.write('status\n')
1836 fp.write('status\n')
1807 fp.write('guards\n')
1837 fp.write('guards\n')
1808 fp.close()
1838 fp.close()
1809 if not os.path.exists(r.wjoin('series')):
1839 if not os.path.exists(r.wjoin('series')):
1810 r.wopener('series', 'w').close()
1840 r.wopener('series', 'w').close()
1811 r.add(['.hgignore', 'series'])
1841 r.add(['.hgignore', 'series'])
1812 commands.add(ui, r)
1842 commands.add(ui, r)
1813 return 0
1843 return 0
1814
1844
1815 def clone(ui, source, dest=None, **opts):
1845 def clone(ui, source, dest=None, **opts):
1816 '''clone main and patch repository at same time
1846 '''clone main and patch repository at same time
1817
1847
1818 If source is local, destination will have no patches applied. If
1848 If source is local, destination will have no patches applied. If
1819 source is remote, this command can not check if patches are
1849 source is remote, this command can not check if patches are
1820 applied in source, so cannot guarantee that patches are not
1850 applied in source, so cannot guarantee that patches are not
1821 applied in destination. If you clone remote repository, be sure
1851 applied in destination. If you clone remote repository, be sure
1822 before that it has no patches applied.
1852 before that it has no patches applied.
1823
1853
1824 Source patch repository is looked for in <src>/.hg/patches by
1854 Source patch repository is looked for in <src>/.hg/patches by
1825 default. Use -p <url> to change.
1855 default. Use -p <url> to change.
1826
1856
1827 The patch directory must be a nested Mercurial repository, as
1857 The patch directory must be a nested Mercurial repository, as
1828 would be created by qinit -c.
1858 would be created by qinit -c.
1829 '''
1859 '''
1830 def patchdir(repo):
1860 def patchdir(repo):
1831 url = repo.url()
1861 url = repo.url()
1832 if url.endswith('/'):
1862 if url.endswith('/'):
1833 url = url[:-1]
1863 url = url[:-1]
1834 return url + '/.hg/patches'
1864 return url + '/.hg/patches'
1835 if dest is None:
1865 if dest is None:
1836 dest = hg.defaultdest(source)
1866 dest = hg.defaultdest(source)
1837 sr = hg.repository(cmdutil.remoteui(ui, opts), ui.expandpath(source))
1867 sr = hg.repository(cmdutil.remoteui(ui, opts), ui.expandpath(source))
1838 if opts['patches']:
1868 if opts['patches']:
1839 patchespath = ui.expandpath(opts['patches'])
1869 patchespath = ui.expandpath(opts['patches'])
1840 else:
1870 else:
1841 patchespath = patchdir(sr)
1871 patchespath = patchdir(sr)
1842 try:
1872 try:
1843 hg.repository(ui, patchespath)
1873 hg.repository(ui, patchespath)
1844 except error.RepoError:
1874 except error.RepoError:
1845 raise util.Abort(_('versioned patch repository not found'
1875 raise util.Abort(_('versioned patch repository not found'
1846 ' (see qinit -c)'))
1876 ' (see qinit -c)'))
1847 qbase, destrev = None, None
1877 qbase, destrev = None, None
1848 if sr.local():
1878 if sr.local():
1849 if sr.mq.applied:
1879 if sr.mq.applied:
1850 qbase = bin(sr.mq.applied[0].rev)
1880 qbase = bin(sr.mq.applied[0].rev)
1851 if not hg.islocal(dest):
1881 if not hg.islocal(dest):
1852 heads = set(sr.heads())
1882 heads = set(sr.heads())
1853 destrev = list(heads.difference(sr.heads(qbase)))
1883 destrev = list(heads.difference(sr.heads(qbase)))
1854 destrev.append(sr.changelog.parents(qbase)[0])
1884 destrev.append(sr.changelog.parents(qbase)[0])
1855 elif sr.capable('lookup'):
1885 elif sr.capable('lookup'):
1856 try:
1886 try:
1857 qbase = sr.lookup('qbase')
1887 qbase = sr.lookup('qbase')
1858 except error.RepoError:
1888 except error.RepoError:
1859 pass
1889 pass
1860 ui.note(_('cloning main repository\n'))
1890 ui.note(_('cloning main repository\n'))
1861 sr, dr = hg.clone(ui, sr.url(), dest,
1891 sr, dr = hg.clone(ui, sr.url(), dest,
1862 pull=opts['pull'],
1892 pull=opts['pull'],
1863 rev=destrev,
1893 rev=destrev,
1864 update=False,
1894 update=False,
1865 stream=opts['uncompressed'])
1895 stream=opts['uncompressed'])
1866 ui.note(_('cloning patch repository\n'))
1896 ui.note(_('cloning patch repository\n'))
1867 hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1897 hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1868 pull=opts['pull'], update=not opts['noupdate'],
1898 pull=opts['pull'], update=not opts['noupdate'],
1869 stream=opts['uncompressed'])
1899 stream=opts['uncompressed'])
1870 if dr.local():
1900 if dr.local():
1871 if qbase:
1901 if qbase:
1872 ui.note(_('stripping applied patches from destination '
1902 ui.note(_('stripping applied patches from destination '
1873 'repository\n'))
1903 'repository\n'))
1874 dr.mq.strip(dr, qbase, update=False, backup=None)
1904 dr.mq.strip(dr, qbase, update=False, backup=None)
1875 if not opts['noupdate']:
1905 if not opts['noupdate']:
1876 ui.note(_('updating destination repository\n'))
1906 ui.note(_('updating destination repository\n'))
1877 hg.update(dr, dr.changelog.tip())
1907 hg.update(dr, dr.changelog.tip())
1878
1908
1879 def commit(ui, repo, *pats, **opts):
1909 def commit(ui, repo, *pats, **opts):
1880 """commit changes in the queue repository"""
1910 """commit changes in the queue repository"""
1881 q = repo.mq
1911 q = repo.mq
1882 r = q.qrepo()
1912 r = q.qrepo()
1883 if not r: raise util.Abort('no queue repository')
1913 if not r: raise util.Abort('no queue repository')
1884 commands.commit(r.ui, r, *pats, **opts)
1914 commands.commit(r.ui, r, *pats, **opts)
1885
1915
1886 def series(ui, repo, **opts):
1916 def series(ui, repo, **opts):
1887 """print the entire series file"""
1917 """print the entire series file"""
1888 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1918 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1889 return 0
1919 return 0
1890
1920
1891 def top(ui, repo, **opts):
1921 def top(ui, repo, **opts):
1892 """print the name of the current patch"""
1922 """print the name of the current patch"""
1893 q = repo.mq
1923 q = repo.mq
1894 t = q.applied and q.series_end(True) or 0
1924 t = q.applied and q.series_end(True) or 0
1895 if t:
1925 if t:
1896 return q.qseries(repo, start=t-1, length=1, status='A',
1926 return q.qseries(repo, start=t-1, length=1, status='A',
1897 summary=opts.get('summary'))
1927 summary=opts.get('summary'))
1898 else:
1928 else:
1899 ui.write(_("no patches applied\n"))
1929 ui.write(_("no patches applied\n"))
1900 return 1
1930 return 1
1901
1931
1902 def next(ui, repo, **opts):
1932 def next(ui, repo, **opts):
1903 """print the name of the next patch"""
1933 """print the name of the next patch"""
1904 q = repo.mq
1934 q = repo.mq
1905 end = q.series_end()
1935 end = q.series_end()
1906 if end == len(q.series):
1936 if end == len(q.series):
1907 ui.write(_("all patches applied\n"))
1937 ui.write(_("all patches applied\n"))
1908 return 1
1938 return 1
1909 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1939 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1910
1940
1911 def prev(ui, repo, **opts):
1941 def prev(ui, repo, **opts):
1912 """print the name of the previous patch"""
1942 """print the name of the previous patch"""
1913 q = repo.mq
1943 q = repo.mq
1914 l = len(q.applied)
1944 l = len(q.applied)
1915 if l == 1:
1945 if l == 1:
1916 ui.write(_("only one patch applied\n"))
1946 ui.write(_("only one patch applied\n"))
1917 return 1
1947 return 1
1918 if not l:
1948 if not l:
1919 ui.write(_("no patches applied\n"))
1949 ui.write(_("no patches applied\n"))
1920 return 1
1950 return 1
1921 return q.qseries(repo, start=l-2, length=1, status='A',
1951 return q.qseries(repo, start=l-2, length=1, status='A',
1922 summary=opts.get('summary'))
1952 summary=opts.get('summary'))
1923
1953
1924 def setupheaderopts(ui, opts):
1954 def setupheaderopts(ui, opts):
1925 if not opts.get('user') and opts.get('currentuser'):
1955 if not opts.get('user') and opts.get('currentuser'):
1926 opts['user'] = ui.username()
1956 opts['user'] = ui.username()
1927 if not opts.get('date') and opts.get('currentdate'):
1957 if not opts.get('date') and opts.get('currentdate'):
1928 opts['date'] = "%d %d" % util.makedate()
1958 opts['date'] = "%d %d" % util.makedate()
1929
1959
1930 def new(ui, repo, patch, *args, **opts):
1960 def new(ui, repo, patch, *args, **opts):
1931 """create a new patch
1961 """create a new patch
1932
1962
1933 qnew creates a new patch on top of the currently-applied patch (if
1963 qnew creates a new patch on top of the currently-applied patch (if
1934 any). It will refuse to run if there are any outstanding changes
1964 any). It will refuse to run if there are any outstanding changes
1935 unless -f/--force is specified, in which case the patch will be
1965 unless -f/--force is specified, in which case the patch will be
1936 initialized with them. You may also use -I/--include,
1966 initialized with them. You may also use -I/--include,
1937 -X/--exclude, and/or a list of files after the patch name to add
1967 -X/--exclude, and/or a list of files after the patch name to add
1938 only changes to matching files to the new patch, leaving the rest
1968 only changes to matching files to the new patch, leaving the rest
1939 as uncommitted modifications.
1969 as uncommitted modifications.
1940
1970
1941 -u/--user and -d/--date can be used to set the (given) user and
1971 -u/--user and -d/--date can be used to set the (given) user and
1942 date, respectively. -U/--currentuser and -D/--currentdate set user
1972 date, respectively. -U/--currentuser and -D/--currentdate set user
1943 to current user and date to current date.
1973 to current user and date to current date.
1944
1974
1945 -e/--edit, -m/--message or -l/--logfile set the patch header as
1975 -e/--edit, -m/--message or -l/--logfile set the patch header as
1946 well as the commit message. If none is specified, the header is
1976 well as the commit message. If none is specified, the header is
1947 empty and the commit message is '[mq]: PATCH'.
1977 empty and the commit message is '[mq]: PATCH'.
1948
1978
1949 Use the -g/--git option to keep the patch in the git extended diff
1979 Use the -g/--git option to keep the patch in the git extended diff
1950 format. Read the diffs help topic for more information on why this
1980 format. Read the diffs help topic for more information on why this
1951 is important for preserving permission changes and copy/rename
1981 is important for preserving permission changes and copy/rename
1952 information.
1982 information.
1953 """
1983 """
1954 msg = cmdutil.logmessage(opts)
1984 msg = cmdutil.logmessage(opts)
1955 def getmsg(): return ui.edit(msg, ui.username())
1985 def getmsg(): return ui.edit(msg, ui.username())
1956 q = repo.mq
1986 q = repo.mq
1957 opts['msg'] = msg
1987 opts['msg'] = msg
1958 if opts.get('edit'):
1988 if opts.get('edit'):
1959 opts['msg'] = getmsg
1989 opts['msg'] = getmsg
1960 else:
1990 else:
1961 opts['msg'] = msg
1991 opts['msg'] = msg
1962 setupheaderopts(ui, opts)
1992 setupheaderopts(ui, opts)
1963 q.new(repo, patch, *args, **opts)
1993 q.new(repo, patch, *args, **opts)
1964 q.save_dirty()
1994 q.save_dirty()
1965 return 0
1995 return 0
1966
1996
1967 def refresh(ui, repo, *pats, **opts):
1997 def refresh(ui, repo, *pats, **opts):
1968 """update the current patch
1998 """update the current patch
1969
1999
1970 If any file patterns are provided, the refreshed patch will
2000 If any file patterns are provided, the refreshed patch will
1971 contain only the modifications that match those patterns; the
2001 contain only the modifications that match those patterns; the
1972 remaining modifications will remain in the working directory.
2002 remaining modifications will remain in the working directory.
1973
2003
1974 If -s/--short is specified, files currently included in the patch
2004 If -s/--short is specified, files currently included in the patch
1975 will be refreshed just like matched files and remain in the patch.
2005 will be refreshed just like matched files and remain in the patch.
1976
2006
1977 hg add/remove/copy/rename work as usual, though you might want to
2007 hg add/remove/copy/rename work as usual, though you might want to
1978 use git-style patches (-g/--git or [diff] git=1) to track copies
2008 use git-style patches (-g/--git or [diff] git=1) to track copies
1979 and renames. See the diffs help topic for more information on the
2009 and renames. See the diffs help topic for more information on the
1980 git diff format.
2010 git diff format.
1981 """
2011 """
1982 q = repo.mq
2012 q = repo.mq
1983 message = cmdutil.logmessage(opts)
2013 message = cmdutil.logmessage(opts)
1984 if opts['edit']:
2014 if opts['edit']:
1985 if not q.applied:
2015 if not q.applied:
1986 ui.write(_("no patches applied\n"))
2016 ui.write(_("no patches applied\n"))
1987 return 1
2017 return 1
1988 if message:
2018 if message:
1989 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2019 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1990 patch = q.applied[-1].name
2020 patch = q.applied[-1].name
1991 ph = patchheader(q.join(patch))
2021 ph = patchheader(q.join(patch))
1992 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2022 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
1993 setupheaderopts(ui, opts)
2023 setupheaderopts(ui, opts)
1994 ret = q.refresh(repo, pats, msg=message, **opts)
2024 ret = q.refresh(repo, pats, msg=message, **opts)
1995 q.save_dirty()
2025 q.save_dirty()
1996 return ret
2026 return ret
1997
2027
1998 def diff(ui, repo, *pats, **opts):
2028 def diff(ui, repo, *pats, **opts):
1999 """diff of the current patch and subsequent modifications
2029 """diff of the current patch and subsequent modifications
2000
2030
2001 Shows a diff which includes the current patch as well as any
2031 Shows a diff which includes the current patch as well as any
2002 changes which have been made in the working directory since the
2032 changes which have been made in the working directory since the
2003 last refresh (thus showing what the current patch would become
2033 last refresh (thus showing what the current patch would become
2004 after a qrefresh).
2034 after a qrefresh).
2005
2035
2006 Use 'hg diff' if you only want to see the changes made since the
2036 Use 'hg diff' if you only want to see the changes made since the
2007 last qrefresh, or 'hg export qtip' if you want to see changes made
2037 last qrefresh, or 'hg export qtip' if you want to see changes made
2008 by the current patch without including changes made since the
2038 by the current patch without including changes made since the
2009 qrefresh.
2039 qrefresh.
2010 """
2040 """
2011 repo.mq.diff(repo, pats, opts)
2041 repo.mq.diff(repo, pats, opts)
2012 return 0
2042 return 0
2013
2043
2014 def fold(ui, repo, *files, **opts):
2044 def fold(ui, repo, *files, **opts):
2015 """fold the named patches into the current patch
2045 """fold the named patches into the current patch
2016
2046
2017 Patches must not yet be applied. Each patch will be successively
2047 Patches must not yet be applied. Each patch will be successively
2018 applied to the current patch in the order given. If all the
2048 applied to the current patch in the order given. If all the
2019 patches apply successfully, the current patch will be refreshed
2049 patches apply successfully, the current patch will be refreshed
2020 with the new cumulative patch, and the folded patches will be
2050 with the new cumulative patch, and the folded patches will be
2021 deleted. With -k/--keep, the folded patch files will not be
2051 deleted. With -k/--keep, the folded patch files will not be
2022 removed afterwards.
2052 removed afterwards.
2023
2053
2024 The header for each folded patch will be concatenated with the
2054 The header for each folded patch will be concatenated with the
2025 current patch header, separated by a line of '* * *'."""
2055 current patch header, separated by a line of '* * *'."""
2026
2056
2027 q = repo.mq
2057 q = repo.mq
2028
2058
2029 if not files:
2059 if not files:
2030 raise util.Abort(_('qfold requires at least one patch name'))
2060 raise util.Abort(_('qfold requires at least one patch name'))
2031 if not q.check_toppatch(repo):
2061 if not q.check_toppatch(repo):
2032 raise util.Abort(_('No patches applied'))
2062 raise util.Abort(_('No patches applied'))
2033 q.check_localchanges(repo)
2063 q.check_localchanges(repo)
2034
2064
2035 message = cmdutil.logmessage(opts)
2065 message = cmdutil.logmessage(opts)
2036 if opts['edit']:
2066 if opts['edit']:
2037 if message:
2067 if message:
2038 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2068 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2039
2069
2040 parent = q.lookup('qtip')
2070 parent = q.lookup('qtip')
2041 patches = []
2071 patches = []
2042 messages = []
2072 messages = []
2043 for f in files:
2073 for f in files:
2044 p = q.lookup(f)
2074 p = q.lookup(f)
2045 if p in patches or p == parent:
2075 if p in patches or p == parent:
2046 ui.warn(_('Skipping already folded patch %s') % p)
2076 ui.warn(_('Skipping already folded patch %s') % p)
2047 if q.isapplied(p):
2077 if q.isapplied(p):
2048 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2078 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2049 patches.append(p)
2079 patches.append(p)
2050
2080
2051 for p in patches:
2081 for p in patches:
2052 if not message:
2082 if not message:
2053 ph = patchheader(q.join(p))
2083 ph = patchheader(q.join(p))
2054 if ph.message:
2084 if ph.message:
2055 messages.append(ph.message)
2085 messages.append(ph.message)
2056 pf = q.join(p)
2086 pf = q.join(p)
2057 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2087 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2058 if not patchsuccess:
2088 if not patchsuccess:
2059 raise util.Abort(_('Error folding patch %s') % p)
2089 raise util.Abort(_('Error folding patch %s') % p)
2060 patch.updatedir(ui, repo, files)
2090 patch.updatedir(ui, repo, files)
2061
2091
2062 if not message:
2092 if not message:
2063 ph = patchheader(q.join(parent))
2093 ph = patchheader(q.join(parent))
2064 message, user = ph.message, ph.user
2094 message, user = ph.message, ph.user
2065 for msg in messages:
2095 for msg in messages:
2066 message.append('* * *')
2096 message.append('* * *')
2067 message.extend(msg)
2097 message.extend(msg)
2068 message = '\n'.join(message)
2098 message = '\n'.join(message)
2069
2099
2070 if opts['edit']:
2100 if opts['edit']:
2071 message = ui.edit(message, user or ui.username())
2101 message = ui.edit(message, user or ui.username())
2072
2102
2073 diffopts = q.patchopts(q.diffopts(), *patches)
2103 diffopts = q.patchopts(q.diffopts(), *patches)
2074 q.refresh(repo, msg=message, git=diffopts.git)
2104 q.refresh(repo, msg=message, git=diffopts.git)
2075 q.delete(repo, patches, opts)
2105 q.delete(repo, patches, opts)
2076 q.save_dirty()
2106 q.save_dirty()
2077
2107
2078 def goto(ui, repo, patch, **opts):
2108 def goto(ui, repo, patch, **opts):
2079 '''push or pop patches until named patch is at top of stack'''
2109 '''push or pop patches until named patch is at top of stack'''
2080 q = repo.mq
2110 q = repo.mq
2081 patch = q.lookup(patch)
2111 patch = q.lookup(patch)
2082 if q.isapplied(patch):
2112 if q.isapplied(patch):
2083 ret = q.pop(repo, patch, force=opts['force'])
2113 ret = q.pop(repo, patch, force=opts['force'])
2084 else:
2114 else:
2085 ret = q.push(repo, patch, force=opts['force'])
2115 ret = q.push(repo, patch, force=opts['force'])
2086 q.save_dirty()
2116 q.save_dirty()
2087 return ret
2117 return ret
2088
2118
2089 def guard(ui, repo, *args, **opts):
2119 def guard(ui, repo, *args, **opts):
2090 '''set or print guards for a patch
2120 '''set or print guards for a patch
2091
2121
2092 Guards control whether a patch can be pushed. A patch with no
2122 Guards control whether a patch can be pushed. A patch with no
2093 guards is always pushed. A patch with a positive guard ("+foo") is
2123 guards is always pushed. A patch with a positive guard ("+foo") is
2094 pushed only if the qselect command has activated it. A patch with
2124 pushed only if the qselect command has activated it. A patch with
2095 a negative guard ("-foo") is never pushed if the qselect command
2125 a negative guard ("-foo") is never pushed if the qselect command
2096 has activated it.
2126 has activated it.
2097
2127
2098 With no arguments, print the currently active guards.
2128 With no arguments, print the currently active guards.
2099 With arguments, set guards for the named patch.
2129 With arguments, set guards for the named patch.
2100 NOTE: Specifying negative guards now requires '--'.
2130 NOTE: Specifying negative guards now requires '--'.
2101
2131
2102 To set guards on another patch::
2132 To set guards on another patch::
2103
2133
2104 hg qguard -- other.patch +2.6.17 -stable
2134 hg qguard -- other.patch +2.6.17 -stable
2105 '''
2135 '''
2106 def status(idx):
2136 def status(idx):
2107 guards = q.series_guards[idx] or ['unguarded']
2137 guards = q.series_guards[idx] or ['unguarded']
2108 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
2138 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
2109 q = repo.mq
2139 q = repo.mq
2110 patch = None
2140 patch = None
2111 args = list(args)
2141 args = list(args)
2112 if opts['list']:
2142 if opts['list']:
2113 if args or opts['none']:
2143 if args or opts['none']:
2114 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2144 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2115 for i in xrange(len(q.series)):
2145 for i in xrange(len(q.series)):
2116 status(i)
2146 status(i)
2117 return
2147 return
2118 if not args or args[0][0:1] in '-+':
2148 if not args or args[0][0:1] in '-+':
2119 if not q.applied:
2149 if not q.applied:
2120 raise util.Abort(_('no patches applied'))
2150 raise util.Abort(_('no patches applied'))
2121 patch = q.applied[-1].name
2151 patch = q.applied[-1].name
2122 if patch is None and args[0][0:1] not in '-+':
2152 if patch is None and args[0][0:1] not in '-+':
2123 patch = args.pop(0)
2153 patch = args.pop(0)
2124 if patch is None:
2154 if patch is None:
2125 raise util.Abort(_('no patch to work with'))
2155 raise util.Abort(_('no patch to work with'))
2126 if args or opts['none']:
2156 if args or opts['none']:
2127 idx = q.find_series(patch)
2157 idx = q.find_series(patch)
2128 if idx is None:
2158 if idx is None:
2129 raise util.Abort(_('no patch named %s') % patch)
2159 raise util.Abort(_('no patch named %s') % patch)
2130 q.set_guards(idx, args)
2160 q.set_guards(idx, args)
2131 q.save_dirty()
2161 q.save_dirty()
2132 else:
2162 else:
2133 status(q.series.index(q.lookup(patch)))
2163 status(q.series.index(q.lookup(patch)))
2134
2164
2135 def header(ui, repo, patch=None):
2165 def header(ui, repo, patch=None):
2136 """print the header of the topmost or specified patch"""
2166 """print the header of the topmost or specified patch"""
2137 q = repo.mq
2167 q = repo.mq
2138
2168
2139 if patch:
2169 if patch:
2140 patch = q.lookup(patch)
2170 patch = q.lookup(patch)
2141 else:
2171 else:
2142 if not q.applied:
2172 if not q.applied:
2143 ui.write('no patches applied\n')
2173 ui.write('no patches applied\n')
2144 return 1
2174 return 1
2145 patch = q.lookup('qtip')
2175 patch = q.lookup('qtip')
2146 ph = patchheader(repo.mq.join(patch))
2176 ph = patchheader(repo.mq.join(patch))
2147
2177
2148 ui.write('\n'.join(ph.message) + '\n')
2178 ui.write('\n'.join(ph.message) + '\n')
2149
2179
2150 def lastsavename(path):
2180 def lastsavename(path):
2151 (directory, base) = os.path.split(path)
2181 (directory, base) = os.path.split(path)
2152 names = os.listdir(directory)
2182 names = os.listdir(directory)
2153 namere = re.compile("%s.([0-9]+)" % base)
2183 namere = re.compile("%s.([0-9]+)" % base)
2154 maxindex = None
2184 maxindex = None
2155 maxname = None
2185 maxname = None
2156 for f in names:
2186 for f in names:
2157 m = namere.match(f)
2187 m = namere.match(f)
2158 if m:
2188 if m:
2159 index = int(m.group(1))
2189 index = int(m.group(1))
2160 if maxindex is None or index > maxindex:
2190 if maxindex is None or index > maxindex:
2161 maxindex = index
2191 maxindex = index
2162 maxname = f
2192 maxname = f
2163 if maxname:
2193 if maxname:
2164 return (os.path.join(directory, maxname), maxindex)
2194 return (os.path.join(directory, maxname), maxindex)
2165 return (None, None)
2195 return (None, None)
2166
2196
2167 def savename(path):
2197 def savename(path):
2168 (last, index) = lastsavename(path)
2198 (last, index) = lastsavename(path)
2169 if last is None:
2199 if last is None:
2170 index = 0
2200 index = 0
2171 newpath = path + ".%d" % (index + 1)
2201 newpath = path + ".%d" % (index + 1)
2172 return newpath
2202 return newpath
2173
2203
2174 def push(ui, repo, patch=None, **opts):
2204 def push(ui, repo, patch=None, **opts):
2175 """push the next patch onto the stack
2205 """push the next patch onto the stack
2176
2206
2177 When -f/--force is applied, all local changes in patched files
2207 When -f/--force is applied, all local changes in patched files
2178 will be lost.
2208 will be lost.
2179 """
2209 """
2180 q = repo.mq
2210 q = repo.mq
2181 mergeq = None
2211 mergeq = None
2182
2212
2183 if opts['merge']:
2213 if opts['merge']:
2184 if opts['name']:
2214 if opts['name']:
2185 newpath = repo.join(opts['name'])
2215 newpath = repo.join(opts['name'])
2186 else:
2216 else:
2187 newpath, i = lastsavename(q.path)
2217 newpath, i = lastsavename(q.path)
2188 if not newpath:
2218 if not newpath:
2189 ui.warn(_("no saved queues found, please use -n\n"))
2219 ui.warn(_("no saved queues found, please use -n\n"))
2190 return 1
2220 return 1
2191 mergeq = queue(ui, repo.join(""), newpath)
2221 mergeq = queue(ui, repo.join(""), newpath)
2192 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2222 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2193 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2223 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2194 mergeq=mergeq, all=opts.get('all'))
2224 mergeq=mergeq, all=opts.get('all'))
2195 return ret
2225 return ret
2196
2226
2197 def pop(ui, repo, patch=None, **opts):
2227 def pop(ui, repo, patch=None, **opts):
2198 """pop the current patch off the stack
2228 """pop the current patch off the stack
2199
2229
2200 By default, pops off the top of the patch stack. If given a patch
2230 By default, pops off the top of the patch stack. If given a patch
2201 name, keeps popping off patches until the named patch is at the
2231 name, keeps popping off patches until the named patch is at the
2202 top of the stack.
2232 top of the stack.
2203 """
2233 """
2204 localupdate = True
2234 localupdate = True
2205 if opts['name']:
2235 if opts['name']:
2206 q = queue(ui, repo.join(""), repo.join(opts['name']))
2236 q = queue(ui, repo.join(""), repo.join(opts['name']))
2207 ui.warn(_('using patch queue: %s\n') % q.path)
2237 ui.warn(_('using patch queue: %s\n') % q.path)
2208 localupdate = False
2238 localupdate = False
2209 else:
2239 else:
2210 q = repo.mq
2240 q = repo.mq
2211 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2241 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2212 all=opts['all'])
2242 all=opts['all'])
2213 q.save_dirty()
2243 q.save_dirty()
2214 return ret
2244 return ret
2215
2245
2216 def rename(ui, repo, patch, name=None, **opts):
2246 def rename(ui, repo, patch, name=None, **opts):
2217 """rename a patch
2247 """rename a patch
2218
2248
2219 With one argument, renames the current patch to PATCH1.
2249 With one argument, renames the current patch to PATCH1.
2220 With two arguments, renames PATCH1 to PATCH2."""
2250 With two arguments, renames PATCH1 to PATCH2."""
2221
2251
2222 q = repo.mq
2252 q = repo.mq
2223
2253
2224 if not name:
2254 if not name:
2225 name = patch
2255 name = patch
2226 patch = None
2256 patch = None
2227
2257
2228 if patch:
2258 if patch:
2229 patch = q.lookup(patch)
2259 patch = q.lookup(patch)
2230 else:
2260 else:
2231 if not q.applied:
2261 if not q.applied:
2232 ui.write(_('no patches applied\n'))
2262 ui.write(_('no patches applied\n'))
2233 return
2263 return
2234 patch = q.lookup('qtip')
2264 patch = q.lookup('qtip')
2235 absdest = q.join(name)
2265 absdest = q.join(name)
2236 if os.path.isdir(absdest):
2266 if os.path.isdir(absdest):
2237 name = normname(os.path.join(name, os.path.basename(patch)))
2267 name = normname(os.path.join(name, os.path.basename(patch)))
2238 absdest = q.join(name)
2268 absdest = q.join(name)
2239 if os.path.exists(absdest):
2269 if os.path.exists(absdest):
2240 raise util.Abort(_('%s already exists') % absdest)
2270 raise util.Abort(_('%s already exists') % absdest)
2241
2271
2242 if name in q.series:
2272 if name in q.series:
2243 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2273 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2244
2274
2245 if ui.verbose:
2275 if ui.verbose:
2246 ui.write('renaming %s to %s\n' % (patch, name))
2276 ui.write('renaming %s to %s\n' % (patch, name))
2247 i = q.find_series(patch)
2277 i = q.find_series(patch)
2248 guards = q.guard_re.findall(q.full_series[i])
2278 guards = q.guard_re.findall(q.full_series[i])
2249 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2279 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2250 q.parse_series()
2280 q.parse_series()
2251 q.series_dirty = 1
2281 q.series_dirty = 1
2252
2282
2253 info = q.isapplied(patch)
2283 info = q.isapplied(patch)
2254 if info:
2284 if info:
2255 q.applied[info[0]] = statusentry(info[1], name)
2285 q.applied[info[0]] = statusentry(info[1], name)
2256 q.applied_dirty = 1
2286 q.applied_dirty = 1
2257
2287
2258 util.rename(q.join(patch), absdest)
2288 util.rename(q.join(patch), absdest)
2259 r = q.qrepo()
2289 r = q.qrepo()
2260 if r:
2290 if r:
2261 wlock = r.wlock()
2291 wlock = r.wlock()
2262 try:
2292 try:
2263 if r.dirstate[patch] == 'a':
2293 if r.dirstate[patch] == 'a':
2264 r.dirstate.forget(patch)
2294 r.dirstate.forget(patch)
2265 r.dirstate.add(name)
2295 r.dirstate.add(name)
2266 else:
2296 else:
2267 if r.dirstate[name] == 'r':
2297 if r.dirstate[name] == 'r':
2268 r.undelete([name])
2298 r.undelete([name])
2269 r.copy(patch, name)
2299 r.copy(patch, name)
2270 r.remove([patch], False)
2300 r.remove([patch], False)
2271 finally:
2301 finally:
2272 wlock.release()
2302 wlock.release()
2273
2303
2274 q.save_dirty()
2304 q.save_dirty()
2275
2305
2276 def restore(ui, repo, rev, **opts):
2306 def restore(ui, repo, rev, **opts):
2277 """restore the queue state saved by a revision"""
2307 """restore the queue state saved by a revision"""
2278 rev = repo.lookup(rev)
2308 rev = repo.lookup(rev)
2279 q = repo.mq
2309 q = repo.mq
2280 q.restore(repo, rev, delete=opts['delete'],
2310 q.restore(repo, rev, delete=opts['delete'],
2281 qupdate=opts['update'])
2311 qupdate=opts['update'])
2282 q.save_dirty()
2312 q.save_dirty()
2283 return 0
2313 return 0
2284
2314
2285 def save(ui, repo, **opts):
2315 def save(ui, repo, **opts):
2286 """save current queue state"""
2316 """save current queue state"""
2287 q = repo.mq
2317 q = repo.mq
2288 message = cmdutil.logmessage(opts)
2318 message = cmdutil.logmessage(opts)
2289 ret = q.save(repo, msg=message)
2319 ret = q.save(repo, msg=message)
2290 if ret:
2320 if ret:
2291 return ret
2321 return ret
2292 q.save_dirty()
2322 q.save_dirty()
2293 if opts['copy']:
2323 if opts['copy']:
2294 path = q.path
2324 path = q.path
2295 if opts['name']:
2325 if opts['name']:
2296 newpath = os.path.join(q.basepath, opts['name'])
2326 newpath = os.path.join(q.basepath, opts['name'])
2297 if os.path.exists(newpath):
2327 if os.path.exists(newpath):
2298 if not os.path.isdir(newpath):
2328 if not os.path.isdir(newpath):
2299 raise util.Abort(_('destination %s exists and is not '
2329 raise util.Abort(_('destination %s exists and is not '
2300 'a directory') % newpath)
2330 'a directory') % newpath)
2301 if not opts['force']:
2331 if not opts['force']:
2302 raise util.Abort(_('destination %s exists, '
2332 raise util.Abort(_('destination %s exists, '
2303 'use -f to force') % newpath)
2333 'use -f to force') % newpath)
2304 else:
2334 else:
2305 newpath = savename(path)
2335 newpath = savename(path)
2306 ui.warn(_("copy %s to %s\n") % (path, newpath))
2336 ui.warn(_("copy %s to %s\n") % (path, newpath))
2307 util.copyfiles(path, newpath)
2337 util.copyfiles(path, newpath)
2308 if opts['empty']:
2338 if opts['empty']:
2309 try:
2339 try:
2310 os.unlink(q.join(q.status_path))
2340 os.unlink(q.join(q.status_path))
2311 except:
2341 except:
2312 pass
2342 pass
2313 return 0
2343 return 0
2314
2344
2315 def strip(ui, repo, rev, **opts):
2345 def strip(ui, repo, rev, **opts):
2316 """strip a revision and all its descendants from the repository
2346 """strip a revision and all its descendants from the repository
2317
2347
2318 If one of the working directory's parent revisions is stripped, the
2348 If one of the working directory's parent revisions is stripped, the
2319 working directory will be updated to the parent of the stripped
2349 working directory will be updated to the parent of the stripped
2320 revision.
2350 revision.
2321 """
2351 """
2322 backup = 'all'
2352 backup = 'all'
2323 if opts['backup']:
2353 if opts['backup']:
2324 backup = 'strip'
2354 backup = 'strip'
2325 elif opts['nobackup']:
2355 elif opts['nobackup']:
2326 backup = 'none'
2356 backup = 'none'
2327
2357
2328 rev = repo.lookup(rev)
2358 rev = repo.lookup(rev)
2329 p = repo.dirstate.parents()
2359 p = repo.dirstate.parents()
2330 cl = repo.changelog
2360 cl = repo.changelog
2331 update = True
2361 update = True
2332 if p[0] == nullid:
2362 if p[0] == nullid:
2333 update = False
2363 update = False
2334 elif p[1] == nullid and rev != cl.ancestor(p[0], rev):
2364 elif p[1] == nullid and rev != cl.ancestor(p[0], rev):
2335 update = False
2365 update = False
2336 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2366 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2337 update = False
2367 update = False
2338
2368
2339 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2369 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2340 return 0
2370 return 0
2341
2371
2342 def select(ui, repo, *args, **opts):
2372 def select(ui, repo, *args, **opts):
2343 '''set or print guarded patches to push
2373 '''set or print guarded patches to push
2344
2374
2345 Use the qguard command to set or print guards on patch, then use
2375 Use the qguard command to set or print guards on patch, then use
2346 qselect to tell mq which guards to use. A patch will be pushed if
2376 qselect to tell mq which guards to use. A patch will be pushed if
2347 it has no guards or any positive guards match the currently
2377 it has no guards or any positive guards match the currently
2348 selected guard, but will not be pushed if any negative guards
2378 selected guard, but will not be pushed if any negative guards
2349 match the current guard. For example::
2379 match the current guard. For example::
2350
2380
2351 qguard foo.patch -stable (negative guard)
2381 qguard foo.patch -stable (negative guard)
2352 qguard bar.patch +stable (positive guard)
2382 qguard bar.patch +stable (positive guard)
2353 qselect stable
2383 qselect stable
2354
2384
2355 This activates the "stable" guard. mq will skip foo.patch (because
2385 This activates the "stable" guard. mq will skip foo.patch (because
2356 it has a negative match) but push bar.patch (because it has a
2386 it has a negative match) but push bar.patch (because it has a
2357 positive match).
2387 positive match).
2358
2388
2359 With no arguments, prints the currently active guards.
2389 With no arguments, prints the currently active guards.
2360 With one argument, sets the active guard.
2390 With one argument, sets the active guard.
2361
2391
2362 Use -n/--none to deactivate guards (no other arguments needed).
2392 Use -n/--none to deactivate guards (no other arguments needed).
2363 When no guards are active, patches with positive guards are
2393 When no guards are active, patches with positive guards are
2364 skipped and patches with negative guards are pushed.
2394 skipped and patches with negative guards are pushed.
2365
2395
2366 qselect can change the guards on applied patches. It does not pop
2396 qselect can change the guards on applied patches. It does not pop
2367 guarded patches by default. Use --pop to pop back to the last
2397 guarded patches by default. Use --pop to pop back to the last
2368 applied patch that is not guarded. Use --reapply (which implies
2398 applied patch that is not guarded. Use --reapply (which implies
2369 --pop) to push back to the current patch afterwards, but skip
2399 --pop) to push back to the current patch afterwards, but skip
2370 guarded patches.
2400 guarded patches.
2371
2401
2372 Use -s/--series to print a list of all guards in the series file
2402 Use -s/--series to print a list of all guards in the series file
2373 (no other arguments needed). Use -v for more information.'''
2403 (no other arguments needed). Use -v for more information.'''
2374
2404
2375 q = repo.mq
2405 q = repo.mq
2376 guards = q.active()
2406 guards = q.active()
2377 if args or opts['none']:
2407 if args or opts['none']:
2378 old_unapplied = q.unapplied(repo)
2408 old_unapplied = q.unapplied(repo)
2379 old_guarded = [i for i in xrange(len(q.applied)) if
2409 old_guarded = [i for i in xrange(len(q.applied)) if
2380 not q.pushable(i)[0]]
2410 not q.pushable(i)[0]]
2381 q.set_active(args)
2411 q.set_active(args)
2382 q.save_dirty()
2412 q.save_dirty()
2383 if not args:
2413 if not args:
2384 ui.status(_('guards deactivated\n'))
2414 ui.status(_('guards deactivated\n'))
2385 if not opts['pop'] and not opts['reapply']:
2415 if not opts['pop'] and not opts['reapply']:
2386 unapplied = q.unapplied(repo)
2416 unapplied = q.unapplied(repo)
2387 guarded = [i for i in xrange(len(q.applied))
2417 guarded = [i for i in xrange(len(q.applied))
2388 if not q.pushable(i)[0]]
2418 if not q.pushable(i)[0]]
2389 if len(unapplied) != len(old_unapplied):
2419 if len(unapplied) != len(old_unapplied):
2390 ui.status(_('number of unguarded, unapplied patches has '
2420 ui.status(_('number of unguarded, unapplied patches has '
2391 'changed from %d to %d\n') %
2421 'changed from %d to %d\n') %
2392 (len(old_unapplied), len(unapplied)))
2422 (len(old_unapplied), len(unapplied)))
2393 if len(guarded) != len(old_guarded):
2423 if len(guarded) != len(old_guarded):
2394 ui.status(_('number of guarded, applied patches has changed '
2424 ui.status(_('number of guarded, applied patches has changed '
2395 'from %d to %d\n') %
2425 'from %d to %d\n') %
2396 (len(old_guarded), len(guarded)))
2426 (len(old_guarded), len(guarded)))
2397 elif opts['series']:
2427 elif opts['series']:
2398 guards = {}
2428 guards = {}
2399 noguards = 0
2429 noguards = 0
2400 for gs in q.series_guards:
2430 for gs in q.series_guards:
2401 if not gs:
2431 if not gs:
2402 noguards += 1
2432 noguards += 1
2403 for g in gs:
2433 for g in gs:
2404 guards.setdefault(g, 0)
2434 guards.setdefault(g, 0)
2405 guards[g] += 1
2435 guards[g] += 1
2406 if ui.verbose:
2436 if ui.verbose:
2407 guards['NONE'] = noguards
2437 guards['NONE'] = noguards
2408 guards = guards.items()
2438 guards = guards.items()
2409 guards.sort(key=lambda x: x[0][1:])
2439 guards.sort(key=lambda x: x[0][1:])
2410 if guards:
2440 if guards:
2411 ui.note(_('guards in series file:\n'))
2441 ui.note(_('guards in series file:\n'))
2412 for guard, count in guards:
2442 for guard, count in guards:
2413 ui.note('%2d ' % count)
2443 ui.note('%2d ' % count)
2414 ui.write(guard, '\n')
2444 ui.write(guard, '\n')
2415 else:
2445 else:
2416 ui.note(_('no guards in series file\n'))
2446 ui.note(_('no guards in series file\n'))
2417 else:
2447 else:
2418 if guards:
2448 if guards:
2419 ui.note(_('active guards:\n'))
2449 ui.note(_('active guards:\n'))
2420 for g in guards:
2450 for g in guards:
2421 ui.write(g, '\n')
2451 ui.write(g, '\n')
2422 else:
2452 else:
2423 ui.write(_('no active guards\n'))
2453 ui.write(_('no active guards\n'))
2424 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2454 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2425 popped = False
2455 popped = False
2426 if opts['pop'] or opts['reapply']:
2456 if opts['pop'] or opts['reapply']:
2427 for i in xrange(len(q.applied)):
2457 for i in xrange(len(q.applied)):
2428 pushable, reason = q.pushable(i)
2458 pushable, reason = q.pushable(i)
2429 if not pushable:
2459 if not pushable:
2430 ui.status(_('popping guarded patches\n'))
2460 ui.status(_('popping guarded patches\n'))
2431 popped = True
2461 popped = True
2432 if i == 0:
2462 if i == 0:
2433 q.pop(repo, all=True)
2463 q.pop(repo, all=True)
2434 else:
2464 else:
2435 q.pop(repo, i-1)
2465 q.pop(repo, i-1)
2436 break
2466 break
2437 if popped:
2467 if popped:
2438 try:
2468 try:
2439 if reapply:
2469 if reapply:
2440 ui.status(_('reapplying unguarded patches\n'))
2470 ui.status(_('reapplying unguarded patches\n'))
2441 q.push(repo, reapply)
2471 q.push(repo, reapply)
2442 finally:
2472 finally:
2443 q.save_dirty()
2473 q.save_dirty()
2444
2474
2445 def finish(ui, repo, *revrange, **opts):
2475 def finish(ui, repo, *revrange, **opts):
2446 """move applied patches into repository history
2476 """move applied patches into repository history
2447
2477
2448 Finishes the specified revisions (corresponding to applied
2478 Finishes the specified revisions (corresponding to applied
2449 patches) by moving them out of mq control into regular repository
2479 patches) by moving them out of mq control into regular repository
2450 history.
2480 history.
2451
2481
2452 Accepts a revision range or the -a/--applied option. If --applied
2482 Accepts a revision range or the -a/--applied option. If --applied
2453 is specified, all applied mq revisions are removed from mq
2483 is specified, all applied mq revisions are removed from mq
2454 control. Otherwise, the given revisions must be at the base of the
2484 control. Otherwise, the given revisions must be at the base of the
2455 stack of applied patches.
2485 stack of applied patches.
2456
2486
2457 This can be especially useful if your changes have been applied to
2487 This can be especially useful if your changes have been applied to
2458 an upstream repository, or if you are about to push your changes
2488 an upstream repository, or if you are about to push your changes
2459 to upstream.
2489 to upstream.
2460 """
2490 """
2461 if not opts['applied'] and not revrange:
2491 if not opts['applied'] and not revrange:
2462 raise util.Abort(_('no revisions specified'))
2492 raise util.Abort(_('no revisions specified'))
2463 elif opts['applied']:
2493 elif opts['applied']:
2464 revrange = ('qbase:qtip',) + revrange
2494 revrange = ('qbase:qtip',) + revrange
2465
2495
2466 q = repo.mq
2496 q = repo.mq
2467 if not q.applied:
2497 if not q.applied:
2468 ui.status(_('no patches applied\n'))
2498 ui.status(_('no patches applied\n'))
2469 return 0
2499 return 0
2470
2500
2471 revs = cmdutil.revrange(repo, revrange)
2501 revs = cmdutil.revrange(repo, revrange)
2472 q.finish(repo, revs)
2502 q.finish(repo, revs)
2473 q.save_dirty()
2503 q.save_dirty()
2474 return 0
2504 return 0
2475
2505
2476 def reposetup(ui, repo):
2506 def reposetup(ui, repo):
2477 class mqrepo(repo.__class__):
2507 class mqrepo(repo.__class__):
2478 @util.propertycache
2508 @util.propertycache
2479 def mq(self):
2509 def mq(self):
2480 return queue(self.ui, self.join(""))
2510 return queue(self.ui, self.join(""))
2481
2511
2482 def abort_if_wdir_patched(self, errmsg, force=False):
2512 def abort_if_wdir_patched(self, errmsg, force=False):
2483 if self.mq.applied and not force:
2513 if self.mq.applied and not force:
2484 parent = hex(self.dirstate.parents()[0])
2514 parent = hex(self.dirstate.parents()[0])
2485 if parent in [s.rev for s in self.mq.applied]:
2515 if parent in [s.rev for s in self.mq.applied]:
2486 raise util.Abort(errmsg)
2516 raise util.Abort(errmsg)
2487
2517
2488 def commit(self, text="", user=None, date=None, match=None,
2518 def commit(self, text="", user=None, date=None, match=None,
2489 force=False, editor=False, extra={}):
2519 force=False, editor=False, extra={}):
2490 self.abort_if_wdir_patched(
2520 self.abort_if_wdir_patched(
2491 _('cannot commit over an applied mq patch'),
2521 _('cannot commit over an applied mq patch'),
2492 force)
2522 force)
2493
2523
2494 return super(mqrepo, self).commit(text, user, date, match, force,
2524 return super(mqrepo, self).commit(text, user, date, match, force,
2495 editor, extra)
2525 editor, extra)
2496
2526
2497 def push(self, remote, force=False, revs=None):
2527 def push(self, remote, force=False, revs=None):
2498 if self.mq.applied and not force and not revs:
2528 if self.mq.applied and not force and not revs:
2499 raise util.Abort(_('source has mq patches applied'))
2529 raise util.Abort(_('source has mq patches applied'))
2500 return super(mqrepo, self).push(remote, force, revs)
2530 return super(mqrepo, self).push(remote, force, revs)
2501
2531
2502 def _findtags(self):
2532 def _findtags(self):
2503 '''augment tags from base class with patch tags'''
2533 '''augment tags from base class with patch tags'''
2504 result = super(mqrepo, self)._findtags()
2534 result = super(mqrepo, self)._findtags()
2505
2535
2506 q = self.mq
2536 q = self.mq
2507 if not q.applied:
2537 if not q.applied:
2508 return result
2538 return result
2509
2539
2510 mqtags = [(bin(patch.rev), patch.name) for patch in q.applied]
2540 mqtags = [(bin(patch.rev), patch.name) for patch in q.applied]
2511
2541
2512 if mqtags[-1][0] not in self.changelog.nodemap:
2542 if mqtags[-1][0] not in self.changelog.nodemap:
2513 self.ui.warn(_('mq status file refers to unknown node %s\n')
2543 self.ui.warn(_('mq status file refers to unknown node %s\n')
2514 % short(mqtags[-1][0]))
2544 % short(mqtags[-1][0]))
2515 return result
2545 return result
2516
2546
2517 mqtags.append((mqtags[-1][0], 'qtip'))
2547 mqtags.append((mqtags[-1][0], 'qtip'))
2518 mqtags.append((mqtags[0][0], 'qbase'))
2548 mqtags.append((mqtags[0][0], 'qbase'))
2519 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2549 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2520 tags = result[0]
2550 tags = result[0]
2521 for patch in mqtags:
2551 for patch in mqtags:
2522 if patch[1] in tags:
2552 if patch[1] in tags:
2523 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2553 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2524 % patch[1])
2554 % patch[1])
2525 else:
2555 else:
2526 tags[patch[1]] = patch[0]
2556 tags[patch[1]] = patch[0]
2527
2557
2528 return result
2558 return result
2529
2559
2530 def _branchtags(self, partial, lrev):
2560 def _branchtags(self, partial, lrev):
2531 q = self.mq
2561 q = self.mq
2532 if not q.applied:
2562 if not q.applied:
2533 return super(mqrepo, self)._branchtags(partial, lrev)
2563 return super(mqrepo, self)._branchtags(partial, lrev)
2534
2564
2535 cl = self.changelog
2565 cl = self.changelog
2536 qbasenode = bin(q.applied[0].rev)
2566 qbasenode = bin(q.applied[0].rev)
2537 if qbasenode not in cl.nodemap:
2567 if qbasenode not in cl.nodemap:
2538 self.ui.warn(_('mq status file refers to unknown node %s\n')
2568 self.ui.warn(_('mq status file refers to unknown node %s\n')
2539 % short(qbasenode))
2569 % short(qbasenode))
2540 return super(mqrepo, self)._branchtags(partial, lrev)
2570 return super(mqrepo, self)._branchtags(partial, lrev)
2541
2571
2542 qbase = cl.rev(qbasenode)
2572 qbase = cl.rev(qbasenode)
2543 start = lrev + 1
2573 start = lrev + 1
2544 if start < qbase:
2574 if start < qbase:
2545 # update the cache (excluding the patches) and save it
2575 # update the cache (excluding the patches) and save it
2546 self._updatebranchcache(partial, lrev+1, qbase)
2576 self._updatebranchcache(partial, lrev+1, qbase)
2547 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2577 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2548 start = qbase
2578 start = qbase
2549 # if start = qbase, the cache is as updated as it should be.
2579 # if start = qbase, the cache is as updated as it should be.
2550 # if start > qbase, the cache includes (part of) the patches.
2580 # if start > qbase, the cache includes (part of) the patches.
2551 # we might as well use it, but we won't save it.
2581 # we might as well use it, but we won't save it.
2552
2582
2553 # update the cache up to the tip
2583 # update the cache up to the tip
2554 self._updatebranchcache(partial, start, len(cl))
2584 self._updatebranchcache(partial, start, len(cl))
2555
2585
2556 return partial
2586 return partial
2557
2587
2558 if repo.local():
2588 if repo.local():
2559 repo.__class__ = mqrepo
2589 repo.__class__ = mqrepo
2560
2590
2561 def mqimport(orig, ui, repo, *args, **kwargs):
2591 def mqimport(orig, ui, repo, *args, **kwargs):
2562 if hasattr(repo, 'abort_if_wdir_patched') and not kwargs.get('no_commit', False):
2592 if hasattr(repo, 'abort_if_wdir_patched') and not kwargs.get('no_commit', False):
2563 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2593 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2564 kwargs.get('force'))
2594 kwargs.get('force'))
2565 return orig(ui, repo, *args, **kwargs)
2595 return orig(ui, repo, *args, **kwargs)
2566
2596
2567 def uisetup(ui):
2597 def uisetup(ui):
2568 extensions.wrapcommand(commands.table, 'import', mqimport)
2598 extensions.wrapcommand(commands.table, 'import', mqimport)
2569
2599
2570 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2600 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2571
2601
2572 cmdtable = {
2602 cmdtable = {
2573 "qapplied":
2603 "qapplied":
2574 (applied,
2604 (applied,
2575 [('1', 'last', None, _('show only the last patch'))] + seriesopts,
2605 [('1', 'last', None, _('show only the last patch'))] + seriesopts,
2576 _('hg qapplied [-1] [-s] [PATCH]')),
2606 _('hg qapplied [-1] [-s] [PATCH]')),
2577 "qclone":
2607 "qclone":
2578 (clone,
2608 (clone,
2579 [('', 'pull', None, _('use pull protocol to copy metadata')),
2609 [('', 'pull', None, _('use pull protocol to copy metadata')),
2580 ('U', 'noupdate', None, _('do not update the new working directories')),
2610 ('U', 'noupdate', None, _('do not update the new working directories')),
2581 ('', 'uncompressed', None,
2611 ('', 'uncompressed', None,
2582 _('use uncompressed transfer (fast over LAN)')),
2612 _('use uncompressed transfer (fast over LAN)')),
2583 ('p', 'patches', '', _('location of source patch repository')),
2613 ('p', 'patches', '', _('location of source patch repository')),
2584 ] + commands.remoteopts,
2614 ] + commands.remoteopts,
2585 _('hg qclone [OPTION]... SOURCE [DEST]')),
2615 _('hg qclone [OPTION]... SOURCE [DEST]')),
2586 "qcommit|qci":
2616 "qcommit|qci":
2587 (commit,
2617 (commit,
2588 commands.table["^commit|ci"][1],
2618 commands.table["^commit|ci"][1],
2589 _('hg qcommit [OPTION]... [FILE]...')),
2619 _('hg qcommit [OPTION]... [FILE]...')),
2590 "^qdiff":
2620 "^qdiff":
2591 (diff,
2621 (diff,
2592 commands.diffopts + commands.diffopts2 + commands.walkopts,
2622 commands.diffopts + commands.diffopts2 + commands.walkopts,
2593 _('hg qdiff [OPTION]... [FILE]...')),
2623 _('hg qdiff [OPTION]... [FILE]...')),
2594 "qdelete|qremove|qrm":
2624 "qdelete|qremove|qrm":
2595 (delete,
2625 (delete,
2596 [('k', 'keep', None, _('keep patch file')),
2626 [('k', 'keep', None, _('keep patch file')),
2597 ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'))],
2627 ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'))],
2598 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2628 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2599 'qfold':
2629 'qfold':
2600 (fold,
2630 (fold,
2601 [('e', 'edit', None, _('edit patch header')),
2631 [('e', 'edit', None, _('edit patch header')),
2602 ('k', 'keep', None, _('keep folded patch files')),
2632 ('k', 'keep', None, _('keep folded patch files')),
2603 ] + commands.commitopts,
2633 ] + commands.commitopts,
2604 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2634 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2605 'qgoto':
2635 'qgoto':
2606 (goto,
2636 (goto,
2607 [('f', 'force', None, _('overwrite any local changes'))],
2637 [('f', 'force', None, _('overwrite any local changes'))],
2608 _('hg qgoto [OPTION]... PATCH')),
2638 _('hg qgoto [OPTION]... PATCH')),
2609 'qguard':
2639 'qguard':
2610 (guard,
2640 (guard,
2611 [('l', 'list', None, _('list all patches and guards')),
2641 [('l', 'list', None, _('list all patches and guards')),
2612 ('n', 'none', None, _('drop all guards'))],
2642 ('n', 'none', None, _('drop all guards'))],
2613 _('hg qguard [-l] [-n] -- [PATCH] [+GUARD]... [-GUARD]...')),
2643 _('hg qguard [-l] [-n] -- [PATCH] [+GUARD]... [-GUARD]...')),
2614 'qheader': (header, [], _('hg qheader [PATCH]')),
2644 'qheader': (header, [], _('hg qheader [PATCH]')),
2615 "^qimport":
2645 "^qimport":
2616 (qimport,
2646 (qimport,
2617 [('e', 'existing', None, _('import file in patch directory')),
2647 [('e', 'existing', None, _('import file in patch directory')),
2618 ('n', 'name', '', _('name of patch file')),
2648 ('n', 'name', '', _('name of patch file')),
2619 ('f', 'force', None, _('overwrite existing files')),
2649 ('f', 'force', None, _('overwrite existing files')),
2620 ('r', 'rev', [], _('place existing revisions under mq control')),
2650 ('r', 'rev', [], _('place existing revisions under mq control')),
2621 ('g', 'git', None, _('use git extended diff format')),
2651 ('g', 'git', None, _('use git extended diff format')),
2622 ('P', 'push', None, _('qpush after importing'))],
2652 ('P', 'push', None, _('qpush after importing'))],
2623 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')),
2653 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')),
2624 "^qinit":
2654 "^qinit":
2625 (init,
2655 (init,
2626 [('c', 'create-repo', None, _('create queue repository'))],
2656 [('c', 'create-repo', None, _('create queue repository'))],
2627 _('hg qinit [-c]')),
2657 _('hg qinit [-c]')),
2628 "qnew":
2658 "qnew":
2629 (new,
2659 (new,
2630 [('e', 'edit', None, _('edit commit message')),
2660 [('e', 'edit', None, _('edit commit message')),
2631 ('f', 'force', None, _('import uncommitted changes into patch')),
2661 ('f', 'force', None, _('import uncommitted changes into patch')),
2632 ('g', 'git', None, _('use git extended diff format')),
2662 ('g', 'git', None, _('use git extended diff format')),
2633 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2663 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2634 ('u', 'user', '', _('add "From: <given user>" to patch')),
2664 ('u', 'user', '', _('add "From: <given user>" to patch')),
2635 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2665 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2636 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2666 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2637 ] + commands.walkopts + commands.commitopts,
2667 ] + commands.walkopts + commands.commitopts,
2638 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2668 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2639 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2669 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2640 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2670 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2641 "^qpop":
2671 "^qpop":
2642 (pop,
2672 (pop,
2643 [('a', 'all', None, _('pop all patches')),
2673 [('a', 'all', None, _('pop all patches')),
2644 ('n', 'name', '', _('queue name to pop')),
2674 ('n', 'name', '', _('queue name to pop')),
2645 ('f', 'force', None, _('forget any local changes to patched files'))],
2675 ('f', 'force', None, _('forget any local changes to patched files'))],
2646 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2676 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2647 "^qpush":
2677 "^qpush":
2648 (push,
2678 (push,
2649 [('f', 'force', None, _('apply if the patch has rejects')),
2679 [('f', 'force', None, _('apply if the patch has rejects')),
2650 ('l', 'list', None, _('list patch name in commit text')),
2680 ('l', 'list', None, _('list patch name in commit text')),
2651 ('a', 'all', None, _('apply all patches')),
2681 ('a', 'all', None, _('apply all patches')),
2652 ('m', 'merge', None, _('merge from another queue')),
2682 ('m', 'merge', None, _('merge from another queue')),
2653 ('n', 'name', '', _('merge queue name'))],
2683 ('n', 'name', '', _('merge queue name'))],
2654 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2684 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2655 "^qrefresh":
2685 "^qrefresh":
2656 (refresh,
2686 (refresh,
2657 [('e', 'edit', None, _('edit commit message')),
2687 [('e', 'edit', None, _('edit commit message')),
2658 ('g', 'git', None, _('use git extended diff format')),
2688 ('g', 'git', None, _('use git extended diff format')),
2659 ('s', 'short', None, _('refresh only files already in the patch and specified files')),
2689 ('s', 'short', None, _('refresh only files already in the patch and specified files')),
2660 ('U', 'currentuser', None, _('add/update author field in patch with current user')),
2690 ('U', 'currentuser', None, _('add/update author field in patch with current user')),
2661 ('u', 'user', '', _('add/update author field in patch with given user')),
2691 ('u', 'user', '', _('add/update author field in patch with given user')),
2662 ('D', 'currentdate', None, _('add/update date field in patch with current date')),
2692 ('D', 'currentdate', None, _('add/update date field in patch with current date')),
2663 ('d', 'date', '', _('add/update date field in patch with given date'))
2693 ('d', 'date', '', _('add/update date field in patch with given date'))
2664 ] + commands.walkopts + commands.commitopts,
2694 ] + commands.walkopts + commands.commitopts,
2665 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2695 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2666 'qrename|qmv':
2696 'qrename|qmv':
2667 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2697 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2668 "qrestore":
2698 "qrestore":
2669 (restore,
2699 (restore,
2670 [('d', 'delete', None, _('delete save entry')),
2700 [('d', 'delete', None, _('delete save entry')),
2671 ('u', 'update', None, _('update queue working directory'))],
2701 ('u', 'update', None, _('update queue working directory'))],
2672 _('hg qrestore [-d] [-u] REV')),
2702 _('hg qrestore [-d] [-u] REV')),
2673 "qsave":
2703 "qsave":
2674 (save,
2704 (save,
2675 [('c', 'copy', None, _('copy patch directory')),
2705 [('c', 'copy', None, _('copy patch directory')),
2676 ('n', 'name', '', _('copy directory name')),
2706 ('n', 'name', '', _('copy directory name')),
2677 ('e', 'empty', None, _('clear queue status file')),
2707 ('e', 'empty', None, _('clear queue status file')),
2678 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2708 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2679 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2709 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2680 "qselect":
2710 "qselect":
2681 (select,
2711 (select,
2682 [('n', 'none', None, _('disable all guards')),
2712 [('n', 'none', None, _('disable all guards')),
2683 ('s', 'series', None, _('list all guards in series file')),
2713 ('s', 'series', None, _('list all guards in series file')),
2684 ('', 'pop', None, _('pop to before first guarded applied patch')),
2714 ('', 'pop', None, _('pop to before first guarded applied patch')),
2685 ('', 'reapply', None, _('pop, then reapply patches'))],
2715 ('', 'reapply', None, _('pop, then reapply patches'))],
2686 _('hg qselect [OPTION]... [GUARD]...')),
2716 _('hg qselect [OPTION]... [GUARD]...')),
2687 "qseries":
2717 "qseries":
2688 (series,
2718 (series,
2689 [('m', 'missing', None, _('print patches not in series')),
2719 [('m', 'missing', None, _('print patches not in series')),
2690 ] + seriesopts,
2720 ] + seriesopts,
2691 _('hg qseries [-ms]')),
2721 _('hg qseries [-ms]')),
2692 "^strip":
2722 "^strip":
2693 (strip,
2723 (strip,
2694 [('f', 'force', None, _('force removal with local changes')),
2724 [('f', 'force', None, _('force removal with local changes')),
2695 ('b', 'backup', None, _('bundle unrelated changesets')),
2725 ('b', 'backup', None, _('bundle unrelated changesets')),
2696 ('n', 'nobackup', None, _('no backups'))],
2726 ('n', 'nobackup', None, _('no backups'))],
2697 _('hg strip [-f] [-b] [-n] REV')),
2727 _('hg strip [-f] [-b] [-n] REV')),
2698 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2728 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2699 "qunapplied":
2729 "qunapplied":
2700 (unapplied,
2730 (unapplied,
2701 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2731 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2702 _('hg qunapplied [-1] [-s] [PATCH]')),
2732 _('hg qunapplied [-1] [-s] [PATCH]')),
2703 "qfinish":
2733 "qfinish":
2704 (finish,
2734 (finish,
2705 [('a', 'applied', None, _('finish all applied changesets'))],
2735 [('a', 'applied', None, _('finish all applied changesets'))],
2706 _('hg qfinish [-a] [REV]...')),
2736 _('hg qfinish [-a] [REV]...')),
2707 }
2737 }
@@ -1,64 +1,66
1 #!/bin/sh
1 #!/bin/sh
2
2
3 # Test interactions between mq and patch.eol
3 # Test interactions between mq and patch.eol
4
4
5 echo "[extensions]" >> $HGRCPATH
5 echo "[extensions]" >> $HGRCPATH
6 echo "mq=" >> $HGRCPATH
6 echo "mq=" >> $HGRCPATH
7 echo "[diff]" >> $HGRCPATH
8 echo "nodates=1" >> $HGRCPATH
7
9
8 cat > makepatch.py <<EOF
10 cat > makepatch.py <<EOF
9 f = file('eol.diff', 'wb')
11 f = file('eol.diff', 'wb')
10 w = f.write
12 w = f.write
11 w('test message\n')
13 w('test message\n')
12 w('diff --git a/a b/a\n')
14 w('diff --git a/a b/a\n')
13 w('--- a/a\n')
15 w('--- a/a\n')
14 w('+++ b/a\n')
16 w('+++ b/a\n')
15 w('@@ -1,5 +1,5 @@\n')
17 w('@@ -1,5 +1,5 @@\n')
16 w(' a\n')
18 w(' a\n')
17 w('-b\r\n')
19 w('-b\r\n')
18 w('+y\r\n')
20 w('+y\r\n')
19 w(' c\r\n')
21 w(' c\r\n')
20 w(' d\n')
22 w(' d\n')
21 w('-e\n')
23 w('-e\n')
22 w('\ No newline at end of file\n')
24 w('\ No newline at end of file\n')
23 w('+z\r\n')
25 w('+z\r\n')
24 w('\ No newline at end of file\r\n')
26 w('\ No newline at end of file\r\n')
25 EOF
27 EOF
26
28
27 cat > cateol.py <<EOF
29 cat > cateol.py <<EOF
28 import sys
30 import sys
29 for line in file(sys.argv[1], 'rb'):
31 for line in file(sys.argv[1], 'rb'):
30 line = line.replace('\r', '<CR>')
32 line = line.replace('\r', '<CR>')
31 line = line.replace('\n', '<LF>')
33 line = line.replace('\n', '<LF>')
32 print line
34 print line
33 EOF
35 EOF
34
36
35 hg init repo
37 hg init repo
36 cd repo
38 cd repo
37 echo '\.diff' > .hgignore
39 echo '\.diff' > .hgignore
38 echo '\.rej' >> .hgignore
40 echo '\.rej' >> .hgignore
39
41
40 # Test different --eol values
42 # Test different --eol values
41 python -c 'file("a", "wb").write("a\nb\nc\nd\ne")'
43 python -c 'file("a", "wb").write("a\nb\nc\nd\ne")'
42 hg ci -Am adda
44 hg ci -Am adda
43 python ../makepatch.py
45 python ../makepatch.py
44 hg qimport eol.diff
46 hg qimport eol.diff
45 echo % should fail in strict mode
47 echo % should fail in strict mode
46 hg qpush
48 hg qpush
47 hg qpop
49 hg qpop
48 echo % invalid eol
50 echo % invalid eol
49 hg --config patch.eol='LFCR' qpush
51 hg --config patch.eol='LFCR' qpush
50 hg qpop
52 hg qpop
51 echo % force LF
53 echo % force LF
52 hg --config patch.eol='CRLF' qpush
54 hg --config patch.eol='CRLF' qpush
53 hg qrefresh
55 hg qrefresh
54 python ../cateol.py .hg/patches/eol.diff
56 python ../cateol.py .hg/patches/eol.diff
55 python ../cateol.py a
57 python ../cateol.py a
56 hg qpop
58 hg qpop
57 echo % push again forcing LF and compare revisions
59 echo % push again forcing LF and compare revisions
58 hg --config patch.eol='CRLF' qpush
60 hg --config patch.eol='CRLF' qpush
59 python ../cateol.py a
61 python ../cateol.py a
60 hg qpop
62 hg qpop
61 echo % push again without LF and compare revisions
63 echo % push again without LF and compare revisions
62 hg qpush
64 hg qpush
63 python ../cateol.py a
65 python ../cateol.py a
64 hg qpop
66 hg qpop
@@ -1,68 +1,68
1 adding .hgignore
1 adding .hgignore
2 adding a
2 adding a
3 adding eol.diff to series file
3 adding eol.diff to series file
4 % should fail in strict mode
4 % should fail in strict mode
5 applying eol.diff
5 applying eol.diff
6 patching file a
6 patching file a
7 Hunk #1 FAILED at 0
7 Hunk #1 FAILED at 0
8 1 out of 1 hunks FAILED -- saving rejects to file a.rej
8 1 out of 1 hunks FAILED -- saving rejects to file a.rej
9 patch failed, unable to continue (try -v)
9 patch failed, unable to continue (try -v)
10 patch failed, rejects left in working dir
10 patch failed, rejects left in working dir
11 errors during apply, please fix and refresh eol.diff
11 errors during apply, please fix and refresh eol.diff
12 popping eol.diff
12 popping eol.diff
13 patch queue now empty
13 patch queue now empty
14 % invalid eol
14 % invalid eol
15 applying eol.diff
15 applying eol.diff
16 patch failed, unable to continue (try -v)
16 patch failed, unable to continue (try -v)
17 patch failed, rejects left in working dir
17 patch failed, rejects left in working dir
18 errors during apply, please fix and refresh eol.diff
18 errors during apply, please fix and refresh eol.diff
19 popping eol.diff
19 popping eol.diff
20 patch queue now empty
20 patch queue now empty
21 % force LF
21 % force LF
22 applying eol.diff
22 applying eol.diff
23 now at: eol.diff
23 now at: eol.diff
24 test message<LF>
24 test message<LF>
25 <LF>
25 <LF>
26 diff --git a/a b/a<LF>
26 diff -r 0d0bf99a8b7a a<LF>
27 --- a/a<LF>
27 --- a/a<LF>
28 +++ b/a<LF>
28 +++ b/a<LF>
29 @@ -1,5 +1,5 @@<LF>
29 @@ -1,5 +1,5 @@<LF>
30 -a<LF>
30 -a<LF>
31 -b<LF>
31 -b<LF>
32 -c<LF>
32 -c<LF>
33 -d<LF>
33 -d<LF>
34 -e<LF>
34 -e<LF>
35 \ No newline at end of file<LF>
35 \ No newline at end of file<LF>
36 +a<CR><LF>
36 +a<CR><LF>
37 +y<CR><LF>
37 +y<CR><LF>
38 +c<CR><LF>
38 +c<CR><LF>
39 +d<CR><LF>
39 +d<CR><LF>
40 +z<LF>
40 +z<LF>
41 \ No newline at end of file<LF>
41 \ No newline at end of file<LF>
42 a<CR><LF>
42 a<CR><LF>
43 y<CR><LF>
43 y<CR><LF>
44 c<CR><LF>
44 c<CR><LF>
45 d<CR><LF>
45 d<CR><LF>
46 z
46 z
47 popping eol.diff
47 popping eol.diff
48 patch queue now empty
48 patch queue now empty
49 % push again forcing LF and compare revisions
49 % push again forcing LF and compare revisions
50 applying eol.diff
50 applying eol.diff
51 now at: eol.diff
51 now at: eol.diff
52 a<CR><LF>
52 a<CR><LF>
53 y<CR><LF>
53 y<CR><LF>
54 c<CR><LF>
54 c<CR><LF>
55 d<CR><LF>
55 d<CR><LF>
56 z
56 z
57 popping eol.diff
57 popping eol.diff
58 patch queue now empty
58 patch queue now empty
59 % push again without LF and compare revisions
59 % push again without LF and compare revisions
60 applying eol.diff
60 applying eol.diff
61 now at: eol.diff
61 now at: eol.diff
62 a<CR><LF>
62 a<CR><LF>
63 y<CR><LF>
63 y<CR><LF>
64 c<CR><LF>
64 c<CR><LF>
65 d<CR><LF>
65 d<CR><LF>
66 z
66 z
67 popping eol.diff
67 popping eol.diff
68 patch queue now empty
68 patch queue now empty
@@ -1,82 +1,84
1 #!/bin/sh
1 #!/bin/sh
2
2
3 # Test issue 529 - mq aborts when merging patch deleting files
3 # Test issue 529 - mq aborts when merging patch deleting files
4
4
5 rewrite_path()
5 rewrite_path()
6 {
6 {
7 sed -e 's:\\:/:g' -e 's:[^ ]*/t/::g'
7 sed -e 's:\\:/:g' -e 's:[^ ]*/t/::g'
8 }
8 }
9
9
10 checkundo()
10 checkundo()
11 {
11 {
12 if [ -f .hg/store/undo ]; then
12 if [ -f .hg/store/undo ]; then
13 echo ".hg/store/undo still exists after $1"
13 echo ".hg/store/undo still exists after $1"
14 fi
14 fi
15 }
15 }
16
16
17 echo "[extensions]" >> $HGRCPATH
17 echo "[extensions]" >> $HGRCPATH
18 echo "mq =" >> $HGRCPATH
18 echo "mq =" >> $HGRCPATH
19 echo "[mq]" >> $HGRCPATH
20 echo "git = keep" >> $HGRCPATH
19
21
20 # Commit two dummy files in "init" changeset
22 # Commit two dummy files in "init" changeset
21 hg init t
23 hg init t
22 cd t
24 cd t
23 echo a > a
25 echo a > a
24 echo b > b
26 echo b > b
25 hg ci -Am init
27 hg ci -Am init
26 hg tag -l init
28 hg tag -l init
27
29
28 # Create a patch removing a
30 # Create a patch removing a
29 hg qnew rm_a
31 hg qnew rm_a
30 hg rm a
32 hg rm a
31 hg qrefresh -m "rm a"
33 hg qrefresh -m "rm a"
32
34
33 # Save the patch queue so we can merge it later
35 # Save the patch queue so we can merge it later
34 hg qsave -c -e 2>&1 | rewrite_path
36 hg qsave -c -e 2>&1 | rewrite_path
35 checkundo qsave
37 checkundo qsave
36
38
37 # Update b and commit in an "update" changeset
39 # Update b and commit in an "update" changeset
38 hg up -C init
40 hg up -C init
39 echo b >> b
41 echo b >> b
40 hg st
42 hg st
41 hg ci -m update
43 hg ci -m update
42
44
43 # Here, qpush used to abort with :
45 # Here, qpush used to abort with :
44 # The system cannot find the file specified => a
46 # The system cannot find the file specified => a
45 hg manifest
47 hg manifest
46 hg qpush -a -m 2>&1 | rewrite_path
48 hg qpush -a -m 2>&1 | rewrite_path
47 checkundo 'qpush -m'
49 checkundo 'qpush -m'
48 hg manifest
50 hg manifest
49
51
50 # ensure status is correct after merge
52 # ensure status is correct after merge
51 hg qpop -a
53 hg qpop -a
52 cd ..
54 cd ..
53
55
54 # Classic MQ merge sequence *with an explicit named queue*
56 # Classic MQ merge sequence *with an explicit named queue*
55 echo
57 echo
56 echo % init t2
58 echo % init t2
57 hg init t2
59 hg init t2
58 cd t2
60 cd t2
59 echo '[diff]' > .hg/hgrc
61 echo '[diff]' > .hg/hgrc
60 echo 'nodates = 1' >> .hg/hgrc
62 echo 'nodates = 1' >> .hg/hgrc
61 echo a > a
63 echo a > a
62 hg ci -Am init
64 hg ci -Am init
63 echo b > a
65 echo b > a
64 hg ci -m changea
66 hg ci -m changea
65 hg up -C 0
67 hg up -C 0
66 hg cp a aa
68 hg cp a aa
67 echo c >> a
69 echo c >> a
68 hg qnew --git -f -e patcha
70 hg qnew --git -f -e patcha
69 echo d >> a
71 echo d >> a
70 hg qnew -d '0 0' -f -e patcha2
72 hg qnew -d '0 0' -f -e patcha2
71 echo % create the reference queue
73 echo % create the reference queue
72 hg qsave -c -e -n refqueue 2> /dev/null
74 hg qsave -c -e -n refqueue 2> /dev/null
73 hg up -C 1
75 hg up -C 1
74 echo % merge
76 echo % merge
75 HGMERGE=internal:other hg qpush -a -m -n refqueue 2>&1 | \
77 HGMERGE=internal:other hg qpush -a -m -n refqueue 2>&1 | \
76 sed 's/merging with queue at.*refqueue/merging with queue at refqueue/'
78 sed 's/merging with queue at.*refqueue/merging with queue at refqueue/'
77 echo % check patcha is still a git patch
79 echo % check patcha is still a git patch
78 cat .hg/patches/patcha
80 cat .hg/patches/patcha
79 echo % check patcha2 is still a regular patch
81 echo % check patcha2 is still a regular patch
80 grep git .hg/patches/patcha2 && echo 'git patch found!'
82 grep git .hg/patches/patcha2 && echo 'git patch found!'
81 cd ..
83 cd ..
82
84
@@ -1,59 +1,61
1 #!/bin/sh
1 #!/bin/sh
2
2
3 echo "[extensions]" >> $HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "mq=" >> $HGRCPATH
4 echo "mq=" >> $HGRCPATH
5 echo "[mq]" >> $HGRCPATH
6 echo "git=keep" >> $HGRCPATH
5
7
6 filterdiff()
8 filterdiff()
7 {
9 {
8 grep -v diff | \
10 grep -v diff | \
9 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
11 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
10 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
12 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
11 }
13 }
12
14
13 echo '% init'
15 echo '% init'
14 hg init repo
16 hg init repo
15 cd repo
17 cd repo
16 echo a > a
18 echo a > a
17 hg ci -Am adda
19 hg ci -Am adda
18 echo a >> a
20 echo a >> a
19 hg qnew -f p1
21 hg qnew -f p1
20 echo b >> a
22 echo b >> a
21 hg qnew -f p2
23 hg qnew -f p2
22 echo c >> a
24 echo c >> a
23 hg qnew -f p3
25 hg qnew -f p3
24 echo '% fold in the middle of the queue'
26 echo '% fold in the middle of the queue'
25 hg qpop p1
27 hg qpop p1
26 hg qdiff | filterdiff
28 hg qdiff | filterdiff
27 hg qfold p2
29 hg qfold p2
28 grep git .hg/patches/p1 && echo 'git patch found!'
30 grep git .hg/patches/p1 && echo 'git patch found!'
29 hg qser
31 hg qser
30 hg qdiff | filterdiff
32 hg qdiff | filterdiff
31 echo '% fold with local changes'
33 echo '% fold with local changes'
32 echo d >> a
34 echo d >> a
33 hg qfold p3
35 hg qfold p3
34 hg diff -c . | filterdiff
36 hg diff -c . | filterdiff
35 hg revert -a --no-backup
37 hg revert -a --no-backup
36
38
37 echo '% fold git patch into a regular patch, expect git patch'
39 echo '% fold git patch into a regular patch, expect git patch'
38 echo a >> a
40 echo a >> a
39 hg qnew -f regular
41 hg qnew -f regular
40 hg cp a aa
42 hg cp a aa
41 hg qnew --git -f git
43 hg qnew --git -f git
42 hg qpop
44 hg qpop
43 hg qfold git
45 hg qfold git
44 cat .hg/patches/regular
46 cat .hg/patches/regular
45 hg qpop
47 hg qpop
46 hg qdel regular
48 hg qdel regular
47
49
48 echo '% fold regular patch into a git patch, expect git patch'
50 echo '% fold regular patch into a git patch, expect git patch'
49 hg cp a aa
51 hg cp a aa
50 hg qnew --git -f git
52 hg qnew --git -f git
51 echo b >> aa
53 echo b >> aa
52 hg qnew -f regular
54 hg qnew -f regular
53 hg qpop
55 hg qpop
54 hg qfold regular
56 hg qfold regular
55 cat .hg/patches/git
57 cat .hg/patches/git
56
58
57 cd ..
59 cd ..
58
60
59
61
@@ -1,618 +1,630
1 % help
1 % help
2 mq extension - manage a stack of patches
2 mq extension - manage a stack of patches
3
3
4 This extension lets you work with a stack of patches in a Mercurial
4 This extension lets you work with a stack of patches in a Mercurial
5 repository. It manages two stacks of patches - all known patches, and applied
5 repository. It manages two stacks of patches - all known patches, and applied
6 patches (subset of known patches).
6 patches (subset of known patches).
7
7
8 Known patches are represented as patch files in the .hg/patches directory.
8 Known patches are represented as patch files in the .hg/patches directory.
9 Applied patches are both patch files and changesets.
9 Applied patches are both patch files and changesets.
10
10
11 Common tasks (use "hg help command" for more details):
11 Common tasks (use "hg help command" for more details):
12
12
13 prepare repository to work with patches qinit
13 prepare repository to work with patches qinit
14 create new patch qnew
14 create new patch qnew
15 import existing patch qimport
15 import existing patch qimport
16
16
17 print patch series qseries
17 print patch series qseries
18 print applied patches qapplied
18 print applied patches qapplied
19
19
20 add known patch to applied stack qpush
20 add known patch to applied stack qpush
21 remove patch from applied stack qpop
21 remove patch from applied stack qpop
22 refresh contents of top applied patch qrefresh
22 refresh contents of top applied patch qrefresh
23
23
24 By default, mq will automatically use git patches when required to avoid
25 losing file mode changes, copy records, binary files or empty files creations
26 or deletions. This behaviour can be configured with:
27
28 [mq]
29 git = auto/keep/yes/no
30
31 If set to 'keep', mq will obey the [diff] section configuration while
32 preserving existing git patches upon qrefresh. If set to 'yes' or 'no', mq
33 will override the [diff] section and always generate git or regular patches,
34 possibly losing data in the second case.
35
24 list of commands:
36 list of commands:
25
37
26 qapplied print the patches already applied
38 qapplied print the patches already applied
27 qclone clone main and patch repository at same time
39 qclone clone main and patch repository at same time
28 qcommit commit changes in the queue repository
40 qcommit commit changes in the queue repository
29 qdelete remove patches from queue
41 qdelete remove patches from queue
30 qdiff diff of the current patch and subsequent modifications
42 qdiff diff of the current patch and subsequent modifications
31 qfinish move applied patches into repository history
43 qfinish move applied patches into repository history
32 qfold fold the named patches into the current patch
44 qfold fold the named patches into the current patch
33 qgoto push or pop patches until named patch is at top of stack
45 qgoto push or pop patches until named patch is at top of stack
34 qguard set or print guards for a patch
46 qguard set or print guards for a patch
35 qheader print the header of the topmost or specified patch
47 qheader print the header of the topmost or specified patch
36 qimport import a patch
48 qimport import a patch
37 qinit init a new queue repository
49 qinit init a new queue repository
38 qnew create a new patch
50 qnew create a new patch
39 qnext print the name of the next patch
51 qnext print the name of the next patch
40 qpop pop the current patch off the stack
52 qpop pop the current patch off the stack
41 qprev print the name of the previous patch
53 qprev print the name of the previous patch
42 qpush push the next patch onto the stack
54 qpush push the next patch onto the stack
43 qrefresh update the current patch
55 qrefresh update the current patch
44 qrename rename a patch
56 qrename rename a patch
45 qrestore restore the queue state saved by a revision
57 qrestore restore the queue state saved by a revision
46 qsave save current queue state
58 qsave save current queue state
47 qselect set or print guarded patches to push
59 qselect set or print guarded patches to push
48 qseries print the entire series file
60 qseries print the entire series file
49 qtop print the name of the current patch
61 qtop print the name of the current patch
50 qunapplied print the patches not yet applied
62 qunapplied print the patches not yet applied
51 strip strip a revision and all its descendants from the repository
63 strip strip a revision and all its descendants from the repository
52
64
53 use "hg -v help mq" to show aliases and global options
65 use "hg -v help mq" to show aliases and global options
54 adding a
66 adding a
55 updating to branch default
67 updating to branch default
56 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 adding b/z
69 adding b/z
58 % qinit
70 % qinit
59 % -R qinit
71 % -R qinit
60 % qinit -c
72 % qinit -c
61 A .hgignore
73 A .hgignore
62 A series
74 A series
63 % qinit; qinit -c
75 % qinit; qinit -c
64 .hgignore:
76 .hgignore:
65 ^\.hg
77 ^\.hg
66 ^\.mq
78 ^\.mq
67 syntax: glob
79 syntax: glob
68 status
80 status
69 guards
81 guards
70 series:
82 series:
71 abort: repository already exists!
83 abort: repository already exists!
72 % qinit; <stuff>; qinit -c
84 % qinit; <stuff>; qinit -c
73 adding .hg/patches/A
85 adding .hg/patches/A
74 adding .hg/patches/B
86 adding .hg/patches/B
75 A .hgignore
87 A .hgignore
76 A A
88 A A
77 A B
89 A B
78 A series
90 A series
79 .hgignore:
91 .hgignore:
80 status
92 status
81 bleh
93 bleh
82 series:
94 series:
83 A
95 A
84 B
96 B
85 % qrefresh
97 % qrefresh
86 foo bar
98 foo bar
87
99
88 diff -r xa
100 diff -r xa
89 --- a/a
101 --- a/a
90 +++ b/a
102 +++ b/a
91 @@ -1,1 +1,2 @@
103 @@ -1,1 +1,2 @@
92 a
104 a
93 +a
105 +a
94 % empty qrefresh
106 % empty qrefresh
95 revision:
107 revision:
96 patch:
108 patch:
97 foo bar
109 foo bar
98
110
99 working dir diff:
111 working dir diff:
100 --- a/a
112 --- a/a
101 +++ b/a
113 +++ b/a
102 @@ -1,1 +1,2 @@
114 @@ -1,1 +1,2 @@
103 a
115 a
104 +a
116 +a
105 % qpop
117 % qpop
106 popping test.patch
118 popping test.patch
107 patch queue now empty
119 patch queue now empty
108 % qpush with dump of tag cache
120 % qpush with dump of tag cache
109 .hg/tags.cache (pre qpush):
121 .hg/tags.cache (pre qpush):
110 1
122 1
111
123
112 applying test.patch
124 applying test.patch
113 now at: test.patch
125 now at: test.patch
114 .hg/tags.cache (post qpush):
126 .hg/tags.cache (post qpush):
115 2
127 2
116
128
117 % pop/push outside repo
129 % pop/push outside repo
118 popping test.patch
130 popping test.patch
119 patch queue now empty
131 patch queue now empty
120 applying test.patch
132 applying test.patch
121 now at: test.patch
133 now at: test.patch
122 % qrefresh in subdir
134 % qrefresh in subdir
123 % pop/push -a in subdir
135 % pop/push -a in subdir
124 popping test2.patch
136 popping test2.patch
125 popping test.patch
137 popping test.patch
126 patch queue now empty
138 patch queue now empty
127 applying test.patch
139 applying test.patch
128 applying test2.patch
140 applying test2.patch
129 now at: test2.patch
141 now at: test2.patch
130 % qseries
142 % qseries
131 test.patch
143 test.patch
132 test2.patch
144 test2.patch
133 0 A test.patch: f...
145 0 A test.patch: f...
134 1 A test2.patch:
146 1 A test2.patch:
135 popping test2.patch
147 popping test2.patch
136 now at: test.patch
148 now at: test.patch
137 0 A test.patch: foo bar
149 0 A test.patch: foo bar
138 1 U test2.patch:
150 1 U test2.patch:
139 applying test2.patch
151 applying test2.patch
140 now at: test2.patch
152 now at: test2.patch
141 % qapplied
153 % qapplied
142 test.patch
154 test.patch
143 test2.patch
155 test2.patch
144 % qtop
156 % qtop
145 test2.patch
157 test2.patch
146 % prev
158 % prev
147 test.patch
159 test.patch
148 % next
160 % next
149 all patches applied
161 all patches applied
150 popping test2.patch
162 popping test2.patch
151 now at: test.patch
163 now at: test.patch
152 % commit should fail
164 % commit should fail
153 abort: cannot commit over an applied mq patch
165 abort: cannot commit over an applied mq patch
154 % push should fail
166 % push should fail
155 pushing to ../../k
167 pushing to ../../k
156 abort: source has mq patches applied
168 abort: source has mq patches applied
157 % import should fail
169 % import should fail
158 abort: cannot import over an applied patch
170 abort: cannot import over an applied patch
159 % import --no-commit should succeed
171 % import --no-commit should succeed
160 applying ../../import.diff
172 applying ../../import.diff
161 M a
173 M a
162 % qunapplied
174 % qunapplied
163 test2.patch
175 test2.patch
164 % qpush/qpop with index
176 % qpush/qpop with index
165 applying test2.patch
177 applying test2.patch
166 now at: test2.patch
178 now at: test2.patch
167 popping test2.patch
179 popping test2.patch
168 popping test1b.patch
180 popping test1b.patch
169 now at: test.patch
181 now at: test.patch
170 applying test1b.patch
182 applying test1b.patch
171 now at: test1b.patch
183 now at: test1b.patch
172 applying test2.patch
184 applying test2.patch
173 now at: test2.patch
185 now at: test2.patch
174 popping test2.patch
186 popping test2.patch
175 now at: test1b.patch
187 now at: test1b.patch
176 popping test1b.patch
188 popping test1b.patch
177 now at: test.patch
189 now at: test.patch
178 applying test1b.patch
190 applying test1b.patch
179 applying test2.patch
191 applying test2.patch
180 now at: test2.patch
192 now at: test2.patch
181 % pop, qapplied, qunapplied
193 % pop, qapplied, qunapplied
182 0 A test.patch
194 0 A test.patch
183 1 A test1b.patch
195 1 A test1b.patch
184 2 A test2.patch
196 2 A test2.patch
185 % qapplied -1 test.patch
197 % qapplied -1 test.patch
186 only one patch applied
198 only one patch applied
187 % qapplied -1 test1b.patch
199 % qapplied -1 test1b.patch
188 test.patch
200 test.patch
189 % qapplied -1 test2.patch
201 % qapplied -1 test2.patch
190 test1b.patch
202 test1b.patch
191 % qapplied -1
203 % qapplied -1
192 test1b.patch
204 test1b.patch
193 % qapplied
205 % qapplied
194 test.patch
206 test.patch
195 test1b.patch
207 test1b.patch
196 test2.patch
208 test2.patch
197 % qapplied test1b.patch
209 % qapplied test1b.patch
198 test.patch
210 test.patch
199 test1b.patch
211 test1b.patch
200 % qunapplied -1
212 % qunapplied -1
201 all patches applied
213 all patches applied
202 % qunapplied
214 % qunapplied
203 % popping
215 % popping
204 popping test2.patch
216 popping test2.patch
205 now at: test1b.patch
217 now at: test1b.patch
206 % qunapplied -1
218 % qunapplied -1
207 test2.patch
219 test2.patch
208 % qunapplied
220 % qunapplied
209 test2.patch
221 test2.patch
210 % qunapplied test2.patch
222 % qunapplied test2.patch
211 % qunapplied -1 test2.patch
223 % qunapplied -1 test2.patch
212 all patches applied
224 all patches applied
213 % popping -a
225 % popping -a
214 popping test1b.patch
226 popping test1b.patch
215 popping test.patch
227 popping test.patch
216 patch queue now empty
228 patch queue now empty
217 % qapplied
229 % qapplied
218 % qapplied -1
230 % qapplied -1
219 no patches applied
231 no patches applied
220 applying test.patch
232 applying test.patch
221 now at: test.patch
233 now at: test.patch
222 % push should succeed
234 % push should succeed
223 popping test.patch
235 popping test.patch
224 patch queue now empty
236 patch queue now empty
225 pushing to ../../k
237 pushing to ../../k
226 searching for changes
238 searching for changes
227 adding changesets
239 adding changesets
228 adding manifests
240 adding manifests
229 adding file changes
241 adding file changes
230 added 1 changesets with 1 changes to 1 files
242 added 1 changesets with 1 changes to 1 files
231 % qpush/qpop error codes
243 % qpush/qpop error codes
232 applying test.patch
244 applying test.patch
233 applying test1b.patch
245 applying test1b.patch
234 applying test2.patch
246 applying test2.patch
235 now at: test2.patch
247 now at: test2.patch
236 % pops all patches and succeeds
248 % pops all patches and succeeds
237 popping test2.patch
249 popping test2.patch
238 popping test1b.patch
250 popping test1b.patch
239 popping test.patch
251 popping test.patch
240 patch queue now empty
252 patch queue now empty
241 qpop -a succeeds
253 qpop -a succeeds
242 % does nothing and succeeds
254 % does nothing and succeeds
243 no patches applied
255 no patches applied
244 qpop -a succeeds
256 qpop -a succeeds
245 % fails - nothing else to pop
257 % fails - nothing else to pop
246 no patches applied
258 no patches applied
247 qpop fails
259 qpop fails
248 % pushes a patch and succeeds
260 % pushes a patch and succeeds
249 applying test.patch
261 applying test.patch
250 now at: test.patch
262 now at: test.patch
251 qpush succeeds
263 qpush succeeds
252 % pops a patch and succeeds
264 % pops a patch and succeeds
253 popping test.patch
265 popping test.patch
254 patch queue now empty
266 patch queue now empty
255 qpop succeeds
267 qpop succeeds
256 % pushes up to test1b.patch and succeeds
268 % pushes up to test1b.patch and succeeds
257 applying test.patch
269 applying test.patch
258 applying test1b.patch
270 applying test1b.patch
259 now at: test1b.patch
271 now at: test1b.patch
260 qpush test1b.patch succeeds
272 qpush test1b.patch succeeds
261 % does nothing and succeeds
273 % does nothing and succeeds
262 qpush: test1b.patch is already at the top
274 qpush: test1b.patch is already at the top
263 qpush test1b.patch succeeds
275 qpush test1b.patch succeeds
264 % does nothing and succeeds
276 % does nothing and succeeds
265 qpop: test1b.patch is already at the top
277 qpop: test1b.patch is already at the top
266 qpop test1b.patch succeeds
278 qpop test1b.patch succeeds
267 % fails - can't push to this patch
279 % fails - can't push to this patch
268 abort: cannot push to a previous patch: test.patch
280 abort: cannot push to a previous patch: test.patch
269 qpush test.patch fails
281 qpush test.patch fails
270 % fails - can't pop to this patch
282 % fails - can't pop to this patch
271 abort: patch test2.patch is not applied
283 abort: patch test2.patch is not applied
272 qpop test2.patch fails
284 qpop test2.patch fails
273 % pops up to test.patch and succeeds
285 % pops up to test.patch and succeeds
274 popping test1b.patch
286 popping test1b.patch
275 now at: test.patch
287 now at: test.patch
276 qpop test.patch succeeds
288 qpop test.patch succeeds
277 % pushes all patches and succeeds
289 % pushes all patches and succeeds
278 applying test1b.patch
290 applying test1b.patch
279 applying test2.patch
291 applying test2.patch
280 now at: test2.patch
292 now at: test2.patch
281 qpush -a succeeds
293 qpush -a succeeds
282 % does nothing and succeeds
294 % does nothing and succeeds
283 all patches are currently applied
295 all patches are currently applied
284 qpush -a succeeds
296 qpush -a succeeds
285 % fails - nothing else to push
297 % fails - nothing else to push
286 patch series already fully applied
298 patch series already fully applied
287 qpush fails
299 qpush fails
288 % does nothing and succeeds
300 % does nothing and succeeds
289 qpush: test2.patch is already at the top
301 qpush: test2.patch is already at the top
290 qpush test2.patch succeeds
302 qpush test2.patch succeeds
291 % strip
303 % strip
292 adding x
304 adding x
293 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
305 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
294 saving bundle to
306 saving bundle to
295 adding changesets
307 adding changesets
296 adding manifests
308 adding manifests
297 adding file changes
309 adding file changes
298 added 1 changesets with 1 changes to 1 files
310 added 1 changesets with 1 changes to 1 files
299 (run 'hg update' to get a working copy)
311 (run 'hg update' to get a working copy)
300 % strip with local changes, should complain
312 % strip with local changes, should complain
301 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
313 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
302 abort: local changes found
314 abort: local changes found
303 % --force strip with local changes
315 % --force strip with local changes
304 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
316 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
305 saving bundle to
317 saving bundle to
306 % cd b; hg qrefresh
318 % cd b; hg qrefresh
307 adding a
319 adding a
308 foo
320 foo
309
321
310 diff -r cb9a9f314b8b a
322 diff -r cb9a9f314b8b a
311 --- a/a
323 --- a/a
312 +++ b/a
324 +++ b/a
313 @@ -1,1 +1,2 @@
325 @@ -1,1 +1,2 @@
314 a
326 a
315 +a
327 +a
316 diff -r cb9a9f314b8b b/f
328 diff -r cb9a9f314b8b b/f
317 --- /dev/null
329 --- /dev/null
318 +++ b/b/f
330 +++ b/b/f
319 @@ -0,0 +1,1 @@
331 @@ -0,0 +1,1 @@
320 +f
332 +f
321 % hg qrefresh .
333 % hg qrefresh .
322 foo
334 foo
323
335
324 diff -r cb9a9f314b8b b/f
336 diff -r cb9a9f314b8b b/f
325 --- /dev/null
337 --- /dev/null
326 +++ b/b/f
338 +++ b/b/f
327 @@ -0,0 +1,1 @@
339 @@ -0,0 +1,1 @@
328 +f
340 +f
329 M a
341 M a
330 % qpush failure
342 % qpush failure
331 popping bar
343 popping bar
332 popping foo
344 popping foo
333 patch queue now empty
345 patch queue now empty
334 applying foo
346 applying foo
335 applying bar
347 applying bar
336 file foo already exists
348 file foo already exists
337 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
349 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
338 patch failed, unable to continue (try -v)
350 patch failed, unable to continue (try -v)
339 patch failed, rejects left in working dir
351 patch failed, rejects left in working dir
340 errors during apply, please fix and refresh bar
352 errors during apply, please fix and refresh bar
341 ? foo
353 ? foo
342 ? foo.rej
354 ? foo.rej
343 % mq tags
355 % mq tags
344 0 qparent
356 0 qparent
345 1 qbase foo
357 1 qbase foo
346 2 qtip bar tip
358 2 qtip bar tip
347 % bad node in status
359 % bad node in status
348 popping bar
360 popping bar
349 now at: foo
361 now at: foo
350 changeset: 0:cb9a9f314b8b
362 changeset: 0:cb9a9f314b8b
351 mq status file refers to unknown node
363 mq status file refers to unknown node
352 tag: tip
364 tag: tip
353 user: test
365 user: test
354 date: Thu Jan 01 00:00:00 1970 +0000
366 date: Thu Jan 01 00:00:00 1970 +0000
355 summary: a
367 summary: a
356
368
357 mq status file refers to unknown node
369 mq status file refers to unknown node
358 default 0:cb9a9f314b8b
370 default 0:cb9a9f314b8b
359 abort: trying to pop unknown node
371 abort: trying to pop unknown node
360 new file
372 new file
361
373
362 diff --git a/new b/new
374 diff --git a/new b/new
363 new file mode 100755
375 new file mode 100755
364 --- /dev/null
376 --- /dev/null
365 +++ b/new
377 +++ b/new
366 @@ -0,0 +1,1 @@
378 @@ -0,0 +1,1 @@
367 +foo
379 +foo
368 copy file
380 copy file
369
381
370 diff --git a/new b/copy
382 diff --git a/new b/copy
371 copy from new
383 copy from new
372 copy to copy
384 copy to copy
373 popping copy
385 popping copy
374 now at: new
386 now at: new
375 applying copy
387 applying copy
376 now at: copy
388 now at: copy
377 diff --git a/new b/copy
389 diff --git a/new b/copy
378 copy from new
390 copy from new
379 copy to copy
391 copy to copy
380 diff --git a/new b/copy
392 diff --git a/new b/copy
381 copy from new
393 copy from new
382 copy to copy
394 copy to copy
383 % test file addition in slow path
395 % test file addition in slow path
384 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
396 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
385 created new head
397 created new head
386 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
398 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
387 popping bar
399 popping bar
388 adding branch
400 adding branch
389 adding changesets
401 adding changesets
390 adding manifests
402 adding manifests
391 adding file changes
403 adding file changes
392 added 1 changesets with 1 changes to 1 files
404 added 1 changesets with 1 changes to 1 files
393 patch queue now empty
405 patch queue now empty
394 (working directory not at a head)
406 (working directory not at a head)
395 applying bar
407 applying bar
396 now at: bar
408 now at: bar
397 diff --git a/bar b/bar
409 diff --git a/bar b/bar
398 new file mode 100644
410 new file mode 100644
399 --- /dev/null
411 --- /dev/null
400 +++ b/bar
412 +++ b/bar
401 @@ -0,0 +1,1 @@
413 @@ -0,0 +1,1 @@
402 +bar
414 +bar
403 diff --git a/foo b/baz
415 diff --git a/foo b/baz
404 rename from foo
416 rename from foo
405 rename to baz
417 rename to baz
406 2 baz (foo)
418 2 baz (foo)
407 diff --git a/bar b/bar
419 diff --git a/bar b/bar
408 new file mode 100644
420 new file mode 100644
409 --- /dev/null
421 --- /dev/null
410 +++ b/bar
422 +++ b/bar
411 @@ -0,0 +1,1 @@
423 @@ -0,0 +1,1 @@
412 +bar
424 +bar
413 diff --git a/foo b/baz
425 diff --git a/foo b/baz
414 rename from foo
426 rename from foo
415 rename to baz
427 rename to baz
416 2 baz (foo)
428 2 baz (foo)
417 diff --git a/bar b/bar
429 diff --git a/bar b/bar
418 diff --git a/foo b/baz
430 diff --git a/foo b/baz
419 % test file move chains in the slow path
431 % test file move chains in the slow path
420 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
432 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
421 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
433 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
422 popping bar
434 popping bar
423 adding branch
435 adding branch
424 adding changesets
436 adding changesets
425 adding manifests
437 adding manifests
426 adding file changes
438 adding file changes
427 added 1 changesets with 1 changes to 1 files
439 added 1 changesets with 1 changes to 1 files
428 patch queue now empty
440 patch queue now empty
429 (working directory not at a head)
441 (working directory not at a head)
430 applying bar
442 applying bar
431 now at: bar
443 now at: bar
432 diff --git a/foo b/bleh
444 diff --git a/foo b/bleh
433 rename from foo
445 rename from foo
434 rename to bleh
446 rename to bleh
435 diff --git a/quux b/quux
447 diff --git a/quux b/quux
436 new file mode 100644
448 new file mode 100644
437 --- /dev/null
449 --- /dev/null
438 +++ b/quux
450 +++ b/quux
439 @@ -0,0 +1,1 @@
451 @@ -0,0 +1,1 @@
440 +bar
452 +bar
441 3 bleh (foo)
453 3 bleh (foo)
442 diff --git a/foo b/barney
454 diff --git a/foo b/barney
443 rename from foo
455 rename from foo
444 rename to barney
456 rename to barney
445 diff --git a/fred b/fred
457 diff --git a/fred b/fred
446 new file mode 100644
458 new file mode 100644
447 --- /dev/null
459 --- /dev/null
448 +++ b/fred
460 +++ b/fred
449 @@ -0,0 +1,1 @@
461 @@ -0,0 +1,1 @@
450 +bar
462 +bar
451 3 barney (foo)
463 3 barney (foo)
452 % refresh omitting an added file
464 % refresh omitting an added file
453 C newfile
465 C newfile
454 A newfile
466 A newfile
455 popping baz
467 popping baz
456 now at: bar
468 now at: bar
457 % create a git patch
469 % create a git patch
458 diff --git a/alexander b/alexander
470 diff --git a/alexander b/alexander
459 % create a git binary patch
471 % create a git binary patch
460 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
472 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
461 diff --git a/bucephalus b/bucephalus
473 diff --git a/bucephalus b/bucephalus
462 % check binary patches can be popped and pushed
474 % check binary patches can be popped and pushed
463 popping addbucephalus
475 popping addbucephalus
464 now at: addalexander
476 now at: addalexander
465 applying addbucephalus
477 applying addbucephalus
466 now at: addbucephalus
478 now at: addbucephalus
467 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
479 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
468 % strip again
480 % strip again
469 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
481 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 created new head
482 created new head
471 merging foo
483 merging foo
472 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
484 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
473 (branch merge, don't forget to commit)
485 (branch merge, don't forget to commit)
474 changeset: 3:99615015637b
486 changeset: 3:99615015637b
475 tag: tip
487 tag: tip
476 parent: 2:20cbbe65cff7
488 parent: 2:20cbbe65cff7
477 parent: 1:d2871fc282d4
489 parent: 1:d2871fc282d4
478 user: test
490 user: test
479 date: Thu Jan 01 00:00:00 1970 +0000
491 date: Thu Jan 01 00:00:00 1970 +0000
480 summary: merge
492 summary: merge
481
493
482 changeset: 2:20cbbe65cff7
494 changeset: 2:20cbbe65cff7
483 parent: 0:53245c60e682
495 parent: 0:53245c60e682
484 user: test
496 user: test
485 date: Thu Jan 01 00:00:00 1970 +0000
497 date: Thu Jan 01 00:00:00 1970 +0000
486 summary: change foo 2
498 summary: change foo 2
487
499
488 changeset: 1:d2871fc282d4
500 changeset: 1:d2871fc282d4
489 user: test
501 user: test
490 date: Thu Jan 01 00:00:00 1970 +0000
502 date: Thu Jan 01 00:00:00 1970 +0000
491 summary: change foo 1
503 summary: change foo 1
492
504
493 changeset: 0:53245c60e682
505 changeset: 0:53245c60e682
494 user: test
506 user: test
495 date: Thu Jan 01 00:00:00 1970 +0000
507 date: Thu Jan 01 00:00:00 1970 +0000
496 summary: add foo
508 summary: add foo
497
509
498 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 saving bundle to
511 saving bundle to
500 saving bundle to
512 saving bundle to
501 adding branch
513 adding branch
502 adding changesets
514 adding changesets
503 adding manifests
515 adding manifests
504 adding file changes
516 adding file changes
505 added 1 changesets with 1 changes to 1 files
517 added 1 changesets with 1 changes to 1 files
506 changeset: 1:20cbbe65cff7
518 changeset: 1:20cbbe65cff7
507 tag: tip
519 tag: tip
508 user: test
520 user: test
509 date: Thu Jan 01 00:00:00 1970 +0000
521 date: Thu Jan 01 00:00:00 1970 +0000
510 summary: change foo 2
522 summary: change foo 2
511
523
512 changeset: 0:53245c60e682
524 changeset: 0:53245c60e682
513 user: test
525 user: test
514 date: Thu Jan 01 00:00:00 1970 +0000
526 date: Thu Jan 01 00:00:00 1970 +0000
515 summary: add foo
527 summary: add foo
516
528
517 % qclone
529 % qclone
518 abort: versioned patch repository not found (see qinit -c)
530 abort: versioned patch repository not found (see qinit -c)
519 adding .hg/patches/patch1
531 adding .hg/patches/patch1
520 main repo:
532 main repo:
521 rev 1: change foo
533 rev 1: change foo
522 rev 0: add foo
534 rev 0: add foo
523 patch repo:
535 patch repo:
524 rev 0: checkpoint
536 rev 0: checkpoint
525 updating to branch default
537 updating to branch default
526 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
527 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
539 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
528 main repo:
540 main repo:
529 rev 0: add foo
541 rev 0: add foo
530 patch repo:
542 patch repo:
531 rev 0: checkpoint
543 rev 0: checkpoint
532 popping patch1
544 popping patch1
533 patch queue now empty
545 patch queue now empty
534 main repo:
546 main repo:
535 rev 0: add foo
547 rev 0: add foo
536 patch repo:
548 patch repo:
537 rev 0: checkpoint
549 rev 0: checkpoint
538 updating to branch default
550 updating to branch default
539 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
551 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
540 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
552 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
541 main repo:
553 main repo:
542 rev 0: add foo
554 rev 0: add foo
543 patch repo:
555 patch repo:
544 rev 0: checkpoint
556 rev 0: checkpoint
545 % test applying on an empty file (issue 1033)
557 % test applying on an empty file (issue 1033)
546 adding a
558 adding a
547 popping changea
559 popping changea
548 patch queue now empty
560 patch queue now empty
549 applying changea
561 applying changea
550 now at: changea
562 now at: changea
551 % test qpush with --force, issue1087
563 % test qpush with --force, issue1087
552 adding bye.txt
564 adding bye.txt
553 adding hello.txt
565 adding hello.txt
554 popping empty
566 popping empty
555 patch queue now empty
567 patch queue now empty
556 % qpush should fail, local changes
568 % qpush should fail, local changes
557 abort: local changes found, refresh first
569 abort: local changes found, refresh first
558 % apply force, should not discard changes with empty patch
570 % apply force, should not discard changes with empty patch
559 applying empty
571 applying empty
560 patch empty is empty
572 patch empty is empty
561 now at: empty
573 now at: empty
562 diff -r bf5fc3f07a0a hello.txt
574 diff -r bf5fc3f07a0a hello.txt
563 --- a/hello.txt
575 --- a/hello.txt
564 +++ b/hello.txt
576 +++ b/hello.txt
565 @@ -1,1 +1,2 @@
577 @@ -1,1 +1,2 @@
566 hello
578 hello
567 +world
579 +world
568 diff -r 9ecee4f634e3 hello.txt
580 diff -r 9ecee4f634e3 hello.txt
569 --- a/hello.txt
581 --- a/hello.txt
570 +++ b/hello.txt
582 +++ b/hello.txt
571 @@ -1,1 +1,2 @@
583 @@ -1,1 +1,2 @@
572 hello
584 hello
573 +world
585 +world
574 changeset: 1:bf5fc3f07a0a
586 changeset: 1:bf5fc3f07a0a
575 tag: qtip
587 tag: qtip
576 tag: tip
588 tag: tip
577 tag: empty
589 tag: empty
578 tag: qbase
590 tag: qbase
579 user: test
591 user: test
580 date: Thu Jan 01 00:00:00 1970 +0000
592 date: Thu Jan 01 00:00:00 1970 +0000
581 summary: imported patch empty
593 summary: imported patch empty
582
594
583
595
584 popping empty
596 popping empty
585 patch queue now empty
597 patch queue now empty
586 % qpush should fail, local changes
598 % qpush should fail, local changes
587 abort: local changes found, refresh first
599 abort: local changes found, refresh first
588 % apply force, should discard changes in hello, but not bye
600 % apply force, should discard changes in hello, but not bye
589 applying empty
601 applying empty
590 now at: empty
602 now at: empty
591 M bye.txt
603 M bye.txt
592 diff -r ba252371dbc1 bye.txt
604 diff -r ba252371dbc1 bye.txt
593 --- a/bye.txt
605 --- a/bye.txt
594 +++ b/bye.txt
606 +++ b/bye.txt
595 @@ -1,1 +1,2 @@
607 @@ -1,1 +1,2 @@
596 bye
608 bye
597 +universe
609 +universe
598 diff -r 9ecee4f634e3 bye.txt
610 diff -r 9ecee4f634e3 bye.txt
599 --- a/bye.txt
611 --- a/bye.txt
600 +++ b/bye.txt
612 +++ b/bye.txt
601 @@ -1,1 +1,2 @@
613 @@ -1,1 +1,2 @@
602 bye
614 bye
603 +universe
615 +universe
604 diff -r 9ecee4f634e3 hello.txt
616 diff -r 9ecee4f634e3 hello.txt
605 --- a/hello.txt
617 --- a/hello.txt
606 +++ b/hello.txt
618 +++ b/hello.txt
607 @@ -1,1 +1,3 @@
619 @@ -1,1 +1,3 @@
608 hello
620 hello
609 +world
621 +world
610 +universe
622 +universe
611 % test popping revisions not in working dir ancestry
623 % test popping revisions not in working dir ancestry
612 0 A empty
624 0 A empty
613 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
625 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
614 popping empty
626 popping empty
615 patch queue now empty
627 patch queue now empty
616 % test popping must remove files added in subdirectories first
628 % test popping must remove files added in subdirectories first
617 popping rename-dir
629 popping rename-dir
618 patch queue now empty
630 patch queue now empty
General Comments 0
You need to be logged in to leave comments. Login now