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