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