Mercurial > hg > mercurial-crew-with-dirclash
annotate hgext/mq.py @ 1959:d53a18f592be
add -f/--force to pull, incoming, outgoing, to work on unrelated repo.
before this, push would not push from e.g. "hg" repo to "kernel" repo
but other commands worked. this was bad idea, could merge unrelated
projects by accident. i did this tonight.
now, all commands still work with unrelated repo but need
--force/-f. abort is default. this is safer.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Tue, 14 Mar 2006 22:58:14 -0800 |
parents | e8b86fb8ae33 |
children | ebf1ecb5f4e8 |
rev | line source |
---|---|
1808 | 1 # queue.py - patch queues for mercurial |
2 # | |
3 # Copyright 2005 Chris Mason <mason@suse.com> | |
4 # | |
5 # This software may be used and distributed according to the terms | |
6 # of the GNU General Public License, incorporated herein by reference. | |
7 | |
8 from mercurial.demandload import * | |
9 demandload(globals(), "os sys re struct traceback errno bz2") | |
10 from mercurial.i18n import gettext as _ | |
11 from mercurial import ui, hg, revlog, commands, util | |
12 | |
13 versionstr = "0.45" | |
14 | |
15 repomap = {} | |
16 | |
17 class queue: | |
18 def __init__(self, ui, path, patchdir=None): | |
19 self.basepath = path | |
20 if patchdir: | |
21 self.path = patchdir | |
22 else: | |
23 self.path = os.path.join(path, "patches") | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
24 self.opener = util.opener(self.path) |
1808 | 25 self.ui = ui |
26 self.applied = [] | |
27 self.full_series = [] | |
28 self.applied_dirty = 0 | |
29 self.series_dirty = 0 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
30 self.series_path = "series" |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
31 self.status_path = "status" |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
32 |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
33 if os.path.exists(os.path.join(self.path, self.series_path)): |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
34 self.full_series = self.opener(self.series_path).read().splitlines() |
1808 | 35 self.read_series(self.full_series) |
36 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
37 if os.path.exists(os.path.join(self.path, self.status_path)): |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
38 self.applied = self.opener(self.status_path).read().splitlines() |
1808 | 39 |
40 def find_series(self, patch): | |
41 pre = re.compile("(\s*)([^#]+)") | |
42 index = 0 | |
43 for l in self.full_series: | |
44 m = pre.match(l) | |
45 if m: | |
46 s = m.group(2) | |
47 s = s.rstrip() | |
48 if s == patch: | |
49 return index | |
50 index += 1 | |
51 return None | |
52 | |
53 def read_series(self, list): | |
54 def matcher(list): | |
55 pre = re.compile("(\s*)([^#]+)") | |
56 for l in list: | |
57 m = pre.match(l) | |
58 if m: | |
59 s = m.group(2) | |
60 s = s.rstrip() | |
61 if len(s) > 0: | |
62 yield s | |
63 self.series = [] | |
64 self.series = [ x for x in matcher(list) ] | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
65 |
1808 | 66 def save_dirty(self): |
67 if self.applied_dirty: | |
68 if len(self.applied) > 0: | |
69 nl = "\n" | |
70 else: | |
71 nl = "" | |
72 f = self.opener(self.status_path, "w") | |
73 f.write("\n".join(self.applied) + nl) | |
74 if self.series_dirty: | |
75 if len(self.full_series) > 0: | |
76 nl = "\n" | |
77 else: | |
78 nl = "" | |
79 f = self.opener(self.series_path, "w") | |
80 f.write("\n".join(self.full_series) + nl) | |
81 | |
82 def readheaders(self, patch): | |
83 def eatdiff(lines): | |
84 while lines: | |
85 l = lines[-1] | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
86 if (l.startswith("diff -") or |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
87 l.startswith("Index:") or |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
88 l.startswith("===========")): |
1808 | 89 del lines[-1] |
90 else: | |
91 break | |
92 def eatempty(lines): | |
93 while lines: | |
94 l = lines[-1] | |
95 if re.match('\s*$', l): | |
96 del lines[-1] | |
97 else: | |
98 break | |
99 | |
100 pf = os.path.join(self.path, patch) | |
101 message = [] | |
102 comments = [] | |
103 user = None | |
104 format = None | |
105 subject = None | |
106 diffstart = 0 | |
107 | |
108 for line in file(pf): | |
109 line = line.rstrip() | |
110 if diffstart: | |
111 if line.startswith('+++ '): | |
112 diffstart = 2 | |
113 break | |
114 if line.startswith("--- "): | |
115 diffstart = 1 | |
116 continue | |
117 elif format == "hgpatch": | |
118 # parse values when importing the result of an hg export | |
119 if line.startswith("# User "): | |
120 user = line[7:] | |
121 elif not line.startswith("# ") and line: | |
122 message.append(line) | |
123 format = None | |
124 elif line == '# HG changeset patch': | |
125 format = "hgpatch" | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
126 elif (format != "tagdone" and (line.startswith("Subject: ") or |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
127 line.startswith("subject: "))): |
1808 | 128 subject = line[9:] |
129 format = "tag" | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
130 elif (format != "tagdone" and (line.startswith("From: ") or |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
131 line.startswith("from: "))): |
1808 | 132 user = line[6:] |
133 format = "tag" | |
134 elif format == "tag" and line == "": | |
135 # when looking for tags (subject: from: etc) they | |
136 # end once you find a blank line in the source | |
137 format = "tagdone" | |
138 else: | |
139 message.append(line) | |
140 comments.append(line) | |
141 | |
142 eatdiff(message) | |
143 eatdiff(comments) | |
144 eatempty(message) | |
145 eatempty(comments) | |
146 | |
147 # make sure message isn't empty | |
148 if format and format.startswith("tag") and subject: | |
149 message.insert(0, "") | |
150 message.insert(0, subject) | |
151 return (message, comments, user, diffstart > 1) | |
152 | |
153 def mergeone(self, repo, mergeq, head, patch, rev, wlock): | |
154 # first try just applying the patch | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
155 (err, n) = self.apply(repo, [ patch ], update_status=False, |
1808 | 156 strict=True, merge=rev, wlock=wlock) |
157 | |
158 if err == 0: | |
159 return (err, n) | |
160 | |
161 if n is None: | |
162 self.ui.warn("apply failed for patch %s\n" % patch) | |
163 sys.exit(1) | |
164 | |
165 self.ui.warn("patch didn't work out, merging %s\n" % patch) | |
166 | |
167 # apply failed, strip away that rev and merge. | |
168 repo.update(head, allow=False, force=True, wlock=wlock) | |
169 self.strip(repo, n, update=False, backup='strip', wlock=wlock) | |
170 | |
171 c = repo.changelog.read(rev) | |
172 ret = repo.update(rev, allow=True, wlock=wlock) | |
173 if ret: | |
174 self.ui.warn("update returned %d\n" % ret) | |
175 sys.exit(1) | |
176 n = repo.commit(None, c[4], c[1], force=1, wlock=wlock) | |
177 if n == None: | |
178 self.ui.warn("repo commit failed\n") | |
179 sys.exit(1) | |
180 try: | |
181 message, comments, user, patchfound = mergeq.readheaders(patch) | |
182 except: | |
183 self.ui.warn("Unable to read %s\n" % patch) | |
184 sys.exit(1) | |
185 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
186 patchf = self.opener(patch, "w") |
1808 | 187 if comments: |
188 comments = "\n".join(comments) + '\n\n' | |
189 patchf.write(comments) | |
190 commands.dodiff(patchf, self.ui, repo, head, n) | |
191 patchf.close() | |
192 return (0, n) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
193 |
1808 | 194 def qparents(self, repo, rev=None): |
195 if rev is None: | |
196 (p1, p2) = repo.dirstate.parents() | |
197 if p2 == revlog.nullid: | |
198 return p1 | |
199 if len(self.applied) == 0: | |
200 return None | |
201 (top, patch) = self.applied[-1].split(':') | |
202 top = revlog.bin(top) | |
203 return top | |
204 pp = repo.changelog.parents(rev) | |
205 if pp[1] != revlog.nullid: | |
206 arevs = [ x.split(':')[0] for x in self.applied ] | |
207 p0 = revlog.hex(pp[0]) | |
208 p1 = revlog.hex(pp[1]) | |
209 if p0 in arevs: | |
210 return pp[0] | |
211 if p1 in arevs: | |
212 return pp[1] | |
213 return None | |
214 return pp[0] | |
215 | |
216 def mergepatch(self, repo, mergeq, series, wlock): | |
217 if len(self.applied) == 0: | |
218 # each of the patches merged in will have two parents. This | |
219 # can confuse the qrefresh, qdiff, and strip code because it | |
220 # needs to know which parent is actually in the patch queue. | |
221 # so, we insert a merge marker with only one parent. This way | |
222 # the first patch in the queue is never a merge patch | |
223 # | |
224 pname = ".hg.patches.merge.marker" | |
225 n = repo.commit(None, '[mq]: merge marker', user=None, force=1, | |
226 wlock=wlock) | |
227 self.applied.append(revlog.hex(n) + ":" + pname) | |
228 self.applied_dirty = 1 | |
229 | |
230 head = self.qparents(repo) | |
231 | |
232 for patch in series: | |
233 patch = mergeq.lookup(patch) | |
234 if not patch: | |
235 self.ui.warn("patch %s does not exist\n" % patch) | |
236 return (1, None) | |
237 | |
238 info = mergeq.isapplied(patch) | |
239 if not info: | |
240 self.ui.warn("patch %s is not applied\n" % patch) | |
241 return (1, None) | |
242 rev = revlog.bin(info[1]) | |
243 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) | |
244 if head: | |
245 self.applied.append(revlog.hex(head) + ":" + patch) | |
246 self.applied_dirty = 1 | |
247 if err: | |
248 return (err, head) | |
249 return (0, head) | |
250 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
251 def apply(self, repo, series, list=False, update_status=True, |
1808 | 252 strict=False, patchdir=None, merge=None, wlock=None): |
253 # TODO unify with commands.py | |
254 if not patchdir: | |
255 patchdir = self.path | |
256 pwd = os.getcwd() | |
257 os.chdir(repo.root) | |
258 err = 0 | |
259 if not wlock: | |
260 wlock = repo.wlock() | |
261 lock = repo.lock() | |
262 tr = repo.transaction() | |
263 n = None | |
264 for patch in series: | |
265 self.ui.warn("applying %s\n" % patch) | |
266 pf = os.path.join(patchdir, patch) | |
267 | |
268 try: | |
269 message, comments, user, patchfound = self.readheaders(patch) | |
270 except: | |
271 self.ui.warn("Unable to read %s\n" % pf) | |
272 err = 1 | |
273 break | |
274 | |
275 if not message: | |
276 message = "imported patch %s\n" % patch | |
277 else: | |
278 if list: | |
279 message.append("\nimported patch %s" % patch) | |
280 message = '\n'.join(message) | |
281 | |
282 try: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
283 f = os.popen("patch -p1 --no-backup-if-mismatch < '%s'" % (pf)) |
1808 | 284 except: |
285 self.ui.warn("patch failed, unable to continue (try -v)\n") | |
286 err = 1 | |
287 break | |
288 files = [] | |
289 fuzz = False | |
290 for l in f: | |
291 l = l.rstrip('\r\n'); | |
292 if self.ui.verbose: | |
293 self.ui.warn(l + "\n") | |
294 if l[:14] == 'patching file ': | |
295 pf = os.path.normpath(l[14:]) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
296 # when patch finds a space in the file name, it puts |
1808 | 297 # single quotes around the filename. strip them off |
298 if pf[0] == "'" and pf[-1] == "'": | |
299 pf = pf[1:-1] | |
300 if pf not in files: | |
301 files.append(pf) | |
302 printed_file = False | |
303 file_str = l | |
304 elif l.find('with fuzz') >= 0: | |
305 if not printed_file: | |
306 self.ui.warn(file_str + '\n') | |
307 printed_file = True | |
308 self.ui.warn(l + '\n') | |
309 fuzz = True | |
310 elif l.find('saving rejects to file') >= 0: | |
311 self.ui.warn(l + '\n') | |
312 elif l.find('FAILED') >= 0: | |
313 if not printed_file: | |
314 self.ui.warn(file_str + '\n') | |
315 printed_file = True | |
316 self.ui.warn(l + '\n') | |
317 patcherr = f.close() | |
318 | |
319 if merge and len(files) > 0: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
320 # Mark as merged and update dirstate parent info |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
321 repo.dirstate.update(repo.dirstate.filterfiles(files), 'm') |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
322 p1, p2 = repo.dirstate.parents() |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
323 repo.dirstate.setparents(p1, merge) |
1808 | 324 if len(files) > 0: |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
325 commands.addremove_lock(self.ui, repo, files, |
1808 | 326 opts={}, wlock=wlock) |
327 n = repo.commit(files, message, user, force=1, lock=lock, | |
328 wlock=wlock) | |
329 | |
330 if n == None: | |
331 self.ui.warn("repo commit failed\n") | |
332 sys.exit(1) | |
333 | |
334 if update_status: | |
335 self.applied.append(revlog.hex(n) + ":" + patch) | |
336 | |
337 if patcherr: | |
338 if not patchfound: | |
339 self.ui.warn("patch %s is empty\n" % patch) | |
340 err = 0 | |
341 else: | |
342 self.ui.warn("patch failed, rejects left in working dir\n") | |
343 err = 1 | |
344 break | |
345 | |
346 if fuzz and strict: | |
347 self.ui.warn("fuzz found when applying patch, stopping\n") | |
348 err = 1 | |
349 break | |
350 tr.close() | |
351 os.chdir(pwd) | |
352 return (err, n) | |
353 | |
354 def delete(self, repo, patch): | |
355 patch = self.lookup(patch) | |
356 info = self.isapplied(patch) | |
357 if info: | |
358 self.ui.warn("cannot delete applied patch %s\n" % patch) | |
359 sys.exit(1) | |
360 if patch not in self.series: | |
361 self.ui.warn("patch %s not in series file\n" % patch) | |
362 sys.exit(1) | |
363 i = self.find_series(patch) | |
364 del self.full_series[i] | |
365 self.read_series(self.full_series) | |
366 self.series_dirty = 1 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
367 |
1808 | 368 def check_toppatch(self, repo): |
369 if len(self.applied) > 0: | |
370 (top, patch) = self.applied[-1].split(':') | |
371 top = revlog.bin(top) | |
372 pp = repo.dirstate.parents() | |
373 if top not in pp: | |
374 self.ui.warn("queue top not at dirstate parents. top %s dirstate %s %s\n" %( revlog.short(top), revlog.short(pp[0]), revlog.short(pp[1]))) | |
375 sys.exit(1) | |
376 return top | |
377 return None | |
378 def check_localchanges(self, repo): | |
379 (c, a, r, d, u) = repo.changes(None, None) | |
380 if c or a or d or r: | |
381 self.ui.write("Local changes found, refresh first\n") | |
382 sys.exit(1) | |
383 def new(self, repo, patch, msg=None, force=None): | |
384 if not force: | |
385 self.check_localchanges(repo) | |
386 self.check_toppatch(repo) | |
387 wlock = repo.wlock() | |
388 insert = self.series_end() | |
389 if msg: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
390 n = repo.commit([], "[mq]: %s" % msg, force=True, wlock=wlock) |
1808 | 391 else: |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
392 n = repo.commit([], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
393 "New patch: %s" % patch, force=True, wlock=wlock) |
1808 | 394 if n == None: |
395 self.ui.warn("repo commit failed\n") | |
396 sys.exit(1) | |
397 self.full_series[insert:insert] = [patch] | |
398 self.applied.append(revlog.hex(n) + ":" + patch) | |
399 self.read_series(self.full_series) | |
400 self.series_dirty = 1 | |
401 self.applied_dirty = 1 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
402 p = self.opener(patch, "w") |
1808 | 403 if msg: |
404 msg = msg + "\n" | |
405 p.write(msg) | |
406 p.close() | |
407 wlock = None | |
408 r = self.qrepo() | |
409 if r: r.add([patch]) | |
410 | |
411 def strip(self, repo, rev, update=True, backup="all", wlock=None): | |
412 def limitheads(chlog, stop): | |
413 """return the list of all nodes that have no children""" | |
414 p = {} | |
415 h = [] | |
416 stoprev = 0 | |
417 if stop in chlog.nodemap: | |
418 stoprev = chlog.rev(stop) | |
419 | |
420 for r in range(chlog.count() - 1, -1, -1): | |
421 n = chlog.node(r) | |
422 if n not in p: | |
423 h.append(n) | |
424 if n == stop: | |
425 break | |
426 if r < stoprev: | |
427 break | |
428 for pn in chlog.parents(n): | |
429 p[pn] = 1 | |
430 return h | |
431 | |
432 def bundle(cg): | |
433 backupdir = repo.join("strip-backup") | |
434 if not os.path.isdir(backupdir): | |
435 os.mkdir(backupdir) | |
436 name = os.path.join(backupdir, "%s" % revlog.short(rev)) | |
437 name = savename(name) | |
438 self.ui.warn("saving bundle to %s\n" % name) | |
439 # TODO, exclusive open | |
440 f = open(name, "wb") | |
441 try: | |
442 f.write("HG10") | |
443 z = bz2.BZ2Compressor(9) | |
444 while 1: | |
445 chunk = cg.read(4096) | |
446 if not chunk: | |
447 break | |
448 f.write(z.compress(chunk)) | |
449 f.write(z.flush()) | |
450 except: | |
451 os.unlink(name) | |
452 raise | |
453 f.close() | |
454 return name | |
455 | |
456 def stripall(rev, revnum): | |
457 cl = repo.changelog | |
458 c = cl.read(rev) | |
459 mm = repo.manifest.read(c[0]) | |
460 seen = {} | |
461 | |
462 for x in xrange(revnum, cl.count()): | |
463 c = cl.read(cl.node(x)) | |
464 for f in c[3]: | |
465 if f in seen: | |
466 continue | |
467 seen[f] = 1 | |
468 if f in mm: | |
469 filerev = mm[f] | |
470 else: | |
471 filerev = 0 | |
472 seen[f] = filerev | |
473 # we go in two steps here so the strip loop happens in a | |
474 # sensible order. When stripping many files, this helps keep | |
475 # our disk access patterns under control. | |
476 list = seen.keys() | |
477 list.sort() | |
478 for f in list: | |
479 ff = repo.file(f) | |
480 filerev = seen[f] | |
481 if filerev != 0: | |
482 if filerev in ff.nodemap: | |
483 filerev = ff.rev(filerev) | |
484 else: | |
485 filerev = 0 | |
486 ff.strip(filerev, revnum) | |
487 | |
488 if not wlock: | |
489 wlock = repo.wlock() | |
490 lock = repo.lock() | |
491 chlog = repo.changelog | |
492 # TODO delete the undo files, and handle undo of merge sets | |
493 pp = chlog.parents(rev) | |
494 revnum = chlog.rev(rev) | |
495 | |
496 if update: | |
497 urev = self.qparents(repo, rev) | |
498 repo.update(urev, allow=False, force=True, wlock=wlock) | |
499 repo.dirstate.write() | |
500 | |
501 # save is a list of all the branches we are truncating away | |
502 # that we actually want to keep. changegroup will be used | |
503 # to preserve them and add them back after the truncate | |
504 saveheads = [] | |
505 savebases = {} | |
506 | |
507 tip = chlog.tip() | |
508 heads = limitheads(chlog, rev) | |
509 seen = {} | |
510 | |
511 # search through all the heads, finding those where the revision | |
512 # we want to strip away is an ancestor. Also look for merges | |
513 # that might be turned into new heads by the strip. | |
514 while heads: | |
515 h = heads.pop() | |
516 n = h | |
517 while True: | |
518 seen[n] = 1 | |
519 pp = chlog.parents(n) | |
520 if pp[1] != revlog.nullid and chlog.rev(pp[1]) > revnum: | |
521 if pp[1] not in seen: | |
522 heads.append(pp[1]) | |
523 if pp[0] == revlog.nullid: | |
524 break | |
525 if chlog.rev(pp[0]) < revnum: | |
526 break | |
527 n = pp[0] | |
528 if n == rev: | |
529 break | |
530 r = chlog.reachable(h, rev) | |
531 if rev not in r: | |
532 saveheads.append(h) | |
533 for x in r: | |
534 if chlog.rev(x) > revnum: | |
535 savebases[x] = 1 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
536 |
1808 | 537 # create a changegroup for all the branches we need to keep |
538 if backup is "all": | |
539 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') | |
540 bundle(backupch) | |
541 if saveheads: | |
542 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip') | |
543 chgrpfile = bundle(backupch) | |
544 | |
545 stripall(rev, revnum) | |
546 | |
547 change = chlog.read(rev) | |
548 repo.manifest.strip(repo.manifest.rev(change[0]), revnum) | |
549 chlog.strip(revnum, revnum) | |
550 if saveheads: | |
551 self.ui.status("adding branch\n") | |
552 commands.unbundle(self.ui, repo, chgrpfile, update=False) | |
553 if backup is not "strip": | |
554 os.unlink(chgrpfile) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
555 |
1808 | 556 def isapplied(self, patch): |
557 """returns (index, rev, patch)""" | |
558 for i in xrange(len(self.applied)): | |
559 p = self.applied[i] | |
560 a = p.split(':') | |
561 if a[1] == patch: | |
562 return (i, a[0], a[1]) | |
563 return None | |
564 | |
565 def lookup(self, patch): | |
566 if patch == None: | |
567 return None | |
568 if patch in self.series: | |
569 return patch | |
570 if not os.path.isfile(os.path.join(self.path, patch)): | |
571 try: | |
572 sno = int(patch) | |
573 except(ValueError, OverflowError): | |
574 self.ui.warn("patch %s not in series\n" % patch) | |
575 sys.exit(1) | |
576 if sno >= len(self.series): | |
577 self.ui.warn("patch number %d is out of range\n" % sno) | |
578 sys.exit(1) | |
579 patch = self.series[sno] | |
580 else: | |
581 self.ui.warn("patch %s not in series\n" % patch) | |
582 sys.exit(1) | |
583 return patch | |
584 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
585 def push(self, repo, patch=None, force=False, list=False, |
1808 | 586 mergeq=None, wlock=None): |
587 if not wlock: | |
588 wlock = repo.wlock() | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
589 patch = self.lookup(patch) |
1808 | 590 if patch and self.isapplied(patch): |
591 self.ui.warn("patch %s is already applied\n" % patch) | |
592 sys.exit(1) | |
593 if self.series_end() == len(self.series): | |
594 self.ui.warn("File series fully applied\n") | |
595 sys.exit(1) | |
596 if not force: | |
597 self.check_localchanges(repo) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
598 |
1808 | 599 self.applied_dirty = 1; |
600 start = self.series_end() | |
601 if start > 0: | |
602 self.check_toppatch(repo) | |
603 if not patch: | |
604 patch = self.series[start] | |
605 end = start + 1 | |
606 else: | |
607 end = self.series.index(patch, start) + 1 | |
608 s = self.series[start:end] | |
609 if mergeq: | |
610 ret = self.mergepatch(repo, mergeq, s, wlock) | |
611 else: | |
612 ret = self.apply(repo, s, list, wlock=wlock) | |
613 top = self.applied[-1].split(':')[1] | |
614 if ret[0]: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
615 self.ui.write("Errors during apply, please fix and refresh %s\n" % |
1808 | 616 top) |
617 else: | |
618 self.ui.write("Now at: %s\n" % top) | |
619 return ret[0] | |
620 | |
621 def pop(self, repo, patch=None, force=False, update=True, wlock=None): | |
622 def getfile(f, rev): | |
623 t = repo.file(f).read(rev) | |
624 try: | |
625 repo.wfile(f, "w").write(t) | |
626 except IOError: | |
627 os.makedirs(os.path.dirname(repo.wjoin(f))) | |
628 repo.wfile(f, "w").write(t) | |
629 | |
630 if not wlock: | |
631 wlock = repo.wlock() | |
632 if patch: | |
633 # index, rev, patch | |
634 info = self.isapplied(patch) | |
635 if not info: | |
636 patch = self.lookup(patch) | |
637 info = self.isapplied(patch) | |
638 if not info: | |
639 self.ui.warn("patch %s is not applied\n" % patch) | |
640 sys.exit(1) | |
641 if len(self.applied) == 0: | |
642 self.ui.warn("No patches applied\n") | |
643 sys.exit(1) | |
644 | |
645 if not update: | |
646 parents = repo.dirstate.parents() | |
647 rr = [ revlog.bin(x.split(':')[0]) for x in self.applied ] | |
648 for p in parents: | |
649 if p in rr: | |
650 self.ui.warn("qpop: forcing dirstate update\n") | |
651 update = True | |
652 | |
653 if not force and update: | |
654 self.check_localchanges(repo) | |
655 | |
656 self.applied_dirty = 1; | |
657 end = len(self.applied) | |
658 if not patch: | |
659 info = [len(self.applied) - 1] + self.applied[-1].split(':') | |
660 start = info[0] | |
661 rev = revlog.bin(info[1]) | |
662 | |
663 # we know there are no local changes, so we can make a simplified | |
664 # form of hg.update. | |
665 if update: | |
666 top = self.check_toppatch(repo) | |
667 qp = self.qparents(repo, rev) | |
668 changes = repo.changelog.read(qp) | |
669 mf1 = repo.manifest.readflags(changes[0]) | |
670 mmap = repo.manifest.read(changes[0]) | |
671 (c, a, r, d, u) = repo.changes(qp, top) | |
672 if d: | |
673 raise util.Abort("deletions found between repo revs") | |
674 for f in c: | |
675 getfile(f, mmap[f]) | |
676 for f in r: | |
677 getfile(f, mmap[f]) | |
678 util.set_exec(repo.wjoin(f), mf1[f]) | |
679 repo.dirstate.update(c + r, 'n') | |
680 for f in a: | |
681 try: os.unlink(repo.wjoin(f)) | |
682 except: raise | |
683 try: os.removedirs(os.path.dirname(repo.wjoin(f))) | |
684 except: pass | |
685 if a: | |
686 repo.dirstate.forget(a) | |
687 repo.dirstate.setparents(qp, revlog.nullid) | |
688 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) | |
689 del self.applied[start:end] | |
690 if len(self.applied): | |
691 self.ui.write("Now at: %s\n" % self.applied[-1].split(':')[1]) | |
692 else: | |
693 self.ui.write("Patch queue now empty\n") | |
694 | |
695 def diff(self, repo, files): | |
696 top = self.check_toppatch(repo) | |
697 if not top: | |
698 self.ui.write("No patches applied\n") | |
699 return | |
700 qp = self.qparents(repo, top) | |
701 commands.dodiff(sys.stdout, self.ui, repo, qp, None, files) | |
702 | |
703 def refresh(self, repo, short=False): | |
704 if len(self.applied) == 0: | |
705 self.ui.write("No patches applied\n") | |
706 return | |
707 wlock = repo.wlock() | |
708 self.check_toppatch(repo) | |
709 qp = self.qparents(repo) | |
710 (top, patch) = self.applied[-1].split(':') | |
711 top = revlog.bin(top) | |
712 cparents = repo.changelog.parents(top) | |
713 patchparent = self.qparents(repo, top) | |
714 message, comments, user, patchfound = self.readheaders(patch) | |
715 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
716 patchf = self.opener(patch, "w") |
1808 | 717 if comments: |
718 comments = "\n".join(comments) + '\n\n' | |
719 patchf.write(comments) | |
720 | |
721 tip = repo.changelog.tip() | |
722 if top == tip: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
723 # if the top of our patch queue is also the tip, there is an |
1808 | 724 # optimization here. We update the dirstate in place and strip |
725 # off the tip commit. Then just commit the current directory | |
726 # tree. We can also send repo.commit the list of files | |
727 # changed to speed up the diff | |
728 # | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
729 # in short mode, we only diff the files included in the |
1808 | 730 # patch already |
731 # | |
732 # this should really read: | |
733 #(cc, dd, aa, aa2, uu) = repo.changes(tip, patchparent) | |
734 # but we do it backwards to take advantage of manifest/chlog | |
735 # caching against the next repo.changes call | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
736 # |
1808 | 737 (cc, aa, dd, aa2, uu) = repo.changes(patchparent, tip) |
738 if short: | |
739 filelist = cc + aa + dd | |
740 else: | |
741 filelist = None | |
742 (c, a, r, d, u) = repo.changes(None, None, filelist) | |
743 | |
744 # we might end up with files that were added between tip and | |
745 # the dirstate parent, but then changed in the local dirstate. | |
746 # in this case, we want them to only show up in the added section | |
747 for x in c: | |
748 if x not in aa: | |
749 cc.append(x) | |
750 # we might end up with files added by the local dirstate that | |
751 # were deleted by the patch. In this case, they should only | |
752 # show up in the changed section. | |
753 for x in a: | |
754 if x in dd: | |
755 del dd[dd.index(x)] | |
756 cc.append(x) | |
757 else: | |
758 aa.append(x) | |
759 # make sure any files deleted in the local dirstate | |
760 # are not in the add or change column of the patch | |
761 forget = [] | |
762 for x in d + r: | |
763 if x in aa: | |
764 del aa[aa.index(x)] | |
765 forget.append(x) | |
766 continue | |
767 elif x in cc: | |
768 del cc[cc.index(x)] | |
769 dd.append(x) | |
770 | |
771 c = list(util.unique(cc)) | |
772 r = list(util.unique(dd)) | |
773 a = list(util.unique(aa)) | |
774 filelist = list(util.unique(c + r + a )) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
775 commands.dodiff(patchf, self.ui, repo, patchparent, None, |
1808 | 776 filelist, changes=(c, a, r, [], u)) |
777 patchf.close() | |
778 | |
779 changes = repo.changelog.read(tip) | |
780 repo.dirstate.setparents(*cparents) | |
781 repo.dirstate.update(a, 'a') | |
782 repo.dirstate.update(r, 'r') | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
783 repo.dirstate.update(c, 'n') |
1808 | 784 repo.dirstate.forget(forget) |
785 | |
786 if not message: | |
787 message = "patch queue: %s\n" % patch | |
788 else: | |
789 message = "\n".join(message) | |
790 self.strip(repo, top, update=False, backup='strip', wlock=wlock) | |
791 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) | |
792 self.applied[-1] = revlog.hex(n) + ':' + patch | |
793 self.applied_dirty = 1 | |
794 else: | |
795 commands.dodiff(patchf, self.ui, repo, patchparent, None) | |
796 patchf.close() | |
797 self.pop(repo, force=True, wlock=wlock) | |
798 self.push(repo, force=True, wlock=wlock) | |
799 | |
800 def init(self, repo, create=False): | |
801 if os.path.isdir(self.path): | |
802 raise util.Abort("patch queue directory already exists") | |
803 os.mkdir(self.path) | |
804 if create: | |
805 return self.qrepo(create=True) | |
806 | |
807 def unapplied(self, repo, patch=None): | |
808 if patch and patch not in self.series: | |
809 self.ui.warn("%s not in the series file\n" % patch) | |
810 sys.exit(1) | |
811 if not patch: | |
812 start = self.series_end() | |
813 else: | |
814 start = self.series.index(patch) + 1 | |
815 for p in self.series[start:]: | |
816 self.ui.write("%s\n" % p) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
817 |
1808 | 818 def qseries(self, repo, missing=None): |
819 start = self.series_end() | |
820 if not missing: | |
821 for p in self.series[:start]: | |
822 if self.ui.verbose: | |
823 self.ui.write("%d A " % self.series.index(p)) | |
824 self.ui.write("%s\n" % p) | |
825 for p in self.series[start:]: | |
826 if self.ui.verbose: | |
827 self.ui.write("%d U " % self.series.index(p)) | |
828 self.ui.write("%s\n" % p) | |
829 else: | |
830 list = [] | |
831 for root, dirs, files in os.walk(self.path): | |
832 d = root[len(self.path) + 1:] | |
833 for f in files: | |
834 fl = os.path.join(d, f) | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
835 if (fl not in self.series and |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
836 fl not in (self.status_path, self.series_path) |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
837 and not fl.startswith('.')): |
1808 | 838 list.append(fl) |
839 list.sort() | |
840 if list: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
841 for x in list: |
1808 | 842 if self.ui.verbose: |
843 self.ui.write("D ") | |
844 self.ui.write("%s\n" % x) | |
845 | |
846 def issaveline(self, l): | |
847 name = l.split(':')[1] | |
848 if name == '.hg.patches.save.line': | |
849 return True | |
850 | |
851 def qrepo(self, create=False): | |
852 if create or os.path.isdir(os.path.join(self.path, ".hg")): | |
1839
876e4e6ad82b
Create local ui object per repository, so .hg/hgrc don't get mixed.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1810
diff
changeset
|
853 return hg.repository(self.ui, path=self.path, create=create) |
1808 | 854 |
855 def restore(self, repo, rev, delete=None, qupdate=None): | |
856 c = repo.changelog.read(rev) | |
857 desc = c[4].strip() | |
858 lines = desc.splitlines() | |
859 i = 0 | |
860 datastart = None | |
861 series = [] | |
862 applied = [] | |
863 qpp = None | |
864 for i in xrange(0, len(lines)): | |
865 if lines[i] == 'Patch Data:': | |
866 datastart = i + 1 | |
867 elif lines[i].startswith('Dirstate:'): | |
868 l = lines[i].rstrip() | |
869 l = l[10:].split(' ') | |
870 qpp = [ hg.bin(x) for x in l ] | |
871 elif datastart != None: | |
872 l = lines[i].rstrip() | |
873 index = l.index(':') | |
874 id = l[:index] | |
875 file = l[index + 1:] | |
876 if id: | |
877 applied.append(l) | |
878 series.append(file) | |
879 if datastart == None: | |
880 self.ui.warn("No saved patch data found\n") | |
881 return 1 | |
882 self.ui.warn("restoring status: %s\n" % lines[0]) | |
883 self.full_series = series | |
884 self.applied = applied | |
885 self.read_series(self.full_series) | |
886 self.series_dirty = 1 | |
887 self.applied_dirty = 1 | |
888 heads = repo.changelog.heads() | |
889 if delete: | |
890 if rev not in heads: | |
891 self.ui.warn("save entry has children, leaving it alone\n") | |
892 else: | |
893 self.ui.warn("removing save entry %s\n" % hg.short(rev)) | |
894 pp = repo.dirstate.parents() | |
895 if rev in pp: | |
896 update = True | |
897 else: | |
898 update = False | |
899 self.strip(repo, rev, update=update, backup='strip') | |
900 if qpp: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
901 self.ui.warn("saved queue repository parents: %s %s\n" % |
1808 | 902 (hg.short(qpp[0]), hg.short(qpp[1]))) |
903 if qupdate: | |
904 print "queue directory updating" | |
905 r = self.qrepo() | |
906 if not r: | |
907 self.ui.warn("Unable to load queue repository\n") | |
908 return 1 | |
909 r.update(qpp[0], allow=False, force=True) | |
910 | |
911 def save(self, repo, msg=None): | |
912 if len(self.applied) == 0: | |
913 self.ui.warn("save: no patches applied, exiting\n") | |
914 return 1 | |
915 if self.issaveline(self.applied[-1]): | |
916 self.ui.warn("status is already saved\n") | |
917 return 1 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
918 |
1808 | 919 ar = [ ':' + x for x in self.full_series ] |
920 if not msg: | |
921 msg = "hg patches saved state" | |
922 else: | |
923 msg = "hg patches: " + msg.rstrip('\r\n') | |
924 r = self.qrepo() | |
925 if r: | |
926 pp = r.dirstate.parents() | |
927 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) | |
928 msg += "\n\nPatch Data:\n" | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
929 text = msg + "\n".join(self.applied) + '\n' + (ar and "\n".join(ar) |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
930 + '\n' or "") |
1808 | 931 n = repo.commit(None, text, user=None, force=1) |
932 if not n: | |
933 self.ui.warn("repo commit failed\n") | |
934 return 1 | |
935 self.applied.append(revlog.hex(n) + ":" + '.hg.patches.save.line') | |
936 self.applied_dirty = 1 | |
937 | |
938 def series_end(self): | |
939 end = 0 | |
940 if len(self.applied) > 0: | |
941 (top, p) = self.applied[-1].split(':') | |
942 try: | |
943 end = self.series.index(p) | |
944 except ValueError: | |
945 return 0 | |
946 return end + 1 | |
947 return end | |
948 | |
949 def qapplied(self, repo, patch=None): | |
950 if patch and patch not in self.series: | |
951 self.ui.warn("%s not in the series file\n" % patch) | |
952 sys.exit(1) | |
953 if not patch: | |
954 end = len(self.applied) | |
955 else: | |
956 end = self.series.index(patch) + 1 | |
957 for x in xrange(end): | |
958 p = self.appliedname(x) | |
959 self.ui.write("%s\n" % p) | |
960 | |
961 def appliedname(self, index): | |
962 p = self.applied[index] | |
963 if not self.ui.verbose: | |
964 p = p.split(':')[1] | |
965 return p | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
966 |
1808 | 967 def top(self, repo): |
968 if len(self.applied): | |
969 p = self.appliedname(-1) | |
970 self.ui.write(p + '\n') | |
971 else: | |
972 self.ui.write("No patches applied\n") | |
973 | |
974 def next(self, repo): | |
975 end = self.series_end() | |
976 if end == len(self.series): | |
977 self.ui.write("All patches applied\n") | |
978 else: | |
979 self.ui.write(self.series[end] + '\n') | |
980 | |
981 def prev(self, repo): | |
982 if len(self.applied) > 1: | |
983 p = self.appliedname(-2) | |
984 self.ui.write(p + '\n') | |
985 elif len(self.applied) == 1: | |
986 self.ui.write("Only one patch applied\n") | |
987 else: | |
988 self.ui.write("No patches applied\n") | |
989 | |
990 def qimport(self, repo, files, patch=None, existing=None, force=None): | |
991 if len(files) > 1 and patch: | |
992 self.ui.warn("-n option not valid when importing multiple files\n") | |
993 sys.exit(1) | |
994 i = 0 | |
995 for filename in files: | |
996 if existing: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
997 if not patch: |
1808 | 998 patch = filename |
999 if not os.path.isfile(os.path.join(self.path, patch)): | |
1000 self.ui.warn("patch %s does not exist\n" % patch) | |
1001 sys.exit(1) | |
1002 else: | |
1003 try: | |
1004 text = file(filename).read() | |
1005 except IOError: | |
1006 self.ui.warn("Unable to read %s\n" % patch) | |
1007 sys.exit(1) | |
1008 if not patch: | |
1009 patch = os.path.split(filename)[1] | |
1010 if not force and os.path.isfile(os.path.join(self.path, patch)): | |
1011 self.ui.warn("patch %s already exists\n" % patch) | |
1012 sys.exit(1) | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
1013 patchf = self.opener(patch, "w") |
1808 | 1014 patchf.write(text) |
1015 if patch in self.series: | |
1016 self.ui.warn("patch %s is already in the series file\n" % patch) | |
1017 sys.exit(1) | |
1018 index = self.series_end() + i | |
1019 self.full_series[index:index] = [patch] | |
1020 self.read_series(self.full_series) | |
1021 self.ui.warn("adding %s to series file\n" % patch) | |
1022 i += 1 | |
1023 patch = None | |
1024 self.series_dirty = 1 | |
1025 | |
1026 def delete(ui, repo, patch, **opts): | |
1027 """remove a patch from the series file""" | |
1028 q = repomap[repo] | |
1029 q.delete(repo, patch) | |
1030 q.save_dirty() | |
1031 return 0 | |
1032 | |
1033 def applied(ui, repo, patch=None, **opts): | |
1034 """print the patches already applied""" | |
1035 repomap[repo].qapplied(repo, patch) | |
1036 return 0 | |
1037 | |
1038 def unapplied(ui, repo, patch=None, **opts): | |
1039 """print the patches not yet applied""" | |
1040 repomap[repo].unapplied(repo, patch) | |
1041 return 0 | |
1042 | |
1043 def qimport(ui, repo, *filename, **opts): | |
1044 """import a patch""" | |
1045 q = repomap[repo] | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1046 q.qimport(repo, filename, patch=opts['name'], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1047 existing=opts['existing'], force=opts['force']) |
1808 | 1048 q.save_dirty() |
1049 return 0 | |
1050 | |
1051 def init(ui, repo, **opts): | |
1052 """init a new queue repository""" | |
1053 q = repomap[repo] | |
1054 r = q.init(repo, create=opts['create_repo']) | |
1055 q.save_dirty() | |
1056 if r: | |
1057 fp = r.wopener('.hgignore', 'w') | |
1058 print >> fp, 'syntax: glob' | |
1059 print >> fp, 'status' | |
1060 fp.close() | |
1061 r.wopener('series', 'w').close() | |
1062 r.add(['.hgignore', 'series']) | |
1063 return 0 | |
1064 | |
1065 def commit(ui, repo, *pats, **opts): | |
1066 q = repomap[repo] | |
1067 r = q.qrepo() | |
1068 if not r: raise util.Abort('no queue repository') | |
1069 commands.commit(r.ui, r, *pats, **opts) | |
1070 | |
1071 def series(ui, repo, **opts): | |
1072 """print the entire series file""" | |
1073 repomap[repo].qseries(repo, missing=opts['missing']) | |
1074 return 0 | |
1075 | |
1076 def top(ui, repo, **opts): | |
1077 """print the name of the current patch""" | |
1078 repomap[repo].top(repo) | |
1079 return 0 | |
1080 | |
1081 def next(ui, repo, **opts): | |
1082 """print the name of the next patch""" | |
1083 repomap[repo].next(repo) | |
1084 return 0 | |
1085 | |
1086 def prev(ui, repo, **opts): | |
1087 """print the name of the previous patch""" | |
1088 repomap[repo].prev(repo) | |
1089 return 0 | |
1090 | |
1091 def new(ui, repo, patch, **opts): | |
1092 """create a new patch""" | |
1093 q = repomap[repo] | |
1094 q.new(repo, patch, msg=opts['message'], force=opts['force']) | |
1095 q.save_dirty() | |
1096 return 0 | |
1097 | |
1098 def refresh(ui, repo, **opts): | |
1099 """update the current patch""" | |
1100 q = repomap[repo] | |
1101 q.refresh(repo, short=opts['short']) | |
1102 q.save_dirty() | |
1103 return 0 | |
1104 | |
1105 def diff(ui, repo, *files, **opts): | |
1106 """diff of the current patch""" | |
1107 repomap[repo].diff(repo, files) | |
1108 return 0 | |
1109 | |
1110 def lastsavename(path): | |
1111 (dir, base) = os.path.split(path) | |
1112 names = os.listdir(dir) | |
1113 namere = re.compile("%s.([0-9]+)" % base) | |
1114 max = None | |
1115 maxname = None | |
1116 for f in names: | |
1117 m = namere.match(f) | |
1118 if m: | |
1119 index = int(m.group(1)) | |
1120 if max == None or index > max: | |
1121 max = index | |
1122 maxname = f | |
1123 if maxname: | |
1124 return (os.path.join(dir, maxname), max) | |
1125 return (None, None) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1126 |
1808 | 1127 def savename(path): |
1128 (last, index) = lastsavename(path) | |
1129 if last is None: | |
1130 index = 0 | |
1131 newpath = path + ".%d" % (index + 1) | |
1132 return newpath | |
1133 | |
1134 def push(ui, repo, patch=None, **opts): | |
1135 """push the next patch onto the stack""" | |
1136 q = repomap[repo] | |
1137 mergeq = None | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1138 |
1808 | 1139 if opts['all']: |
1140 patch = q.series[-1] | |
1141 if opts['merge']: | |
1142 if opts['name']: | |
1143 newpath = opts['name'] | |
1144 else: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1145 newpath, i = lastsavename(q.path) |
1808 | 1146 if not newpath: |
1147 ui.warn("no saved queues found, please use -n\n") | |
1148 return 1 | |
1149 mergeq = queue(ui, repo.join(""), newpath) | |
1150 ui.warn("merging with queue at: %s\n" % mergeq.path) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1151 ret = q.push(repo, patch, force=opts['force'], list=opts['list'], |
1808 | 1152 mergeq=mergeq) |
1153 q.save_dirty() | |
1154 return ret | |
1155 | |
1156 def pop(ui, repo, patch=None, **opts): | |
1157 """pop the current patch off the stack""" | |
1158 localupdate = True | |
1159 if opts['name']: | |
1160 q = queue(ui, repo.join(""), repo.join(opts['name'])) | |
1161 ui.warn('using patch queue: %s\n' % q.path) | |
1162 localupdate = False | |
1163 else: | |
1164 q = repomap[repo] | |
1165 if opts['all'] and len(q.applied) > 0: | |
1166 patch = q.applied[0].split(':')[1] | |
1167 q.pop(repo, patch, force=opts['force'], update=localupdate) | |
1168 q.save_dirty() | |
1169 return 0 | |
1170 | |
1171 def restore(ui, repo, rev, **opts): | |
1172 """restore the queue state saved by a rev""" | |
1173 rev = repo.lookup(rev) | |
1174 q = repomap[repo] | |
1175 q.restore(repo, rev, delete=opts['delete'], | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1176 qupdate=opts['update']) |
1808 | 1177 q.save_dirty() |
1178 return 0 | |
1179 | |
1180 def save(ui, repo, **opts): | |
1181 """save current queue state""" | |
1182 q = repomap[repo] | |
1183 ret = q.save(repo, msg=opts['message']) | |
1184 if ret: | |
1185 return ret | |
1186 q.save_dirty() | |
1187 if opts['copy']: | |
1188 path = q.path | |
1189 if opts['name']: | |
1190 newpath = os.path.join(q.basepath, opts['name']) | |
1191 if os.path.exists(newpath): | |
1192 if not os.path.isdir(newpath): | |
1193 ui.warn("destination %s exists and is not a directory\n" % | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1194 newpath) |
1808 | 1195 sys.exit(1) |
1196 if not opts['force']: | |
1197 ui.warn("destination %s exists, use -f to force\n" % | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1198 newpath) |
1808 | 1199 sys.exit(1) |
1200 else: | |
1201 newpath = savename(path) | |
1202 ui.warn("copy %s to %s\n" % (path, newpath)) | |
1203 util.copyfiles(path, newpath) | |
1204 if opts['empty']: | |
1205 try: | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
1206 os.unlink(os.path.join(q.path, q.status_path)) |
1808 | 1207 except: |
1208 pass | |
1209 return 0 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1210 |
1808 | 1211 def strip(ui, repo, rev, **opts): |
1212 """strip a revision and all later revs on the same branch""" | |
1213 rev = repo.lookup(rev) | |
1214 backup = 'all' | |
1215 if opts['backup']: | |
1216 backup = 'strip' | |
1217 elif opts['nobackup']: | |
1218 backup = 'none' | |
1219 repomap[repo].strip(repo, rev, backup=backup) | |
1220 return 0 | |
1221 | |
1222 def version(ui, q=None): | |
1223 """print the version number""" | |
1224 ui.write("mq version %s\n" % versionstr) | |
1225 return 0 | |
1226 | |
1227 def reposetup(ui, repo): | |
1228 repomap[repo] = queue(ui, repo.join("")) | |
1229 | |
1230 cmdtable = { | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1231 "qapplied": (applied, [], 'hg qapplied [patch]'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1232 "qcommit|qci": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1233 (commit, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1234 [('A', 'addremove', None, _('run addremove during commit')), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1235 ('I', 'include', [], _('include names matching the given patterns')), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1236 ('X', 'exclude', [], _('exclude names matching the given patterns')), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1237 ('m', 'message', '', _('use <text> as commit message')), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1238 ('l', 'logfile', '', _('read the commit message from <file>')), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1239 ('d', 'date', '', _('record datecode as commit date')), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1240 ('u', 'user', '', _('record user as commiter'))], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1241 'hg qcommit [options] [files]'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1242 "^qdiff": (diff, [], 'hg qdiff [files]'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1243 "qdelete": (delete, [], 'hg qdelete [patch]'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1244 "^qimport": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1245 (qimport, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1246 [('e', 'existing', None, 'import file in patch dir'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1247 ('n', 'name', '', 'patch file name'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1248 ('f', 'force', None, 'overwrite existing files')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1249 'hg qimport'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1250 "^qinit": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1251 (init, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1252 [('c', 'create-repo', None, 'create patch repository')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1253 'hg [-c] qinit'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1254 "qnew": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1255 (new, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1256 [('m', 'message', '', 'commit message'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1257 ('f', 'force', None, 'force')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1258 'hg qnew [-m message ] patch'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1259 "qnext": (next, [], 'hg qnext'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1260 "qprev": (prev, [], 'hg qprev'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1261 "^qpop": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1262 (pop, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1263 [('a', 'all', None, 'pop all patches'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1264 ('n', 'name', '', 'queue name to pop'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1265 ('f', 'force', None, 'forget any local changes')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1266 'hg qpop [options] [patch/index]'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1267 "^qpush": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1268 (push, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1269 [('f', 'force', None, 'apply if the patch has rejects'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1270 ('l', 'list', None, 'list patch name in commit text'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1271 ('a', 'all', None, 'apply all patches'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1272 ('m', 'merge', None, 'merge from another queue'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1273 ('n', 'name', '', 'merge queue name')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1274 'hg qpush [options] [patch/index]'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1275 "^qrefresh": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1276 (refresh, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1277 [('s', 'short', None, 'short refresh')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1278 'hg qrefresh'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1279 "qrestore": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1280 (restore, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1281 [('d', 'delete', None, 'delete save entry'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1282 ('u', 'update', None, 'update queue working dir')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1283 'hg qrestore rev'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1284 "qsave": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1285 (save, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1286 [('m', 'message', '', 'commit message'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1287 ('c', 'copy', None, 'copy patch directory'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1288 ('n', 'name', '', 'copy directory name'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1289 ('e', 'empty', None, 'clear queue status file'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1290 ('f', 'force', None, 'force copy')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1291 'hg qsave'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1292 "qseries": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1293 (series, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1294 [('m', 'missing', None, 'print patches not in series')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1295 'hg qseries'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1296 "^strip": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1297 (strip, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1298 [('f', 'force', None, 'force multi-head removal'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1299 ('b', 'backup', None, 'bundle unrelated changesets'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1300 ('n', 'nobackup', None, 'no backups')], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1301 'hg strip rev'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1302 "qtop": (top, [], 'hg qtop'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1303 "qunapplied": (unapplied, [], 'hg qunapplied [patch]'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1304 "qversion": (version, [], 'hg qversion') |
1808 | 1305 } |
1306 |