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