##// END OF EJS Templates
mq: correctly make an empty line after description in new patches...
Mads Kiilerich -
r22519:c87f2a5a default
parent child Browse files
Show More
@@ -1,3483 +1,3483 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 or any later version.
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 create new patch qnew
20 20 import existing patch qimport
21 21
22 22 print patch series qseries
23 23 print applied patches qapplied
24 24
25 25 add known patch to applied stack qpush
26 26 remove patch from applied stack qpop
27 27 refresh contents of top applied patch qrefresh
28 28
29 29 By default, mq will automatically use git patches when required to
30 30 avoid losing file mode changes, copy records, binary files or empty
31 31 files creations or deletions. This behaviour can be configured with::
32 32
33 33 [mq]
34 34 git = auto/keep/yes/no
35 35
36 36 If set to 'keep', mq will obey the [diff] section configuration while
37 37 preserving existing git patches upon qrefresh. If set to 'yes' or
38 38 'no', mq will override the [diff] section and always generate git or
39 39 regular patches, possibly losing data in the second case.
40 40
41 41 It may be desirable for mq changesets to be kept in the secret phase (see
42 42 :hg:`help phases`), which can be enabled with the following setting::
43 43
44 44 [mq]
45 45 secret = True
46 46
47 47 You will by default be managing a patch queue named "patches". You can
48 48 create other, independent patch queues with the :hg:`qqueue` command.
49 49
50 50 If the working directory contains uncommitted files, qpush, qpop and
51 51 qgoto abort immediately. If -f/--force is used, the changes are
52 52 discarded. Setting::
53 53
54 54 [mq]
55 55 keepchanges = True
56 56
57 57 make them behave as if --keep-changes were passed, and non-conflicting
58 58 local changes will be tolerated and preserved. If incompatible options
59 59 such as -f/--force or --exact are passed, this setting is ignored.
60 60
61 61 This extension used to provide a strip command. This command now lives
62 62 in the strip extension.
63 63 '''
64 64
65 65 from mercurial.i18n import _
66 66 from mercurial.node import bin, hex, short, nullid, nullrev
67 67 from mercurial.lock import release
68 68 from mercurial import commands, cmdutil, hg, scmutil, util, revset
69 69 from mercurial import extensions, error, phases
70 70 from mercurial import patch as patchmod
71 71 from mercurial import localrepo
72 72 from mercurial import subrepo
73 73 import os, re, errno, shutil
74 74
75 75 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
76 76
77 77 cmdtable = {}
78 78 command = cmdutil.command(cmdtable)
79 79 testedwith = 'internal'
80 80
81 81 # force load strip extension formerly included in mq and import some utility
82 82 try:
83 83 stripext = extensions.find('strip')
84 84 except KeyError:
85 85 # note: load is lazy so we could avoid the try-except,
86 86 # but I (marmoute) prefer this explicit code.
87 87 class dummyui(object):
88 88 def debug(self, msg):
89 89 pass
90 90 stripext = extensions.load(dummyui(), 'strip', '')
91 91
92 92 strip = stripext.strip
93 93 checksubstate = stripext.checksubstate
94 94 checklocalchanges = stripext.checklocalchanges
95 95
96 96
97 97 # Patch names looks like unix-file names.
98 98 # They must be joinable with queue directory and result in the patch path.
99 99 normname = util.normpath
100 100
101 101 class statusentry(object):
102 102 def __init__(self, node, name):
103 103 self.node, self.name = node, name
104 104 def __repr__(self):
105 105 return hex(self.node) + ':' + self.name
106 106
107 107 class patchheader(object):
108 108 def __init__(self, pf, plainmode=False):
109 109 def eatdiff(lines):
110 110 while lines:
111 111 l = lines[-1]
112 112 if (l.startswith("diff -") or
113 113 l.startswith("Index:") or
114 114 l.startswith("===========")):
115 115 del lines[-1]
116 116 else:
117 117 break
118 118 def eatempty(lines):
119 119 while lines:
120 120 if not lines[-1].strip():
121 121 del lines[-1]
122 122 else:
123 123 break
124 124
125 125 message = []
126 126 comments = []
127 127 user = None
128 128 date = None
129 129 parent = None
130 130 format = None
131 131 subject = None
132 132 branch = None
133 133 nodeid = None
134 134 diffstart = 0
135 135
136 136 for line in file(pf):
137 137 line = line.rstrip()
138 138 if (line.startswith('diff --git')
139 139 or (diffstart and line.startswith('+++ '))):
140 140 diffstart = 2
141 141 break
142 142 diffstart = 0 # reset
143 143 if line.startswith("--- "):
144 144 diffstart = 1
145 145 continue
146 146 elif format == "hgpatch":
147 147 # parse values when importing the result of an hg export
148 148 if line.startswith("# User "):
149 149 user = line[7:]
150 150 elif line.startswith("# Date "):
151 151 date = line[7:]
152 152 elif line.startswith("# Parent "):
153 153 parent = line[9:].lstrip()
154 154 elif line.startswith("# Branch "):
155 155 branch = line[9:]
156 156 elif line.startswith("# Node ID "):
157 157 nodeid = line[10:]
158 158 elif not line.startswith("# ") and line:
159 159 message.append(line)
160 160 format = None
161 161 elif line == '# HG changeset patch':
162 162 message = []
163 163 format = "hgpatch"
164 164 elif (format != "tagdone" and (line.startswith("Subject: ") or
165 165 line.startswith("subject: "))):
166 166 subject = line[9:]
167 167 format = "tag"
168 168 elif (format != "tagdone" and (line.startswith("From: ") or
169 169 line.startswith("from: "))):
170 170 user = line[6:]
171 171 format = "tag"
172 172 elif (format != "tagdone" and (line.startswith("Date: ") or
173 173 line.startswith("date: "))):
174 174 date = line[6:]
175 175 format = "tag"
176 176 elif format == "tag" and line == "":
177 177 # when looking for tags (subject: from: etc) they
178 178 # end once you find a blank line in the source
179 179 format = "tagdone"
180 180 elif message or line:
181 181 message.append(line)
182 182 comments.append(line)
183 183
184 184 eatdiff(message)
185 185 eatdiff(comments)
186 186 # Remember the exact starting line of the patch diffs before consuming
187 187 # empty lines, for external use by TortoiseHg and others
188 188 self.diffstartline = len(comments)
189 189 eatempty(message)
190 190 eatempty(comments)
191 191
192 192 # make sure message isn't empty
193 193 if format and format.startswith("tag") and subject:
194 194 message.insert(0, "")
195 195 message.insert(0, subject)
196 196
197 197 self.message = message
198 198 self.comments = comments
199 199 self.user = user
200 200 self.date = date
201 201 self.parent = parent
202 202 # nodeid and branch are for external use by TortoiseHg and others
203 203 self.nodeid = nodeid
204 204 self.branch = branch
205 205 self.haspatch = diffstart > 1
206 206 self.plainmode = plainmode
207 207
208 208 def setuser(self, user):
209 209 if not self.updateheader(['From: ', '# User '], user):
210 210 try:
211 211 patchheaderat = self.comments.index('# HG changeset patch')
212 212 self.comments.insert(patchheaderat + 1, '# User ' + user)
213 213 except ValueError:
214 214 if self.plainmode or self._hasheader(['Date: ']):
215 215 self.comments = ['From: ' + user] + self.comments
216 216 else:
217 217 tmp = ['# HG changeset patch', '# User ' + user, '']
218 218 self.comments = tmp + self.comments
219 219 self.user = user
220 220
221 221 def setdate(self, date):
222 222 if not self.updateheader(['Date: ', '# Date '], date):
223 223 try:
224 224 patchheaderat = self.comments.index('# HG changeset patch')
225 225 self.comments.insert(patchheaderat + 1, '# Date ' + date)
226 226 except ValueError:
227 227 if self.plainmode or self._hasheader(['From: ']):
228 228 self.comments = ['Date: ' + date] + self.comments
229 229 else:
230 230 tmp = ['# HG changeset patch', '# Date ' + date, '']
231 231 self.comments = tmp + self.comments
232 232 self.date = date
233 233
234 234 def setparent(self, parent):
235 235 if not self.updateheader(['# Parent '], parent):
236 236 try:
237 237 patchheaderat = self.comments.index('# HG changeset patch')
238 238 self.comments.insert(patchheaderat + 1, '# Parent ' + parent)
239 239 except ValueError:
240 240 pass
241 241 self.parent = parent
242 242
243 243 def setmessage(self, message):
244 244 if self.comments:
245 245 self._delmsg()
246 246 self.message = [message]
247 247 self.comments += self.message
248 248
249 249 def updateheader(self, prefixes, new):
250 250 '''Update all references to a field in the patch header.
251 251 Return whether the field is present.'''
252 252 res = False
253 253 for prefix in prefixes:
254 254 for i in xrange(len(self.comments)):
255 255 if self.comments[i].startswith(prefix):
256 256 self.comments[i] = prefix + new
257 257 res = True
258 258 break
259 259 return res
260 260
261 261 def _hasheader(self, prefixes):
262 262 '''Check if a header starts with any of the given prefixes.'''
263 263 for prefix in prefixes:
264 264 for comment in self.comments:
265 265 if comment.startswith(prefix):
266 266 return True
267 267 return False
268 268
269 269 def __str__(self):
270 270 if not self.comments:
271 271 return ''
272 272 return '\n'.join(self.comments) + '\n\n'
273 273
274 274 def _delmsg(self):
275 275 '''Remove existing message, keeping the rest of the comments fields.
276 276 If comments contains 'subject: ', message will prepend
277 277 the field and a blank line.'''
278 278 if self.message:
279 279 subj = 'subject: ' + self.message[0].lower()
280 280 for i in xrange(len(self.comments)):
281 281 if subj == self.comments[i].lower():
282 282 del self.comments[i]
283 283 self.message = self.message[2:]
284 284 break
285 285 ci = 0
286 286 for mi in self.message:
287 287 while mi != self.comments[ci]:
288 288 ci += 1
289 289 del self.comments[ci]
290 290
291 291 def newcommit(repo, phase, *args, **kwargs):
292 292 """helper dedicated to ensure a commit respect mq.secret setting
293 293
294 294 It should be used instead of repo.commit inside the mq source for operation
295 295 creating new changeset.
296 296 """
297 297 repo = repo.unfiltered()
298 298 if phase is None:
299 299 if repo.ui.configbool('mq', 'secret', False):
300 300 phase = phases.secret
301 301 if phase is not None:
302 302 backup = repo.ui.backupconfig('phases', 'new-commit')
303 303 try:
304 304 if phase is not None:
305 305 repo.ui.setconfig('phases', 'new-commit', phase, 'mq')
306 306 return repo.commit(*args, **kwargs)
307 307 finally:
308 308 if phase is not None:
309 309 repo.ui.restoreconfig(backup)
310 310
311 311 class AbortNoCleanup(error.Abort):
312 312 pass
313 313
314 314 class queue(object):
315 315 def __init__(self, ui, baseui, path, patchdir=None):
316 316 self.basepath = path
317 317 try:
318 318 fh = open(os.path.join(path, 'patches.queue'))
319 319 cur = fh.read().rstrip()
320 320 fh.close()
321 321 if not cur:
322 322 curpath = os.path.join(path, 'patches')
323 323 else:
324 324 curpath = os.path.join(path, 'patches-' + cur)
325 325 except IOError:
326 326 curpath = os.path.join(path, 'patches')
327 327 self.path = patchdir or curpath
328 328 self.opener = scmutil.opener(self.path)
329 329 self.ui = ui
330 330 self.baseui = baseui
331 331 self.applieddirty = False
332 332 self.seriesdirty = False
333 333 self.added = []
334 334 self.seriespath = "series"
335 335 self.statuspath = "status"
336 336 self.guardspath = "guards"
337 337 self.activeguards = None
338 338 self.guardsdirty = False
339 339 # Handle mq.git as a bool with extended values
340 340 try:
341 341 gitmode = ui.configbool('mq', 'git', None)
342 342 if gitmode is None:
343 343 raise error.ConfigError
344 344 self.gitmode = gitmode and 'yes' or 'no'
345 345 except error.ConfigError:
346 346 self.gitmode = ui.config('mq', 'git', 'auto').lower()
347 347 self.plainmode = ui.configbool('mq', 'plain', False)
348 348 self.checkapplied = True
349 349
350 350 @util.propertycache
351 351 def applied(self):
352 352 def parselines(lines):
353 353 for l in lines:
354 354 entry = l.split(':', 1)
355 355 if len(entry) > 1:
356 356 n, name = entry
357 357 yield statusentry(bin(n), name)
358 358 elif l.strip():
359 359 self.ui.warn(_('malformated mq status line: %s\n') % entry)
360 360 # else we ignore empty lines
361 361 try:
362 362 lines = self.opener.read(self.statuspath).splitlines()
363 363 return list(parselines(lines))
364 364 except IOError, e:
365 365 if e.errno == errno.ENOENT:
366 366 return []
367 367 raise
368 368
369 369 @util.propertycache
370 370 def fullseries(self):
371 371 try:
372 372 return self.opener.read(self.seriespath).splitlines()
373 373 except IOError, e:
374 374 if e.errno == errno.ENOENT:
375 375 return []
376 376 raise
377 377
378 378 @util.propertycache
379 379 def series(self):
380 380 self.parseseries()
381 381 return self.series
382 382
383 383 @util.propertycache
384 384 def seriesguards(self):
385 385 self.parseseries()
386 386 return self.seriesguards
387 387
388 388 def invalidate(self):
389 389 for a in 'applied fullseries series seriesguards'.split():
390 390 if a in self.__dict__:
391 391 delattr(self, a)
392 392 self.applieddirty = False
393 393 self.seriesdirty = False
394 394 self.guardsdirty = False
395 395 self.activeguards = None
396 396
397 397 def diffopts(self, opts={}, patchfn=None):
398 398 diffopts = patchmod.diffopts(self.ui, opts)
399 399 if self.gitmode == 'auto':
400 400 diffopts.upgrade = True
401 401 elif self.gitmode == 'keep':
402 402 pass
403 403 elif self.gitmode in ('yes', 'no'):
404 404 diffopts.git = self.gitmode == 'yes'
405 405 else:
406 406 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
407 407 ' got %s') % self.gitmode)
408 408 if patchfn:
409 409 diffopts = self.patchopts(diffopts, patchfn)
410 410 return diffopts
411 411
412 412 def patchopts(self, diffopts, *patches):
413 413 """Return a copy of input diff options with git set to true if
414 414 referenced patch is a git patch and should be preserved as such.
415 415 """
416 416 diffopts = diffopts.copy()
417 417 if not diffopts.git and self.gitmode == 'keep':
418 418 for patchfn in patches:
419 419 patchf = self.opener(patchfn, 'r')
420 420 # if the patch was a git patch, refresh it as a git patch
421 421 for line in patchf:
422 422 if line.startswith('diff --git'):
423 423 diffopts.git = True
424 424 break
425 425 patchf.close()
426 426 return diffopts
427 427
428 428 def join(self, *p):
429 429 return os.path.join(self.path, *p)
430 430
431 431 def findseries(self, patch):
432 432 def matchpatch(l):
433 433 l = l.split('#', 1)[0]
434 434 return l.strip() == patch
435 435 for index, l in enumerate(self.fullseries):
436 436 if matchpatch(l):
437 437 return index
438 438 return None
439 439
440 440 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
441 441
442 442 def parseseries(self):
443 443 self.series = []
444 444 self.seriesguards = []
445 445 for l in self.fullseries:
446 446 h = l.find('#')
447 447 if h == -1:
448 448 patch = l
449 449 comment = ''
450 450 elif h == 0:
451 451 continue
452 452 else:
453 453 patch = l[:h]
454 454 comment = l[h:]
455 455 patch = patch.strip()
456 456 if patch:
457 457 if patch in self.series:
458 458 raise util.Abort(_('%s appears more than once in %s') %
459 459 (patch, self.join(self.seriespath)))
460 460 self.series.append(patch)
461 461 self.seriesguards.append(self.guard_re.findall(comment))
462 462
463 463 def checkguard(self, guard):
464 464 if not guard:
465 465 return _('guard cannot be an empty string')
466 466 bad_chars = '# \t\r\n\f'
467 467 first = guard[0]
468 468 if first in '-+':
469 469 return (_('guard %r starts with invalid character: %r') %
470 470 (guard, first))
471 471 for c in bad_chars:
472 472 if c in guard:
473 473 return _('invalid character in guard %r: %r') % (guard, c)
474 474
475 475 def setactive(self, guards):
476 476 for guard in guards:
477 477 bad = self.checkguard(guard)
478 478 if bad:
479 479 raise util.Abort(bad)
480 480 guards = sorted(set(guards))
481 481 self.ui.debug('active guards: %s\n' % ' '.join(guards))
482 482 self.activeguards = guards
483 483 self.guardsdirty = True
484 484
485 485 def active(self):
486 486 if self.activeguards is None:
487 487 self.activeguards = []
488 488 try:
489 489 guards = self.opener.read(self.guardspath).split()
490 490 except IOError, err:
491 491 if err.errno != errno.ENOENT:
492 492 raise
493 493 guards = []
494 494 for i, guard in enumerate(guards):
495 495 bad = self.checkguard(guard)
496 496 if bad:
497 497 self.ui.warn('%s:%d: %s\n' %
498 498 (self.join(self.guardspath), i + 1, bad))
499 499 else:
500 500 self.activeguards.append(guard)
501 501 return self.activeguards
502 502
503 503 def setguards(self, idx, guards):
504 504 for g in guards:
505 505 if len(g) < 2:
506 506 raise util.Abort(_('guard %r too short') % g)
507 507 if g[0] not in '-+':
508 508 raise util.Abort(_('guard %r starts with invalid char') % g)
509 509 bad = self.checkguard(g[1:])
510 510 if bad:
511 511 raise util.Abort(bad)
512 512 drop = self.guard_re.sub('', self.fullseries[idx])
513 513 self.fullseries[idx] = drop + ''.join([' #' + g for g in guards])
514 514 self.parseseries()
515 515 self.seriesdirty = True
516 516
517 517 def pushable(self, idx):
518 518 if isinstance(idx, str):
519 519 idx = self.series.index(idx)
520 520 patchguards = self.seriesguards[idx]
521 521 if not patchguards:
522 522 return True, None
523 523 guards = self.active()
524 524 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
525 525 if exactneg:
526 526 return False, repr(exactneg[0])
527 527 pos = [g for g in patchguards if g[0] == '+']
528 528 exactpos = [g for g in pos if g[1:] in guards]
529 529 if pos:
530 530 if exactpos:
531 531 return True, repr(exactpos[0])
532 532 return False, ' '.join(map(repr, pos))
533 533 return True, ''
534 534
535 535 def explainpushable(self, idx, all_patches=False):
536 536 write = all_patches and self.ui.write or self.ui.warn
537 537 if all_patches or self.ui.verbose:
538 538 if isinstance(idx, str):
539 539 idx = self.series.index(idx)
540 540 pushable, why = self.pushable(idx)
541 541 if all_patches and pushable:
542 542 if why is None:
543 543 write(_('allowing %s - no guards in effect\n') %
544 544 self.series[idx])
545 545 else:
546 546 if not why:
547 547 write(_('allowing %s - no matching negative guards\n') %
548 548 self.series[idx])
549 549 else:
550 550 write(_('allowing %s - guarded by %s\n') %
551 551 (self.series[idx], why))
552 552 if not pushable:
553 553 if why:
554 554 write(_('skipping %s - guarded by %s\n') %
555 555 (self.series[idx], why))
556 556 else:
557 557 write(_('skipping %s - no matching guards\n') %
558 558 self.series[idx])
559 559
560 560 def savedirty(self):
561 561 def writelist(items, path):
562 562 fp = self.opener(path, 'w')
563 563 for i in items:
564 564 fp.write("%s\n" % i)
565 565 fp.close()
566 566 if self.applieddirty:
567 567 writelist(map(str, self.applied), self.statuspath)
568 568 self.applieddirty = False
569 569 if self.seriesdirty:
570 570 writelist(self.fullseries, self.seriespath)
571 571 self.seriesdirty = False
572 572 if self.guardsdirty:
573 573 writelist(self.activeguards, self.guardspath)
574 574 self.guardsdirty = False
575 575 if self.added:
576 576 qrepo = self.qrepo()
577 577 if qrepo:
578 578 qrepo[None].add(f for f in self.added if f not in qrepo[None])
579 579 self.added = []
580 580
581 581 def removeundo(self, repo):
582 582 undo = repo.sjoin('undo')
583 583 if not os.path.exists(undo):
584 584 return
585 585 try:
586 586 os.unlink(undo)
587 587 except OSError, inst:
588 588 self.ui.warn(_('error removing undo: %s\n') % str(inst))
589 589
590 590 def backup(self, repo, files, copy=False):
591 591 # backup local changes in --force case
592 592 for f in sorted(files):
593 593 absf = repo.wjoin(f)
594 594 if os.path.lexists(absf):
595 595 self.ui.note(_('saving current version of %s as %s\n') %
596 596 (f, f + '.orig'))
597 597 if copy:
598 598 util.copyfile(absf, absf + '.orig')
599 599 else:
600 600 util.rename(absf, absf + '.orig')
601 601
602 602 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
603 603 fp=None, changes=None, opts={}):
604 604 stat = opts.get('stat')
605 605 m = scmutil.match(repo[node1], files, opts)
606 606 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
607 607 changes, stat, fp)
608 608
609 609 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
610 610 # first try just applying the patch
611 611 (err, n) = self.apply(repo, [patch], update_status=False,
612 612 strict=True, merge=rev)
613 613
614 614 if err == 0:
615 615 return (err, n)
616 616
617 617 if n is None:
618 618 raise util.Abort(_("apply failed for patch %s") % patch)
619 619
620 620 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
621 621
622 622 # apply failed, strip away that rev and merge.
623 623 hg.clean(repo, head)
624 624 strip(self.ui, repo, [n], update=False, backup=False)
625 625
626 626 ctx = repo[rev]
627 627 ret = hg.merge(repo, rev)
628 628 if ret:
629 629 raise util.Abort(_("update returned %d") % ret)
630 630 n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
631 631 if n is None:
632 632 raise util.Abort(_("repo commit failed"))
633 633 try:
634 634 ph = patchheader(mergeq.join(patch), self.plainmode)
635 635 except Exception:
636 636 raise util.Abort(_("unable to read %s") % patch)
637 637
638 638 diffopts = self.patchopts(diffopts, patch)
639 639 patchf = self.opener(patch, "w")
640 640 comments = str(ph)
641 641 if comments:
642 642 patchf.write(comments)
643 643 self.printdiff(repo, diffopts, head, n, fp=patchf)
644 644 patchf.close()
645 645 self.removeundo(repo)
646 646 return (0, n)
647 647
648 648 def qparents(self, repo, rev=None):
649 649 """return the mq handled parent or p1
650 650
651 651 In some case where mq get himself in being the parent of a merge the
652 652 appropriate parent may be p2.
653 653 (eg: an in progress merge started with mq disabled)
654 654
655 655 If no parent are managed by mq, p1 is returned.
656 656 """
657 657 if rev is None:
658 658 (p1, p2) = repo.dirstate.parents()
659 659 if p2 == nullid:
660 660 return p1
661 661 if not self.applied:
662 662 return None
663 663 return self.applied[-1].node
664 664 p1, p2 = repo.changelog.parents(rev)
665 665 if p2 != nullid and p2 in [x.node for x in self.applied]:
666 666 return p2
667 667 return p1
668 668
669 669 def mergepatch(self, repo, mergeq, series, diffopts):
670 670 if not self.applied:
671 671 # each of the patches merged in will have two parents. This
672 672 # can confuse the qrefresh, qdiff, and strip code because it
673 673 # needs to know which parent is actually in the patch queue.
674 674 # so, we insert a merge marker with only one parent. This way
675 675 # the first patch in the queue is never a merge patch
676 676 #
677 677 pname = ".hg.patches.merge.marker"
678 678 n = newcommit(repo, None, '[mq]: merge marker', force=True)
679 679 self.removeundo(repo)
680 680 self.applied.append(statusentry(n, pname))
681 681 self.applieddirty = True
682 682
683 683 head = self.qparents(repo)
684 684
685 685 for patch in series:
686 686 patch = mergeq.lookup(patch, strict=True)
687 687 if not patch:
688 688 self.ui.warn(_("patch %s does not exist\n") % patch)
689 689 return (1, None)
690 690 pushable, reason = self.pushable(patch)
691 691 if not pushable:
692 692 self.explainpushable(patch, all_patches=True)
693 693 continue
694 694 info = mergeq.isapplied(patch)
695 695 if not info:
696 696 self.ui.warn(_("patch %s is not applied\n") % patch)
697 697 return (1, None)
698 698 rev = info[1]
699 699 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
700 700 if head:
701 701 self.applied.append(statusentry(head, patch))
702 702 self.applieddirty = True
703 703 if err:
704 704 return (err, head)
705 705 self.savedirty()
706 706 return (0, head)
707 707
708 708 def patch(self, repo, patchfile):
709 709 '''Apply patchfile to the working directory.
710 710 patchfile: name of patch file'''
711 711 files = set()
712 712 try:
713 713 fuzz = patchmod.patch(self.ui, repo, patchfile, strip=1,
714 714 files=files, eolmode=None)
715 715 return (True, list(files), fuzz)
716 716 except Exception, inst:
717 717 self.ui.note(str(inst) + '\n')
718 718 if not self.ui.verbose:
719 719 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
720 720 self.ui.traceback()
721 721 return (False, list(files), False)
722 722
723 723 def apply(self, repo, series, list=False, update_status=True,
724 724 strict=False, patchdir=None, merge=None, all_files=None,
725 725 tobackup=None, keepchanges=False):
726 726 wlock = lock = tr = None
727 727 try:
728 728 wlock = repo.wlock()
729 729 lock = repo.lock()
730 730 tr = repo.transaction("qpush")
731 731 try:
732 732 ret = self._apply(repo, series, list, update_status,
733 733 strict, patchdir, merge, all_files=all_files,
734 734 tobackup=tobackup, keepchanges=keepchanges)
735 735 tr.close()
736 736 self.savedirty()
737 737 return ret
738 738 except AbortNoCleanup:
739 739 tr.close()
740 740 self.savedirty()
741 741 return 2, repo.dirstate.p1()
742 742 except: # re-raises
743 743 try:
744 744 tr.abort()
745 745 finally:
746 746 repo.invalidate()
747 747 repo.dirstate.invalidate()
748 748 self.invalidate()
749 749 raise
750 750 finally:
751 751 release(tr, lock, wlock)
752 752 self.removeundo(repo)
753 753
754 754 def _apply(self, repo, series, list=False, update_status=True,
755 755 strict=False, patchdir=None, merge=None, all_files=None,
756 756 tobackup=None, keepchanges=False):
757 757 """returns (error, hash)
758 758
759 759 error = 1 for unable to read, 2 for patch failed, 3 for patch
760 760 fuzz. tobackup is None or a set of files to backup before they
761 761 are modified by a patch.
762 762 """
763 763 # TODO unify with commands.py
764 764 if not patchdir:
765 765 patchdir = self.path
766 766 err = 0
767 767 n = None
768 768 for patchname in series:
769 769 pushable, reason = self.pushable(patchname)
770 770 if not pushable:
771 771 self.explainpushable(patchname, all_patches=True)
772 772 continue
773 773 self.ui.status(_("applying %s\n") % patchname)
774 774 pf = os.path.join(patchdir, patchname)
775 775
776 776 try:
777 777 ph = patchheader(self.join(patchname), self.plainmode)
778 778 except IOError:
779 779 self.ui.warn(_("unable to read %s\n") % patchname)
780 780 err = 1
781 781 break
782 782
783 783 message = ph.message
784 784 if not message:
785 785 # The commit message should not be translated
786 786 message = "imported patch %s\n" % patchname
787 787 else:
788 788 if list:
789 789 # The commit message should not be translated
790 790 message.append("\nimported patch %s" % patchname)
791 791 message = '\n'.join(message)
792 792
793 793 if ph.haspatch:
794 794 if tobackup:
795 795 touched = patchmod.changedfiles(self.ui, repo, pf)
796 796 touched = set(touched) & tobackup
797 797 if touched and keepchanges:
798 798 raise AbortNoCleanup(
799 799 _("local changes found, refresh first"))
800 800 self.backup(repo, touched, copy=True)
801 801 tobackup = tobackup - touched
802 802 (patcherr, files, fuzz) = self.patch(repo, pf)
803 803 if all_files is not None:
804 804 all_files.update(files)
805 805 patcherr = not patcherr
806 806 else:
807 807 self.ui.warn(_("patch %s is empty\n") % patchname)
808 808 patcherr, files, fuzz = 0, [], 0
809 809
810 810 if merge and files:
811 811 # Mark as removed/merged and update dirstate parent info
812 812 removed = []
813 813 merged = []
814 814 for f in files:
815 815 if os.path.lexists(repo.wjoin(f)):
816 816 merged.append(f)
817 817 else:
818 818 removed.append(f)
819 819 repo.dirstate.beginparentchange()
820 820 for f in removed:
821 821 repo.dirstate.remove(f)
822 822 for f in merged:
823 823 repo.dirstate.merge(f)
824 824 p1, p2 = repo.dirstate.parents()
825 825 repo.setparents(p1, merge)
826 826 repo.dirstate.endparentchange()
827 827
828 828 if all_files and '.hgsubstate' in all_files:
829 829 wctx = repo[None]
830 830 pctx = repo['.']
831 831 overwrite = False
832 832 mergedsubstate = subrepo.submerge(repo, pctx, wctx, wctx,
833 833 overwrite)
834 834 files += mergedsubstate.keys()
835 835
836 836 match = scmutil.matchfiles(repo, files or [])
837 837 oldtip = repo['tip']
838 838 n = newcommit(repo, None, message, ph.user, ph.date, match=match,
839 839 force=True)
840 840 if repo['tip'] == oldtip:
841 841 raise util.Abort(_("qpush exactly duplicates child changeset"))
842 842 if n is None:
843 843 raise util.Abort(_("repository commit failed"))
844 844
845 845 if update_status:
846 846 self.applied.append(statusentry(n, patchname))
847 847
848 848 if patcherr:
849 849 self.ui.warn(_("patch failed, rejects left in working dir\n"))
850 850 err = 2
851 851 break
852 852
853 853 if fuzz and strict:
854 854 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
855 855 err = 3
856 856 break
857 857 return (err, n)
858 858
859 859 def _cleanup(self, patches, numrevs, keep=False):
860 860 if not keep:
861 861 r = self.qrepo()
862 862 if r:
863 863 r[None].forget(patches)
864 864 for p in patches:
865 865 try:
866 866 os.unlink(self.join(p))
867 867 except OSError, inst:
868 868 if inst.errno != errno.ENOENT:
869 869 raise
870 870
871 871 qfinished = []
872 872 if numrevs:
873 873 qfinished = self.applied[:numrevs]
874 874 del self.applied[:numrevs]
875 875 self.applieddirty = True
876 876
877 877 unknown = []
878 878
879 879 for (i, p) in sorted([(self.findseries(p), p) for p in patches],
880 880 reverse=True):
881 881 if i is not None:
882 882 del self.fullseries[i]
883 883 else:
884 884 unknown.append(p)
885 885
886 886 if unknown:
887 887 if numrevs:
888 888 rev = dict((entry.name, entry.node) for entry in qfinished)
889 889 for p in unknown:
890 890 msg = _('revision %s refers to unknown patches: %s\n')
891 891 self.ui.warn(msg % (short(rev[p]), p))
892 892 else:
893 893 msg = _('unknown patches: %s\n')
894 894 raise util.Abort(''.join(msg % p for p in unknown))
895 895
896 896 self.parseseries()
897 897 self.seriesdirty = True
898 898 return [entry.node for entry in qfinished]
899 899
900 900 def _revpatches(self, repo, revs):
901 901 firstrev = repo[self.applied[0].node].rev()
902 902 patches = []
903 903 for i, rev in enumerate(revs):
904 904
905 905 if rev < firstrev:
906 906 raise util.Abort(_('revision %d is not managed') % rev)
907 907
908 908 ctx = repo[rev]
909 909 base = self.applied[i].node
910 910 if ctx.node() != base:
911 911 msg = _('cannot delete revision %d above applied patches')
912 912 raise util.Abort(msg % rev)
913 913
914 914 patch = self.applied[i].name
915 915 for fmt in ('[mq]: %s', 'imported patch %s'):
916 916 if ctx.description() == fmt % patch:
917 917 msg = _('patch %s finalized without changeset message\n')
918 918 repo.ui.status(msg % patch)
919 919 break
920 920
921 921 patches.append(patch)
922 922 return patches
923 923
924 924 def finish(self, repo, revs):
925 925 # Manually trigger phase computation to ensure phasedefaults is
926 926 # executed before we remove the patches.
927 927 repo._phasecache
928 928 patches = self._revpatches(repo, sorted(revs))
929 929 qfinished = self._cleanup(patches, len(patches))
930 930 if qfinished and repo.ui.configbool('mq', 'secret', False):
931 931 # only use this logic when the secret option is added
932 932 oldqbase = repo[qfinished[0]]
933 933 tphase = repo.ui.config('phases', 'new-commit', phases.draft)
934 934 if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
935 935 tr = repo.transaction('qfinish')
936 936 try:
937 937 phases.advanceboundary(repo, tr, tphase, qfinished)
938 938 tr.close()
939 939 finally:
940 940 tr.release()
941 941
942 942 def delete(self, repo, patches, opts):
943 943 if not patches and not opts.get('rev'):
944 944 raise util.Abort(_('qdelete requires at least one revision or '
945 945 'patch name'))
946 946
947 947 realpatches = []
948 948 for patch in patches:
949 949 patch = self.lookup(patch, strict=True)
950 950 info = self.isapplied(patch)
951 951 if info:
952 952 raise util.Abort(_("cannot delete applied patch %s") % patch)
953 953 if patch not in self.series:
954 954 raise util.Abort(_("patch %s not in series file") % patch)
955 955 if patch not in realpatches:
956 956 realpatches.append(patch)
957 957
958 958 numrevs = 0
959 959 if opts.get('rev'):
960 960 if not self.applied:
961 961 raise util.Abort(_('no patches applied'))
962 962 revs = scmutil.revrange(repo, opts.get('rev'))
963 963 if len(revs) > 1 and revs[0] > revs[1]:
964 964 revs.reverse()
965 965 revpatches = self._revpatches(repo, revs)
966 966 realpatches += revpatches
967 967 numrevs = len(revpatches)
968 968
969 969 self._cleanup(realpatches, numrevs, opts.get('keep'))
970 970
971 971 def checktoppatch(self, repo):
972 972 '''check that working directory is at qtip'''
973 973 if self.applied:
974 974 top = self.applied[-1].node
975 975 patch = self.applied[-1].name
976 976 if repo.dirstate.p1() != top:
977 977 raise util.Abort(_("working directory revision is not qtip"))
978 978 return top, patch
979 979 return None, None
980 980
981 981 def putsubstate2changes(self, substatestate, changes):
982 982 for files in changes[:3]:
983 983 if '.hgsubstate' in files:
984 984 return # already listed up
985 985 # not yet listed up
986 986 if substatestate in 'a?':
987 987 changes[1].append('.hgsubstate')
988 988 elif substatestate in 'r':
989 989 changes[2].append('.hgsubstate')
990 990 else: # modified
991 991 changes[0].append('.hgsubstate')
992 992
993 993 def checklocalchanges(self, repo, force=False, refresh=True):
994 994 excsuffix = ''
995 995 if refresh:
996 996 excsuffix = ', refresh first'
997 997 # plain versions for i18n tool to detect them
998 998 _("local changes found, refresh first")
999 999 _("local changed subrepos found, refresh first")
1000 1000 return checklocalchanges(repo, force, excsuffix)
1001 1001
1002 1002 _reserved = ('series', 'status', 'guards', '.', '..')
1003 1003 def checkreservedname(self, name):
1004 1004 if name in self._reserved:
1005 1005 raise util.Abort(_('"%s" cannot be used as the name of a patch')
1006 1006 % name)
1007 1007 for prefix in ('.hg', '.mq'):
1008 1008 if name.startswith(prefix):
1009 1009 raise util.Abort(_('patch name cannot begin with "%s"')
1010 1010 % prefix)
1011 1011 for c in ('#', ':'):
1012 1012 if c in name:
1013 1013 raise util.Abort(_('"%s" cannot be used in the name of a patch')
1014 1014 % c)
1015 1015
1016 1016 def checkpatchname(self, name, force=False):
1017 1017 self.checkreservedname(name)
1018 1018 if not force and os.path.exists(self.join(name)):
1019 1019 if os.path.isdir(self.join(name)):
1020 1020 raise util.Abort(_('"%s" already exists as a directory')
1021 1021 % name)
1022 1022 else:
1023 1023 raise util.Abort(_('patch "%s" already exists') % name)
1024 1024
1025 1025 def checkkeepchanges(self, keepchanges, force):
1026 1026 if force and keepchanges:
1027 1027 raise util.Abort(_('cannot use both --force and --keep-changes'))
1028 1028
1029 1029 def new(self, repo, patchfn, *pats, **opts):
1030 1030 """options:
1031 1031 msg: a string or a no-argument function returning a string
1032 1032 """
1033 1033 msg = opts.get('msg')
1034 1034 edit = opts.get('edit')
1035 1035 editform = opts.get('editform', 'mq.qnew')
1036 1036 user = opts.get('user')
1037 1037 date = opts.get('date')
1038 1038 if date:
1039 1039 date = util.parsedate(date)
1040 1040 diffopts = self.diffopts({'git': opts.get('git')})
1041 1041 if opts.get('checkname', True):
1042 1042 self.checkpatchname(patchfn)
1043 1043 inclsubs = checksubstate(repo)
1044 1044 if inclsubs:
1045 1045 substatestate = repo.dirstate['.hgsubstate']
1046 1046 if opts.get('include') or opts.get('exclude') or pats:
1047 1047 match = scmutil.match(repo[None], pats, opts)
1048 1048 # detect missing files in pats
1049 1049 def badfn(f, msg):
1050 1050 if f != '.hgsubstate': # .hgsubstate is auto-created
1051 1051 raise util.Abort('%s: %s' % (f, msg))
1052 1052 match.bad = badfn
1053 1053 changes = repo.status(match=match)
1054 1054 else:
1055 1055 changes = self.checklocalchanges(repo, force=True)
1056 1056 commitfiles = list(inclsubs)
1057 1057 for files in changes[:3]:
1058 1058 commitfiles.extend(files)
1059 1059 match = scmutil.matchfiles(repo, commitfiles)
1060 1060 if len(repo[None].parents()) > 1:
1061 1061 raise util.Abort(_('cannot manage merge changesets'))
1062 1062 self.checktoppatch(repo)
1063 1063 insert = self.fullseriesend()
1064 1064 wlock = repo.wlock()
1065 1065 try:
1066 1066 try:
1067 1067 # if patch file write fails, abort early
1068 1068 p = self.opener(patchfn, "w")
1069 1069 except IOError, e:
1070 1070 raise util.Abort(_('cannot write patch "%s": %s')
1071 1071 % (patchfn, e.strerror))
1072 1072 try:
1073 1073 if self.plainmode:
1074 1074 if user:
1075 1075 p.write("From: " + user + "\n")
1076 if not date:
1077 p.write("\n")
1078 1076 if date:
1079 p.write("Date: %d %d\n\n" % date)
1077 p.write("Date: %d %d\n" % date)
1080 1078 else:
1081 1079 p.write("# HG changeset patch\n")
1082 1080 p.write("# Parent "
1083 1081 + hex(repo[None].p1().node()) + "\n")
1084 1082 if user:
1085 1083 p.write("# User " + user + "\n")
1086 1084 if date:
1087 p.write("# Date %s %s\n\n" % date)
1085 p.write("# Date %s %s\n" % date)
1088 1086
1089 1087 defaultmsg = "[mq]: %s" % patchfn
1090 1088 editor = cmdutil.getcommiteditor(editform=editform)
1091 1089 if edit:
1092 1090 def finishdesc(desc):
1093 1091 if desc.rstrip():
1094 1092 return desc
1095 1093 else:
1096 1094 return defaultmsg
1097 1095 # i18n: this message is shown in editor with "HG: " prefix
1098 1096 extramsg = _('Leave message empty to use default message.')
1099 1097 editor = cmdutil.getcommiteditor(finishdesc=finishdesc,
1100 1098 extramsg=extramsg,
1101 1099 editform=editform)
1102 1100 commitmsg = msg
1103 1101 else:
1104 1102 commitmsg = msg or defaultmsg
1105 1103
1106 1104 n = newcommit(repo, None, commitmsg, user, date, match=match,
1107 1105 force=True, editor=editor)
1108 1106 if n is None:
1109 1107 raise util.Abort(_("repo commit failed"))
1110 1108 try:
1111 1109 self.fullseries[insert:insert] = [patchfn]
1112 1110 self.applied.append(statusentry(n, patchfn))
1113 1111 self.parseseries()
1114 1112 self.seriesdirty = True
1115 1113 self.applieddirty = True
1116 1114 nctx = repo[n]
1117 1115 if nctx.description() != defaultmsg.rstrip():
1118 1116 msg = nctx.description() + "\n\n"
1119 1117 p.write(msg)
1118 elif not self.plainmode or date or user:
1119 p.write('\n')
1120 1120 if commitfiles:
1121 1121 parent = self.qparents(repo, n)
1122 1122 if inclsubs:
1123 1123 self.putsubstate2changes(substatestate, changes)
1124 1124 chunks = patchmod.diff(repo, node1=parent, node2=n,
1125 1125 changes=changes, opts=diffopts)
1126 1126 for chunk in chunks:
1127 1127 p.write(chunk)
1128 1128 p.close()
1129 1129 r = self.qrepo()
1130 1130 if r:
1131 1131 r[None].add([patchfn])
1132 1132 except: # re-raises
1133 1133 repo.rollback()
1134 1134 raise
1135 1135 except Exception:
1136 1136 patchpath = self.join(patchfn)
1137 1137 try:
1138 1138 os.unlink(patchpath)
1139 1139 except OSError:
1140 1140 self.ui.warn(_('error unlinking %s\n') % patchpath)
1141 1141 raise
1142 1142 self.removeundo(repo)
1143 1143 finally:
1144 1144 release(wlock)
1145 1145
1146 1146 def isapplied(self, patch):
1147 1147 """returns (index, rev, patch)"""
1148 1148 for i, a in enumerate(self.applied):
1149 1149 if a.name == patch:
1150 1150 return (i, a.node, a.name)
1151 1151 return None
1152 1152
1153 1153 # if the exact patch name does not exist, we try a few
1154 1154 # variations. If strict is passed, we try only #1
1155 1155 #
1156 1156 # 1) a number (as string) to indicate an offset in the series file
1157 1157 # 2) a unique substring of the patch name was given
1158 1158 # 3) patchname[-+]num to indicate an offset in the series file
1159 1159 def lookup(self, patch, strict=False):
1160 1160 def partialname(s):
1161 1161 if s in self.series:
1162 1162 return s
1163 1163 matches = [x for x in self.series if s in x]
1164 1164 if len(matches) > 1:
1165 1165 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
1166 1166 for m in matches:
1167 1167 self.ui.warn(' %s\n' % m)
1168 1168 return None
1169 1169 if matches:
1170 1170 return matches[0]
1171 1171 if self.series and self.applied:
1172 1172 if s == 'qtip':
1173 1173 return self.series[self.seriesend(True) - 1]
1174 1174 if s == 'qbase':
1175 1175 return self.series[0]
1176 1176 return None
1177 1177
1178 1178 if patch in self.series:
1179 1179 return patch
1180 1180
1181 1181 if not os.path.isfile(self.join(patch)):
1182 1182 try:
1183 1183 sno = int(patch)
1184 1184 except (ValueError, OverflowError):
1185 1185 pass
1186 1186 else:
1187 1187 if -len(self.series) <= sno < len(self.series):
1188 1188 return self.series[sno]
1189 1189
1190 1190 if not strict:
1191 1191 res = partialname(patch)
1192 1192 if res:
1193 1193 return res
1194 1194 minus = patch.rfind('-')
1195 1195 if minus >= 0:
1196 1196 res = partialname(patch[:minus])
1197 1197 if res:
1198 1198 i = self.series.index(res)
1199 1199 try:
1200 1200 off = int(patch[minus + 1:] or 1)
1201 1201 except (ValueError, OverflowError):
1202 1202 pass
1203 1203 else:
1204 1204 if i - off >= 0:
1205 1205 return self.series[i - off]
1206 1206 plus = patch.rfind('+')
1207 1207 if plus >= 0:
1208 1208 res = partialname(patch[:plus])
1209 1209 if res:
1210 1210 i = self.series.index(res)
1211 1211 try:
1212 1212 off = int(patch[plus + 1:] or 1)
1213 1213 except (ValueError, OverflowError):
1214 1214 pass
1215 1215 else:
1216 1216 if i + off < len(self.series):
1217 1217 return self.series[i + off]
1218 1218 raise util.Abort(_("patch %s not in series") % patch)
1219 1219
1220 1220 def push(self, repo, patch=None, force=False, list=False, mergeq=None,
1221 1221 all=False, move=False, exact=False, nobackup=False,
1222 1222 keepchanges=False):
1223 1223 self.checkkeepchanges(keepchanges, force)
1224 1224 diffopts = self.diffopts()
1225 1225 wlock = repo.wlock()
1226 1226 try:
1227 1227 heads = []
1228 1228 for hs in repo.branchmap().itervalues():
1229 1229 heads.extend(hs)
1230 1230 if not heads:
1231 1231 heads = [nullid]
1232 1232 if repo.dirstate.p1() not in heads and not exact:
1233 1233 self.ui.status(_("(working directory not at a head)\n"))
1234 1234
1235 1235 if not self.series:
1236 1236 self.ui.warn(_('no patches in series\n'))
1237 1237 return 0
1238 1238
1239 1239 # Suppose our series file is: A B C and the current 'top'
1240 1240 # patch is B. qpush C should be performed (moving forward)
1241 1241 # qpush B is a NOP (no change) qpush A is an error (can't
1242 1242 # go backwards with qpush)
1243 1243 if patch:
1244 1244 patch = self.lookup(patch)
1245 1245 info = self.isapplied(patch)
1246 1246 if info and info[0] >= len(self.applied) - 1:
1247 1247 self.ui.warn(
1248 1248 _('qpush: %s is already at the top\n') % patch)
1249 1249 return 0
1250 1250
1251 1251 pushable, reason = self.pushable(patch)
1252 1252 if pushable:
1253 1253 if self.series.index(patch) < self.seriesend():
1254 1254 raise util.Abort(
1255 1255 _("cannot push to a previous patch: %s") % patch)
1256 1256 else:
1257 1257 if reason:
1258 1258 reason = _('guarded by %s') % reason
1259 1259 else:
1260 1260 reason = _('no matching guards')
1261 1261 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1262 1262 return 1
1263 1263 elif all:
1264 1264 patch = self.series[-1]
1265 1265 if self.isapplied(patch):
1266 1266 self.ui.warn(_('all patches are currently applied\n'))
1267 1267 return 0
1268 1268
1269 1269 # Following the above example, starting at 'top' of B:
1270 1270 # qpush should be performed (pushes C), but a subsequent
1271 1271 # qpush without an argument is an error (nothing to
1272 1272 # apply). This allows a loop of "...while hg qpush..." to
1273 1273 # work as it detects an error when done
1274 1274 start = self.seriesend()
1275 1275 if start == len(self.series):
1276 1276 self.ui.warn(_('patch series already fully applied\n'))
1277 1277 return 1
1278 1278 if not force and not keepchanges:
1279 1279 self.checklocalchanges(repo, refresh=self.applied)
1280 1280
1281 1281 if exact:
1282 1282 if keepchanges:
1283 1283 raise util.Abort(
1284 1284 _("cannot use --exact and --keep-changes together"))
1285 1285 if move:
1286 1286 raise util.Abort(_('cannot use --exact and --move '
1287 1287 'together'))
1288 1288 if self.applied:
1289 1289 raise util.Abort(_('cannot push --exact with applied '
1290 1290 'patches'))
1291 1291 root = self.series[start]
1292 1292 target = patchheader(self.join(root), self.plainmode).parent
1293 1293 if not target:
1294 1294 raise util.Abort(
1295 1295 _("%s does not have a parent recorded") % root)
1296 1296 if not repo[target] == repo['.']:
1297 1297 hg.update(repo, target)
1298 1298
1299 1299 if move:
1300 1300 if not patch:
1301 1301 raise util.Abort(_("please specify the patch to move"))
1302 1302 for fullstart, rpn in enumerate(self.fullseries):
1303 1303 # strip markers for patch guards
1304 1304 if self.guard_re.split(rpn, 1)[0] == self.series[start]:
1305 1305 break
1306 1306 for i, rpn in enumerate(self.fullseries[fullstart:]):
1307 1307 # strip markers for patch guards
1308 1308 if self.guard_re.split(rpn, 1)[0] == patch:
1309 1309 break
1310 1310 index = fullstart + i
1311 1311 assert index < len(self.fullseries)
1312 1312 fullpatch = self.fullseries[index]
1313 1313 del self.fullseries[index]
1314 1314 self.fullseries.insert(fullstart, fullpatch)
1315 1315 self.parseseries()
1316 1316 self.seriesdirty = True
1317 1317
1318 1318 self.applieddirty = True
1319 1319 if start > 0:
1320 1320 self.checktoppatch(repo)
1321 1321 if not patch:
1322 1322 patch = self.series[start]
1323 1323 end = start + 1
1324 1324 else:
1325 1325 end = self.series.index(patch, start) + 1
1326 1326
1327 1327 tobackup = set()
1328 1328 if (not nobackup and force) or keepchanges:
1329 1329 m, a, r, d = self.checklocalchanges(repo, force=True)
1330 1330 if keepchanges:
1331 1331 tobackup.update(m + a + r + d)
1332 1332 else:
1333 1333 tobackup.update(m + a)
1334 1334
1335 1335 s = self.series[start:end]
1336 1336 all_files = set()
1337 1337 try:
1338 1338 if mergeq:
1339 1339 ret = self.mergepatch(repo, mergeq, s, diffopts)
1340 1340 else:
1341 1341 ret = self.apply(repo, s, list, all_files=all_files,
1342 1342 tobackup=tobackup, keepchanges=keepchanges)
1343 1343 except: # re-raises
1344 1344 self.ui.warn(_('cleaning up working directory...'))
1345 1345 node = repo.dirstate.p1()
1346 1346 hg.revert(repo, node, None)
1347 1347 # only remove unknown files that we know we touched or
1348 1348 # created while patching
1349 1349 for f in all_files:
1350 1350 if f not in repo.dirstate:
1351 1351 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1352 1352 self.ui.warn(_('done\n'))
1353 1353 raise
1354 1354
1355 1355 if not self.applied:
1356 1356 return ret[0]
1357 1357 top = self.applied[-1].name
1358 1358 if ret[0] and ret[0] > 1:
1359 1359 msg = _("errors during apply, please fix and refresh %s\n")
1360 1360 self.ui.write(msg % top)
1361 1361 else:
1362 1362 self.ui.write(_("now at: %s\n") % top)
1363 1363 return ret[0]
1364 1364
1365 1365 finally:
1366 1366 wlock.release()
1367 1367
1368 1368 def pop(self, repo, patch=None, force=False, update=True, all=False,
1369 1369 nobackup=False, keepchanges=False):
1370 1370 self.checkkeepchanges(keepchanges, force)
1371 1371 wlock = repo.wlock()
1372 1372 try:
1373 1373 if patch:
1374 1374 # index, rev, patch
1375 1375 info = self.isapplied(patch)
1376 1376 if not info:
1377 1377 patch = self.lookup(patch)
1378 1378 info = self.isapplied(patch)
1379 1379 if not info:
1380 1380 raise util.Abort(_("patch %s is not applied") % patch)
1381 1381
1382 1382 if not self.applied:
1383 1383 # Allow qpop -a to work repeatedly,
1384 1384 # but not qpop without an argument
1385 1385 self.ui.warn(_("no patches applied\n"))
1386 1386 return not all
1387 1387
1388 1388 if all:
1389 1389 start = 0
1390 1390 elif patch:
1391 1391 start = info[0] + 1
1392 1392 else:
1393 1393 start = len(self.applied) - 1
1394 1394
1395 1395 if start >= len(self.applied):
1396 1396 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1397 1397 return
1398 1398
1399 1399 if not update:
1400 1400 parents = repo.dirstate.parents()
1401 1401 rr = [x.node for x in self.applied]
1402 1402 for p in parents:
1403 1403 if p in rr:
1404 1404 self.ui.warn(_("qpop: forcing dirstate update\n"))
1405 1405 update = True
1406 1406 else:
1407 1407 parents = [p.node() for p in repo[None].parents()]
1408 1408 needupdate = False
1409 1409 for entry in self.applied[start:]:
1410 1410 if entry.node in parents:
1411 1411 needupdate = True
1412 1412 break
1413 1413 update = needupdate
1414 1414
1415 1415 tobackup = set()
1416 1416 if update:
1417 1417 m, a, r, d = self.checklocalchanges(
1418 1418 repo, force=force or keepchanges)
1419 1419 if force:
1420 1420 if not nobackup:
1421 1421 tobackup.update(m + a)
1422 1422 elif keepchanges:
1423 1423 tobackup.update(m + a + r + d)
1424 1424
1425 1425 self.applieddirty = True
1426 1426 end = len(self.applied)
1427 1427 rev = self.applied[start].node
1428 1428
1429 1429 try:
1430 1430 heads = repo.changelog.heads(rev)
1431 1431 except error.LookupError:
1432 1432 node = short(rev)
1433 1433 raise util.Abort(_('trying to pop unknown node %s') % node)
1434 1434
1435 1435 if heads != [self.applied[-1].node]:
1436 1436 raise util.Abort(_("popping would remove a revision not "
1437 1437 "managed by this patch queue"))
1438 1438 if not repo[self.applied[-1].node].mutable():
1439 1439 raise util.Abort(
1440 1440 _("popping would remove an immutable revision"),
1441 1441 hint=_('see "hg help phases" for details'))
1442 1442
1443 1443 # we know there are no local changes, so we can make a simplified
1444 1444 # form of hg.update.
1445 1445 if update:
1446 1446 qp = self.qparents(repo, rev)
1447 1447 ctx = repo[qp]
1448 1448 m, a, r, d = repo.status(qp, '.')[:4]
1449 1449 if d:
1450 1450 raise util.Abort(_("deletions found between repo revs"))
1451 1451
1452 1452 tobackup = set(a + m + r) & tobackup
1453 1453 if keepchanges and tobackup:
1454 1454 raise util.Abort(_("local changes found, refresh first"))
1455 1455 self.backup(repo, tobackup)
1456 1456 repo.dirstate.beginparentchange()
1457 1457 for f in a:
1458 1458 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1459 1459 repo.dirstate.drop(f)
1460 1460 for f in m + r:
1461 1461 fctx = ctx[f]
1462 1462 repo.wwrite(f, fctx.data(), fctx.flags())
1463 1463 repo.dirstate.normal(f)
1464 1464 repo.setparents(qp, nullid)
1465 1465 repo.dirstate.endparentchange()
1466 1466 for patch in reversed(self.applied[start:end]):
1467 1467 self.ui.status(_("popping %s\n") % patch.name)
1468 1468 del self.applied[start:end]
1469 1469 strip(self.ui, repo, [rev], update=False, backup=False)
1470 1470 for s, state in repo['.'].substate.items():
1471 1471 repo['.'].sub(s).get(state)
1472 1472 if self.applied:
1473 1473 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1474 1474 else:
1475 1475 self.ui.write(_("patch queue now empty\n"))
1476 1476 finally:
1477 1477 wlock.release()
1478 1478
1479 1479 def diff(self, repo, pats, opts):
1480 1480 top, patch = self.checktoppatch(repo)
1481 1481 if not top:
1482 1482 self.ui.write(_("no patches applied\n"))
1483 1483 return
1484 1484 qp = self.qparents(repo, top)
1485 1485 if opts.get('reverse'):
1486 1486 node1, node2 = None, qp
1487 1487 else:
1488 1488 node1, node2 = qp, None
1489 1489 diffopts = self.diffopts(opts, patch)
1490 1490 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1491 1491
1492 1492 def refresh(self, repo, pats=None, **opts):
1493 1493 if not self.applied:
1494 1494 self.ui.write(_("no patches applied\n"))
1495 1495 return 1
1496 1496 msg = opts.get('msg', '').rstrip()
1497 1497 edit = opts.get('edit')
1498 1498 editform = opts.get('editform', 'mq.qrefresh')
1499 1499 newuser = opts.get('user')
1500 1500 newdate = opts.get('date')
1501 1501 if newdate:
1502 1502 newdate = '%d %d' % util.parsedate(newdate)
1503 1503 wlock = repo.wlock()
1504 1504
1505 1505 try:
1506 1506 self.checktoppatch(repo)
1507 1507 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1508 1508 if repo.changelog.heads(top) != [top]:
1509 1509 raise util.Abort(_("cannot refresh a revision with children"))
1510 1510 if not repo[top].mutable():
1511 1511 raise util.Abort(_("cannot refresh immutable revision"),
1512 1512 hint=_('see "hg help phases" for details'))
1513 1513
1514 1514 cparents = repo.changelog.parents(top)
1515 1515 patchparent = self.qparents(repo, top)
1516 1516
1517 1517 inclsubs = checksubstate(repo, hex(patchparent))
1518 1518 if inclsubs:
1519 1519 substatestate = repo.dirstate['.hgsubstate']
1520 1520
1521 1521 ph = patchheader(self.join(patchfn), self.plainmode)
1522 1522 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1523 1523 if newuser:
1524 1524 ph.setuser(newuser)
1525 1525 if newdate:
1526 1526 ph.setdate(newdate)
1527 1527 ph.setparent(hex(patchparent))
1528 1528
1529 1529 # only commit new patch when write is complete
1530 1530 patchf = self.opener(patchfn, 'w', atomictemp=True)
1531 1531
1532 1532 # update the dirstate in place, strip off the qtip commit
1533 1533 # and then commit.
1534 1534 #
1535 1535 # this should really read:
1536 1536 # mm, dd, aa = repo.status(top, patchparent)[:3]
1537 1537 # but we do it backwards to take advantage of manifest/changelog
1538 1538 # caching against the next repo.status call
1539 1539 mm, aa, dd = repo.status(patchparent, top)[:3]
1540 1540 changes = repo.changelog.read(top)
1541 1541 man = repo.manifest.read(changes[0])
1542 1542 aaa = aa[:]
1543 1543 matchfn = scmutil.match(repo[None], pats, opts)
1544 1544 # in short mode, we only diff the files included in the
1545 1545 # patch already plus specified files
1546 1546 if opts.get('short'):
1547 1547 # if amending a patch, we start with existing
1548 1548 # files plus specified files - unfiltered
1549 1549 match = scmutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1550 1550 # filter with include/exclude options
1551 1551 matchfn = scmutil.match(repo[None], opts=opts)
1552 1552 else:
1553 1553 match = scmutil.matchall(repo)
1554 1554 m, a, r, d = repo.status(match=match)[:4]
1555 1555 mm = set(mm)
1556 1556 aa = set(aa)
1557 1557 dd = set(dd)
1558 1558
1559 1559 # we might end up with files that were added between
1560 1560 # qtip and the dirstate parent, but then changed in the
1561 1561 # local dirstate. in this case, we want them to only
1562 1562 # show up in the added section
1563 1563 for x in m:
1564 1564 if x not in aa:
1565 1565 mm.add(x)
1566 1566 # we might end up with files added by the local dirstate that
1567 1567 # were deleted by the patch. In this case, they should only
1568 1568 # show up in the changed section.
1569 1569 for x in a:
1570 1570 if x in dd:
1571 1571 dd.remove(x)
1572 1572 mm.add(x)
1573 1573 else:
1574 1574 aa.add(x)
1575 1575 # make sure any files deleted in the local dirstate
1576 1576 # are not in the add or change column of the patch
1577 1577 forget = []
1578 1578 for x in d + r:
1579 1579 if x in aa:
1580 1580 aa.remove(x)
1581 1581 forget.append(x)
1582 1582 continue
1583 1583 else:
1584 1584 mm.discard(x)
1585 1585 dd.add(x)
1586 1586
1587 1587 m = list(mm)
1588 1588 r = list(dd)
1589 1589 a = list(aa)
1590 1590
1591 1591 # create 'match' that includes the files to be recommitted.
1592 1592 # apply matchfn via repo.status to ensure correct case handling.
1593 1593 cm, ca, cr, cd = repo.status(patchparent, match=matchfn)[:4]
1594 1594 allmatches = set(cm + ca + cr + cd)
1595 1595 refreshchanges = [x.intersection(allmatches) for x in (mm, aa, dd)]
1596 1596
1597 1597 files = set(inclsubs)
1598 1598 for x in refreshchanges:
1599 1599 files.update(x)
1600 1600 match = scmutil.matchfiles(repo, files)
1601 1601
1602 1602 bmlist = repo[top].bookmarks()
1603 1603
1604 1604 try:
1605 1605 repo.dirstate.beginparentchange()
1606 1606 if diffopts.git or diffopts.upgrade:
1607 1607 copies = {}
1608 1608 for dst in a:
1609 1609 src = repo.dirstate.copied(dst)
1610 1610 # during qfold, the source file for copies may
1611 1611 # be removed. Treat this as a simple add.
1612 1612 if src is not None and src in repo.dirstate:
1613 1613 copies.setdefault(src, []).append(dst)
1614 1614 repo.dirstate.add(dst)
1615 1615 # remember the copies between patchparent and qtip
1616 1616 for dst in aaa:
1617 1617 f = repo.file(dst)
1618 1618 src = f.renamed(man[dst])
1619 1619 if src:
1620 1620 copies.setdefault(src[0], []).extend(
1621 1621 copies.get(dst, []))
1622 1622 if dst in a:
1623 1623 copies[src[0]].append(dst)
1624 1624 # we can't copy a file created by the patch itself
1625 1625 if dst in copies:
1626 1626 del copies[dst]
1627 1627 for src, dsts in copies.iteritems():
1628 1628 for dst in dsts:
1629 1629 repo.dirstate.copy(src, dst)
1630 1630 else:
1631 1631 for dst in a:
1632 1632 repo.dirstate.add(dst)
1633 1633 # Drop useless copy information
1634 1634 for f in list(repo.dirstate.copies()):
1635 1635 repo.dirstate.copy(None, f)
1636 1636 for f in r:
1637 1637 repo.dirstate.remove(f)
1638 1638 # if the patch excludes a modified file, mark that
1639 1639 # file with mtime=0 so status can see it.
1640 1640 mm = []
1641 1641 for i in xrange(len(m) - 1, -1, -1):
1642 1642 if not matchfn(m[i]):
1643 1643 mm.append(m[i])
1644 1644 del m[i]
1645 1645 for f in m:
1646 1646 repo.dirstate.normal(f)
1647 1647 for f in mm:
1648 1648 repo.dirstate.normallookup(f)
1649 1649 for f in forget:
1650 1650 repo.dirstate.drop(f)
1651 1651
1652 1652 user = ph.user or changes[1]
1653 1653
1654 1654 oldphase = repo[top].phase()
1655 1655
1656 1656 # assumes strip can roll itself back if interrupted
1657 1657 repo.setparents(*cparents)
1658 1658 repo.dirstate.endparentchange()
1659 1659 self.applied.pop()
1660 1660 self.applieddirty = True
1661 1661 strip(self.ui, repo, [top], update=False, backup=False)
1662 1662 except: # re-raises
1663 1663 repo.dirstate.invalidate()
1664 1664 raise
1665 1665
1666 1666 try:
1667 1667 # might be nice to attempt to roll back strip after this
1668 1668
1669 1669 defaultmsg = "[mq]: %s" % patchfn
1670 1670 editor = cmdutil.getcommiteditor(editform=editform)
1671 1671 if edit:
1672 1672 def finishdesc(desc):
1673 1673 if desc.rstrip():
1674 1674 ph.setmessage(desc)
1675 1675 return desc
1676 1676 return defaultmsg
1677 1677 # i18n: this message is shown in editor with "HG: " prefix
1678 1678 extramsg = _('Leave message empty to use default message.')
1679 1679 editor = cmdutil.getcommiteditor(finishdesc=finishdesc,
1680 1680 extramsg=extramsg,
1681 1681 editform=editform)
1682 1682 message = msg or "\n".join(ph.message)
1683 1683 elif not msg:
1684 1684 if not ph.message:
1685 1685 message = defaultmsg
1686 1686 else:
1687 1687 message = "\n".join(ph.message)
1688 1688 else:
1689 1689 message = msg
1690 1690 ph.setmessage(msg)
1691 1691
1692 1692 # Ensure we create a new changeset in the same phase than
1693 1693 # the old one.
1694 1694 n = newcommit(repo, oldphase, message, user, ph.date,
1695 1695 match=match, force=True, editor=editor)
1696 1696 # only write patch after a successful commit
1697 1697 c = [list(x) for x in refreshchanges]
1698 1698 if inclsubs:
1699 1699 self.putsubstate2changes(substatestate, c)
1700 1700 chunks = patchmod.diff(repo, patchparent,
1701 1701 changes=c, opts=diffopts)
1702 1702 comments = str(ph)
1703 1703 if comments:
1704 1704 patchf.write(comments)
1705 1705 for chunk in chunks:
1706 1706 patchf.write(chunk)
1707 1707 patchf.close()
1708 1708
1709 1709 marks = repo._bookmarks
1710 1710 for bm in bmlist:
1711 1711 marks[bm] = n
1712 1712 marks.write()
1713 1713
1714 1714 self.applied.append(statusentry(n, patchfn))
1715 1715 except: # re-raises
1716 1716 ctx = repo[cparents[0]]
1717 1717 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1718 1718 self.savedirty()
1719 1719 self.ui.warn(_('refresh interrupted while patch was popped! '
1720 1720 '(revert --all, qpush to recover)\n'))
1721 1721 raise
1722 1722 finally:
1723 1723 wlock.release()
1724 1724 self.removeundo(repo)
1725 1725
1726 1726 def init(self, repo, create=False):
1727 1727 if not create and os.path.isdir(self.path):
1728 1728 raise util.Abort(_("patch queue directory already exists"))
1729 1729 try:
1730 1730 os.mkdir(self.path)
1731 1731 except OSError, inst:
1732 1732 if inst.errno != errno.EEXIST or not create:
1733 1733 raise
1734 1734 if create:
1735 1735 return self.qrepo(create=True)
1736 1736
1737 1737 def unapplied(self, repo, patch=None):
1738 1738 if patch and patch not in self.series:
1739 1739 raise util.Abort(_("patch %s is not in series file") % patch)
1740 1740 if not patch:
1741 1741 start = self.seriesend()
1742 1742 else:
1743 1743 start = self.series.index(patch) + 1
1744 1744 unapplied = []
1745 1745 for i in xrange(start, len(self.series)):
1746 1746 pushable, reason = self.pushable(i)
1747 1747 if pushable:
1748 1748 unapplied.append((i, self.series[i]))
1749 1749 self.explainpushable(i)
1750 1750 return unapplied
1751 1751
1752 1752 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1753 1753 summary=False):
1754 1754 def displayname(pfx, patchname, state):
1755 1755 if pfx:
1756 1756 self.ui.write(pfx)
1757 1757 if summary:
1758 1758 ph = patchheader(self.join(patchname), self.plainmode)
1759 1759 msg = ph.message and ph.message[0] or ''
1760 1760 if self.ui.formatted():
1761 1761 width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
1762 1762 if width > 0:
1763 1763 msg = util.ellipsis(msg, width)
1764 1764 else:
1765 1765 msg = ''
1766 1766 self.ui.write(patchname, label='qseries.' + state)
1767 1767 self.ui.write(': ')
1768 1768 self.ui.write(msg, label='qseries.message.' + state)
1769 1769 else:
1770 1770 self.ui.write(patchname, label='qseries.' + state)
1771 1771 self.ui.write('\n')
1772 1772
1773 1773 applied = set([p.name for p in self.applied])
1774 1774 if length is None:
1775 1775 length = len(self.series) - start
1776 1776 if not missing:
1777 1777 if self.ui.verbose:
1778 1778 idxwidth = len(str(start + length - 1))
1779 1779 for i in xrange(start, start + length):
1780 1780 patch = self.series[i]
1781 1781 if patch in applied:
1782 1782 char, state = 'A', 'applied'
1783 1783 elif self.pushable(i)[0]:
1784 1784 char, state = 'U', 'unapplied'
1785 1785 else:
1786 1786 char, state = 'G', 'guarded'
1787 1787 pfx = ''
1788 1788 if self.ui.verbose:
1789 1789 pfx = '%*d %s ' % (idxwidth, i, char)
1790 1790 elif status and status != char:
1791 1791 continue
1792 1792 displayname(pfx, patch, state)
1793 1793 else:
1794 1794 msng_list = []
1795 1795 for root, dirs, files in os.walk(self.path):
1796 1796 d = root[len(self.path) + 1:]
1797 1797 for f in files:
1798 1798 fl = os.path.join(d, f)
1799 1799 if (fl not in self.series and
1800 1800 fl not in (self.statuspath, self.seriespath,
1801 1801 self.guardspath)
1802 1802 and not fl.startswith('.')):
1803 1803 msng_list.append(fl)
1804 1804 for x in sorted(msng_list):
1805 1805 pfx = self.ui.verbose and ('D ') or ''
1806 1806 displayname(pfx, x, 'missing')
1807 1807
1808 1808 def issaveline(self, l):
1809 1809 if l.name == '.hg.patches.save.line':
1810 1810 return True
1811 1811
1812 1812 def qrepo(self, create=False):
1813 1813 ui = self.baseui.copy()
1814 1814 if create or os.path.isdir(self.join(".hg")):
1815 1815 return hg.repository(ui, path=self.path, create=create)
1816 1816
1817 1817 def restore(self, repo, rev, delete=None, qupdate=None):
1818 1818 desc = repo[rev].description().strip()
1819 1819 lines = desc.splitlines()
1820 1820 i = 0
1821 1821 datastart = None
1822 1822 series = []
1823 1823 applied = []
1824 1824 qpp = None
1825 1825 for i, line in enumerate(lines):
1826 1826 if line == 'Patch Data:':
1827 1827 datastart = i + 1
1828 1828 elif line.startswith('Dirstate:'):
1829 1829 l = line.rstrip()
1830 1830 l = l[10:].split(' ')
1831 1831 qpp = [bin(x) for x in l]
1832 1832 elif datastart is not None:
1833 1833 l = line.rstrip()
1834 1834 n, name = l.split(':', 1)
1835 1835 if n:
1836 1836 applied.append(statusentry(bin(n), name))
1837 1837 else:
1838 1838 series.append(l)
1839 1839 if datastart is None:
1840 1840 self.ui.warn(_("no saved patch data found\n"))
1841 1841 return 1
1842 1842 self.ui.warn(_("restoring status: %s\n") % lines[0])
1843 1843 self.fullseries = series
1844 1844 self.applied = applied
1845 1845 self.parseseries()
1846 1846 self.seriesdirty = True
1847 1847 self.applieddirty = True
1848 1848 heads = repo.changelog.heads()
1849 1849 if delete:
1850 1850 if rev not in heads:
1851 1851 self.ui.warn(_("save entry has children, leaving it alone\n"))
1852 1852 else:
1853 1853 self.ui.warn(_("removing save entry %s\n") % short(rev))
1854 1854 pp = repo.dirstate.parents()
1855 1855 if rev in pp:
1856 1856 update = True
1857 1857 else:
1858 1858 update = False
1859 1859 strip(self.ui, repo, [rev], update=update, backup=False)
1860 1860 if qpp:
1861 1861 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1862 1862 (short(qpp[0]), short(qpp[1])))
1863 1863 if qupdate:
1864 1864 self.ui.status(_("updating queue directory\n"))
1865 1865 r = self.qrepo()
1866 1866 if not r:
1867 1867 self.ui.warn(_("unable to load queue repository\n"))
1868 1868 return 1
1869 1869 hg.clean(r, qpp[0])
1870 1870
1871 1871 def save(self, repo, msg=None):
1872 1872 if not self.applied:
1873 1873 self.ui.warn(_("save: no patches applied, exiting\n"))
1874 1874 return 1
1875 1875 if self.issaveline(self.applied[-1]):
1876 1876 self.ui.warn(_("status is already saved\n"))
1877 1877 return 1
1878 1878
1879 1879 if not msg:
1880 1880 msg = _("hg patches saved state")
1881 1881 else:
1882 1882 msg = "hg patches: " + msg.rstrip('\r\n')
1883 1883 r = self.qrepo()
1884 1884 if r:
1885 1885 pp = r.dirstate.parents()
1886 1886 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1887 1887 msg += "\n\nPatch Data:\n"
1888 1888 msg += ''.join('%s\n' % x for x in self.applied)
1889 1889 msg += ''.join(':%s\n' % x for x in self.fullseries)
1890 1890 n = repo.commit(msg, force=True)
1891 1891 if not n:
1892 1892 self.ui.warn(_("repo commit failed\n"))
1893 1893 return 1
1894 1894 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1895 1895 self.applieddirty = True
1896 1896 self.removeundo(repo)
1897 1897
1898 1898 def fullseriesend(self):
1899 1899 if self.applied:
1900 1900 p = self.applied[-1].name
1901 1901 end = self.findseries(p)
1902 1902 if end is None:
1903 1903 return len(self.fullseries)
1904 1904 return end + 1
1905 1905 return 0
1906 1906
1907 1907 def seriesend(self, all_patches=False):
1908 1908 """If all_patches is False, return the index of the next pushable patch
1909 1909 in the series, or the series length. If all_patches is True, return the
1910 1910 index of the first patch past the last applied one.
1911 1911 """
1912 1912 end = 0
1913 1913 def nextpatch(start):
1914 1914 if all_patches or start >= len(self.series):
1915 1915 return start
1916 1916 for i in xrange(start, len(self.series)):
1917 1917 p, reason = self.pushable(i)
1918 1918 if p:
1919 1919 return i
1920 1920 self.explainpushable(i)
1921 1921 return len(self.series)
1922 1922 if self.applied:
1923 1923 p = self.applied[-1].name
1924 1924 try:
1925 1925 end = self.series.index(p)
1926 1926 except ValueError:
1927 1927 return 0
1928 1928 return nextpatch(end + 1)
1929 1929 return nextpatch(end)
1930 1930
1931 1931 def appliedname(self, index):
1932 1932 pname = self.applied[index].name
1933 1933 if not self.ui.verbose:
1934 1934 p = pname
1935 1935 else:
1936 1936 p = str(self.series.index(pname)) + " " + pname
1937 1937 return p
1938 1938
1939 1939 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1940 1940 force=None, git=False):
1941 1941 def checkseries(patchname):
1942 1942 if patchname in self.series:
1943 1943 raise util.Abort(_('patch %s is already in the series file')
1944 1944 % patchname)
1945 1945
1946 1946 if rev:
1947 1947 if files:
1948 1948 raise util.Abort(_('option "-r" not valid when importing '
1949 1949 'files'))
1950 1950 rev = scmutil.revrange(repo, rev)
1951 1951 rev.sort(reverse=True)
1952 1952 elif not files:
1953 1953 raise util.Abort(_('no files or revisions specified'))
1954 1954 if (len(files) > 1 or len(rev) > 1) and patchname:
1955 1955 raise util.Abort(_('option "-n" not valid when importing multiple '
1956 1956 'patches'))
1957 1957 imported = []
1958 1958 if rev:
1959 1959 # If mq patches are applied, we can only import revisions
1960 1960 # that form a linear path to qbase.
1961 1961 # Otherwise, they should form a linear path to a head.
1962 1962 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1963 1963 if len(heads) > 1:
1964 1964 raise util.Abort(_('revision %d is the root of more than one '
1965 1965 'branch') % rev[-1])
1966 1966 if self.applied:
1967 1967 base = repo.changelog.node(rev[0])
1968 1968 if base in [n.node for n in self.applied]:
1969 1969 raise util.Abort(_('revision %d is already managed')
1970 1970 % rev[0])
1971 1971 if heads != [self.applied[-1].node]:
1972 1972 raise util.Abort(_('revision %d is not the parent of '
1973 1973 'the queue') % rev[0])
1974 1974 base = repo.changelog.rev(self.applied[0].node)
1975 1975 lastparent = repo.changelog.parentrevs(base)[0]
1976 1976 else:
1977 1977 if heads != [repo.changelog.node(rev[0])]:
1978 1978 raise util.Abort(_('revision %d has unmanaged children')
1979 1979 % rev[0])
1980 1980 lastparent = None
1981 1981
1982 1982 diffopts = self.diffopts({'git': git})
1983 1983 tr = repo.transaction('qimport')
1984 1984 try:
1985 1985 for r in rev:
1986 1986 if not repo[r].mutable():
1987 1987 raise util.Abort(_('revision %d is not mutable') % r,
1988 1988 hint=_('see "hg help phases" '
1989 1989 'for details'))
1990 1990 p1, p2 = repo.changelog.parentrevs(r)
1991 1991 n = repo.changelog.node(r)
1992 1992 if p2 != nullrev:
1993 1993 raise util.Abort(_('cannot import merge revision %d')
1994 1994 % r)
1995 1995 if lastparent and lastparent != r:
1996 1996 raise util.Abort(_('revision %d is not the parent of '
1997 1997 '%d')
1998 1998 % (r, lastparent))
1999 1999 lastparent = p1
2000 2000
2001 2001 if not patchname:
2002 2002 patchname = normname('%d.diff' % r)
2003 2003 checkseries(patchname)
2004 2004 self.checkpatchname(patchname, force)
2005 2005 self.fullseries.insert(0, patchname)
2006 2006
2007 2007 patchf = self.opener(patchname, "w")
2008 2008 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
2009 2009 patchf.close()
2010 2010
2011 2011 se = statusentry(n, patchname)
2012 2012 self.applied.insert(0, se)
2013 2013
2014 2014 self.added.append(patchname)
2015 2015 imported.append(patchname)
2016 2016 patchname = None
2017 2017 if rev and repo.ui.configbool('mq', 'secret', False):
2018 2018 # if we added anything with --rev, move the secret root
2019 2019 phases.retractboundary(repo, tr, phases.secret, [n])
2020 2020 self.parseseries()
2021 2021 self.applieddirty = True
2022 2022 self.seriesdirty = True
2023 2023 tr.close()
2024 2024 finally:
2025 2025 tr.release()
2026 2026
2027 2027 for i, filename in enumerate(files):
2028 2028 if existing:
2029 2029 if filename == '-':
2030 2030 raise util.Abort(_('-e is incompatible with import from -'))
2031 2031 filename = normname(filename)
2032 2032 self.checkreservedname(filename)
2033 2033 if util.url(filename).islocal():
2034 2034 originpath = self.join(filename)
2035 2035 if not os.path.isfile(originpath):
2036 2036 raise util.Abort(
2037 2037 _("patch %s does not exist") % filename)
2038 2038
2039 2039 if patchname:
2040 2040 self.checkpatchname(patchname, force)
2041 2041
2042 2042 self.ui.write(_('renaming %s to %s\n')
2043 2043 % (filename, patchname))
2044 2044 util.rename(originpath, self.join(patchname))
2045 2045 else:
2046 2046 patchname = filename
2047 2047
2048 2048 else:
2049 2049 if filename == '-' and not patchname:
2050 2050 raise util.Abort(_('need --name to import a patch from -'))
2051 2051 elif not patchname:
2052 2052 patchname = normname(os.path.basename(filename.rstrip('/')))
2053 2053 self.checkpatchname(patchname, force)
2054 2054 try:
2055 2055 if filename == '-':
2056 2056 text = self.ui.fin.read()
2057 2057 else:
2058 2058 fp = hg.openpath(self.ui, filename)
2059 2059 text = fp.read()
2060 2060 fp.close()
2061 2061 except (OSError, IOError):
2062 2062 raise util.Abort(_("unable to read file %s") % filename)
2063 2063 patchf = self.opener(patchname, "w")
2064 2064 patchf.write(text)
2065 2065 patchf.close()
2066 2066 if not force:
2067 2067 checkseries(patchname)
2068 2068 if patchname not in self.series:
2069 2069 index = self.fullseriesend() + i
2070 2070 self.fullseries[index:index] = [patchname]
2071 2071 self.parseseries()
2072 2072 self.seriesdirty = True
2073 2073 self.ui.warn(_("adding %s to series file\n") % patchname)
2074 2074 self.added.append(patchname)
2075 2075 imported.append(patchname)
2076 2076 patchname = None
2077 2077
2078 2078 self.removeundo(repo)
2079 2079 return imported
2080 2080
2081 2081 def fixkeepchangesopts(ui, opts):
2082 2082 if (not ui.configbool('mq', 'keepchanges') or opts.get('force')
2083 2083 or opts.get('exact')):
2084 2084 return opts
2085 2085 opts = dict(opts)
2086 2086 opts['keep_changes'] = True
2087 2087 return opts
2088 2088
2089 2089 @command("qdelete|qremove|qrm",
2090 2090 [('k', 'keep', None, _('keep patch file')),
2091 2091 ('r', 'rev', [],
2092 2092 _('stop managing a revision (DEPRECATED)'), _('REV'))],
2093 2093 _('hg qdelete [-k] [PATCH]...'))
2094 2094 def delete(ui, repo, *patches, **opts):
2095 2095 """remove patches from queue
2096 2096
2097 2097 The patches must not be applied, and at least one patch is required. Exact
2098 2098 patch identifiers must be given. With -k/--keep, the patch files are
2099 2099 preserved in the patch directory.
2100 2100
2101 2101 To stop managing a patch and move it into permanent history,
2102 2102 use the :hg:`qfinish` command."""
2103 2103 q = repo.mq
2104 2104 q.delete(repo, patches, opts)
2105 2105 q.savedirty()
2106 2106 return 0
2107 2107
2108 2108 @command("qapplied",
2109 2109 [('1', 'last', None, _('show only the preceding applied patch'))
2110 2110 ] + seriesopts,
2111 2111 _('hg qapplied [-1] [-s] [PATCH]'))
2112 2112 def applied(ui, repo, patch=None, **opts):
2113 2113 """print the patches already applied
2114 2114
2115 2115 Returns 0 on success."""
2116 2116
2117 2117 q = repo.mq
2118 2118
2119 2119 if patch:
2120 2120 if patch not in q.series:
2121 2121 raise util.Abort(_("patch %s is not in series file") % patch)
2122 2122 end = q.series.index(patch) + 1
2123 2123 else:
2124 2124 end = q.seriesend(True)
2125 2125
2126 2126 if opts.get('last') and not end:
2127 2127 ui.write(_("no patches applied\n"))
2128 2128 return 1
2129 2129 elif opts.get('last') and end == 1:
2130 2130 ui.write(_("only one patch applied\n"))
2131 2131 return 1
2132 2132 elif opts.get('last'):
2133 2133 start = end - 2
2134 2134 end = 1
2135 2135 else:
2136 2136 start = 0
2137 2137
2138 2138 q.qseries(repo, length=end, start=start, status='A',
2139 2139 summary=opts.get('summary'))
2140 2140
2141 2141
2142 2142 @command("qunapplied",
2143 2143 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2144 2144 _('hg qunapplied [-1] [-s] [PATCH]'))
2145 2145 def unapplied(ui, repo, patch=None, **opts):
2146 2146 """print the patches not yet applied
2147 2147
2148 2148 Returns 0 on success."""
2149 2149
2150 2150 q = repo.mq
2151 2151 if patch:
2152 2152 if patch not in q.series:
2153 2153 raise util.Abort(_("patch %s is not in series file") % patch)
2154 2154 start = q.series.index(patch) + 1
2155 2155 else:
2156 2156 start = q.seriesend(True)
2157 2157
2158 2158 if start == len(q.series) and opts.get('first'):
2159 2159 ui.write(_("all patches applied\n"))
2160 2160 return 1
2161 2161
2162 2162 length = opts.get('first') and 1 or None
2163 2163 q.qseries(repo, start=start, length=length, status='U',
2164 2164 summary=opts.get('summary'))
2165 2165
2166 2166 @command("qimport",
2167 2167 [('e', 'existing', None, _('import file in patch directory')),
2168 2168 ('n', 'name', '',
2169 2169 _('name of patch file'), _('NAME')),
2170 2170 ('f', 'force', None, _('overwrite existing files')),
2171 2171 ('r', 'rev', [],
2172 2172 _('place existing revisions under mq control'), _('REV')),
2173 2173 ('g', 'git', None, _('use git extended diff format')),
2174 2174 ('P', 'push', None, _('qpush after importing'))],
2175 2175 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...'))
2176 2176 def qimport(ui, repo, *filename, **opts):
2177 2177 """import a patch or existing changeset
2178 2178
2179 2179 The patch is inserted into the series after the last applied
2180 2180 patch. If no patches have been applied, qimport prepends the patch
2181 2181 to the series.
2182 2182
2183 2183 The patch will have the same name as its source file unless you
2184 2184 give it a new one with -n/--name.
2185 2185
2186 2186 You can register an existing patch inside the patch directory with
2187 2187 the -e/--existing flag.
2188 2188
2189 2189 With -f/--force, an existing patch of the same name will be
2190 2190 overwritten.
2191 2191
2192 2192 An existing changeset may be placed under mq control with -r/--rev
2193 2193 (e.g. qimport --rev . -n patch will place the current revision
2194 2194 under mq control). With -g/--git, patches imported with --rev will
2195 2195 use the git diff format. See the diffs help topic for information
2196 2196 on why this is important for preserving rename/copy information
2197 2197 and permission changes. Use :hg:`qfinish` to remove changesets
2198 2198 from mq control.
2199 2199
2200 2200 To import a patch from standard input, pass - as the patch file.
2201 2201 When importing from standard input, a patch name must be specified
2202 2202 using the --name flag.
2203 2203
2204 2204 To import an existing patch while renaming it::
2205 2205
2206 2206 hg qimport -e existing-patch -n new-name
2207 2207
2208 2208 Returns 0 if import succeeded.
2209 2209 """
2210 2210 lock = repo.lock() # cause this may move phase
2211 2211 try:
2212 2212 q = repo.mq
2213 2213 try:
2214 2214 imported = q.qimport(
2215 2215 repo, filename, patchname=opts.get('name'),
2216 2216 existing=opts.get('existing'), force=opts.get('force'),
2217 2217 rev=opts.get('rev'), git=opts.get('git'))
2218 2218 finally:
2219 2219 q.savedirty()
2220 2220 finally:
2221 2221 lock.release()
2222 2222
2223 2223 if imported and opts.get('push') and not opts.get('rev'):
2224 2224 return q.push(repo, imported[-1])
2225 2225 return 0
2226 2226
2227 2227 def qinit(ui, repo, create):
2228 2228 """initialize a new queue repository
2229 2229
2230 2230 This command also creates a series file for ordering patches, and
2231 2231 an mq-specific .hgignore file in the queue repository, to exclude
2232 2232 the status and guards files (these contain mostly transient state).
2233 2233
2234 2234 Returns 0 if initialization succeeded."""
2235 2235 q = repo.mq
2236 2236 r = q.init(repo, create)
2237 2237 q.savedirty()
2238 2238 if r:
2239 2239 if not os.path.exists(r.wjoin('.hgignore')):
2240 2240 fp = r.wopener('.hgignore', 'w')
2241 2241 fp.write('^\\.hg\n')
2242 2242 fp.write('^\\.mq\n')
2243 2243 fp.write('syntax: glob\n')
2244 2244 fp.write('status\n')
2245 2245 fp.write('guards\n')
2246 2246 fp.close()
2247 2247 if not os.path.exists(r.wjoin('series')):
2248 2248 r.wopener('series', 'w').close()
2249 2249 r[None].add(['.hgignore', 'series'])
2250 2250 commands.add(ui, r)
2251 2251 return 0
2252 2252
2253 2253 @command("^qinit",
2254 2254 [('c', 'create-repo', None, _('create queue repository'))],
2255 2255 _('hg qinit [-c]'))
2256 2256 def init(ui, repo, **opts):
2257 2257 """init a new queue repository (DEPRECATED)
2258 2258
2259 2259 The queue repository is unversioned by default. If
2260 2260 -c/--create-repo is specified, qinit will create a separate nested
2261 2261 repository for patches (qinit -c may also be run later to convert
2262 2262 an unversioned patch repository into a versioned one). You can use
2263 2263 qcommit to commit changes to this queue repository.
2264 2264
2265 2265 This command is deprecated. Without -c, it's implied by other relevant
2266 2266 commands. With -c, use :hg:`init --mq` instead."""
2267 2267 return qinit(ui, repo, create=opts.get('create_repo'))
2268 2268
2269 2269 @command("qclone",
2270 2270 [('', 'pull', None, _('use pull protocol to copy metadata')),
2271 2271 ('U', 'noupdate', None,
2272 2272 _('do not update the new working directories')),
2273 2273 ('', 'uncompressed', None,
2274 2274 _('use uncompressed transfer (fast over LAN)')),
2275 2275 ('p', 'patches', '',
2276 2276 _('location of source patch repository'), _('REPO')),
2277 2277 ] + commands.remoteopts,
2278 2278 _('hg qclone [OPTION]... SOURCE [DEST]'),
2279 2279 norepo=True)
2280 2280 def clone(ui, source, dest=None, **opts):
2281 2281 '''clone main and patch repository at same time
2282 2282
2283 2283 If source is local, destination will have no patches applied. If
2284 2284 source is remote, this command can not check if patches are
2285 2285 applied in source, so cannot guarantee that patches are not
2286 2286 applied in destination. If you clone remote repository, be sure
2287 2287 before that it has no patches applied.
2288 2288
2289 2289 Source patch repository is looked for in <src>/.hg/patches by
2290 2290 default. Use -p <url> to change.
2291 2291
2292 2292 The patch directory must be a nested Mercurial repository, as
2293 2293 would be created by :hg:`init --mq`.
2294 2294
2295 2295 Return 0 on success.
2296 2296 '''
2297 2297 def patchdir(repo):
2298 2298 """compute a patch repo url from a repo object"""
2299 2299 url = repo.url()
2300 2300 if url.endswith('/'):
2301 2301 url = url[:-1]
2302 2302 return url + '/.hg/patches'
2303 2303
2304 2304 # main repo (destination and sources)
2305 2305 if dest is None:
2306 2306 dest = hg.defaultdest(source)
2307 2307 sr = hg.peer(ui, opts, ui.expandpath(source))
2308 2308
2309 2309 # patches repo (source only)
2310 2310 if opts.get('patches'):
2311 2311 patchespath = ui.expandpath(opts.get('patches'))
2312 2312 else:
2313 2313 patchespath = patchdir(sr)
2314 2314 try:
2315 2315 hg.peer(ui, opts, patchespath)
2316 2316 except error.RepoError:
2317 2317 raise util.Abort(_('versioned patch repository not found'
2318 2318 ' (see init --mq)'))
2319 2319 qbase, destrev = None, None
2320 2320 if sr.local():
2321 2321 repo = sr.local()
2322 2322 if repo.mq.applied and repo[qbase].phase() != phases.secret:
2323 2323 qbase = repo.mq.applied[0].node
2324 2324 if not hg.islocal(dest):
2325 2325 heads = set(repo.heads())
2326 2326 destrev = list(heads.difference(repo.heads(qbase)))
2327 2327 destrev.append(repo.changelog.parents(qbase)[0])
2328 2328 elif sr.capable('lookup'):
2329 2329 try:
2330 2330 qbase = sr.lookup('qbase')
2331 2331 except error.RepoError:
2332 2332 pass
2333 2333
2334 2334 ui.note(_('cloning main repository\n'))
2335 2335 sr, dr = hg.clone(ui, opts, sr.url(), dest,
2336 2336 pull=opts.get('pull'),
2337 2337 rev=destrev,
2338 2338 update=False,
2339 2339 stream=opts.get('uncompressed'))
2340 2340
2341 2341 ui.note(_('cloning patch repository\n'))
2342 2342 hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
2343 2343 pull=opts.get('pull'), update=not opts.get('noupdate'),
2344 2344 stream=opts.get('uncompressed'))
2345 2345
2346 2346 if dr.local():
2347 2347 repo = dr.local()
2348 2348 if qbase:
2349 2349 ui.note(_('stripping applied patches from destination '
2350 2350 'repository\n'))
2351 2351 strip(ui, repo, [qbase], update=False, backup=None)
2352 2352 if not opts.get('noupdate'):
2353 2353 ui.note(_('updating destination repository\n'))
2354 2354 hg.update(repo, repo.changelog.tip())
2355 2355
2356 2356 @command("qcommit|qci",
2357 2357 commands.table["^commit|ci"][1],
2358 2358 _('hg qcommit [OPTION]... [FILE]...'),
2359 2359 inferrepo=True)
2360 2360 def commit(ui, repo, *pats, **opts):
2361 2361 """commit changes in the queue repository (DEPRECATED)
2362 2362
2363 2363 This command is deprecated; use :hg:`commit --mq` instead."""
2364 2364 q = repo.mq
2365 2365 r = q.qrepo()
2366 2366 if not r:
2367 2367 raise util.Abort('no queue repository')
2368 2368 commands.commit(r.ui, r, *pats, **opts)
2369 2369
2370 2370 @command("qseries",
2371 2371 [('m', 'missing', None, _('print patches not in series')),
2372 2372 ] + seriesopts,
2373 2373 _('hg qseries [-ms]'))
2374 2374 def series(ui, repo, **opts):
2375 2375 """print the entire series file
2376 2376
2377 2377 Returns 0 on success."""
2378 2378 repo.mq.qseries(repo, missing=opts.get('missing'),
2379 2379 summary=opts.get('summary'))
2380 2380 return 0
2381 2381
2382 2382 @command("qtop", seriesopts, _('hg qtop [-s]'))
2383 2383 def top(ui, repo, **opts):
2384 2384 """print the name of the current patch
2385 2385
2386 2386 Returns 0 on success."""
2387 2387 q = repo.mq
2388 2388 t = q.applied and q.seriesend(True) or 0
2389 2389 if t:
2390 2390 q.qseries(repo, start=t - 1, length=1, status='A',
2391 2391 summary=opts.get('summary'))
2392 2392 else:
2393 2393 ui.write(_("no patches applied\n"))
2394 2394 return 1
2395 2395
2396 2396 @command("qnext", seriesopts, _('hg qnext [-s]'))
2397 2397 def next(ui, repo, **opts):
2398 2398 """print the name of the next pushable patch
2399 2399
2400 2400 Returns 0 on success."""
2401 2401 q = repo.mq
2402 2402 end = q.seriesend()
2403 2403 if end == len(q.series):
2404 2404 ui.write(_("all patches applied\n"))
2405 2405 return 1
2406 2406 q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
2407 2407
2408 2408 @command("qprev", seriesopts, _('hg qprev [-s]'))
2409 2409 def prev(ui, repo, **opts):
2410 2410 """print the name of the preceding applied patch
2411 2411
2412 2412 Returns 0 on success."""
2413 2413 q = repo.mq
2414 2414 l = len(q.applied)
2415 2415 if l == 1:
2416 2416 ui.write(_("only one patch applied\n"))
2417 2417 return 1
2418 2418 if not l:
2419 2419 ui.write(_("no patches applied\n"))
2420 2420 return 1
2421 2421 idx = q.series.index(q.applied[-2].name)
2422 2422 q.qseries(repo, start=idx, length=1, status='A',
2423 2423 summary=opts.get('summary'))
2424 2424
2425 2425 def setupheaderopts(ui, opts):
2426 2426 if not opts.get('user') and opts.get('currentuser'):
2427 2427 opts['user'] = ui.username()
2428 2428 if not opts.get('date') and opts.get('currentdate'):
2429 2429 opts['date'] = "%d %d" % util.makedate()
2430 2430
2431 2431 @command("^qnew",
2432 2432 [('e', 'edit', None, _('invoke editor on commit messages')),
2433 2433 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2434 2434 ('g', 'git', None, _('use git extended diff format')),
2435 2435 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2436 2436 ('u', 'user', '',
2437 2437 _('add "From: <USER>" to patch'), _('USER')),
2438 2438 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2439 2439 ('d', 'date', '',
2440 2440 _('add "Date: <DATE>" to patch'), _('DATE'))
2441 2441 ] + commands.walkopts + commands.commitopts,
2442 2442 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'),
2443 2443 inferrepo=True)
2444 2444 def new(ui, repo, patch, *args, **opts):
2445 2445 """create a new patch
2446 2446
2447 2447 qnew creates a new patch on top of the currently-applied patch (if
2448 2448 any). The patch will be initialized with any outstanding changes
2449 2449 in the working directory. You may also use -I/--include,
2450 2450 -X/--exclude, and/or a list of files after the patch name to add
2451 2451 only changes to matching files to the new patch, leaving the rest
2452 2452 as uncommitted modifications.
2453 2453
2454 2454 -u/--user and -d/--date can be used to set the (given) user and
2455 2455 date, respectively. -U/--currentuser and -D/--currentdate set user
2456 2456 to current user and date to current date.
2457 2457
2458 2458 -e/--edit, -m/--message or -l/--logfile set the patch header as
2459 2459 well as the commit message. If none is specified, the header is
2460 2460 empty and the commit message is '[mq]: PATCH'.
2461 2461
2462 2462 Use the -g/--git option to keep the patch in the git extended diff
2463 2463 format. Read the diffs help topic for more information on why this
2464 2464 is important for preserving permission changes and copy/rename
2465 2465 information.
2466 2466
2467 2467 Returns 0 on successful creation of a new patch.
2468 2468 """
2469 2469 msg = cmdutil.logmessage(ui, opts)
2470 2470 q = repo.mq
2471 2471 opts['msg'] = msg
2472 2472 setupheaderopts(ui, opts)
2473 2473 q.new(repo, patch, *args, **opts)
2474 2474 q.savedirty()
2475 2475 return 0
2476 2476
2477 2477 @command("^qrefresh",
2478 2478 [('e', 'edit', None, _('invoke editor on commit messages')),
2479 2479 ('g', 'git', None, _('use git extended diff format')),
2480 2480 ('s', 'short', None,
2481 2481 _('refresh only files already in the patch and specified files')),
2482 2482 ('U', 'currentuser', None,
2483 2483 _('add/update author field in patch with current user')),
2484 2484 ('u', 'user', '',
2485 2485 _('add/update author field in patch with given user'), _('USER')),
2486 2486 ('D', 'currentdate', None,
2487 2487 _('add/update date field in patch with current date')),
2488 2488 ('d', 'date', '',
2489 2489 _('add/update date field in patch with given date'), _('DATE'))
2490 2490 ] + commands.walkopts + commands.commitopts,
2491 2491 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
2492 2492 inferrepo=True)
2493 2493 def refresh(ui, repo, *pats, **opts):
2494 2494 """update the current patch
2495 2495
2496 2496 If any file patterns are provided, the refreshed patch will
2497 2497 contain only the modifications that match those patterns; the
2498 2498 remaining modifications will remain in the working directory.
2499 2499
2500 2500 If -s/--short is specified, files currently included in the patch
2501 2501 will be refreshed just like matched files and remain in the patch.
2502 2502
2503 2503 If -e/--edit is specified, Mercurial will start your configured editor for
2504 2504 you to enter a message. In case qrefresh fails, you will find a backup of
2505 2505 your message in ``.hg/last-message.txt``.
2506 2506
2507 2507 hg add/remove/copy/rename work as usual, though you might want to
2508 2508 use git-style patches (-g/--git or [diff] git=1) to track copies
2509 2509 and renames. See the diffs help topic for more information on the
2510 2510 git diff format.
2511 2511
2512 2512 Returns 0 on success.
2513 2513 """
2514 2514 q = repo.mq
2515 2515 message = cmdutil.logmessage(ui, opts)
2516 2516 setupheaderopts(ui, opts)
2517 2517 wlock = repo.wlock()
2518 2518 try:
2519 2519 ret = q.refresh(repo, pats, msg=message, **opts)
2520 2520 q.savedirty()
2521 2521 return ret
2522 2522 finally:
2523 2523 wlock.release()
2524 2524
2525 2525 @command("^qdiff",
2526 2526 commands.diffopts + commands.diffopts2 + commands.walkopts,
2527 2527 _('hg qdiff [OPTION]... [FILE]...'),
2528 2528 inferrepo=True)
2529 2529 def diff(ui, repo, *pats, **opts):
2530 2530 """diff of the current patch and subsequent modifications
2531 2531
2532 2532 Shows a diff which includes the current patch as well as any
2533 2533 changes which have been made in the working directory since the
2534 2534 last refresh (thus showing what the current patch would become
2535 2535 after a qrefresh).
2536 2536
2537 2537 Use :hg:`diff` if you only want to see the changes made since the
2538 2538 last qrefresh, or :hg:`export qtip` if you want to see changes
2539 2539 made by the current patch without including changes made since the
2540 2540 qrefresh.
2541 2541
2542 2542 Returns 0 on success.
2543 2543 """
2544 2544 repo.mq.diff(repo, pats, opts)
2545 2545 return 0
2546 2546
2547 2547 @command('qfold',
2548 2548 [('e', 'edit', None, _('invoke editor on commit messages')),
2549 2549 ('k', 'keep', None, _('keep folded patch files')),
2550 2550 ] + commands.commitopts,
2551 2551 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'))
2552 2552 def fold(ui, repo, *files, **opts):
2553 2553 """fold the named patches into the current patch
2554 2554
2555 2555 Patches must not yet be applied. Each patch will be successively
2556 2556 applied to the current patch in the order given. If all the
2557 2557 patches apply successfully, the current patch will be refreshed
2558 2558 with the new cumulative patch, and the folded patches will be
2559 2559 deleted. With -k/--keep, the folded patch files will not be
2560 2560 removed afterwards.
2561 2561
2562 2562 The header for each folded patch will be concatenated with the
2563 2563 current patch header, separated by a line of ``* * *``.
2564 2564
2565 2565 Returns 0 on success."""
2566 2566 q = repo.mq
2567 2567 if not files:
2568 2568 raise util.Abort(_('qfold requires at least one patch name'))
2569 2569 if not q.checktoppatch(repo)[0]:
2570 2570 raise util.Abort(_('no patches applied'))
2571 2571 q.checklocalchanges(repo)
2572 2572
2573 2573 message = cmdutil.logmessage(ui, opts)
2574 2574
2575 2575 parent = q.lookup('qtip')
2576 2576 patches = []
2577 2577 messages = []
2578 2578 for f in files:
2579 2579 p = q.lookup(f)
2580 2580 if p in patches or p == parent:
2581 2581 ui.warn(_('skipping already folded patch %s\n') % p)
2582 2582 if q.isapplied(p):
2583 2583 raise util.Abort(_('qfold cannot fold already applied patch %s')
2584 2584 % p)
2585 2585 patches.append(p)
2586 2586
2587 2587 for p in patches:
2588 2588 if not message:
2589 2589 ph = patchheader(q.join(p), q.plainmode)
2590 2590 if ph.message:
2591 2591 messages.append(ph.message)
2592 2592 pf = q.join(p)
2593 2593 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2594 2594 if not patchsuccess:
2595 2595 raise util.Abort(_('error folding patch %s') % p)
2596 2596
2597 2597 if not message:
2598 2598 ph = patchheader(q.join(parent), q.plainmode)
2599 2599 message = ph.message
2600 2600 for msg in messages:
2601 2601 if msg:
2602 2602 if message:
2603 2603 message.append('* * *')
2604 2604 message.extend(msg)
2605 2605 message = '\n'.join(message)
2606 2606
2607 2607 diffopts = q.patchopts(q.diffopts(), *patches)
2608 2608 wlock = repo.wlock()
2609 2609 try:
2610 2610 q.refresh(repo, msg=message, git=diffopts.git, edit=opts.get('edit'),
2611 2611 editform='mq.qfold')
2612 2612 q.delete(repo, patches, opts)
2613 2613 q.savedirty()
2614 2614 finally:
2615 2615 wlock.release()
2616 2616
2617 2617 @command("qgoto",
2618 2618 [('', 'keep-changes', None,
2619 2619 _('tolerate non-conflicting local changes')),
2620 2620 ('f', 'force', None, _('overwrite any local changes')),
2621 2621 ('', 'no-backup', None, _('do not save backup copies of files'))],
2622 2622 _('hg qgoto [OPTION]... PATCH'))
2623 2623 def goto(ui, repo, patch, **opts):
2624 2624 '''push or pop patches until named patch is at top of stack
2625 2625
2626 2626 Returns 0 on success.'''
2627 2627 opts = fixkeepchangesopts(ui, opts)
2628 2628 q = repo.mq
2629 2629 patch = q.lookup(patch)
2630 2630 nobackup = opts.get('no_backup')
2631 2631 keepchanges = opts.get('keep_changes')
2632 2632 if q.isapplied(patch):
2633 2633 ret = q.pop(repo, patch, force=opts.get('force'), nobackup=nobackup,
2634 2634 keepchanges=keepchanges)
2635 2635 else:
2636 2636 ret = q.push(repo, patch, force=opts.get('force'), nobackup=nobackup,
2637 2637 keepchanges=keepchanges)
2638 2638 q.savedirty()
2639 2639 return ret
2640 2640
2641 2641 @command("qguard",
2642 2642 [('l', 'list', None, _('list all patches and guards')),
2643 2643 ('n', 'none', None, _('drop all guards'))],
2644 2644 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'))
2645 2645 def guard(ui, repo, *args, **opts):
2646 2646 '''set or print guards for a patch
2647 2647
2648 2648 Guards control whether a patch can be pushed. A patch with no
2649 2649 guards is always pushed. A patch with a positive guard ("+foo") is
2650 2650 pushed only if the :hg:`qselect` command has activated it. A patch with
2651 2651 a negative guard ("-foo") is never pushed if the :hg:`qselect` command
2652 2652 has activated it.
2653 2653
2654 2654 With no arguments, print the currently active guards.
2655 2655 With arguments, set guards for the named patch.
2656 2656
2657 2657 .. note::
2658 2658
2659 2659 Specifying negative guards now requires '--'.
2660 2660
2661 2661 To set guards on another patch::
2662 2662
2663 2663 hg qguard other.patch -- +2.6.17 -stable
2664 2664
2665 2665 Returns 0 on success.
2666 2666 '''
2667 2667 def status(idx):
2668 2668 guards = q.seriesguards[idx] or ['unguarded']
2669 2669 if q.series[idx] in applied:
2670 2670 state = 'applied'
2671 2671 elif q.pushable(idx)[0]:
2672 2672 state = 'unapplied'
2673 2673 else:
2674 2674 state = 'guarded'
2675 2675 label = 'qguard.patch qguard.%s qseries.%s' % (state, state)
2676 2676 ui.write('%s: ' % ui.label(q.series[idx], label))
2677 2677
2678 2678 for i, guard in enumerate(guards):
2679 2679 if guard.startswith('+'):
2680 2680 ui.write(guard, label='qguard.positive')
2681 2681 elif guard.startswith('-'):
2682 2682 ui.write(guard, label='qguard.negative')
2683 2683 else:
2684 2684 ui.write(guard, label='qguard.unguarded')
2685 2685 if i != len(guards) - 1:
2686 2686 ui.write(' ')
2687 2687 ui.write('\n')
2688 2688 q = repo.mq
2689 2689 applied = set(p.name for p in q.applied)
2690 2690 patch = None
2691 2691 args = list(args)
2692 2692 if opts.get('list'):
2693 2693 if args or opts.get('none'):
2694 2694 raise util.Abort(_('cannot mix -l/--list with options or '
2695 2695 'arguments'))
2696 2696 for i in xrange(len(q.series)):
2697 2697 status(i)
2698 2698 return
2699 2699 if not args or args[0][0:1] in '-+':
2700 2700 if not q.applied:
2701 2701 raise util.Abort(_('no patches applied'))
2702 2702 patch = q.applied[-1].name
2703 2703 if patch is None and args[0][0:1] not in '-+':
2704 2704 patch = args.pop(0)
2705 2705 if patch is None:
2706 2706 raise util.Abort(_('no patch to work with'))
2707 2707 if args or opts.get('none'):
2708 2708 idx = q.findseries(patch)
2709 2709 if idx is None:
2710 2710 raise util.Abort(_('no patch named %s') % patch)
2711 2711 q.setguards(idx, args)
2712 2712 q.savedirty()
2713 2713 else:
2714 2714 status(q.series.index(q.lookup(patch)))
2715 2715
2716 2716 @command("qheader", [], _('hg qheader [PATCH]'))
2717 2717 def header(ui, repo, patch=None):
2718 2718 """print the header of the topmost or specified patch
2719 2719
2720 2720 Returns 0 on success."""
2721 2721 q = repo.mq
2722 2722
2723 2723 if patch:
2724 2724 patch = q.lookup(patch)
2725 2725 else:
2726 2726 if not q.applied:
2727 2727 ui.write(_('no patches applied\n'))
2728 2728 return 1
2729 2729 patch = q.lookup('qtip')
2730 2730 ph = patchheader(q.join(patch), q.plainmode)
2731 2731
2732 2732 ui.write('\n'.join(ph.message) + '\n')
2733 2733
2734 2734 def lastsavename(path):
2735 2735 (directory, base) = os.path.split(path)
2736 2736 names = os.listdir(directory)
2737 2737 namere = re.compile("%s.([0-9]+)" % base)
2738 2738 maxindex = None
2739 2739 maxname = None
2740 2740 for f in names:
2741 2741 m = namere.match(f)
2742 2742 if m:
2743 2743 index = int(m.group(1))
2744 2744 if maxindex is None or index > maxindex:
2745 2745 maxindex = index
2746 2746 maxname = f
2747 2747 if maxname:
2748 2748 return (os.path.join(directory, maxname), maxindex)
2749 2749 return (None, None)
2750 2750
2751 2751 def savename(path):
2752 2752 (last, index) = lastsavename(path)
2753 2753 if last is None:
2754 2754 index = 0
2755 2755 newpath = path + ".%d" % (index + 1)
2756 2756 return newpath
2757 2757
2758 2758 @command("^qpush",
2759 2759 [('', 'keep-changes', None,
2760 2760 _('tolerate non-conflicting local changes')),
2761 2761 ('f', 'force', None, _('apply on top of local changes')),
2762 2762 ('e', 'exact', None,
2763 2763 _('apply the target patch to its recorded parent')),
2764 2764 ('l', 'list', None, _('list patch name in commit text')),
2765 2765 ('a', 'all', None, _('apply all patches')),
2766 2766 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2767 2767 ('n', 'name', '',
2768 2768 _('merge queue name (DEPRECATED)'), _('NAME')),
2769 2769 ('', 'move', None,
2770 2770 _('reorder patch series and apply only the patch')),
2771 2771 ('', 'no-backup', None, _('do not save backup copies of files'))],
2772 2772 _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'))
2773 2773 def push(ui, repo, patch=None, **opts):
2774 2774 """push the next patch onto the stack
2775 2775
2776 2776 By default, abort if the working directory contains uncommitted
2777 2777 changes. With --keep-changes, abort only if the uncommitted files
2778 2778 overlap with patched files. With -f/--force, backup and patch over
2779 2779 uncommitted changes.
2780 2780
2781 2781 Return 0 on success.
2782 2782 """
2783 2783 q = repo.mq
2784 2784 mergeq = None
2785 2785
2786 2786 opts = fixkeepchangesopts(ui, opts)
2787 2787 if opts.get('merge'):
2788 2788 if opts.get('name'):
2789 2789 newpath = repo.join(opts.get('name'))
2790 2790 else:
2791 2791 newpath, i = lastsavename(q.path)
2792 2792 if not newpath:
2793 2793 ui.warn(_("no saved queues found, please use -n\n"))
2794 2794 return 1
2795 2795 mergeq = queue(ui, repo.baseui, repo.path, newpath)
2796 2796 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2797 2797 ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
2798 2798 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
2799 2799 exact=opts.get('exact'), nobackup=opts.get('no_backup'),
2800 2800 keepchanges=opts.get('keep_changes'))
2801 2801 return ret
2802 2802
2803 2803 @command("^qpop",
2804 2804 [('a', 'all', None, _('pop all patches')),
2805 2805 ('n', 'name', '',
2806 2806 _('queue name to pop (DEPRECATED)'), _('NAME')),
2807 2807 ('', 'keep-changes', None,
2808 2808 _('tolerate non-conflicting local changes')),
2809 2809 ('f', 'force', None, _('forget any local changes to patched files')),
2810 2810 ('', 'no-backup', None, _('do not save backup copies of files'))],
2811 2811 _('hg qpop [-a] [-f] [PATCH | INDEX]'))
2812 2812 def pop(ui, repo, patch=None, **opts):
2813 2813 """pop the current patch off the stack
2814 2814
2815 2815 Without argument, pops off the top of the patch stack. If given a
2816 2816 patch name, keeps popping off patches until the named patch is at
2817 2817 the top of the stack.
2818 2818
2819 2819 By default, abort if the working directory contains uncommitted
2820 2820 changes. With --keep-changes, abort only if the uncommitted files
2821 2821 overlap with patched files. With -f/--force, backup and discard
2822 2822 changes made to such files.
2823 2823
2824 2824 Return 0 on success.
2825 2825 """
2826 2826 opts = fixkeepchangesopts(ui, opts)
2827 2827 localupdate = True
2828 2828 if opts.get('name'):
2829 2829 q = queue(ui, repo.baseui, repo.path, repo.join(opts.get('name')))
2830 2830 ui.warn(_('using patch queue: %s\n') % q.path)
2831 2831 localupdate = False
2832 2832 else:
2833 2833 q = repo.mq
2834 2834 ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
2835 2835 all=opts.get('all'), nobackup=opts.get('no_backup'),
2836 2836 keepchanges=opts.get('keep_changes'))
2837 2837 q.savedirty()
2838 2838 return ret
2839 2839
2840 2840 @command("qrename|qmv", [], _('hg qrename PATCH1 [PATCH2]'))
2841 2841 def rename(ui, repo, patch, name=None, **opts):
2842 2842 """rename a patch
2843 2843
2844 2844 With one argument, renames the current patch to PATCH1.
2845 2845 With two arguments, renames PATCH1 to PATCH2.
2846 2846
2847 2847 Returns 0 on success."""
2848 2848 q = repo.mq
2849 2849 if not name:
2850 2850 name = patch
2851 2851 patch = None
2852 2852
2853 2853 if patch:
2854 2854 patch = q.lookup(patch)
2855 2855 else:
2856 2856 if not q.applied:
2857 2857 ui.write(_('no patches applied\n'))
2858 2858 return
2859 2859 patch = q.lookup('qtip')
2860 2860 absdest = q.join(name)
2861 2861 if os.path.isdir(absdest):
2862 2862 name = normname(os.path.join(name, os.path.basename(patch)))
2863 2863 absdest = q.join(name)
2864 2864 q.checkpatchname(name)
2865 2865
2866 2866 ui.note(_('renaming %s to %s\n') % (patch, name))
2867 2867 i = q.findseries(patch)
2868 2868 guards = q.guard_re.findall(q.fullseries[i])
2869 2869 q.fullseries[i] = name + ''.join([' #' + g for g in guards])
2870 2870 q.parseseries()
2871 2871 q.seriesdirty = True
2872 2872
2873 2873 info = q.isapplied(patch)
2874 2874 if info:
2875 2875 q.applied[info[0]] = statusentry(info[1], name)
2876 2876 q.applieddirty = True
2877 2877
2878 2878 destdir = os.path.dirname(absdest)
2879 2879 if not os.path.isdir(destdir):
2880 2880 os.makedirs(destdir)
2881 2881 util.rename(q.join(patch), absdest)
2882 2882 r = q.qrepo()
2883 2883 if r and patch in r.dirstate:
2884 2884 wctx = r[None]
2885 2885 wlock = r.wlock()
2886 2886 try:
2887 2887 if r.dirstate[patch] == 'a':
2888 2888 r.dirstate.drop(patch)
2889 2889 r.dirstate.add(name)
2890 2890 else:
2891 2891 wctx.copy(patch, name)
2892 2892 wctx.forget([patch])
2893 2893 finally:
2894 2894 wlock.release()
2895 2895
2896 2896 q.savedirty()
2897 2897
2898 2898 @command("qrestore",
2899 2899 [('d', 'delete', None, _('delete save entry')),
2900 2900 ('u', 'update', None, _('update queue working directory'))],
2901 2901 _('hg qrestore [-d] [-u] REV'))
2902 2902 def restore(ui, repo, rev, **opts):
2903 2903 """restore the queue state saved by a revision (DEPRECATED)
2904 2904
2905 2905 This command is deprecated, use :hg:`rebase` instead."""
2906 2906 rev = repo.lookup(rev)
2907 2907 q = repo.mq
2908 2908 q.restore(repo, rev, delete=opts.get('delete'),
2909 2909 qupdate=opts.get('update'))
2910 2910 q.savedirty()
2911 2911 return 0
2912 2912
2913 2913 @command("qsave",
2914 2914 [('c', 'copy', None, _('copy patch directory')),
2915 2915 ('n', 'name', '',
2916 2916 _('copy directory name'), _('NAME')),
2917 2917 ('e', 'empty', None, _('clear queue status file')),
2918 2918 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2919 2919 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'))
2920 2920 def save(ui, repo, **opts):
2921 2921 """save current queue state (DEPRECATED)
2922 2922
2923 2923 This command is deprecated, use :hg:`rebase` instead."""
2924 2924 q = repo.mq
2925 2925 message = cmdutil.logmessage(ui, opts)
2926 2926 ret = q.save(repo, msg=message)
2927 2927 if ret:
2928 2928 return ret
2929 2929 q.savedirty() # save to .hg/patches before copying
2930 2930 if opts.get('copy'):
2931 2931 path = q.path
2932 2932 if opts.get('name'):
2933 2933 newpath = os.path.join(q.basepath, opts.get('name'))
2934 2934 if os.path.exists(newpath):
2935 2935 if not os.path.isdir(newpath):
2936 2936 raise util.Abort(_('destination %s exists and is not '
2937 2937 'a directory') % newpath)
2938 2938 if not opts.get('force'):
2939 2939 raise util.Abort(_('destination %s exists, '
2940 2940 'use -f to force') % newpath)
2941 2941 else:
2942 2942 newpath = savename(path)
2943 2943 ui.warn(_("copy %s to %s\n") % (path, newpath))
2944 2944 util.copyfiles(path, newpath)
2945 2945 if opts.get('empty'):
2946 2946 del q.applied[:]
2947 2947 q.applieddirty = True
2948 2948 q.savedirty()
2949 2949 return 0
2950 2950
2951 2951
2952 2952 @command("qselect",
2953 2953 [('n', 'none', None, _('disable all guards')),
2954 2954 ('s', 'series', None, _('list all guards in series file')),
2955 2955 ('', 'pop', None, _('pop to before first guarded applied patch')),
2956 2956 ('', 'reapply', None, _('pop, then reapply patches'))],
2957 2957 _('hg qselect [OPTION]... [GUARD]...'))
2958 2958 def select(ui, repo, *args, **opts):
2959 2959 '''set or print guarded patches to push
2960 2960
2961 2961 Use the :hg:`qguard` command to set or print guards on patch, then use
2962 2962 qselect to tell mq which guards to use. A patch will be pushed if
2963 2963 it has no guards or any positive guards match the currently
2964 2964 selected guard, but will not be pushed if any negative guards
2965 2965 match the current guard. For example::
2966 2966
2967 2967 qguard foo.patch -- -stable (negative guard)
2968 2968 qguard bar.patch +stable (positive guard)
2969 2969 qselect stable
2970 2970
2971 2971 This activates the "stable" guard. mq will skip foo.patch (because
2972 2972 it has a negative match) but push bar.patch (because it has a
2973 2973 positive match).
2974 2974
2975 2975 With no arguments, prints the currently active guards.
2976 2976 With one argument, sets the active guard.
2977 2977
2978 2978 Use -n/--none to deactivate guards (no other arguments needed).
2979 2979 When no guards are active, patches with positive guards are
2980 2980 skipped and patches with negative guards are pushed.
2981 2981
2982 2982 qselect can change the guards on applied patches. It does not pop
2983 2983 guarded patches by default. Use --pop to pop back to the last
2984 2984 applied patch that is not guarded. Use --reapply (which implies
2985 2985 --pop) to push back to the current patch afterwards, but skip
2986 2986 guarded patches.
2987 2987
2988 2988 Use -s/--series to print a list of all guards in the series file
2989 2989 (no other arguments needed). Use -v for more information.
2990 2990
2991 2991 Returns 0 on success.'''
2992 2992
2993 2993 q = repo.mq
2994 2994 guards = q.active()
2995 2995 pushable = lambda i: q.pushable(q.applied[i].name)[0]
2996 2996 if args or opts.get('none'):
2997 2997 old_unapplied = q.unapplied(repo)
2998 2998 old_guarded = [i for i in xrange(len(q.applied)) if not pushable(i)]
2999 2999 q.setactive(args)
3000 3000 q.savedirty()
3001 3001 if not args:
3002 3002 ui.status(_('guards deactivated\n'))
3003 3003 if not opts.get('pop') and not opts.get('reapply'):
3004 3004 unapplied = q.unapplied(repo)
3005 3005 guarded = [i for i in xrange(len(q.applied)) if not pushable(i)]
3006 3006 if len(unapplied) != len(old_unapplied):
3007 3007 ui.status(_('number of unguarded, unapplied patches has '
3008 3008 'changed from %d to %d\n') %
3009 3009 (len(old_unapplied), len(unapplied)))
3010 3010 if len(guarded) != len(old_guarded):
3011 3011 ui.status(_('number of guarded, applied patches has changed '
3012 3012 'from %d to %d\n') %
3013 3013 (len(old_guarded), len(guarded)))
3014 3014 elif opts.get('series'):
3015 3015 guards = {}
3016 3016 noguards = 0
3017 3017 for gs in q.seriesguards:
3018 3018 if not gs:
3019 3019 noguards += 1
3020 3020 for g in gs:
3021 3021 guards.setdefault(g, 0)
3022 3022 guards[g] += 1
3023 3023 if ui.verbose:
3024 3024 guards['NONE'] = noguards
3025 3025 guards = guards.items()
3026 3026 guards.sort(key=lambda x: x[0][1:])
3027 3027 if guards:
3028 3028 ui.note(_('guards in series file:\n'))
3029 3029 for guard, count in guards:
3030 3030 ui.note('%2d ' % count)
3031 3031 ui.write(guard, '\n')
3032 3032 else:
3033 3033 ui.note(_('no guards in series file\n'))
3034 3034 else:
3035 3035 if guards:
3036 3036 ui.note(_('active guards:\n'))
3037 3037 for g in guards:
3038 3038 ui.write(g, '\n')
3039 3039 else:
3040 3040 ui.write(_('no active guards\n'))
3041 3041 reapply = opts.get('reapply') and q.applied and q.applied[-1].name
3042 3042 popped = False
3043 3043 if opts.get('pop') or opts.get('reapply'):
3044 3044 for i in xrange(len(q.applied)):
3045 3045 if not pushable(i):
3046 3046 ui.status(_('popping guarded patches\n'))
3047 3047 popped = True
3048 3048 if i == 0:
3049 3049 q.pop(repo, all=True)
3050 3050 else:
3051 3051 q.pop(repo, q.applied[i - 1].name)
3052 3052 break
3053 3053 if popped:
3054 3054 try:
3055 3055 if reapply:
3056 3056 ui.status(_('reapplying unguarded patches\n'))
3057 3057 q.push(repo, reapply)
3058 3058 finally:
3059 3059 q.savedirty()
3060 3060
3061 3061 @command("qfinish",
3062 3062 [('a', 'applied', None, _('finish all applied changesets'))],
3063 3063 _('hg qfinish [-a] [REV]...'))
3064 3064 def finish(ui, repo, *revrange, **opts):
3065 3065 """move applied patches into repository history
3066 3066
3067 3067 Finishes the specified revisions (corresponding to applied
3068 3068 patches) by moving them out of mq control into regular repository
3069 3069 history.
3070 3070
3071 3071 Accepts a revision range or the -a/--applied option. If --applied
3072 3072 is specified, all applied mq revisions are removed from mq
3073 3073 control. Otherwise, the given revisions must be at the base of the
3074 3074 stack of applied patches.
3075 3075
3076 3076 This can be especially useful if your changes have been applied to
3077 3077 an upstream repository, or if you are about to push your changes
3078 3078 to upstream.
3079 3079
3080 3080 Returns 0 on success.
3081 3081 """
3082 3082 if not opts.get('applied') and not revrange:
3083 3083 raise util.Abort(_('no revisions specified'))
3084 3084 elif opts.get('applied'):
3085 3085 revrange = ('qbase::qtip',) + revrange
3086 3086
3087 3087 q = repo.mq
3088 3088 if not q.applied:
3089 3089 ui.status(_('no patches applied\n'))
3090 3090 return 0
3091 3091
3092 3092 revs = scmutil.revrange(repo, revrange)
3093 3093 if repo['.'].rev() in revs and repo[None].files():
3094 3094 ui.warn(_('warning: uncommitted changes in the working directory\n'))
3095 3095 # queue.finish may changes phases but leave the responsibility to lock the
3096 3096 # repo to the caller to avoid deadlock with wlock. This command code is
3097 3097 # responsibility for this locking.
3098 3098 lock = repo.lock()
3099 3099 try:
3100 3100 q.finish(repo, revs)
3101 3101 q.savedirty()
3102 3102 finally:
3103 3103 lock.release()
3104 3104 return 0
3105 3105
3106 3106 @command("qqueue",
3107 3107 [('l', 'list', False, _('list all available queues')),
3108 3108 ('', 'active', False, _('print name of active queue')),
3109 3109 ('c', 'create', False, _('create new queue')),
3110 3110 ('', 'rename', False, _('rename active queue')),
3111 3111 ('', 'delete', False, _('delete reference to queue')),
3112 3112 ('', 'purge', False, _('delete queue, and remove patch dir')),
3113 3113 ],
3114 3114 _('[OPTION] [QUEUE]'))
3115 3115 def qqueue(ui, repo, name=None, **opts):
3116 3116 '''manage multiple patch queues
3117 3117
3118 3118 Supports switching between different patch queues, as well as creating
3119 3119 new patch queues and deleting existing ones.
3120 3120
3121 3121 Omitting a queue name or specifying -l/--list will show you the registered
3122 3122 queues - by default the "normal" patches queue is registered. The currently
3123 3123 active queue will be marked with "(active)". Specifying --active will print
3124 3124 only the name of the active queue.
3125 3125
3126 3126 To create a new queue, use -c/--create. The queue is automatically made
3127 3127 active, except in the case where there are applied patches from the
3128 3128 currently active queue in the repository. Then the queue will only be
3129 3129 created and switching will fail.
3130 3130
3131 3131 To delete an existing queue, use --delete. You cannot delete the currently
3132 3132 active queue.
3133 3133
3134 3134 Returns 0 on success.
3135 3135 '''
3136 3136 q = repo.mq
3137 3137 _defaultqueue = 'patches'
3138 3138 _allqueues = 'patches.queues'
3139 3139 _activequeue = 'patches.queue'
3140 3140
3141 3141 def _getcurrent():
3142 3142 cur = os.path.basename(q.path)
3143 3143 if cur.startswith('patches-'):
3144 3144 cur = cur[8:]
3145 3145 return cur
3146 3146
3147 3147 def _noqueues():
3148 3148 try:
3149 3149 fh = repo.opener(_allqueues, 'r')
3150 3150 fh.close()
3151 3151 except IOError:
3152 3152 return True
3153 3153
3154 3154 return False
3155 3155
3156 3156 def _getqueues():
3157 3157 current = _getcurrent()
3158 3158
3159 3159 try:
3160 3160 fh = repo.opener(_allqueues, 'r')
3161 3161 queues = [queue.strip() for queue in fh if queue.strip()]
3162 3162 fh.close()
3163 3163 if current not in queues:
3164 3164 queues.append(current)
3165 3165 except IOError:
3166 3166 queues = [_defaultqueue]
3167 3167
3168 3168 return sorted(queues)
3169 3169
3170 3170 def _setactive(name):
3171 3171 if q.applied:
3172 3172 raise util.Abort(_('new queue created, but cannot make active '
3173 3173 'as patches are applied'))
3174 3174 _setactivenocheck(name)
3175 3175
3176 3176 def _setactivenocheck(name):
3177 3177 fh = repo.opener(_activequeue, 'w')
3178 3178 if name != 'patches':
3179 3179 fh.write(name)
3180 3180 fh.close()
3181 3181
3182 3182 def _addqueue(name):
3183 3183 fh = repo.opener(_allqueues, 'a')
3184 3184 fh.write('%s\n' % (name,))
3185 3185 fh.close()
3186 3186
3187 3187 def _queuedir(name):
3188 3188 if name == 'patches':
3189 3189 return repo.join('patches')
3190 3190 else:
3191 3191 return repo.join('patches-' + name)
3192 3192
3193 3193 def _validname(name):
3194 3194 for n in name:
3195 3195 if n in ':\\/.':
3196 3196 return False
3197 3197 return True
3198 3198
3199 3199 def _delete(name):
3200 3200 if name not in existing:
3201 3201 raise util.Abort(_('cannot delete queue that does not exist'))
3202 3202
3203 3203 current = _getcurrent()
3204 3204
3205 3205 if name == current:
3206 3206 raise util.Abort(_('cannot delete currently active queue'))
3207 3207
3208 3208 fh = repo.opener('patches.queues.new', 'w')
3209 3209 for queue in existing:
3210 3210 if queue == name:
3211 3211 continue
3212 3212 fh.write('%s\n' % (queue,))
3213 3213 fh.close()
3214 3214 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3215 3215
3216 3216 if not name or opts.get('list') or opts.get('active'):
3217 3217 current = _getcurrent()
3218 3218 if opts.get('active'):
3219 3219 ui.write('%s\n' % (current,))
3220 3220 return
3221 3221 for queue in _getqueues():
3222 3222 ui.write('%s' % (queue,))
3223 3223 if queue == current and not ui.quiet:
3224 3224 ui.write(_(' (active)\n'))
3225 3225 else:
3226 3226 ui.write('\n')
3227 3227 return
3228 3228
3229 3229 if not _validname(name):
3230 3230 raise util.Abort(
3231 3231 _('invalid queue name, may not contain the characters ":\\/."'))
3232 3232
3233 3233 existing = _getqueues()
3234 3234
3235 3235 if opts.get('create'):
3236 3236 if name in existing:
3237 3237 raise util.Abort(_('queue "%s" already exists') % name)
3238 3238 if _noqueues():
3239 3239 _addqueue(_defaultqueue)
3240 3240 _addqueue(name)
3241 3241 _setactive(name)
3242 3242 elif opts.get('rename'):
3243 3243 current = _getcurrent()
3244 3244 if name == current:
3245 3245 raise util.Abort(_('can\'t rename "%s" to its current name') % name)
3246 3246 if name in existing:
3247 3247 raise util.Abort(_('queue "%s" already exists') % name)
3248 3248
3249 3249 olddir = _queuedir(current)
3250 3250 newdir = _queuedir(name)
3251 3251
3252 3252 if os.path.exists(newdir):
3253 3253 raise util.Abort(_('non-queue directory "%s" already exists') %
3254 3254 newdir)
3255 3255
3256 3256 fh = repo.opener('patches.queues.new', 'w')
3257 3257 for queue in existing:
3258 3258 if queue == current:
3259 3259 fh.write('%s\n' % (name,))
3260 3260 if os.path.exists(olddir):
3261 3261 util.rename(olddir, newdir)
3262 3262 else:
3263 3263 fh.write('%s\n' % (queue,))
3264 3264 fh.close()
3265 3265 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3266 3266 _setactivenocheck(name)
3267 3267 elif opts.get('delete'):
3268 3268 _delete(name)
3269 3269 elif opts.get('purge'):
3270 3270 if name in existing:
3271 3271 _delete(name)
3272 3272 qdir = _queuedir(name)
3273 3273 if os.path.exists(qdir):
3274 3274 shutil.rmtree(qdir)
3275 3275 else:
3276 3276 if name not in existing:
3277 3277 raise util.Abort(_('use --create to create a new queue'))
3278 3278 _setactive(name)
3279 3279
3280 3280 def mqphasedefaults(repo, roots):
3281 3281 """callback used to set mq changeset as secret when no phase data exists"""
3282 3282 if repo.mq.applied:
3283 3283 if repo.ui.configbool('mq', 'secret', False):
3284 3284 mqphase = phases.secret
3285 3285 else:
3286 3286 mqphase = phases.draft
3287 3287 qbase = repo[repo.mq.applied[0].node]
3288 3288 roots[mqphase].add(qbase.node())
3289 3289 return roots
3290 3290
3291 3291 def reposetup(ui, repo):
3292 3292 class mqrepo(repo.__class__):
3293 3293 @localrepo.unfilteredpropertycache
3294 3294 def mq(self):
3295 3295 return queue(self.ui, self.baseui, self.path)
3296 3296
3297 3297 def invalidateall(self):
3298 3298 super(mqrepo, self).invalidateall()
3299 3299 if localrepo.hasunfilteredcache(self, 'mq'):
3300 3300 # recreate mq in case queue path was changed
3301 3301 delattr(self.unfiltered(), 'mq')
3302 3302
3303 3303 def abortifwdirpatched(self, errmsg, force=False):
3304 3304 if self.mq.applied and self.mq.checkapplied and not force:
3305 3305 parents = self.dirstate.parents()
3306 3306 patches = [s.node for s in self.mq.applied]
3307 3307 if parents[0] in patches or parents[1] in patches:
3308 3308 raise util.Abort(errmsg)
3309 3309
3310 3310 def commit(self, text="", user=None, date=None, match=None,
3311 3311 force=False, editor=False, extra={}):
3312 3312 self.abortifwdirpatched(
3313 3313 _('cannot commit over an applied mq patch'),
3314 3314 force)
3315 3315
3316 3316 return super(mqrepo, self).commit(text, user, date, match, force,
3317 3317 editor, extra)
3318 3318
3319 3319 def checkpush(self, pushop):
3320 3320 if self.mq.applied and self.mq.checkapplied and not pushop.force:
3321 3321 outapplied = [e.node for e in self.mq.applied]
3322 3322 if pushop.revs:
3323 3323 # Assume applied patches have no non-patch descendants and
3324 3324 # are not on remote already. Filtering any changeset not
3325 3325 # pushed.
3326 3326 heads = set(pushop.revs)
3327 3327 for node in reversed(outapplied):
3328 3328 if node in heads:
3329 3329 break
3330 3330 else:
3331 3331 outapplied.pop()
3332 3332 # looking for pushed and shared changeset
3333 3333 for node in outapplied:
3334 3334 if self[node].phase() < phases.secret:
3335 3335 raise util.Abort(_('source has mq patches applied'))
3336 3336 # no non-secret patches pushed
3337 3337 super(mqrepo, self).checkpush(pushop)
3338 3338
3339 3339 def _findtags(self):
3340 3340 '''augment tags from base class with patch tags'''
3341 3341 result = super(mqrepo, self)._findtags()
3342 3342
3343 3343 q = self.mq
3344 3344 if not q.applied:
3345 3345 return result
3346 3346
3347 3347 mqtags = [(patch.node, patch.name) for patch in q.applied]
3348 3348
3349 3349 try:
3350 3350 # for now ignore filtering business
3351 3351 self.unfiltered().changelog.rev(mqtags[-1][0])
3352 3352 except error.LookupError:
3353 3353 self.ui.warn(_('mq status file refers to unknown node %s\n')
3354 3354 % short(mqtags[-1][0]))
3355 3355 return result
3356 3356
3357 3357 # do not add fake tags for filtered revisions
3358 3358 included = self.changelog.hasnode
3359 3359 mqtags = [mqt for mqt in mqtags if included(mqt[0])]
3360 3360 if not mqtags:
3361 3361 return result
3362 3362
3363 3363 mqtags.append((mqtags[-1][0], 'qtip'))
3364 3364 mqtags.append((mqtags[0][0], 'qbase'))
3365 3365 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
3366 3366 tags = result[0]
3367 3367 for patch in mqtags:
3368 3368 if patch[1] in tags:
3369 3369 self.ui.warn(_('tag %s overrides mq patch of the same '
3370 3370 'name\n') % patch[1])
3371 3371 else:
3372 3372 tags[patch[1]] = patch[0]
3373 3373
3374 3374 return result
3375 3375
3376 3376 if repo.local():
3377 3377 repo.__class__ = mqrepo
3378 3378
3379 3379 repo._phasedefaults.append(mqphasedefaults)
3380 3380
3381 3381 def mqimport(orig, ui, repo, *args, **kwargs):
3382 3382 if (util.safehasattr(repo, 'abortifwdirpatched')
3383 3383 and not kwargs.get('no_commit', False)):
3384 3384 repo.abortifwdirpatched(_('cannot import over an applied patch'),
3385 3385 kwargs.get('force'))
3386 3386 return orig(ui, repo, *args, **kwargs)
3387 3387
3388 3388 def mqinit(orig, ui, *args, **kwargs):
3389 3389 mq = kwargs.pop('mq', None)
3390 3390
3391 3391 if not mq:
3392 3392 return orig(ui, *args, **kwargs)
3393 3393
3394 3394 if args:
3395 3395 repopath = args[0]
3396 3396 if not hg.islocal(repopath):
3397 3397 raise util.Abort(_('only a local queue repository '
3398 3398 'may be initialized'))
3399 3399 else:
3400 3400 repopath = cmdutil.findrepo(os.getcwd())
3401 3401 if not repopath:
3402 3402 raise util.Abort(_('there is no Mercurial repository here '
3403 3403 '(.hg not found)'))
3404 3404 repo = hg.repository(ui, repopath)
3405 3405 return qinit(ui, repo, True)
3406 3406
3407 3407 def mqcommand(orig, ui, repo, *args, **kwargs):
3408 3408 """Add --mq option to operate on patch repository instead of main"""
3409 3409
3410 3410 # some commands do not like getting unknown options
3411 3411 mq = kwargs.pop('mq', None)
3412 3412
3413 3413 if not mq:
3414 3414 return orig(ui, repo, *args, **kwargs)
3415 3415
3416 3416 q = repo.mq
3417 3417 r = q.qrepo()
3418 3418 if not r:
3419 3419 raise util.Abort(_('no queue repository'))
3420 3420 return orig(r.ui, r, *args, **kwargs)
3421 3421
3422 3422 def summaryhook(ui, repo):
3423 3423 q = repo.mq
3424 3424 m = []
3425 3425 a, u = len(q.applied), len(q.unapplied(repo))
3426 3426 if a:
3427 3427 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
3428 3428 if u:
3429 3429 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
3430 3430 if m:
3431 3431 # i18n: column positioning for "hg summary"
3432 3432 ui.write(_("mq: %s\n") % ', '.join(m))
3433 3433 else:
3434 3434 # i18n: column positioning for "hg summary"
3435 3435 ui.note(_("mq: (empty queue)\n"))
3436 3436
3437 3437 def revsetmq(repo, subset, x):
3438 3438 """``mq()``
3439 3439 Changesets managed by MQ.
3440 3440 """
3441 3441 revset.getargs(x, 0, 0, _("mq takes no arguments"))
3442 3442 applied = set([repo[r.node].rev() for r in repo.mq.applied])
3443 3443 return revset.baseset([r for r in subset if r in applied])
3444 3444
3445 3445 # tell hggettext to extract docstrings from these functions:
3446 3446 i18nfunctions = [revsetmq]
3447 3447
3448 3448 def extsetup(ui):
3449 3449 # Ensure mq wrappers are called first, regardless of extension load order by
3450 3450 # NOT wrapping in uisetup() and instead deferring to init stage two here.
3451 3451 mqopt = [('', 'mq', None, _("operate on patch repository"))]
3452 3452
3453 3453 extensions.wrapcommand(commands.table, 'import', mqimport)
3454 3454 cmdutil.summaryhooks.add('mq', summaryhook)
3455 3455
3456 3456 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
3457 3457 entry[1].extend(mqopt)
3458 3458
3459 3459 nowrap = set(commands.norepo.split(" "))
3460 3460
3461 3461 def dotable(cmdtable):
3462 3462 for cmd in cmdtable.keys():
3463 3463 cmd = cmdutil.parsealiases(cmd)[0]
3464 3464 if cmd in nowrap:
3465 3465 continue
3466 3466 entry = extensions.wrapcommand(cmdtable, cmd, mqcommand)
3467 3467 entry[1].extend(mqopt)
3468 3468
3469 3469 dotable(commands.table)
3470 3470
3471 3471 for extname, extmodule in extensions.extensions():
3472 3472 if extmodule.__file__ != __file__:
3473 3473 dotable(getattr(extmodule, 'cmdtable', {}))
3474 3474
3475 3475 revset.symbols['mq'] = revsetmq
3476 3476
3477 3477 colortable = {'qguard.negative': 'red',
3478 3478 'qguard.positive': 'yellow',
3479 3479 'qguard.unguarded': 'green',
3480 3480 'qseries.applied': 'blue bold underline',
3481 3481 'qseries.guarded': 'black bold',
3482 3482 'qseries.missing': 'red bold',
3483 3483 'qseries.unapplied': 'black bold'}
@@ -1,902 +1,892 b''
1 1
2 2 $ echo "[extensions]" >> $HGRCPATH
3 3 $ echo "mq=" >> $HGRCPATH
4 4 $ echo "[diff]" >> $HGRCPATH
5 5 $ echo "nodates=true" >> $HGRCPATH
6 6 $ catpatch() {
7 7 > cat .hg/patches/$1.patch | sed -e "s/^diff \-r [0-9a-f]* /diff -r ... /" \
8 8 > -e "s/^\(# Parent \).*/\1/"
9 9 > }
10 10 $ catlog() {
11 11 > catpatch $1
12 12 > hg log --template "{rev}: {desc} - {author}\n"
13 13 > }
14 14 $ catlogd() {
15 15 > catpatch $1
16 16 > hg log --template "{rev}: {desc} - {author} - {date}\n"
17 17 > }
18 18 $ drop() {
19 19 > hg qpop
20 20 > hg qdel $1.patch
21 21 > }
22 22 $ runtest() {
23 23 > echo ==== init
24 24 > hg init a
25 25 > cd a
26 26 > hg qinit
27 27 >
28 28 >
29 29 > echo ==== qnew -d
30 30 > hg qnew -d '3 0' 1.patch
31 31 > catlogd 1
32 32 >
33 33 > echo ==== qref
34 34 > echo "1" >1
35 35 > hg add
36 36 > hg qref
37 37 > catlogd 1
38 38 >
39 39 > echo ==== qref -d
40 40 > hg qref -d '4 0'
41 41 > catlogd 1
42 42 >
43 43 >
44 44 > echo ==== qnew
45 45 > hg qnew 2.patch
46 46 > echo "2" >2
47 47 > hg add
48 48 > hg qref
49 49 > catlog 2
50 50 >
51 51 > echo ==== qref -d
52 52 > hg qref -d '5 0'
53 53 > catlog 2
54 54 >
55 55 > drop 2
56 56 >
57 57 >
58 58 > echo ==== qnew -d -m
59 59 > hg qnew -d '6 0' -m "Three" 3.patch
60 60 > catlogd 3
61 61 >
62 62 > echo ==== qref
63 63 > echo "3" >3
64 64 > hg add
65 65 > hg qref
66 66 > catlogd 3
67 67 >
68 68 > echo ==== qref -m
69 69 > hg qref -m "Drei"
70 70 > catlogd 3
71 71 >
72 72 > echo ==== qref -d
73 73 > hg qref -d '7 0'
74 74 > catlogd 3
75 75 >
76 76 > echo ==== qref -d -m
77 77 > hg qref -d '8 0' -m "Three (again)"
78 78 > catlogd 3
79 79 >
80 80 >
81 81 > echo ==== qnew -m
82 82 > hg qnew -m "Four" 4.patch
83 83 > echo "4" >4
84 84 > hg add
85 85 > hg qref
86 86 > catlog 4
87 87 >
88 88 > echo ==== qref -d
89 89 > hg qref -d '9 0'
90 90 > catlog 4
91 91 >
92 92 > drop 4
93 93 >
94 94 >
95 95 > echo ==== qnew with HG header
96 96 > hg qnew --config 'mq.plain=true' 5.patch
97 97 > hg qpop
98 98 > echo "# HG changeset patch" >>.hg/patches/5.patch
99 99 > echo "# Date 10 0" >>.hg/patches/5.patch
100 100 > hg qpush 2>&1 | grep 'Now at'
101 101 > catlogd 5
102 102 >
103 103 > echo ==== hg qref
104 104 > echo "5" >5
105 105 > hg add
106 106 > hg qref
107 107 > catlogd 5
108 108 >
109 109 > echo ==== hg qref -d
110 110 > hg qref -d '11 0'
111 111 > catlogd 5
112 112 >
113 113 >
114 114 > echo ==== qnew with plain header
115 115 > hg qnew --config 'mq.plain=true' -d '12 0' 6.patch
116 116 > hg qpop
117 117 > hg qpush 2>&1 | grep 'now at'
118 118 > catlog 6
119 119 >
120 120 > echo ==== hg qref
121 121 > echo "6" >6
122 122 > hg add
123 123 > hg qref
124 124 > catlogd 6
125 125 >
126 126 > echo ==== hg qref -d
127 127 > hg qref -d '13 0'
128 128 > catlogd 6
129 129 >
130 130 > drop 6
131 131 >
132 132 >
133 133 > echo ==== qnew -u
134 134 > hg qnew -u jane 6.patch
135 135 > echo "6" >6
136 136 > hg add
137 137 > hg qref
138 138 > catlog 6
139 139 >
140 140 > echo ==== qref -d
141 141 > hg qref -d '12 0'
142 142 > catlog 6
143 143 >
144 144 > drop 6
145 145 >
146 146 >
147 147 > echo ==== qnew -d
148 148 > hg qnew -d '13 0' 7.patch
149 149 > echo "7" >7
150 150 > hg add
151 151 > hg qref
152 152 > catlog 7
153 153 >
154 154 > echo ==== qref -u
155 155 > hg qref -u john
156 156 > catlogd 7
157 157 >
158 158 >
159 159 > echo ==== qnew
160 160 > hg qnew 8.patch
161 161 > echo "8" >8
162 162 > hg add
163 163 > hg qref
164 164 > catlog 8
165 165 >
166 166 > echo ==== qref -u -d
167 167 > hg qref -u john -d '14 0'
168 168 > catlog 8
169 169 >
170 170 > drop 8
171 171 >
172 172 >
173 173 > echo ==== qnew -m
174 174 > hg qnew -m "Nine" 9.patch
175 175 > echo "9" >9
176 176 > hg add
177 177 > hg qref
178 178 > catlog 9
179 179 >
180 180 > echo ==== qref -u -d
181 181 > hg qref -u john -d '15 0'
182 182 > catlog 9
183 183 >
184 184 > drop 9
185 185 >
186 186 >
187 187 > echo ==== "qpop -a / qpush -a"
188 188 > hg qpop -a
189 189 > hg qpush -a
190 190 > hg log --template "{rev}: {desc} - {author} - {date}\n"
191 191 > }
192 192
193 193 ======= plain headers
194 194
195 195 $ echo "[mq]" >> $HGRCPATH
196 196 $ echo "plain=true" >> $HGRCPATH
197 197 $ mkdir sandbox
198 198 $ (cd sandbox ; runtest)
199 199 ==== init
200 200 ==== qnew -d
201 201 Date: 3 0
202 202
203 203 0: [mq]: 1.patch - test - 3.00
204 204 ==== qref
205 205 adding 1
206 206 Date: 3 0
207 207
208 208 diff -r ... 1
209 209 --- /dev/null
210 210 +++ b/1
211 211 @@ -0,0 +1,1 @@
212 212 +1
213 213 0: [mq]: 1.patch - test - 3.00
214 214 ==== qref -d
215 215 Date: 4 0
216 216
217 217 diff -r ... 1
218 218 --- /dev/null
219 219 +++ b/1
220 220 @@ -0,0 +1,1 @@
221 221 +1
222 222 0: [mq]: 1.patch - test - 4.00
223 223 ==== qnew
224 224 adding 2
225 225 diff -r ... 2
226 226 --- /dev/null
227 227 +++ b/2
228 228 @@ -0,0 +1,1 @@
229 229 +2
230 230 1: [mq]: 2.patch - test
231 231 0: [mq]: 1.patch - test
232 232 ==== qref -d
233 233 Date: 5 0
234 234
235 235 diff -r ... 2
236 236 --- /dev/null
237 237 +++ b/2
238 238 @@ -0,0 +1,1 @@
239 239 +2
240 240 1: [mq]: 2.patch - test
241 241 0: [mq]: 1.patch - test
242 242 popping 2.patch
243 243 now at: 1.patch
244 244 ==== qnew -d -m
245 245 Date: 6 0
246
247 246 Three
248 247
249 248 1: Three - test - 6.00
250 249 0: [mq]: 1.patch - test - 4.00
251 250 ==== qref
252 251 adding 3
253 252 Date: 6 0
254
255 253 Three
256 254
257 255 diff -r ... 3
258 256 --- /dev/null
259 257 +++ b/3
260 258 @@ -0,0 +1,1 @@
261 259 +3
262 260 1: Three - test - 6.00
263 261 0: [mq]: 1.patch - test - 4.00
264 262 ==== qref -m
265 263 Date: 6 0
266
267 264 Drei
268 265
269 266 diff -r ... 3
270 267 --- /dev/null
271 268 +++ b/3
272 269 @@ -0,0 +1,1 @@
273 270 +3
274 271 1: Drei - test - 6.00
275 272 0: [mq]: 1.patch - test - 4.00
276 273 ==== qref -d
277 274 Date: 7 0
278
279 275 Drei
280 276
281 277 diff -r ... 3
282 278 --- /dev/null
283 279 +++ b/3
284 280 @@ -0,0 +1,1 @@
285 281 +3
286 282 1: Drei - test - 7.00
287 283 0: [mq]: 1.patch - test - 4.00
288 284 ==== qref -d -m
289 285 Date: 8 0
290
291 286 Three (again)
292 287
293 288 diff -r ... 3
294 289 --- /dev/null
295 290 +++ b/3
296 291 @@ -0,0 +1,1 @@
297 292 +3
298 293 1: Three (again) - test - 8.00
299 294 0: [mq]: 1.patch - test - 4.00
300 295 ==== qnew -m
301 296 adding 4
302 297 Four
303 298
304 299 diff -r ... 4
305 300 --- /dev/null
306 301 +++ b/4
307 302 @@ -0,0 +1,1 @@
308 303 +4
309 304 2: Four - test
310 305 1: Three (again) - test
311 306 0: [mq]: 1.patch - test
312 307 ==== qref -d
313 308 Date: 9 0
314 309 Four
315 310
316 311 diff -r ... 4
317 312 --- /dev/null
318 313 +++ b/4
319 314 @@ -0,0 +1,1 @@
320 315 +4
321 316 2: Four - test
322 317 1: Three (again) - test
323 318 0: [mq]: 1.patch - test
324 319 popping 4.patch
325 320 now at: 3.patch
326 321 ==== qnew with HG header
327 322 popping 5.patch
328 323 now at: 3.patch
329 324 # HG changeset patch
330 325 # Date 10 0
331 326 2: imported patch 5.patch - test - 10.00
332 327 1: Three (again) - test - 8.00
333 328 0: [mq]: 1.patch - test - 4.00
334 329 ==== hg qref
335 330 adding 5
336 331 # HG changeset patch
337 332 # Parent
338 333 # Date 10 0
339 334
340 335 diff -r ... 5
341 336 --- /dev/null
342 337 +++ b/5
343 338 @@ -0,0 +1,1 @@
344 339 +5
345 340 2: [mq]: 5.patch - test - 10.00
346 341 1: Three (again) - test - 8.00
347 342 0: [mq]: 1.patch - test - 4.00
348 343 ==== hg qref -d
349 344 # HG changeset patch
350 345 # Parent
351 346 # Date 11 0
352 347
353 348 diff -r ... 5
354 349 --- /dev/null
355 350 +++ b/5
356 351 @@ -0,0 +1,1 @@
357 352 +5
358 353 2: [mq]: 5.patch - test - 11.00
359 354 1: Three (again) - test - 8.00
360 355 0: [mq]: 1.patch - test - 4.00
361 356 ==== qnew with plain header
362 357 popping 6.patch
363 358 now at: 5.patch
364 359 now at: 6.patch
365 360 Date: 12 0
366 361
367 362 3: imported patch 6.patch - test
368 363 2: [mq]: 5.patch - test
369 364 1: Three (again) - test
370 365 0: [mq]: 1.patch - test
371 366 ==== hg qref
372 367 adding 6
373 368 Date: 12 0
374 369
375 370 diff -r ... 6
376 371 --- /dev/null
377 372 +++ b/6
378 373 @@ -0,0 +1,1 @@
379 374 +6
380 375 3: [mq]: 6.patch - test - 12.00
381 376 2: [mq]: 5.patch - test - 11.00
382 377 1: Three (again) - test - 8.00
383 378 0: [mq]: 1.patch - test - 4.00
384 379 ==== hg qref -d
385 380 Date: 13 0
386 381
387 382 diff -r ... 6
388 383 --- /dev/null
389 384 +++ b/6
390 385 @@ -0,0 +1,1 @@
391 386 +6
392 387 3: [mq]: 6.patch - test - 13.00
393 388 2: [mq]: 5.patch - test - 11.00
394 389 1: Three (again) - test - 8.00
395 390 0: [mq]: 1.patch - test - 4.00
396 391 popping 6.patch
397 392 now at: 5.patch
398 393 ==== qnew -u
399 394 adding 6
400 395 From: jane
401 396
402 397 diff -r ... 6
403 398 --- /dev/null
404 399 +++ b/6
405 400 @@ -0,0 +1,1 @@
406 401 +6
407 402 3: [mq]: 6.patch - jane
408 403 2: [mq]: 5.patch - test
409 404 1: Three (again) - test
410 405 0: [mq]: 1.patch - test
411 406 ==== qref -d
412 407 Date: 12 0
413 408 From: jane
414 409
415 410 diff -r ... 6
416 411 --- /dev/null
417 412 +++ b/6
418 413 @@ -0,0 +1,1 @@
419 414 +6
420 415 3: [mq]: 6.patch - jane
421 416 2: [mq]: 5.patch - test
422 417 1: Three (again) - test
423 418 0: [mq]: 1.patch - test
424 419 popping 6.patch
425 420 now at: 5.patch
426 421 ==== qnew -d
427 422 adding 7
428 423 Date: 13 0
429 424
430 425 diff -r ... 7
431 426 --- /dev/null
432 427 +++ b/7
433 428 @@ -0,0 +1,1 @@
434 429 +7
435 430 3: [mq]: 7.patch - test
436 431 2: [mq]: 5.patch - test
437 432 1: Three (again) - test
438 433 0: [mq]: 1.patch - test
439 434 ==== qref -u
440 435 From: john
441 436 Date: 13 0
442 437
443 438 diff -r ... 7
444 439 --- /dev/null
445 440 +++ b/7
446 441 @@ -0,0 +1,1 @@
447 442 +7
448 443 3: [mq]: 7.patch - john - 13.00
449 444 2: [mq]: 5.patch - test - 11.00
450 445 1: Three (again) - test - 8.00
451 446 0: [mq]: 1.patch - test - 4.00
452 447 ==== qnew
453 448 adding 8
454 449 diff -r ... 8
455 450 --- /dev/null
456 451 +++ b/8
457 452 @@ -0,0 +1,1 @@
458 453 +8
459 454 4: [mq]: 8.patch - test
460 455 3: [mq]: 7.patch - john
461 456 2: [mq]: 5.patch - test
462 457 1: Three (again) - test
463 458 0: [mq]: 1.patch - test
464 459 ==== qref -u -d
465 460 Date: 14 0
466 461 From: john
467 462
468 463 diff -r ... 8
469 464 --- /dev/null
470 465 +++ b/8
471 466 @@ -0,0 +1,1 @@
472 467 +8
473 468 4: [mq]: 8.patch - john
474 469 3: [mq]: 7.patch - john
475 470 2: [mq]: 5.patch - test
476 471 1: Three (again) - test
477 472 0: [mq]: 1.patch - test
478 473 popping 8.patch
479 474 now at: 7.patch
480 475 ==== qnew -m
481 476 adding 9
482 477 Nine
483 478
484 479 diff -r ... 9
485 480 --- /dev/null
486 481 +++ b/9
487 482 @@ -0,0 +1,1 @@
488 483 +9
489 484 4: Nine - test
490 485 3: [mq]: 7.patch - john
491 486 2: [mq]: 5.patch - test
492 487 1: Three (again) - test
493 488 0: [mq]: 1.patch - test
494 489 ==== qref -u -d
495 490 Date: 15 0
496 491 From: john
497 492 Nine
498 493
499 494 diff -r ... 9
500 495 --- /dev/null
501 496 +++ b/9
502 497 @@ -0,0 +1,1 @@
503 498 +9
504 499 4: Nine - john
505 500 3: [mq]: 7.patch - john
506 501 2: [mq]: 5.patch - test
507 502 1: Three (again) - test
508 503 0: [mq]: 1.patch - test
509 504 popping 9.patch
510 505 now at: 7.patch
511 506 ==== qpop -a / qpush -a
512 507 popping 7.patch
513 508 popping 5.patch
514 509 popping 3.patch
515 510 popping 1.patch
516 511 patch queue now empty
517 512 applying 1.patch
518 513 applying 3.patch
519 514 applying 5.patch
520 515 applying 7.patch
521 516 now at: 7.patch
522 517 3: imported patch 7.patch - john - 13.00
523 518 2: imported patch 5.patch - test - 11.00
524 519 1: Three (again) - test - 8.00
525 520 0: imported patch 1.patch - test - 4.00
526 521 $ rm -r sandbox
527 522
528 523 ======= hg headers
529 524
530 525 $ echo "plain=false" >> $HGRCPATH
531 526 $ mkdir sandbox
532 527 $ (cd sandbox ; runtest)
533 528 ==== init
534 529 ==== qnew -d
535 530 # HG changeset patch
536 531 # Parent
537 532 # Date 3 0
538 533
539 534 0: [mq]: 1.patch - test - 3.00
540 535 ==== qref
541 536 adding 1
542 537 # HG changeset patch
543 538 # Parent
544 539 # Date 3 0
545 540
546 541 diff -r ... 1
547 542 --- /dev/null
548 543 +++ b/1
549 544 @@ -0,0 +1,1 @@
550 545 +1
551 546 0: [mq]: 1.patch - test - 3.00
552 547 ==== qref -d
553 548 # HG changeset patch
554 549 # Parent
555 550 # Date 4 0
556 551
557 552 diff -r ... 1
558 553 --- /dev/null
559 554 +++ b/1
560 555 @@ -0,0 +1,1 @@
561 556 +1
562 557 0: [mq]: 1.patch - test - 4.00
563 558 ==== qnew
564 559 adding 2
565 560 # HG changeset patch
566 561 # Parent
567 562
568 563 diff -r ... 2
569 564 --- /dev/null
570 565 +++ b/2
571 566 @@ -0,0 +1,1 @@
572 567 +2
573 568 1: [mq]: 2.patch - test
574 569 0: [mq]: 1.patch - test
575 570 ==== qref -d
576 571 # HG changeset patch
577 572 # Date 5 0
578 573 # Parent
579 574
580 575 diff -r ... 2
581 576 --- /dev/null
582 577 +++ b/2
583 578 @@ -0,0 +1,1 @@
584 579 +2
585 580 1: [mq]: 2.patch - test
586 581 0: [mq]: 1.patch - test
587 582 popping 2.patch
588 583 now at: 1.patch
589 584 ==== qnew -d -m
590 585 # HG changeset patch
591 586 # Parent
592 587 # Date 6 0
593
594 588 Three
595 589
596 590 1: Three - test - 6.00
597 591 0: [mq]: 1.patch - test - 4.00
598 592 ==== qref
599 593 adding 3
600 594 # HG changeset patch
601 595 # Parent
602 596 # Date 6 0
603
604 597 Three
605 598
606 599 diff -r ... 3
607 600 --- /dev/null
608 601 +++ b/3
609 602 @@ -0,0 +1,1 @@
610 603 +3
611 604 1: Three - test - 6.00
612 605 0: [mq]: 1.patch - test - 4.00
613 606 ==== qref -m
614 607 # HG changeset patch
615 608 # Parent
616 609 # Date 6 0
617
618 610 Drei
619 611
620 612 diff -r ... 3
621 613 --- /dev/null
622 614 +++ b/3
623 615 @@ -0,0 +1,1 @@
624 616 +3
625 617 1: Drei - test - 6.00
626 618 0: [mq]: 1.patch - test - 4.00
627 619 ==== qref -d
628 620 # HG changeset patch
629 621 # Parent
630 622 # Date 7 0
631
632 623 Drei
633 624
634 625 diff -r ... 3
635 626 --- /dev/null
636 627 +++ b/3
637 628 @@ -0,0 +1,1 @@
638 629 +3
639 630 1: Drei - test - 7.00
640 631 0: [mq]: 1.patch - test - 4.00
641 632 ==== qref -d -m
642 633 # HG changeset patch
643 634 # Parent
644 635 # Date 8 0
645
646 636 Three (again)
647 637
648 638 diff -r ... 3
649 639 --- /dev/null
650 640 +++ b/3
651 641 @@ -0,0 +1,1 @@
652 642 +3
653 643 1: Three (again) - test - 8.00
654 644 0: [mq]: 1.patch - test - 4.00
655 645 ==== qnew -m
656 646 adding 4
657 647 # HG changeset patch
658 648 # Parent
659 649 Four
660 650
661 651 diff -r ... 4
662 652 --- /dev/null
663 653 +++ b/4
664 654 @@ -0,0 +1,1 @@
665 655 +4
666 656 2: Four - test
667 657 1: Three (again) - test
668 658 0: [mq]: 1.patch - test
669 659 ==== qref -d
670 660 # HG changeset patch
671 661 # Date 9 0
672 662 # Parent
673 663 Four
674 664
675 665 diff -r ... 4
676 666 --- /dev/null
677 667 +++ b/4
678 668 @@ -0,0 +1,1 @@
679 669 +4
680 670 2: Four - test
681 671 1: Three (again) - test
682 672 0: [mq]: 1.patch - test
683 673 popping 4.patch
684 674 now at: 3.patch
685 675 ==== qnew with HG header
686 676 popping 5.patch
687 677 now at: 3.patch
688 678 # HG changeset patch
689 679 # Date 10 0
690 680 2: imported patch 5.patch - test - 10.00
691 681 1: Three (again) - test - 8.00
692 682 0: [mq]: 1.patch - test - 4.00
693 683 ==== hg qref
694 684 adding 5
695 685 # HG changeset patch
696 686 # Parent
697 687 # Date 10 0
698 688
699 689 diff -r ... 5
700 690 --- /dev/null
701 691 +++ b/5
702 692 @@ -0,0 +1,1 @@
703 693 +5
704 694 2: [mq]: 5.patch - test - 10.00
705 695 1: Three (again) - test - 8.00
706 696 0: [mq]: 1.patch - test - 4.00
707 697 ==== hg qref -d
708 698 # HG changeset patch
709 699 # Parent
710 700 # Date 11 0
711 701
712 702 diff -r ... 5
713 703 --- /dev/null
714 704 +++ b/5
715 705 @@ -0,0 +1,1 @@
716 706 +5
717 707 2: [mq]: 5.patch - test - 11.00
718 708 1: Three (again) - test - 8.00
719 709 0: [mq]: 1.patch - test - 4.00
720 710 ==== qnew with plain header
721 711 popping 6.patch
722 712 now at: 5.patch
723 713 now at: 6.patch
724 714 Date: 12 0
725 715
726 716 3: imported patch 6.patch - test
727 717 2: [mq]: 5.patch - test
728 718 1: Three (again) - test
729 719 0: [mq]: 1.patch - test
730 720 ==== hg qref
731 721 adding 6
732 722 Date: 12 0
733 723
734 724 diff -r ... 6
735 725 --- /dev/null
736 726 +++ b/6
737 727 @@ -0,0 +1,1 @@
738 728 +6
739 729 3: [mq]: 6.patch - test - 12.00
740 730 2: [mq]: 5.patch - test - 11.00
741 731 1: Three (again) - test - 8.00
742 732 0: [mq]: 1.patch - test - 4.00
743 733 ==== hg qref -d
744 734 Date: 13 0
745 735
746 736 diff -r ... 6
747 737 --- /dev/null
748 738 +++ b/6
749 739 @@ -0,0 +1,1 @@
750 740 +6
751 741 3: [mq]: 6.patch - test - 13.00
752 742 2: [mq]: 5.patch - test - 11.00
753 743 1: Three (again) - test - 8.00
754 744 0: [mq]: 1.patch - test - 4.00
755 745 popping 6.patch
756 746 now at: 5.patch
757 747 ==== qnew -u
758 748 adding 6
759 749 # HG changeset patch
760 750 # Parent
761 751 # User jane
762 752
763 753 diff -r ... 6
764 754 --- /dev/null
765 755 +++ b/6
766 756 @@ -0,0 +1,1 @@
767 757 +6
768 758 3: [mq]: 6.patch - jane
769 759 2: [mq]: 5.patch - test
770 760 1: Three (again) - test
771 761 0: [mq]: 1.patch - test
772 762 ==== qref -d
773 763 # HG changeset patch
774 764 # Date 12 0
775 765 # Parent
776 766 # User jane
777 767
778 768 diff -r ... 6
779 769 --- /dev/null
780 770 +++ b/6
781 771 @@ -0,0 +1,1 @@
782 772 +6
783 773 3: [mq]: 6.patch - jane
784 774 2: [mq]: 5.patch - test
785 775 1: Three (again) - test
786 776 0: [mq]: 1.patch - test
787 777 popping 6.patch
788 778 now at: 5.patch
789 779 ==== qnew -d
790 780 adding 7
791 781 # HG changeset patch
792 782 # Parent
793 783 # Date 13 0
794 784
795 785 diff -r ... 7
796 786 --- /dev/null
797 787 +++ b/7
798 788 @@ -0,0 +1,1 @@
799 789 +7
800 790 3: [mq]: 7.patch - test
801 791 2: [mq]: 5.patch - test
802 792 1: Three (again) - test
803 793 0: [mq]: 1.patch - test
804 794 ==== qref -u
805 795 # HG changeset patch
806 796 # User john
807 797 # Parent
808 798 # Date 13 0
809 799
810 800 diff -r ... 7
811 801 --- /dev/null
812 802 +++ b/7
813 803 @@ -0,0 +1,1 @@
814 804 +7
815 805 3: [mq]: 7.patch - john - 13.00
816 806 2: [mq]: 5.patch - test - 11.00
817 807 1: Three (again) - test - 8.00
818 808 0: [mq]: 1.patch - test - 4.00
819 809 ==== qnew
820 810 adding 8
821 811 # HG changeset patch
822 812 # Parent
823 813
824 814 diff -r ... 8
825 815 --- /dev/null
826 816 +++ b/8
827 817 @@ -0,0 +1,1 @@
828 818 +8
829 819 4: [mq]: 8.patch - test
830 820 3: [mq]: 7.patch - john
831 821 2: [mq]: 5.patch - test
832 822 1: Three (again) - test
833 823 0: [mq]: 1.patch - test
834 824 ==== qref -u -d
835 825 # HG changeset patch
836 826 # Date 14 0
837 827 # User john
838 828 # Parent
839 829
840 830 diff -r ... 8
841 831 --- /dev/null
842 832 +++ b/8
843 833 @@ -0,0 +1,1 @@
844 834 +8
845 835 4: [mq]: 8.patch - john
846 836 3: [mq]: 7.patch - john
847 837 2: [mq]: 5.patch - test
848 838 1: Three (again) - test
849 839 0: [mq]: 1.patch - test
850 840 popping 8.patch
851 841 now at: 7.patch
852 842 ==== qnew -m
853 843 adding 9
854 844 # HG changeset patch
855 845 # Parent
856 846 Nine
857 847
858 848 diff -r ... 9
859 849 --- /dev/null
860 850 +++ b/9
861 851 @@ -0,0 +1,1 @@
862 852 +9
863 853 4: Nine - test
864 854 3: [mq]: 7.patch - john
865 855 2: [mq]: 5.patch - test
866 856 1: Three (again) - test
867 857 0: [mq]: 1.patch - test
868 858 ==== qref -u -d
869 859 # HG changeset patch
870 860 # Date 15 0
871 861 # User john
872 862 # Parent
873 863 Nine
874 864
875 865 diff -r ... 9
876 866 --- /dev/null
877 867 +++ b/9
878 868 @@ -0,0 +1,1 @@
879 869 +9
880 870 4: Nine - john
881 871 3: [mq]: 7.patch - john
882 872 2: [mq]: 5.patch - test
883 873 1: Three (again) - test
884 874 0: [mq]: 1.patch - test
885 875 popping 9.patch
886 876 now at: 7.patch
887 877 ==== qpop -a / qpush -a
888 878 popping 7.patch
889 879 popping 5.patch
890 880 popping 3.patch
891 881 popping 1.patch
892 882 patch queue now empty
893 883 applying 1.patch
894 884 applying 3.patch
895 885 applying 5.patch
896 886 applying 7.patch
897 887 now at: 7.patch
898 888 3: imported patch 7.patch - john - 13.00
899 889 2: imported patch 5.patch - test - 11.00
900 890 1: Three (again) - test - 8.00
901 891 0: imported patch 1.patch - test - 4.00
902 892 $ rm -r sandbox
@@ -1,971 +1,968 b''
1 1
2 2 $ echo "[extensions]" >> $HGRCPATH
3 3 $ echo "mq=" >> $HGRCPATH
4 4 $ echo "[diff]" >> $HGRCPATH
5 5 $ echo "nodates=true" >> $HGRCPATH
6 6 $ catlog() {
7 7 > cat .hg/patches/$1.patch | sed -e "s/^diff \-r [0-9a-f]* /diff -r ... /" \
8 8 > -e "s/^\(# Parent \).*/\1/"
9 9 > hg log --template "{rev}: {desc} - {author}\n"
10 10 > }
11 11 $ runtest() {
12 12 > echo ==== init
13 13 > hg init a
14 14 > cd a
15 15 > hg qinit
16 16 >
17 17 >
18 18 > echo ==== qnew -U
19 19 > hg qnew -U 1.patch
20 20 > catlog 1
21 21 >
22 22 > echo ==== qref
23 23 > echo "1" >1
24 24 > hg add
25 25 > hg qref
26 26 > catlog 1
27 27 >
28 28 > echo ==== qref -u
29 29 > hg qref -u mary
30 30 > catlog 1
31 31 >
32 32 > echo ==== qnew
33 33 > hg qnew 2.patch
34 34 > echo "2" >2
35 35 > hg add
36 36 > hg qref
37 37 > catlog 2
38 38 >
39 39 > echo ==== qref -u
40 40 > hg qref -u jane
41 41 > catlog 2
42 42 >
43 43 >
44 44 > echo ==== qnew -U -m
45 45 > hg qnew -U -m "Three" 3.patch
46 46 > catlog 3
47 47 >
48 48 > echo ==== qref
49 49 > echo "3" >3
50 50 > hg add
51 51 > hg qref
52 52 > catlog 3
53 53 >
54 54 > echo ==== qref -m
55 55 > hg qref -m "Drei"
56 56 > catlog 3
57 57 >
58 58 > echo ==== qref -u
59 59 > hg qref -u mary
60 60 > catlog 3
61 61 >
62 62 > echo ==== qref -u -m
63 63 > hg qref -u maria -m "Three (again)"
64 64 > catlog 3
65 65 >
66 66 > echo ==== qnew -m
67 67 > hg qnew -m "Four" 4.patch
68 68 > echo "4" >4of t
69 69 > hg add
70 70 > hg qref
71 71 > catlog 4
72 72 >
73 73 > echo ==== qref -u
74 74 > hg qref -u jane
75 75 > catlog 4
76 76 >
77 77 >
78 78 > echo ==== qnew with HG header
79 79 > hg qnew --config 'mq.plain=true' 5.patch
80 80 > hg qpop
81 81 > echo "# HG changeset patch" >>.hg/patches/5.patch
82 82 > echo "# User johndoe" >>.hg/patches/5.patch
83 83 > hg qpush 2>&1 | grep 'now at'
84 84 > catlog 5
85 85 >
86 86 > echo ==== hg qref
87 87 > echo "5" >5
88 88 > hg add
89 89 > hg qref
90 90 > catlog 5
91 91 >
92 92 > echo ==== hg qref -U
93 93 > hg qref -U
94 94 > catlog 5
95 95 >
96 96 > echo ==== hg qref -u
97 97 > hg qref -u johndeere
98 98 > catlog 5
99 99 >
100 100 >
101 101 > echo ==== qnew with plain header
102 102 > hg qnew --config 'mq.plain=true' -U 6.patch
103 103 > hg qpop
104 104 > hg qpush 2>&1 | grep 'now at'
105 105 > catlog 6
106 106 >
107 107 > echo ==== hg qref
108 108 > echo "6" >6
109 109 > hg add
110 110 > hg qref
111 111 > catlog 6
112 112 >
113 113 > echo ==== hg qref -U
114 114 > hg qref -U
115 115 > catlog 6
116 116 >
117 117 > echo ==== hg qref -u
118 118 > hg qref -u johndeere
119 119 > catlog 6
120 120 >
121 121 >
122 122 > echo ==== "qpop -a / qpush -a"
123 123 > hg qpop -a
124 124 > hg qpush -a
125 125 > hg log --template "{rev}: {desc} - {author}\n"
126 126 > }
127 127
128 128 ======= plain headers
129 129
130 130 $ echo "[mq]" >> $HGRCPATH
131 131 $ echo "plain=true" >> $HGRCPATH
132 132 $ mkdir sandbox
133 133 $ (cd sandbox ; runtest)
134 134 ==== init
135 135 ==== qnew -U
136 136 From: test
137 137
138 138 0: [mq]: 1.patch - test
139 139 ==== qref
140 140 adding 1
141 141 From: test
142 142
143 143 diff -r ... 1
144 144 --- /dev/null
145 145 +++ b/1
146 146 @@ -0,0 +1,1 @@
147 147 +1
148 148 0: [mq]: 1.patch - test
149 149 ==== qref -u
150 150 From: mary
151 151
152 152 diff -r ... 1
153 153 --- /dev/null
154 154 +++ b/1
155 155 @@ -0,0 +1,1 @@
156 156 +1
157 157 0: [mq]: 1.patch - mary
158 158 ==== qnew
159 159 adding 2
160 160 diff -r ... 2
161 161 --- /dev/null
162 162 +++ b/2
163 163 @@ -0,0 +1,1 @@
164 164 +2
165 165 1: [mq]: 2.patch - test
166 166 0: [mq]: 1.patch - mary
167 167 ==== qref -u
168 168 From: jane
169 169
170 170 diff -r ... 2
171 171 --- /dev/null
172 172 +++ b/2
173 173 @@ -0,0 +1,1 @@
174 174 +2
175 175 1: [mq]: 2.patch - jane
176 176 0: [mq]: 1.patch - mary
177 177 ==== qnew -U -m
178 178 From: test
179
180 179 Three
181 180
182 181 2: Three - test
183 182 1: [mq]: 2.patch - jane
184 183 0: [mq]: 1.patch - mary
185 184 ==== qref
186 185 adding 3
187 186 From: test
188
189 187 Three
190 188
191 189 diff -r ... 3
192 190 --- /dev/null
193 191 +++ b/3
194 192 @@ -0,0 +1,1 @@
195 193 +3
196 194 2: Three - test
197 195 1: [mq]: 2.patch - jane
198 196 0: [mq]: 1.patch - mary
199 197 ==== qref -m
200 198 From: test
201
202 199 Drei
203 200
204 201 diff -r ... 3
205 202 --- /dev/null
206 203 +++ b/3
207 204 @@ -0,0 +1,1 @@
208 205 +3
209 206 2: Drei - test
210 207 1: [mq]: 2.patch - jane
211 208 0: [mq]: 1.patch - mary
212 209 ==== qref -u
213 210 From: mary
214
215 211 Drei
216 212
217 213 diff -r ... 3
218 214 --- /dev/null
219 215 +++ b/3
220 216 @@ -0,0 +1,1 @@
221 217 +3
222 218 2: Drei - mary
223 219 1: [mq]: 2.patch - jane
224 220 0: [mq]: 1.patch - mary
225 221 ==== qref -u -m
226 222 From: maria
227
228 223 Three (again)
229 224
230 225 diff -r ... 3
231 226 --- /dev/null
232 227 +++ b/3
233 228 @@ -0,0 +1,1 @@
234 229 +3
235 230 2: Three (again) - maria
236 231 1: [mq]: 2.patch - jane
237 232 0: [mq]: 1.patch - mary
238 233 ==== qnew -m
239 234 adding 4of
240 235 Four
241 236
242 237 diff -r ... 4of
243 238 --- /dev/null
244 239 +++ b/4of
245 240 @@ -0,0 +1,1 @@
246 241 +4 t
247 242 3: Four - test
248 243 2: Three (again) - maria
249 244 1: [mq]: 2.patch - jane
250 245 0: [mq]: 1.patch - mary
251 246 ==== qref -u
252 247 From: jane
253 248 Four
254 249
255 250 diff -r ... 4of
256 251 --- /dev/null
257 252 +++ b/4of
258 253 @@ -0,0 +1,1 @@
259 254 +4 t
260 255 3: Four - jane
261 256 2: Three (again) - maria
262 257 1: [mq]: 2.patch - jane
263 258 0: [mq]: 1.patch - mary
264 259 ==== qnew with HG header
265 260 popping 5.patch
266 261 now at: 4.patch
267 262 now at: 5.patch
268 263 # HG changeset patch
269 264 # User johndoe
270 265 4: imported patch 5.patch - johndoe
271 266 3: Four - jane
272 267 2: Three (again) - maria
273 268 1: [mq]: 2.patch - jane
274 269 0: [mq]: 1.patch - mary
275 270 ==== hg qref
276 271 adding 5
277 272 # HG changeset patch
278 273 # Parent
279 274 # User johndoe
280 275
281 276 diff -r ... 5
282 277 --- /dev/null
283 278 +++ b/5
284 279 @@ -0,0 +1,1 @@
285 280 +5
286 281 4: [mq]: 5.patch - johndoe
287 282 3: Four - jane
288 283 2: Three (again) - maria
289 284 1: [mq]: 2.patch - jane
290 285 0: [mq]: 1.patch - mary
291 286 ==== hg qref -U
292 287 # HG changeset patch
293 288 # Parent
294 289 # User test
295 290
296 291 diff -r ... 5
297 292 --- /dev/null
298 293 +++ b/5
299 294 @@ -0,0 +1,1 @@
300 295 +5
301 296 4: [mq]: 5.patch - test
302 297 3: Four - jane
303 298 2: Three (again) - maria
304 299 1: [mq]: 2.patch - jane
305 300 0: [mq]: 1.patch - mary
306 301 ==== hg qref -u
307 302 # HG changeset patch
308 303 # Parent
309 304 # User johndeere
310 305
311 306 diff -r ... 5
312 307 --- /dev/null
313 308 +++ b/5
314 309 @@ -0,0 +1,1 @@
315 310 +5
316 311 4: [mq]: 5.patch - johndeere
317 312 3: Four - jane
318 313 2: Three (again) - maria
319 314 1: [mq]: 2.patch - jane
320 315 0: [mq]: 1.patch - mary
321 316 ==== qnew with plain header
322 317 popping 6.patch
323 318 now at: 5.patch
324 319 now at: 6.patch
325 320 From: test
326 321
327 322 5: imported patch 6.patch - test
328 323 4: [mq]: 5.patch - johndeere
329 324 3: Four - jane
330 325 2: Three (again) - maria
331 326 1: [mq]: 2.patch - jane
332 327 0: [mq]: 1.patch - mary
333 328 ==== hg qref
334 329 adding 6
335 330 From: test
336 331
337 332 diff -r ... 6
338 333 --- /dev/null
339 334 +++ b/6
340 335 @@ -0,0 +1,1 @@
341 336 +6
342 337 5: [mq]: 6.patch - test
343 338 4: [mq]: 5.patch - johndeere
344 339 3: Four - jane
345 340 2: Three (again) - maria
346 341 1: [mq]: 2.patch - jane
347 342 0: [mq]: 1.patch - mary
348 343 ==== hg qref -U
349 344 From: test
350 345
351 346 diff -r ... 6
352 347 --- /dev/null
353 348 +++ b/6
354 349 @@ -0,0 +1,1 @@
355 350 +6
356 351 5: [mq]: 6.patch - test
357 352 4: [mq]: 5.patch - johndeere
358 353 3: Four - jane
359 354 2: Three (again) - maria
360 355 1: [mq]: 2.patch - jane
361 356 0: [mq]: 1.patch - mary
362 357 ==== hg qref -u
363 358 From: johndeere
364 359
365 360 diff -r ... 6
366 361 --- /dev/null
367 362 +++ b/6
368 363 @@ -0,0 +1,1 @@
369 364 +6
370 365 5: [mq]: 6.patch - johndeere
371 366 4: [mq]: 5.patch - johndeere
372 367 3: Four - jane
373 368 2: Three (again) - maria
374 369 1: [mq]: 2.patch - jane
375 370 0: [mq]: 1.patch - mary
376 371 ==== qpop -a / qpush -a
377 372 popping 6.patch
378 373 popping 5.patch
379 374 popping 4.patch
380 375 popping 3.patch
381 376 popping 2.patch
382 377 popping 1.patch
383 378 patch queue now empty
384 379 applying 1.patch
385 380 applying 2.patch
386 381 applying 3.patch
387 382 applying 4.patch
388 383 applying 5.patch
389 384 applying 6.patch
390 385 now at: 6.patch
391 386 5: imported patch 6.patch - johndeere
392 387 4: imported patch 5.patch - johndeere
393 388 3: Four - jane
394 389 2: Three (again) - maria
395 390 1: imported patch 2.patch - jane
396 391 0: imported patch 1.patch - mary
397 392 $ rm -r sandbox
398 393
399 394 ======= hg headers
400 395
401 396 $ echo "plain=false" >> $HGRCPATH
402 397 $ mkdir sandbox
403 398 $ (cd sandbox ; runtest)
404 399 ==== init
405 400 ==== qnew -U
406 401 # HG changeset patch
407 402 # Parent
408 403 # User test
404
409 405 0: [mq]: 1.patch - test
410 406 ==== qref
411 407 adding 1
412 408 # HG changeset patch
413 409 # Parent
414 410 # User test
415 411
416 412 diff -r ... 1
417 413 --- /dev/null
418 414 +++ b/1
419 415 @@ -0,0 +1,1 @@
420 416 +1
421 417 0: [mq]: 1.patch - test
422 418 ==== qref -u
423 419 # HG changeset patch
424 420 # Parent
425 421 # User mary
426 422
427 423 diff -r ... 1
428 424 --- /dev/null
429 425 +++ b/1
430 426 @@ -0,0 +1,1 @@
431 427 +1
432 428 0: [mq]: 1.patch - mary
433 429 ==== qnew
434 430 adding 2
435 431 # HG changeset patch
436 432 # Parent
437 433
438 434 diff -r ... 2
439 435 --- /dev/null
440 436 +++ b/2
441 437 @@ -0,0 +1,1 @@
442 438 +2
443 439 1: [mq]: 2.patch - test
444 440 0: [mq]: 1.patch - mary
445 441 ==== qref -u
446 442 # HG changeset patch
447 443 # User jane
448 444 # Parent
449 445
450 446 diff -r ... 2
451 447 --- /dev/null
452 448 +++ b/2
453 449 @@ -0,0 +1,1 @@
454 450 +2
455 451 1: [mq]: 2.patch - jane
456 452 0: [mq]: 1.patch - mary
457 453 ==== qnew -U -m
458 454 # HG changeset patch
459 455 # Parent
460 456 # User test
461 457 Three
462 458
463 459 2: Three - test
464 460 1: [mq]: 2.patch - jane
465 461 0: [mq]: 1.patch - mary
466 462 ==== qref
467 463 adding 3
468 464 # HG changeset patch
469 465 # Parent
470 466 # User test
471 467 Three
472 468
473 469 diff -r ... 3
474 470 --- /dev/null
475 471 +++ b/3
476 472 @@ -0,0 +1,1 @@
477 473 +3
478 474 2: Three - test
479 475 1: [mq]: 2.patch - jane
480 476 0: [mq]: 1.patch - mary
481 477 ==== qref -m
482 478 # HG changeset patch
483 479 # Parent
484 480 # User test
485 481 Drei
486 482
487 483 diff -r ... 3
488 484 --- /dev/null
489 485 +++ b/3
490 486 @@ -0,0 +1,1 @@
491 487 +3
492 488 2: Drei - test
493 489 1: [mq]: 2.patch - jane
494 490 0: [mq]: 1.patch - mary
495 491 ==== qref -u
496 492 # HG changeset patch
497 493 # Parent
498 494 # User mary
499 495 Drei
500 496
501 497 diff -r ... 3
502 498 --- /dev/null
503 499 +++ b/3
504 500 @@ -0,0 +1,1 @@
505 501 +3
506 502 2: Drei - mary
507 503 1: [mq]: 2.patch - jane
508 504 0: [mq]: 1.patch - mary
509 505 ==== qref -u -m
510 506 # HG changeset patch
511 507 # Parent
512 508 # User maria
513 509 Three (again)
514 510
515 511 diff -r ... 3
516 512 --- /dev/null
517 513 +++ b/3
518 514 @@ -0,0 +1,1 @@
519 515 +3
520 516 2: Three (again) - maria
521 517 1: [mq]: 2.patch - jane
522 518 0: [mq]: 1.patch - mary
523 519 ==== qnew -m
524 520 adding 4of
525 521 # HG changeset patch
526 522 # Parent
527 523 Four
528 524
529 525 diff -r ... 4of
530 526 --- /dev/null
531 527 +++ b/4of
532 528 @@ -0,0 +1,1 @@
533 529 +4 t
534 530 3: Four - test
535 531 2: Three (again) - maria
536 532 1: [mq]: 2.patch - jane
537 533 0: [mq]: 1.patch - mary
538 534 ==== qref -u
539 535 # HG changeset patch
540 536 # User jane
541 537 # Parent
542 538 Four
543 539
544 540 diff -r ... 4of
545 541 --- /dev/null
546 542 +++ b/4of
547 543 @@ -0,0 +1,1 @@
548 544 +4 t
549 545 3: Four - jane
550 546 2: Three (again) - maria
551 547 1: [mq]: 2.patch - jane
552 548 0: [mq]: 1.patch - mary
553 549 ==== qnew with HG header
554 550 popping 5.patch
555 551 now at: 4.patch
556 552 now at: 5.patch
557 553 # HG changeset patch
558 554 # User johndoe
559 555 4: imported patch 5.patch - johndoe
560 556 3: Four - jane
561 557 2: Three (again) - maria
562 558 1: [mq]: 2.patch - jane
563 559 0: [mq]: 1.patch - mary
564 560 ==== hg qref
565 561 adding 5
566 562 # HG changeset patch
567 563 # Parent
568 564 # User johndoe
569 565
570 566 diff -r ... 5
571 567 --- /dev/null
572 568 +++ b/5
573 569 @@ -0,0 +1,1 @@
574 570 +5
575 571 4: [mq]: 5.patch - johndoe
576 572 3: Four - jane
577 573 2: Three (again) - maria
578 574 1: [mq]: 2.patch - jane
579 575 0: [mq]: 1.patch - mary
580 576 ==== hg qref -U
581 577 # HG changeset patch
582 578 # Parent
583 579 # User test
584 580
585 581 diff -r ... 5
586 582 --- /dev/null
587 583 +++ b/5
588 584 @@ -0,0 +1,1 @@
589 585 +5
590 586 4: [mq]: 5.patch - test
591 587 3: Four - jane
592 588 2: Three (again) - maria
593 589 1: [mq]: 2.patch - jane
594 590 0: [mq]: 1.patch - mary
595 591 ==== hg qref -u
596 592 # HG changeset patch
597 593 # Parent
598 594 # User johndeere
599 595
600 596 diff -r ... 5
601 597 --- /dev/null
602 598 +++ b/5
603 599 @@ -0,0 +1,1 @@
604 600 +5
605 601 4: [mq]: 5.patch - johndeere
606 602 3: Four - jane
607 603 2: Three (again) - maria
608 604 1: [mq]: 2.patch - jane
609 605 0: [mq]: 1.patch - mary
610 606 ==== qnew with plain header
611 607 popping 6.patch
612 608 now at: 5.patch
613 609 now at: 6.patch
614 610 From: test
615 611
616 612 5: imported patch 6.patch - test
617 613 4: [mq]: 5.patch - johndeere
618 614 3: Four - jane
619 615 2: Three (again) - maria
620 616 1: [mq]: 2.patch - jane
621 617 0: [mq]: 1.patch - mary
622 618 ==== hg qref
623 619 adding 6
624 620 From: test
625 621
626 622 diff -r ... 6
627 623 --- /dev/null
628 624 +++ b/6
629 625 @@ -0,0 +1,1 @@
630 626 +6
631 627 5: [mq]: 6.patch - test
632 628 4: [mq]: 5.patch - johndeere
633 629 3: Four - jane
634 630 2: Three (again) - maria
635 631 1: [mq]: 2.patch - jane
636 632 0: [mq]: 1.patch - mary
637 633 ==== hg qref -U
638 634 From: test
639 635
640 636 diff -r ... 6
641 637 --- /dev/null
642 638 +++ b/6
643 639 @@ -0,0 +1,1 @@
644 640 +6
645 641 5: [mq]: 6.patch - test
646 642 4: [mq]: 5.patch - johndeere
647 643 3: Four - jane
648 644 2: Three (again) - maria
649 645 1: [mq]: 2.patch - jane
650 646 0: [mq]: 1.patch - mary
651 647 ==== hg qref -u
652 648 From: johndeere
653 649
654 650 diff -r ... 6
655 651 --- /dev/null
656 652 +++ b/6
657 653 @@ -0,0 +1,1 @@
658 654 +6
659 655 5: [mq]: 6.patch - johndeere
660 656 4: [mq]: 5.patch - johndeere
661 657 3: Four - jane
662 658 2: Three (again) - maria
663 659 1: [mq]: 2.patch - jane
664 660 0: [mq]: 1.patch - mary
665 661 ==== qpop -a / qpush -a
666 662 popping 6.patch
667 663 popping 5.patch
668 664 popping 4.patch
669 665 popping 3.patch
670 666 popping 2.patch
671 667 popping 1.patch
672 668 patch queue now empty
673 669 applying 1.patch
674 670 applying 2.patch
675 671 applying 3.patch
676 672 applying 4.patch
677 673 applying 5.patch
678 674 applying 6.patch
679 675 now at: 6.patch
680 676 5: imported patch 6.patch - johndeere
681 677 4: imported patch 5.patch - johndeere
682 678 3: Four - jane
683 679 2: Three (again) - maria
684 680 1: imported patch 2.patch - jane
685 681 0: imported patch 1.patch - mary
686 682 $ rm -r sandbox
687 683 $ runtest
688 684 ==== init
689 685 ==== qnew -U
690 686 # HG changeset patch
691 687 # Parent
692 688 # User test
689
693 690 0: [mq]: 1.patch - test
694 691 ==== qref
695 692 adding 1
696 693 # HG changeset patch
697 694 # Parent
698 695 # User test
699 696
700 697 diff -r ... 1
701 698 --- /dev/null
702 699 +++ b/1
703 700 @@ -0,0 +1,1 @@
704 701 +1
705 702 0: [mq]: 1.patch - test
706 703 ==== qref -u
707 704 # HG changeset patch
708 705 # Parent
709 706 # User mary
710 707
711 708 diff -r ... 1
712 709 --- /dev/null
713 710 +++ b/1
714 711 @@ -0,0 +1,1 @@
715 712 +1
716 713 0: [mq]: 1.patch - mary
717 714 ==== qnew
718 715 adding 2
719 716 # HG changeset patch
720 717 # Parent
721 718
722 719 diff -r ... 2
723 720 --- /dev/null
724 721 +++ b/2
725 722 @@ -0,0 +1,1 @@
726 723 +2
727 724 1: [mq]: 2.patch - test
728 725 0: [mq]: 1.patch - mary
729 726 ==== qref -u
730 727 # HG changeset patch
731 728 # User jane
732 729 # Parent
733 730
734 731 diff -r ... 2
735 732 --- /dev/null
736 733 +++ b/2
737 734 @@ -0,0 +1,1 @@
738 735 +2
739 736 1: [mq]: 2.patch - jane
740 737 0: [mq]: 1.patch - mary
741 738 ==== qnew -U -m
742 739 # HG changeset patch
743 740 # Parent
744 741 # User test
745 742 Three
746 743
747 744 2: Three - test
748 745 1: [mq]: 2.patch - jane
749 746 0: [mq]: 1.patch - mary
750 747 ==== qref
751 748 adding 3
752 749 # HG changeset patch
753 750 # Parent
754 751 # User test
755 752 Three
756 753
757 754 diff -r ... 3
758 755 --- /dev/null
759 756 +++ b/3
760 757 @@ -0,0 +1,1 @@
761 758 +3
762 759 2: Three - test
763 760 1: [mq]: 2.patch - jane
764 761 0: [mq]: 1.patch - mary
765 762 ==== qref -m
766 763 # HG changeset patch
767 764 # Parent
768 765 # User test
769 766 Drei
770 767
771 768 diff -r ... 3
772 769 --- /dev/null
773 770 +++ b/3
774 771 @@ -0,0 +1,1 @@
775 772 +3
776 773 2: Drei - test
777 774 1: [mq]: 2.patch - jane
778 775 0: [mq]: 1.patch - mary
779 776 ==== qref -u
780 777 # HG changeset patch
781 778 # Parent
782 779 # User mary
783 780 Drei
784 781
785 782 diff -r ... 3
786 783 --- /dev/null
787 784 +++ b/3
788 785 @@ -0,0 +1,1 @@
789 786 +3
790 787 2: Drei - mary
791 788 1: [mq]: 2.patch - jane
792 789 0: [mq]: 1.patch - mary
793 790 ==== qref -u -m
794 791 # HG changeset patch
795 792 # Parent
796 793 # User maria
797 794 Three (again)
798 795
799 796 diff -r ... 3
800 797 --- /dev/null
801 798 +++ b/3
802 799 @@ -0,0 +1,1 @@
803 800 +3
804 801 2: Three (again) - maria
805 802 1: [mq]: 2.patch - jane
806 803 0: [mq]: 1.patch - mary
807 804 ==== qnew -m
808 805 adding 4of
809 806 # HG changeset patch
810 807 # Parent
811 808 Four
812 809
813 810 diff -r ... 4of
814 811 --- /dev/null
815 812 +++ b/4of
816 813 @@ -0,0 +1,1 @@
817 814 +4 t
818 815 3: Four - test
819 816 2: Three (again) - maria
820 817 1: [mq]: 2.patch - jane
821 818 0: [mq]: 1.patch - mary
822 819 ==== qref -u
823 820 # HG changeset patch
824 821 # User jane
825 822 # Parent
826 823 Four
827 824
828 825 diff -r ... 4of
829 826 --- /dev/null
830 827 +++ b/4of
831 828 @@ -0,0 +1,1 @@
832 829 +4 t
833 830 3: Four - jane
834 831 2: Three (again) - maria
835 832 1: [mq]: 2.patch - jane
836 833 0: [mq]: 1.patch - mary
837 834 ==== qnew with HG header
838 835 popping 5.patch
839 836 now at: 4.patch
840 837 now at: 5.patch
841 838 # HG changeset patch
842 839 # User johndoe
843 840 4: imported patch 5.patch - johndoe
844 841 3: Four - jane
845 842 2: Three (again) - maria
846 843 1: [mq]: 2.patch - jane
847 844 0: [mq]: 1.patch - mary
848 845 ==== hg qref
849 846 adding 5
850 847 # HG changeset patch
851 848 # Parent
852 849 # User johndoe
853 850
854 851 diff -r ... 5
855 852 --- /dev/null
856 853 +++ b/5
857 854 @@ -0,0 +1,1 @@
858 855 +5
859 856 4: [mq]: 5.patch - johndoe
860 857 3: Four - jane
861 858 2: Three (again) - maria
862 859 1: [mq]: 2.patch - jane
863 860 0: [mq]: 1.patch - mary
864 861 ==== hg qref -U
865 862 # HG changeset patch
866 863 # Parent
867 864 # User test
868 865
869 866 diff -r ... 5
870 867 --- /dev/null
871 868 +++ b/5
872 869 @@ -0,0 +1,1 @@
873 870 +5
874 871 4: [mq]: 5.patch - test
875 872 3: Four - jane
876 873 2: Three (again) - maria
877 874 1: [mq]: 2.patch - jane
878 875 0: [mq]: 1.patch - mary
879 876 ==== hg qref -u
880 877 # HG changeset patch
881 878 # Parent
882 879 # User johndeere
883 880
884 881 diff -r ... 5
885 882 --- /dev/null
886 883 +++ b/5
887 884 @@ -0,0 +1,1 @@
888 885 +5
889 886 4: [mq]: 5.patch - johndeere
890 887 3: Four - jane
891 888 2: Three (again) - maria
892 889 1: [mq]: 2.patch - jane
893 890 0: [mq]: 1.patch - mary
894 891 ==== qnew with plain header
895 892 popping 6.patch
896 893 now at: 5.patch
897 894 now at: 6.patch
898 895 From: test
899 896
900 897 5: imported patch 6.patch - test
901 898 4: [mq]: 5.patch - johndeere
902 899 3: Four - jane
903 900 2: Three (again) - maria
904 901 1: [mq]: 2.patch - jane
905 902 0: [mq]: 1.patch - mary
906 903 ==== hg qref
907 904 adding 6
908 905 From: test
909 906
910 907 diff -r ... 6
911 908 --- /dev/null
912 909 +++ b/6
913 910 @@ -0,0 +1,1 @@
914 911 +6
915 912 5: [mq]: 6.patch - test
916 913 4: [mq]: 5.patch - johndeere
917 914 3: Four - jane
918 915 2: Three (again) - maria
919 916 1: [mq]: 2.patch - jane
920 917 0: [mq]: 1.patch - mary
921 918 ==== hg qref -U
922 919 From: test
923 920
924 921 diff -r ... 6
925 922 --- /dev/null
926 923 +++ b/6
927 924 @@ -0,0 +1,1 @@
928 925 +6
929 926 5: [mq]: 6.patch - test
930 927 4: [mq]: 5.patch - johndeere
931 928 3: Four - jane
932 929 2: Three (again) - maria
933 930 1: [mq]: 2.patch - jane
934 931 0: [mq]: 1.patch - mary
935 932 ==== hg qref -u
936 933 From: johndeere
937 934
938 935 diff -r ... 6
939 936 --- /dev/null
940 937 +++ b/6
941 938 @@ -0,0 +1,1 @@
942 939 +6
943 940 5: [mq]: 6.patch - johndeere
944 941 4: [mq]: 5.patch - johndeere
945 942 3: Four - jane
946 943 2: Three (again) - maria
947 944 1: [mq]: 2.patch - jane
948 945 0: [mq]: 1.patch - mary
949 946 ==== qpop -a / qpush -a
950 947 popping 6.patch
951 948 popping 5.patch
952 949 popping 4.patch
953 950 popping 3.patch
954 951 popping 2.patch
955 952 popping 1.patch
956 953 patch queue now empty
957 954 applying 1.patch
958 955 applying 2.patch
959 956 applying 3.patch
960 957 applying 4.patch
961 958 applying 5.patch
962 959 applying 6.patch
963 960 now at: 6.patch
964 961 5: imported patch 6.patch - johndeere
965 962 4: imported patch 5.patch - johndeere
966 963 3: Four - jane
967 964 2: Three (again) - maria
968 965 1: imported patch 2.patch - jane
969 966 0: imported patch 1.patch - mary
970 967
971 968 $ cd ..
@@ -1,343 +1,347 b''
1 1
2 2 $ catpatch() {
3 3 > cat $1 | sed -e "s/^\(# Parent \).*/\1/"
4 4 > }
5 5 $ echo "[extensions]" >> $HGRCPATH
6 6 $ echo "mq=" >> $HGRCPATH
7 7 $ runtest() {
8 8 > hg init mq
9 9 > cd mq
10 10 >
11 11 > echo a > a
12 12 > hg ci -Ama
13 13 >
14 14 > echo '% qnew should refuse bad patch names'
15 15 > hg qnew series
16 16 > hg qnew status
17 17 > hg qnew guards
18 18 > hg qnew .
19 19 > hg qnew ..
20 20 > hg qnew .hgignore
21 21 > hg qnew .mqfoo
22 22 > hg qnew 'foo#bar'
23 23 > hg qnew 'foo:bar'
24 24 >
25 25 > hg qinit -c
26 26 >
27 27 > echo '% qnew with name containing slash'
28 28 > hg qnew foo/
29 29 > hg qnew foo/bar.patch
30 30 > hg qnew foo
31 31 > hg qseries
32 32 > hg qpop
33 33 > hg qdelete foo/bar.patch
34 34 >
35 35 > echo '% qnew with uncommitted changes'
36 36 > echo a > somefile
37 37 > hg add somefile
38 38 > hg qnew uncommitted.patch
39 39 > hg st
40 40 > hg qseries
41 41 >
42 42 > echo '% qnew implies add'
43 43 > hg -R .hg/patches st
44 44 >
45 45 > echo '% qnew missing'
46 46 > hg qnew missing.patch missing
47 47 >
48 48 > echo '% qnew -m'
49 49 > hg qnew -m 'foo bar' mtest.patch
50 50 > catpatch .hg/patches/mtest.patch
51 51 >
52 52 > echo '% qnew twice'
53 53 > hg qnew first.patch
54 54 > hg qnew first.patch
55 55 >
56 56 > touch ../first.patch
57 57 > hg qimport ../first.patch
58 58 >
59 59 > echo '% qnew -f from a subdirectory'
60 60 > hg qpop -a
61 61 > mkdir d
62 62 > cd d
63 63 > echo b > b
64 64 > hg ci -Am t
65 65 > echo b >> b
66 66 > hg st
67 67 > hg qnew -g -f p
68 68 > catpatch ../.hg/patches/p
69 69 >
70 70 > echo '% qnew -u with no username configured'
71 71 > HGUSER= hg qnew -u blue red
72 72 > catpatch ../.hg/patches/red
73 73 >
74 74 > echo '% qnew -e -u with no username configured'
75 75 > HGUSER= hg qnew -e -u chartreuse fucsia
76 76 > catpatch ../.hg/patches/fucsia
77 77 >
78 78 > echo '% fail when trying to import a merge'
79 79 > hg init merge
80 80 > cd merge
81 81 > touch a
82 82 > hg ci -Am null
83 83 > echo a >> a
84 84 > hg ci -m a
85 85 > hg up -r 0
86 86 > echo b >> a
87 87 > hg ci -m b
88 88 > hg merge -f 1
89 89 > hg resolve --mark a
90 90 > hg qnew -f merge
91 91 >
92 92 > cd ../../..
93 93 > rm -r mq
94 94 > }
95 95
96 96 plain headers
97 97
98 98 $ echo "[mq]" >> $HGRCPATH
99 99 $ echo "plain=true" >> $HGRCPATH
100 100 $ mkdir sandbox
101 101 $ (cd sandbox ; runtest)
102 102 adding a
103 103 % qnew should refuse bad patch names
104 104 abort: "series" cannot be used as the name of a patch
105 105 abort: "status" cannot be used as the name of a patch
106 106 abort: "guards" cannot be used as the name of a patch
107 107 abort: "." cannot be used as the name of a patch
108 108 abort: ".." cannot be used as the name of a patch
109 109 abort: patch name cannot begin with ".hg"
110 110 abort: patch name cannot begin with ".mq"
111 111 abort: "#" cannot be used in the name of a patch
112 112 abort: ":" cannot be used in the name of a patch
113 113 % qnew with name containing slash
114 114 abort: path ends in directory separator: foo/ (glob)
115 115 abort: "foo" already exists as a directory
116 116 foo/bar.patch
117 117 popping foo/bar.patch
118 118 patch queue now empty
119 119 % qnew with uncommitted changes
120 120 uncommitted.patch
121 121 % qnew implies add
122 122 A .hgignore
123 123 A series
124 124 A uncommitted.patch
125 125 % qnew missing
126 126 abort: missing: * (glob)
127 127 % qnew -m
128 128 foo bar
129 129
130 130 % qnew twice
131 131 abort: patch "first.patch" already exists
132 132 abort: patch "first.patch" already exists
133 133 % qnew -f from a subdirectory
134 134 popping first.patch
135 135 popping mtest.patch
136 136 popping uncommitted.patch
137 137 patch queue now empty
138 138 adding d/b
139 139 M d/b
140 140 diff --git a/d/b b/d/b
141 141 --- a/d/b
142 142 +++ b/d/b
143 143 @@ -1,1 +1,2 @@
144 144 b
145 145 +b
146 146 % qnew -u with no username configured
147 147 From: blue
148 148
149 149 % qnew -e -u with no username configured
150 150 From: chartreuse
151 151
152 152 % fail when trying to import a merge
153 153 adding a
154 154 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 155 created new head
156 156 merging a
157 157 warning: conflicts during merge.
158 158 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
159 159 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
160 160 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
161 161 (no more unresolved files)
162 162 abort: cannot manage merge changesets
163 163 $ rm -r sandbox
164 164
165 165 hg headers
166 166
167 167 $ echo "plain=false" >> $HGRCPATH
168 168 $ mkdir sandbox
169 169 $ (cd sandbox ; runtest)
170 170 adding a
171 171 % qnew should refuse bad patch names
172 172 abort: "series" cannot be used as the name of a patch
173 173 abort: "status" cannot be used as the name of a patch
174 174 abort: "guards" cannot be used as the name of a patch
175 175 abort: "." cannot be used as the name of a patch
176 176 abort: ".." cannot be used as the name of a patch
177 177 abort: patch name cannot begin with ".hg"
178 178 abort: patch name cannot begin with ".mq"
179 179 abort: "#" cannot be used in the name of a patch
180 180 abort: ":" cannot be used in the name of a patch
181 181 % qnew with name containing slash
182 182 abort: path ends in directory separator: foo/ (glob)
183 183 abort: "foo" already exists as a directory
184 184 foo/bar.patch
185 185 popping foo/bar.patch
186 186 patch queue now empty
187 187 % qnew with uncommitted changes
188 188 uncommitted.patch
189 189 % qnew implies add
190 190 A .hgignore
191 191 A series
192 192 A uncommitted.patch
193 193 % qnew missing
194 194 abort: missing: * (glob)
195 195 % qnew -m
196 196 # HG changeset patch
197 197 # Parent
198 198 foo bar
199 199
200 200 % qnew twice
201 201 abort: patch "first.patch" already exists
202 202 abort: patch "first.patch" already exists
203 203 % qnew -f from a subdirectory
204 204 popping first.patch
205 205 popping mtest.patch
206 206 popping uncommitted.patch
207 207 patch queue now empty
208 208 adding d/b
209 209 M d/b
210 210 # HG changeset patch
211 211 # Parent
212
212 213 diff --git a/d/b b/d/b
213 214 --- a/d/b
214 215 +++ b/d/b
215 216 @@ -1,1 +1,2 @@
216 217 b
217 218 +b
218 219 % qnew -u with no username configured
219 220 # HG changeset patch
220 221 # Parent
221 222 # User blue
223
222 224 % qnew -e -u with no username configured
223 225 # HG changeset patch
224 226 # Parent
225 227 # User chartreuse
228
226 229 % fail when trying to import a merge
227 230 adding a
228 231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 232 created new head
230 233 merging a
231 234 warning: conflicts during merge.
232 235 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
233 236 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
234 237 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
235 238 (no more unresolved files)
236 239 abort: cannot manage merge changesets
237 240 $ rm -r sandbox
238 241
239 242 Test saving last-message.txt
240 243
241 244 $ hg init repo
242 245 $ cd repo
243 246
244 247 $ cat > $TESTTMP/commitfailure.py <<EOF
245 248 > from mercurial import util
246 249 > def reposetup(ui, repo):
247 250 > class commitfailure(repo.__class__):
248 251 > def commit(self, *args, **kwargs):
249 252 > raise util.Abort('emulating unexpected abort')
250 253 > repo.__class__ = commitfailure
251 254 > EOF
252 255 $ cat >> .hg/hgrc <<EOF
253 256 > [extensions]
254 257 > # this failure occurs before editor invocation
255 258 > commitfailure = $TESTTMP/commitfailure.py
256 259 > EOF
257 260
258 261 $ cat > $TESTTMP/editor.sh << EOF
259 262 > echo "==== before editing"
260 263 > cat \$1
261 264 > echo "===="
262 265 > echo "test saving last-message.txt" >> \$1
263 266 > EOF
264 267
265 268 (test that editor is not invoked before transaction starting)
266 269
267 270 $ rm -f .hg/last-message.txt
268 271 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qnew -e patch
269 272 abort: emulating unexpected abort
270 273 [255]
271 274 $ test -f .hg/last-message.txt
272 275 [1]
273 276
274 277 (test that editor is invoked and commit message is saved into
275 278 "last-message.txt")
276 279
277 280 $ cat >> .hg/hgrc <<EOF
278 281 > [extensions]
279 282 > commitfailure = !
280 283 > [hooks]
281 284 > # this failure occurs after editor invocation
282 285 > pretxncommit.unexpectedabort = false
283 286 > EOF
284 287
285 288 $ rm -f .hg/last-message.txt
286 289 $ hg status
287 290 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qnew -e patch
288 291 ==== before editing
289 292
290 293
291 294 HG: Enter commit message. Lines beginning with 'HG:' are removed.
292 295 HG: Leave message empty to use default message.
293 296 HG: --
294 297 HG: user: test
295 298 HG: branch 'default'
296 299 HG: no files changed
297 300 ====
298 301 transaction abort!
299 302 rollback completed
300 303 note: commit message saved in .hg/last-message.txt
301 304 abort: pretxncommit.unexpectedabort hook exited with status 1
302 305 [255]
303 306 $ cat .hg/last-message.txt
304 307
305 308
306 309 test saving last-message.txt
307 310
308 311 $ cat >> .hg/hgrc <<EOF
309 312 > [hooks]
310 313 > pretxncommit.unexpectedabort =
311 314 > EOF
312 315
313 316 #if unix-permissions
314 317
315 318 Test handling default message with the patch filename with tail whitespaces
316 319
317 320 $ cat > $TESTTMP/editor.sh << EOF
318 321 > echo "==== before editing"
319 322 > cat \$1
320 323 > echo "===="
321 324 > echo "[mq]: patch " > \$1
322 325 > EOF
323 326
324 327 $ rm -f .hg/last-message.txt
325 328 $ hg status
326 329 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qnew -e "patch "
327 330 ==== before editing
328 331
329 332
330 333 HG: Enter commit message. Lines beginning with 'HG:' are removed.
331 334 HG: Leave message empty to use default message.
332 335 HG: --
333 336 HG: user: test
334 337 HG: branch 'default'
335 338 HG: no files changed
336 339 ====
337 340 $ cat ".hg/patches/patch "
338 341 # HG changeset patch
339 342 # Parent 0000000000000000000000000000000000000000
340 343
344
341 345 $ cd ..
342 346
343 347 #endif
@@ -1,548 +1,550 b''
1 1 $ echo "[extensions]" >> $HGRCPATH
2 2 $ echo "mq=" >> $HGRCPATH
3 3 $ echo "[diff]" >> $HGRCPATH
4 4 $ echo "nodates=1" >> $HGRCPATH
5 5
6 6 $ hg init a
7 7 $ cd a
8 8
9 9 $ mkdir 1 2
10 10 $ echo 'base' > 1/base
11 11 $ echo 'base' > 2/base
12 12 $ hg ci -Ambase
13 13 adding 1/base
14 14 adding 2/base
15 15
16 16 $ hg qnew -mmqbase mqbase
17 17
18 18 $ echo 'patched' > 1/base
19 19 $ echo 'patched' > 2/base
20 20 $ hg qrefresh
21 21
22 22 $ hg qdiff
23 23 diff -r e7af5904b465 1/base
24 24 --- a/1/base
25 25 +++ b/1/base
26 26 @@ -1,1 +1,1 @@
27 27 -base
28 28 +patched
29 29 diff -r e7af5904b465 2/base
30 30 --- a/2/base
31 31 +++ b/2/base
32 32 @@ -1,1 +1,1 @@
33 33 -base
34 34 +patched
35 35
36 36 $ hg qdiff .
37 37 diff -r e7af5904b465 1/base
38 38 --- a/1/base
39 39 +++ b/1/base
40 40 @@ -1,1 +1,1 @@
41 41 -base
42 42 +patched
43 43 diff -r e7af5904b465 2/base
44 44 --- a/2/base
45 45 +++ b/2/base
46 46 @@ -1,1 +1,1 @@
47 47 -base
48 48 +patched
49 49
50 50 $ cat .hg/patches/mqbase
51 51 # HG changeset patch
52 52 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
53 53 mqbase
54 54
55 55 diff -r e7af5904b465 1/base
56 56 --- a/1/base
57 57 +++ b/1/base
58 58 @@ -1,1 +1,1 @@
59 59 -base
60 60 +patched
61 61 diff -r e7af5904b465 2/base
62 62 --- a/2/base
63 63 +++ b/2/base
64 64 @@ -1,1 +1,1 @@
65 65 -base
66 66 +patched
67 67
68 68 $ echo 'patched again' > base
69 69 $ hg qrefresh 1
70 70
71 71 $ hg qdiff
72 72 diff -r e7af5904b465 1/base
73 73 --- a/1/base
74 74 +++ b/1/base
75 75 @@ -1,1 +1,1 @@
76 76 -base
77 77 +patched
78 78 diff -r e7af5904b465 2/base
79 79 --- a/2/base
80 80 +++ b/2/base
81 81 @@ -1,1 +1,1 @@
82 82 -base
83 83 +patched
84 84
85 85 $ hg qdiff .
86 86 diff -r e7af5904b465 1/base
87 87 --- a/1/base
88 88 +++ b/1/base
89 89 @@ -1,1 +1,1 @@
90 90 -base
91 91 +patched
92 92 diff -r e7af5904b465 2/base
93 93 --- a/2/base
94 94 +++ b/2/base
95 95 @@ -1,1 +1,1 @@
96 96 -base
97 97 +patched
98 98
99 99 $ cat .hg/patches/mqbase
100 100 # HG changeset patch
101 101 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
102 102 mqbase
103 103
104 104 diff -r e7af5904b465 1/base
105 105 --- a/1/base
106 106 +++ b/1/base
107 107 @@ -1,1 +1,1 @@
108 108 -base
109 109 +patched
110 110
111 111 qrefresh . in subdir:
112 112
113 113 $ ( cd 1 ; hg qrefresh . )
114 114
115 115 $ hg qdiff
116 116 diff -r e7af5904b465 1/base
117 117 --- a/1/base
118 118 +++ b/1/base
119 119 @@ -1,1 +1,1 @@
120 120 -base
121 121 +patched
122 122 diff -r e7af5904b465 2/base
123 123 --- a/2/base
124 124 +++ b/2/base
125 125 @@ -1,1 +1,1 @@
126 126 -base
127 127 +patched
128 128
129 129 $ hg qdiff .
130 130 diff -r e7af5904b465 1/base
131 131 --- a/1/base
132 132 +++ b/1/base
133 133 @@ -1,1 +1,1 @@
134 134 -base
135 135 +patched
136 136 diff -r e7af5904b465 2/base
137 137 --- a/2/base
138 138 +++ b/2/base
139 139 @@ -1,1 +1,1 @@
140 140 -base
141 141 +patched
142 142
143 143 $ cat .hg/patches/mqbase
144 144 # HG changeset patch
145 145 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
146 146 mqbase
147 147
148 148 diff -r e7af5904b465 1/base
149 149 --- a/1/base
150 150 +++ b/1/base
151 151 @@ -1,1 +1,1 @@
152 152 -base
153 153 +patched
154 154
155 155 qrefresh in hg-root again:
156 156
157 157 $ hg qrefresh
158 158
159 159 $ hg qdiff
160 160 diff -r e7af5904b465 1/base
161 161 --- a/1/base
162 162 +++ b/1/base
163 163 @@ -1,1 +1,1 @@
164 164 -base
165 165 +patched
166 166 diff -r e7af5904b465 2/base
167 167 --- a/2/base
168 168 +++ b/2/base
169 169 @@ -1,1 +1,1 @@
170 170 -base
171 171 +patched
172 172
173 173 $ hg qdiff .
174 174 diff -r e7af5904b465 1/base
175 175 --- a/1/base
176 176 +++ b/1/base
177 177 @@ -1,1 +1,1 @@
178 178 -base
179 179 +patched
180 180 diff -r e7af5904b465 2/base
181 181 --- a/2/base
182 182 +++ b/2/base
183 183 @@ -1,1 +1,1 @@
184 184 -base
185 185 +patched
186 186
187 187 $ cat .hg/patches/mqbase
188 188 # HG changeset patch
189 189 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
190 190 mqbase
191 191
192 192 diff -r e7af5904b465 1/base
193 193 --- a/1/base
194 194 +++ b/1/base
195 195 @@ -1,1 +1,1 @@
196 196 -base
197 197 +patched
198 198 diff -r e7af5904b465 2/base
199 199 --- a/2/base
200 200 +++ b/2/base
201 201 @@ -1,1 +1,1 @@
202 202 -base
203 203 +patched
204 204
205 205
206 206 qrefresh --short tests:
207 207
208 208 $ echo 'orphan' > orphanchild
209 209 $ hg add orphanchild
210 210 $ hg qrefresh nonexistentfilename # clear patch
211 211 nonexistentfilename: * (glob)
212 212 $ hg diff -c qtip
213 213 $ hg qrefresh --short 1/base
214 214 $ hg qrefresh --short 2/base
215 215
216 216 $ hg qdiff
217 217 diff -r e7af5904b465 1/base
218 218 --- a/1/base
219 219 +++ b/1/base
220 220 @@ -1,1 +1,1 @@
221 221 -base
222 222 +patched
223 223 diff -r e7af5904b465 2/base
224 224 --- a/2/base
225 225 +++ b/2/base
226 226 @@ -1,1 +1,1 @@
227 227 -base
228 228 +patched
229 229 diff -r e7af5904b465 orphanchild
230 230 --- /dev/null
231 231 +++ b/orphanchild
232 232 @@ -0,0 +1,1 @@
233 233 +orphan
234 234
235 235 $ cat .hg/patches/mqbase
236 236 # HG changeset patch
237 237 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
238 238 mqbase
239 239
240 240 diff -r e7af5904b465 1/base
241 241 --- a/1/base
242 242 +++ b/1/base
243 243 @@ -1,1 +1,1 @@
244 244 -base
245 245 +patched
246 246 diff -r e7af5904b465 2/base
247 247 --- a/2/base
248 248 +++ b/2/base
249 249 @@ -1,1 +1,1 @@
250 250 -base
251 251 +patched
252 252
253 253 $ hg st
254 254 A orphanchild
255 255 ? base
256 256
257 257 diff shows what is not in patch:
258 258
259 259 $ hg diff
260 260 diff -r ???????????? orphanchild (glob)
261 261 --- /dev/null
262 262 +++ b/orphanchild
263 263 @@ -0,0 +1,1 @@
264 264 +orphan
265 265
266 266 Before starting exclusive tests:
267 267
268 268 $ cat .hg/patches/mqbase
269 269 # HG changeset patch
270 270 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
271 271 mqbase
272 272
273 273 diff -r e7af5904b465 1/base
274 274 --- a/1/base
275 275 +++ b/1/base
276 276 @@ -1,1 +1,1 @@
277 277 -base
278 278 +patched
279 279 diff -r e7af5904b465 2/base
280 280 --- a/2/base
281 281 +++ b/2/base
282 282 @@ -1,1 +1,1 @@
283 283 -base
284 284 +patched
285 285
286 286 Exclude 2/base:
287 287
288 288 $ hg qref -s -X 2/base
289 289
290 290 $ cat .hg/patches/mqbase
291 291 # HG changeset patch
292 292 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
293 293 mqbase
294 294
295 295 diff -r e7af5904b465 1/base
296 296 --- a/1/base
297 297 +++ b/1/base
298 298 @@ -1,1 +1,1 @@
299 299 -base
300 300 +patched
301 301
302 302 status shows 2/base as dirty:
303 303
304 304 $ hg status
305 305 M 2/base
306 306 A orphanchild
307 307 ? base
308 308
309 309 Remove 1/base and add 2/base again but not orphanchild:
310 310
311 311 $ hg qref -s -X orphanchild -X 1/base 2/base orphanchild
312 312
313 313 $ cat .hg/patches/mqbase
314 314 # HG changeset patch
315 315 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
316 316 mqbase
317 317
318 318 diff -r e7af5904b465 2/base
319 319 --- a/2/base
320 320 +++ b/2/base
321 321 @@ -1,1 +1,1 @@
322 322 -base
323 323 +patched
324 324
325 325 Add 1/base with include filter - and thus remove 2/base from patch:
326 326
327 327 $ hg qref -s -I 1/ o* */*
328 328
329 329 $ cat .hg/patches/mqbase
330 330 # HG changeset patch
331 331 # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa
332 332 mqbase
333 333
334 334 diff -r e7af5904b465 1/base
335 335 --- a/1/base
336 336 +++ b/1/base
337 337 @@ -1,1 +1,1 @@
338 338 -base
339 339 +patched
340 340
341 341 $ cd ..
342 342
343 343
344 344 Test qrefresh --git losing copy metadata:
345 345
346 346 $ hg init repo
347 347 $ cd repo
348 348
349 349 $ echo "[diff]" >> .hg/hgrc
350 350 $ echo "git=True" >> .hg/hgrc
351 351 $ echo a > a
352 352
353 353 $ hg ci -Am adda
354 354 adding a
355 355 $ hg copy a ab
356 356 $ echo b >> ab
357 357 $ hg copy a ac
358 358 $ echo c >> ac
359 359
360 360 Capture changes:
361 361
362 362 $ hg qnew -f p1
363 363
364 364 $ hg qdiff
365 365 diff --git a/a b/ab
366 366 copy from a
367 367 copy to ab
368 368 --- a/a
369 369 +++ b/ab
370 370 @@ -1,1 +1,2 @@
371 371 a
372 372 +b
373 373 diff --git a/a b/ac
374 374 copy from a
375 375 copy to ac
376 376 --- a/a
377 377 +++ b/ac
378 378 @@ -1,1 +1,2 @@
379 379 a
380 380 +c
381 381
382 382 Refresh and check changes again:
383 383
384 384 $ hg qrefresh
385 385
386 386 $ hg qdiff
387 387 diff --git a/a b/ab
388 388 copy from a
389 389 copy to ab
390 390 --- a/a
391 391 +++ b/ab
392 392 @@ -1,1 +1,2 @@
393 393 a
394 394 +b
395 395 diff --git a/a b/ac
396 396 copy from a
397 397 copy to ac
398 398 --- a/a
399 399 +++ b/ac
400 400 @@ -1,1 +1,2 @@
401 401 a
402 402 +c
403 403
404 404 $ cd ..
405 405
406 406
407 407 Issue1441: qrefresh confused after hg rename:
408 408
409 409 $ hg init repo-1441
410 410 $ cd repo-1441
411 411 $ echo a > a
412 412 $ hg add a
413 413 $ hg qnew -f p
414 414 $ hg mv a b
415 415 $ hg qrefresh
416 416
417 417 $ hg qdiff
418 418 diff -r 000000000000 b
419 419 --- /dev/null
420 420 +++ b/b
421 421 @@ -0,0 +1,1 @@
422 422 +a
423 423
424 424 $ cd ..
425 425
426 426
427 427 Issue2025: qrefresh does not honor filtering options when tip !=
428 428 qtip:
429 429
430 430 $ hg init repo-2025
431 431 $ cd repo-2025
432 432 $ echo a > a
433 433 $ echo b > b
434 434 $ hg ci -qAm addab
435 435 $ echo a >> a
436 436 $ echo b >> b
437 437 $ hg qnew -f patch
438 438 $ hg up -qC 0
439 439 $ echo c > c
440 440 $ hg ci -qAm addc
441 441 $ hg up -qC 1
442 442
443 443 refresh with tip != qtip:
444 444
445 445 $ hg --config diff.nodates=1 qrefresh -I b
446 446
447 447 $ hg st
448 448 M a
449 449
450 450 $ cat b
451 451 b
452 452 b
453 453
454 454 $ cat .hg/patches/patch
455 455 # HG changeset patch
456 456 # Parent 1a60229be7ac3e4a7f647508e99b87bef1f03593
457 457
458 458 diff -r 1a60229be7ac b
459 459 --- a/b
460 460 +++ b/b
461 461 @@ -1,1 +1,2 @@
462 462 b
463 463 +b
464 464
465 465 $ cd ..
466 466
467 467
468 468 Issue1441 with git patches:
469 469
470 470 $ hg init repo-1441-git
471 471 $ cd repo-1441-git
472 472
473 473 $ echo "[diff]" >> .hg/hgrc
474 474 $ echo "git=True" >> .hg/hgrc
475 475
476 476 $ echo a > a
477 477 $ hg add a
478 478 $ hg qnew -f p
479 479 $ hg mv a b
480 480 $ hg qrefresh
481 481
482 482 $ hg qdiff --nodates
483 483 diff --git a/b b/b
484 484 new file mode 100644
485 485 --- /dev/null
486 486 +++ b/b
487 487 @@ -0,0 +1,1 @@
488 488 +a
489 489
490 490 $ cd ..
491 491
492 492 Refresh with bad usernames. Mercurial used to abort on bad usernames,
493 493 but only after writing the bad name into the patch.
494 494
495 495 $ hg init bad-usernames
496 496 $ cd bad-usernames
497 497 $ touch a
498 498 $ hg add a
499 499 $ hg qnew a
500 500 $ hg qrefresh -u 'foo
501 501 > bar'
502 502 transaction abort!
503 503 rollback completed
504 504 refresh interrupted while patch was popped! (revert --all, qpush to recover)
505 505 abort: username 'foo\nbar' contains a newline!
506 506 [255]
507 507 $ rm a
508 508 $ cat .hg/patches/a
509 509 # HG changeset patch
510 510 # Parent 0000000000000000000000000000000000000000
511
511 512 diff --git a/a b/a
512 513 new file mode 100644
513 514 $ hg qpush
514 515 applying a
515 516 now at: a
516 517 $ hg qrefresh -u ' '
517 518 transaction abort!
518 519 rollback completed
519 520 refresh interrupted while patch was popped! (revert --all, qpush to recover)
520 521 abort: empty username!
521 522 [255]
522 523 $ cat .hg/patches/a
523 524 # HG changeset patch
524 525 # Parent 0000000000000000000000000000000000000000
526
525 527 diff --git a/a b/a
526 528 new file mode 100644
527 529 $ cd ..
528 530
529 531 Refresh with phase data:
530 532
531 533
532 534
533 535 $ cd repo
534 536 $ echo 'babar' >> a
535 537 $ hg qnew -m 'update a' p2.diff
536 538 $ hg phase p2.diff
537 539 2: draft
538 540 $ echo 'beber' >> a
539 541 $ hg qref
540 542 $ hg phase p2.diff
541 543 2: draft
542 544 $ hg phase --force --secret p2.diff
543 545 $ echo 'bibir' >> a
544 546 $ hg qref
545 547 $ hg phase p2.diff
546 548 2: secret
547 549
548 550 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now