##// END OF EJS Templates
templatekw: force noprefix=False to insure diffstat consistency (issue4755)...
Matthieu Laneuville -
r30811:cf1e15f9 default
parent child Browse files
Show More
@@ -1,607 +1,607 b''
1 1 # templatekw.py - common changeset template keywords
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.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 from __future__ import absolute_import
9 9
10 10 from .node import hex, nullid
11 11 from . import (
12 12 encoding,
13 13 error,
14 14 hbisect,
15 15 patch,
16 16 registrar,
17 17 scmutil,
18 18 util,
19 19 )
20 20
21 21 # This helper class allows us to handle both:
22 22 # "{files}" (legacy command-line-specific list hack) and
23 23 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
24 24 # and to access raw values:
25 25 # "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
26 26 # "{get(extras, key)}"
27 27
28 28 class _hybrid(object):
29 29 def __init__(self, gen, values, makemap, joinfmt):
30 30 self.gen = gen
31 31 self.values = values
32 32 self._makemap = makemap
33 33 self.joinfmt = joinfmt
34 34 def __iter__(self):
35 35 return self.gen
36 36 def itermaps(self):
37 37 makemap = self._makemap
38 38 for x in self.values:
39 39 yield makemap(x)
40 40 def __contains__(self, x):
41 41 return x in self.values
42 42 def __len__(self):
43 43 return len(self.values)
44 44 def __getattr__(self, name):
45 45 if name != 'get':
46 46 raise AttributeError(name)
47 47 return getattr(self.values, name)
48 48
49 49 def showlist(name, values, plural=None, element=None, separator=' ', **args):
50 50 if not element:
51 51 element = name
52 52 f = _showlist(name, values, plural, separator, **args)
53 53 return _hybrid(f, values, lambda x: {element: x}, lambda d: d[element])
54 54
55 55 def _showlist(name, values, plural=None, separator=' ', **args):
56 56 '''expand set of values.
57 57 name is name of key in template map.
58 58 values is list of strings or dicts.
59 59 plural is plural of name, if not simply name + 's'.
60 60 separator is used to join values as a string
61 61
62 62 expansion works like this, given name 'foo'.
63 63
64 64 if values is empty, expand 'no_foos'.
65 65
66 66 if 'foo' not in template map, return values as a string,
67 67 joined by 'separator'.
68 68
69 69 expand 'start_foos'.
70 70
71 71 for each value, expand 'foo'. if 'last_foo' in template
72 72 map, expand it instead of 'foo' for last key.
73 73
74 74 expand 'end_foos'.
75 75 '''
76 76 templ = args['templ']
77 77 if plural:
78 78 names = plural
79 79 else: names = name + 's'
80 80 if not values:
81 81 noname = 'no_' + names
82 82 if noname in templ:
83 83 yield templ(noname, **args)
84 84 return
85 85 if name not in templ:
86 86 if isinstance(values[0], str):
87 87 yield separator.join(values)
88 88 else:
89 89 for v in values:
90 90 yield dict(v, **args)
91 91 return
92 92 startname = 'start_' + names
93 93 if startname in templ:
94 94 yield templ(startname, **args)
95 95 vargs = args.copy()
96 96 def one(v, tag=name):
97 97 try:
98 98 vargs.update(v)
99 99 except (AttributeError, ValueError):
100 100 try:
101 101 for a, b in v:
102 102 vargs[a] = b
103 103 except ValueError:
104 104 vargs[name] = v
105 105 return templ(tag, **vargs)
106 106 lastname = 'last_' + name
107 107 if lastname in templ:
108 108 last = values.pop()
109 109 else:
110 110 last = None
111 111 for v in values:
112 112 yield one(v)
113 113 if last is not None:
114 114 yield one(last, tag=lastname)
115 115 endname = 'end_' + names
116 116 if endname in templ:
117 117 yield templ(endname, **args)
118 118
119 119 def _formatrevnode(ctx):
120 120 """Format changeset as '{rev}:{node|formatnode}', which is the default
121 121 template provided by cmdutil.changeset_templater"""
122 122 repo = ctx.repo()
123 123 if repo.ui.debugflag:
124 124 hexnode = ctx.hex()
125 125 else:
126 126 hexnode = ctx.hex()[:12]
127 127 return '%d:%s' % (scmutil.intrev(ctx.rev()), hexnode)
128 128
129 129 def getfiles(repo, ctx, revcache):
130 130 if 'files' not in revcache:
131 131 revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
132 132 return revcache['files']
133 133
134 134 def getlatesttags(repo, ctx, cache, pattern=None):
135 135 '''return date, distance and name for the latest tag of rev'''
136 136
137 137 cachename = 'latesttags'
138 138 if pattern is not None:
139 139 cachename += '-' + pattern
140 140 match = util.stringmatcher(pattern)[2]
141 141 else:
142 142 match = util.always
143 143
144 144 if cachename not in cache:
145 145 # Cache mapping from rev to a tuple with tag date, tag
146 146 # distance and tag name
147 147 cache[cachename] = {-1: (0, 0, ['null'])}
148 148 latesttags = cache[cachename]
149 149
150 150 rev = ctx.rev()
151 151 todo = [rev]
152 152 while todo:
153 153 rev = todo.pop()
154 154 if rev in latesttags:
155 155 continue
156 156 ctx = repo[rev]
157 157 tags = [t for t in ctx.tags()
158 158 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
159 159 and match(t))]
160 160 if tags:
161 161 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
162 162 continue
163 163 try:
164 164 # The tuples are laid out so the right one can be found by
165 165 # comparison.
166 166 pdate, pdist, ptag = max(
167 167 latesttags[p.rev()] for p in ctx.parents())
168 168 except KeyError:
169 169 # Cache miss - recurse
170 170 todo.append(rev)
171 171 todo.extend(p.rev() for p in ctx.parents())
172 172 continue
173 173 latesttags[rev] = pdate, pdist + 1, ptag
174 174 return latesttags[rev]
175 175
176 176 def getrenamedfn(repo, endrev=None):
177 177 rcache = {}
178 178 if endrev is None:
179 179 endrev = len(repo)
180 180
181 181 def getrenamed(fn, rev):
182 182 '''looks up all renames for a file (up to endrev) the first
183 183 time the file is given. It indexes on the changerev and only
184 184 parses the manifest if linkrev != changerev.
185 185 Returns rename info for fn at changerev rev.'''
186 186 if fn not in rcache:
187 187 rcache[fn] = {}
188 188 fl = repo.file(fn)
189 189 for i in fl:
190 190 lr = fl.linkrev(i)
191 191 renamed = fl.renamed(fl.node(i))
192 192 rcache[fn][lr] = renamed
193 193 if lr >= endrev:
194 194 break
195 195 if rev in rcache[fn]:
196 196 return rcache[fn][rev]
197 197
198 198 # If linkrev != rev (i.e. rev not found in rcache) fallback to
199 199 # filectx logic.
200 200 try:
201 201 return repo[rev][fn].renamed()
202 202 except error.LookupError:
203 203 return None
204 204
205 205 return getrenamed
206 206
207 207 # keywords are callables like:
208 208 # fn(repo, ctx, templ, cache, revcache, **args)
209 209 # with:
210 210 # repo - current repository instance
211 211 # ctx - the changectx being displayed
212 212 # templ - the templater instance
213 213 # cache - a cache dictionary for the whole templater run
214 214 # revcache - a cache dictionary for the current revision
215 215 keywords = {}
216 216
217 217 templatekeyword = registrar.templatekeyword(keywords)
218 218
219 219 @templatekeyword('author')
220 220 def showauthor(repo, ctx, templ, **args):
221 221 """String. The unmodified author of the changeset."""
222 222 return ctx.user()
223 223
224 224 @templatekeyword('bisect')
225 225 def showbisect(repo, ctx, templ, **args):
226 226 """String. The changeset bisection status."""
227 227 return hbisect.label(repo, ctx.node())
228 228
229 229 @templatekeyword('branch')
230 230 def showbranch(**args):
231 231 """String. The name of the branch on which the changeset was
232 232 committed.
233 233 """
234 234 return args['ctx'].branch()
235 235
236 236 @templatekeyword('branches')
237 237 def showbranches(**args):
238 238 """List of strings. The name of the branch on which the
239 239 changeset was committed. Will be empty if the branch name was
240 240 default. (DEPRECATED)
241 241 """
242 242 branch = args['ctx'].branch()
243 243 if branch != 'default':
244 244 return showlist('branch', [branch], plural='branches', **args)
245 245 return showlist('branch', [], plural='branches', **args)
246 246
247 247 @templatekeyword('bookmarks')
248 248 def showbookmarks(**args):
249 249 """List of strings. Any bookmarks associated with the
250 250 changeset. Also sets 'active', the name of the active bookmark.
251 251 """
252 252 repo = args['ctx']._repo
253 253 bookmarks = args['ctx'].bookmarks()
254 254 active = repo._activebookmark
255 255 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
256 256 f = _showlist('bookmark', bookmarks, **args)
257 257 return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
258 258
259 259 @templatekeyword('children')
260 260 def showchildren(**args):
261 261 """List of strings. The children of the changeset."""
262 262 ctx = args['ctx']
263 263 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
264 264 return showlist('children', childrevs, element='child', **args)
265 265
266 266 # Deprecated, but kept alive for help generation a purpose.
267 267 @templatekeyword('currentbookmark')
268 268 def showcurrentbookmark(**args):
269 269 """String. The active bookmark, if it is
270 270 associated with the changeset (DEPRECATED)"""
271 271 return showactivebookmark(**args)
272 272
273 273 @templatekeyword('activebookmark')
274 274 def showactivebookmark(**args):
275 275 """String. The active bookmark, if it is
276 276 associated with the changeset"""
277 277 active = args['repo']._activebookmark
278 278 if active and active in args['ctx'].bookmarks():
279 279 return active
280 280 return ''
281 281
282 282 @templatekeyword('date')
283 283 def showdate(repo, ctx, templ, **args):
284 284 """Date information. The date when the changeset was committed."""
285 285 return ctx.date()
286 286
287 287 @templatekeyword('desc')
288 288 def showdescription(repo, ctx, templ, **args):
289 289 """String. The text of the changeset description."""
290 290 s = ctx.description()
291 291 if isinstance(s, encoding.localstr):
292 292 # try hard to preserve utf-8 bytes
293 293 return encoding.tolocal(encoding.fromlocal(s).strip())
294 294 else:
295 295 return s.strip()
296 296
297 297 @templatekeyword('diffstat')
298 298 def showdiffstat(repo, ctx, templ, **args):
299 299 """String. Statistics of changes with the following format:
300 300 "modified files: +added/-removed lines"
301 301 """
302 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
302 stats = patch.diffstatdata(util.iterlines(ctx.diff(noprefix=False)))
303 303 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
304 304 return '%s: +%s/-%s' % (len(stats), adds, removes)
305 305
306 306 @templatekeyword('extras')
307 307 def showextras(**args):
308 308 """List of dicts with key, value entries of the 'extras'
309 309 field of this changeset."""
310 310 extras = args['ctx'].extra()
311 311 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
312 312 makemap = lambda k: {'key': k, 'value': extras[k]}
313 313 c = [makemap(k) for k in extras]
314 314 f = _showlist('extra', c, plural='extras', **args)
315 315 return _hybrid(f, extras, makemap,
316 316 lambda x: '%s=%s' % (x['key'], x['value']))
317 317
318 318 @templatekeyword('file_adds')
319 319 def showfileadds(**args):
320 320 """List of strings. Files added by this changeset."""
321 321 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
322 322 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
323 323 element='file', **args)
324 324
325 325 @templatekeyword('file_copies')
326 326 def showfilecopies(**args):
327 327 """List of strings. Files copied in this changeset with
328 328 their sources.
329 329 """
330 330 cache, ctx = args['cache'], args['ctx']
331 331 copies = args['revcache'].get('copies')
332 332 if copies is None:
333 333 if 'getrenamed' not in cache:
334 334 cache['getrenamed'] = getrenamedfn(args['repo'])
335 335 copies = []
336 336 getrenamed = cache['getrenamed']
337 337 for fn in ctx.files():
338 338 rename = getrenamed(fn, ctx.rev())
339 339 if rename:
340 340 copies.append((fn, rename[0]))
341 341
342 342 copies = util.sortdict(copies)
343 343 makemap = lambda k: {'name': k, 'source': copies[k]}
344 344 c = [makemap(k) for k in copies]
345 345 f = _showlist('file_copy', c, plural='file_copies', **args)
346 346 return _hybrid(f, copies, makemap,
347 347 lambda x: '%s (%s)' % (x['name'], x['source']))
348 348
349 349 # showfilecopiesswitch() displays file copies only if copy records are
350 350 # provided before calling the templater, usually with a --copies
351 351 # command line switch.
352 352 @templatekeyword('file_copies_switch')
353 353 def showfilecopiesswitch(**args):
354 354 """List of strings. Like "file_copies" but displayed
355 355 only if the --copied switch is set.
356 356 """
357 357 copies = args['revcache'].get('copies') or []
358 358 copies = util.sortdict(copies)
359 359 makemap = lambda k: {'name': k, 'source': copies[k]}
360 360 c = [makemap(k) for k in copies]
361 361 f = _showlist('file_copy', c, plural='file_copies', **args)
362 362 return _hybrid(f, copies, makemap,
363 363 lambda x: '%s (%s)' % (x['name'], x['source']))
364 364
365 365 @templatekeyword('file_dels')
366 366 def showfiledels(**args):
367 367 """List of strings. Files removed by this changeset."""
368 368 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
369 369 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
370 370 element='file', **args)
371 371
372 372 @templatekeyword('file_mods')
373 373 def showfilemods(**args):
374 374 """List of strings. Files modified by this changeset."""
375 375 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
376 376 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
377 377 element='file', **args)
378 378
379 379 @templatekeyword('files')
380 380 def showfiles(**args):
381 381 """List of strings. All files modified, added, or removed by this
382 382 changeset.
383 383 """
384 384 return showlist('file', args['ctx'].files(), **args)
385 385
386 386 @templatekeyword('graphnode')
387 387 def showgraphnode(repo, ctx, **args):
388 388 """String. The character representing the changeset node in
389 389 an ASCII revision graph"""
390 390 wpnodes = repo.dirstate.parents()
391 391 if wpnodes[1] == nullid:
392 392 wpnodes = wpnodes[:1]
393 393 if ctx.node() in wpnodes:
394 394 return '@'
395 395 elif ctx.obsolete():
396 396 return 'x'
397 397 elif ctx.closesbranch():
398 398 return '_'
399 399 else:
400 400 return 'o'
401 401
402 402 @templatekeyword('latesttag')
403 403 def showlatesttag(**args):
404 404 """List of strings. The global tags on the most recent globally
405 405 tagged ancestor of this changeset.
406 406 """
407 407 return showlatesttags(None, **args)
408 408
409 409 def showlatesttags(pattern, **args):
410 410 """helper method for the latesttag keyword and function"""
411 411 repo, ctx = args['repo'], args['ctx']
412 412 cache = args['cache']
413 413 latesttags = getlatesttags(repo, ctx, cache, pattern)
414 414
415 415 # latesttag[0] is an implementation detail for sorting csets on different
416 416 # branches in a stable manner- it is the date the tagged cset was created,
417 417 # not the date the tag was created. Therefore it isn't made visible here.
418 418 makemap = lambda v: {
419 419 'changes': _showchangessincetag,
420 420 'distance': latesttags[1],
421 421 'latesttag': v, # BC with {latesttag % '{latesttag}'}
422 422 'tag': v
423 423 }
424 424
425 425 tags = latesttags[2]
426 426 f = _showlist('latesttag', tags, separator=':', **args)
427 427 return _hybrid(f, tags, makemap, lambda x: x['latesttag'])
428 428
429 429 @templatekeyword('latesttagdistance')
430 430 def showlatesttagdistance(repo, ctx, templ, cache, **args):
431 431 """Integer. Longest path to the latest tag."""
432 432 return getlatesttags(repo, ctx, cache)[1]
433 433
434 434 @templatekeyword('changessincelatesttag')
435 435 def showchangessincelatesttag(repo, ctx, templ, cache, **args):
436 436 """Integer. All ancestors not in the latest tag."""
437 437 latesttag = getlatesttags(repo, ctx, cache)[2][0]
438 438
439 439 return _showchangessincetag(repo, ctx, tag=latesttag, **args)
440 440
441 441 def _showchangessincetag(repo, ctx, **args):
442 442 offset = 0
443 443 revs = [ctx.rev()]
444 444 tag = args['tag']
445 445
446 446 # The only() revset doesn't currently support wdir()
447 447 if ctx.rev() is None:
448 448 offset = 1
449 449 revs = [p.rev() for p in ctx.parents()]
450 450
451 451 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
452 452
453 453 @templatekeyword('manifest')
454 454 def showmanifest(**args):
455 455 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
456 456 mnode = ctx.manifestnode()
457 457 if mnode is None:
458 458 # just avoid crash, we might want to use the 'ff...' hash in future
459 459 return
460 460 args = args.copy()
461 461 args.update({'rev': repo.manifestlog._revlog.rev(mnode),
462 462 'node': hex(mnode)})
463 463 return templ('manifest', **args)
464 464
465 465 def shownames(namespace, **args):
466 466 """helper method to generate a template keyword for a namespace"""
467 467 ctx = args['ctx']
468 468 repo = ctx.repo()
469 469 ns = repo.names[namespace]
470 470 names = ns.names(repo, ctx.node())
471 471 return showlist(ns.templatename, names, plural=namespace, **args)
472 472
473 473 @templatekeyword('namespaces')
474 474 def shownamespaces(**args):
475 475 """Dict of lists. Names attached to this changeset per
476 476 namespace."""
477 477 ctx = args['ctx']
478 478 repo = ctx.repo()
479 479 namespaces = util.sortdict((k, showlist('name', ns.names(repo, ctx.node()),
480 480 **args))
481 481 for k, ns in repo.names.iteritems())
482 482 f = _showlist('namespace', list(namespaces), **args)
483 483 return _hybrid(f, namespaces,
484 484 lambda k: {'namespace': k, 'names': namespaces[k]},
485 485 lambda x: x['namespace'])
486 486
487 487 @templatekeyword('node')
488 488 def shownode(repo, ctx, templ, **args):
489 489 """String. The changeset identification hash, as a 40 hexadecimal
490 490 digit string.
491 491 """
492 492 return ctx.hex()
493 493
494 494 @templatekeyword('p1rev')
495 495 def showp1rev(repo, ctx, templ, **args):
496 496 """Integer. The repository-local revision number of the changeset's
497 497 first parent, or -1 if the changeset has no parents."""
498 498 return ctx.p1().rev()
499 499
500 500 @templatekeyword('p2rev')
501 501 def showp2rev(repo, ctx, templ, **args):
502 502 """Integer. The repository-local revision number of the changeset's
503 503 second parent, or -1 if the changeset has no second parent."""
504 504 return ctx.p2().rev()
505 505
506 506 @templatekeyword('p1node')
507 507 def showp1node(repo, ctx, templ, **args):
508 508 """String. The identification hash of the changeset's first parent,
509 509 as a 40 digit hexadecimal string. If the changeset has no parents, all
510 510 digits are 0."""
511 511 return ctx.p1().hex()
512 512
513 513 @templatekeyword('p2node')
514 514 def showp2node(repo, ctx, templ, **args):
515 515 """String. The identification hash of the changeset's second
516 516 parent, as a 40 digit hexadecimal string. If the changeset has no second
517 517 parent, all digits are 0."""
518 518 return ctx.p2().hex()
519 519
520 520 @templatekeyword('parents')
521 521 def showparents(**args):
522 522 """List of strings. The parents of the changeset in "rev:node"
523 523 format. If the changeset has only one "natural" parent (the predecessor
524 524 revision) nothing is shown."""
525 525 repo = args['repo']
526 526 ctx = args['ctx']
527 527 pctxs = scmutil.meaningfulparents(repo, ctx)
528 528 prevs = [str(p.rev()) for p in pctxs] # ifcontains() needs a list of str
529 529 parents = [[('rev', p.rev()),
530 530 ('node', p.hex()),
531 531 ('phase', p.phasestr())]
532 532 for p in pctxs]
533 533 f = _showlist('parent', parents, **args)
534 534 return _hybrid(f, prevs, lambda x: {'ctx': repo[int(x)], 'revcache': {}},
535 535 lambda d: _formatrevnode(d['ctx']))
536 536
537 537 @templatekeyword('phase')
538 538 def showphase(repo, ctx, templ, **args):
539 539 """String. The changeset phase name."""
540 540 return ctx.phasestr()
541 541
542 542 @templatekeyword('phaseidx')
543 543 def showphaseidx(repo, ctx, templ, **args):
544 544 """Integer. The changeset phase index."""
545 545 return ctx.phase()
546 546
547 547 @templatekeyword('rev')
548 548 def showrev(repo, ctx, templ, **args):
549 549 """Integer. The repository-local changeset revision number."""
550 550 return scmutil.intrev(ctx.rev())
551 551
552 552 def showrevslist(name, revs, **args):
553 553 """helper to generate a list of revisions in which a mapped template will
554 554 be evaluated"""
555 555 repo = args['ctx'].repo()
556 556 revs = [str(r) for r in revs] # ifcontains() needs a list of str
557 557 f = _showlist(name, revs, **args)
558 558 return _hybrid(f, revs,
559 559 lambda x: {name: x, 'ctx': repo[int(x)], 'revcache': {}},
560 560 lambda d: d[name])
561 561
562 562 @templatekeyword('subrepos')
563 563 def showsubrepos(**args):
564 564 """List of strings. Updated subrepositories in the changeset."""
565 565 ctx = args['ctx']
566 566 substate = ctx.substate
567 567 if not substate:
568 568 return showlist('subrepo', [], **args)
569 569 psubstate = ctx.parents()[0].substate or {}
570 570 subrepos = []
571 571 for sub in substate:
572 572 if sub not in psubstate or substate[sub] != psubstate[sub]:
573 573 subrepos.append(sub) # modified or newly added in ctx
574 574 for sub in psubstate:
575 575 if sub not in substate:
576 576 subrepos.append(sub) # removed in ctx
577 577 return showlist('subrepo', sorted(subrepos), **args)
578 578
579 579 # don't remove "showtags" definition, even though namespaces will put
580 580 # a helper function for "tags" keyword into "keywords" map automatically,
581 581 # because online help text is built without namespaces initialization
582 582 @templatekeyword('tags')
583 583 def showtags(**args):
584 584 """List of strings. Any tags associated with the changeset."""
585 585 return shownames('tags', **args)
586 586
587 587 def loadkeyword(ui, extname, registrarobj):
588 588 """Load template keyword from specified registrarobj
589 589 """
590 590 for name, func in registrarobj._table.iteritems():
591 591 keywords[name] = func
592 592
593 593 @templatekeyword('termwidth')
594 594 def termwidth(repo, ctx, templ, **args):
595 595 """Integer. The width of the current terminal."""
596 596 return repo.ui.termwidth()
597 597
598 598 @templatekeyword('troubles')
599 599 def showtroubles(**args):
600 600 """List of strings. Evolution troubles affecting the changeset.
601 601
602 602 (EXPERIMENTAL)
603 603 """
604 604 return showlist('trouble', args['ctx'].troubles(), **args)
605 605
606 606 # tell hggettext to extract docstrings from these functions:
607 607 i18nfunctions = keywords.values()
@@ -1,1805 +1,1812 b''
1 1 $ hg init a
2 2 $ mkdir a/d1
3 3 $ mkdir a/d1/d2
4 4 $ echo line 1 > a/a
5 5 $ echo line 1 > a/d1/d2/a
6 6 $ hg --cwd a ci -Ama
7 7 adding a
8 8 adding d1/d2/a
9 9
10 10 $ echo line 2 >> a/a
11 11 $ hg --cwd a ci -u someone -d '1 0' -m'second change'
12 12
13 13 import with no args:
14 14
15 15 $ hg --cwd a import
16 16 abort: need at least one patch to import
17 17 [255]
18 18
19 19 generate patches for the test
20 20
21 21 $ hg --cwd a export tip > exported-tip.patch
22 22 $ hg --cwd a diff -r0:1 > diffed-tip.patch
23 23
24 24
25 25 import exported patch
26 26 (this also tests that editor is not invoked, if the patch contains the
27 27 commit message and '--edit' is not specified)
28 28
29 29 $ hg clone -r0 a b
30 30 adding changesets
31 31 adding manifests
32 32 adding file changes
33 33 added 1 changesets with 2 changes to 2 files
34 34 updating to branch default
35 35 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
36 36 $ HGEDITOR=cat hg --cwd b import ../exported-tip.patch
37 37 applying ../exported-tip.patch
38 38
39 39 message and committer and date should be same
40 40
41 41 $ hg --cwd b tip
42 42 changeset: 1:1d4bd90af0e4
43 43 tag: tip
44 44 user: someone
45 45 date: Thu Jan 01 00:00:01 1970 +0000
46 46 summary: second change
47 47
48 48 $ rm -r b
49 49
50 50
51 51 import exported patch with external patcher
52 52 (this also tests that editor is invoked, if the '--edit' is specified,
53 53 regardless of the commit message in the patch)
54 54
55 55 $ cat > dummypatch.py <<EOF
56 56 > from __future__ import print_function
57 57 > print('patching file a')
58 58 > file('a', 'wb').write('line2\n')
59 59 > EOF
60 60 $ hg clone -r0 a b
61 61 adding changesets
62 62 adding manifests
63 63 adding file changes
64 64 added 1 changesets with 2 changes to 2 files
65 65 updating to branch default
66 66 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 67 $ HGEDITOR=cat hg --config ui.patch='python ../dummypatch.py' --cwd b import --edit ../exported-tip.patch
68 68 applying ../exported-tip.patch
69 69 second change
70 70
71 71
72 72 HG: Enter commit message. Lines beginning with 'HG:' are removed.
73 73 HG: Leave message empty to abort commit.
74 74 HG: --
75 75 HG: user: someone
76 76 HG: branch 'default'
77 77 HG: changed a
78 78 $ cat b/a
79 79 line2
80 80 $ rm -r b
81 81
82 82
83 83 import of plain diff should fail without message
84 84 (this also tests that editor is invoked, if the patch doesn't contain
85 85 the commit message, regardless of '--edit')
86 86
87 87 $ hg clone -r0 a b
88 88 adding changesets
89 89 adding manifests
90 90 adding file changes
91 91 added 1 changesets with 2 changes to 2 files
92 92 updating to branch default
93 93 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 94 $ cat > $TESTTMP/editor.sh <<EOF
95 95 > env | grep HGEDITFORM
96 96 > cat \$1
97 97 > EOF
98 98 $ HGEDITOR="sh $TESTTMP/editor.sh" hg --cwd b import ../diffed-tip.patch
99 99 applying ../diffed-tip.patch
100 100 HGEDITFORM=import.normal.normal
101 101
102 102
103 103 HG: Enter commit message. Lines beginning with 'HG:' are removed.
104 104 HG: Leave message empty to abort commit.
105 105 HG: --
106 106 HG: user: test
107 107 HG: branch 'default'
108 108 HG: changed a
109 109 abort: empty commit message
110 110 [255]
111 111
112 112 Test avoiding editor invocation at applying the patch with --exact,
113 113 even if commit message is empty
114 114
115 115 $ echo a >> b/a
116 116 $ hg --cwd b commit -m ' '
117 117 $ hg --cwd b tip -T "{node}\n"
118 118 d8804f3f5396d800812f579c8452796a5993bdb2
119 119 $ hg --cwd b export -o ../empty-log.diff .
120 120 $ hg --cwd b update -q -C ".^1"
121 121 $ hg --cwd b --config extensions.strip= strip -q tip
122 122 $ HGEDITOR=cat hg --cwd b import --exact ../empty-log.diff
123 123 applying ../empty-log.diff
124 124 $ hg --cwd b tip -T "{node}\n"
125 125 d8804f3f5396d800812f579c8452796a5993bdb2
126 126
127 127 $ rm -r b
128 128
129 129
130 130 import of plain diff should be ok with message
131 131
132 132 $ hg clone -r0 a b
133 133 adding changesets
134 134 adding manifests
135 135 adding file changes
136 136 added 1 changesets with 2 changes to 2 files
137 137 updating to branch default
138 138 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
139 139 $ hg --cwd b import -mpatch ../diffed-tip.patch
140 140 applying ../diffed-tip.patch
141 141 $ rm -r b
142 142
143 143
144 144 import of plain diff with specific date and user
145 145 (this also tests that editor is not invoked, if
146 146 '--message'/'--logfile' is specified and '--edit' is not)
147 147
148 148 $ hg clone -r0 a b
149 149 adding changesets
150 150 adding manifests
151 151 adding file changes
152 152 added 1 changesets with 2 changes to 2 files
153 153 updating to branch default
154 154 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 155 $ hg --cwd b import -mpatch -d '1 0' -u 'user@nowhere.net' ../diffed-tip.patch
156 156 applying ../diffed-tip.patch
157 157 $ hg -R b tip -pv
158 158 changeset: 1:ca68f19f3a40
159 159 tag: tip
160 160 user: user@nowhere.net
161 161 date: Thu Jan 01 00:00:01 1970 +0000
162 162 files: a
163 163 description:
164 164 patch
165 165
166 166
167 167 diff -r 80971e65b431 -r ca68f19f3a40 a
168 168 --- a/a Thu Jan 01 00:00:00 1970 +0000
169 169 +++ b/a Thu Jan 01 00:00:01 1970 +0000
170 170 @@ -1,1 +1,2 @@
171 171 line 1
172 172 +line 2
173 173
174 174 $ rm -r b
175 175
176 176
177 177 import of plain diff should be ok with --no-commit
178 178 (this also tests that editor is not invoked, if '--no-commit' is
179 179 specified, regardless of '--edit')
180 180
181 181 $ hg clone -r0 a b
182 182 adding changesets
183 183 adding manifests
184 184 adding file changes
185 185 added 1 changesets with 2 changes to 2 files
186 186 updating to branch default
187 187 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
188 188 $ HGEDITOR=cat hg --cwd b import --no-commit --edit ../diffed-tip.patch
189 189 applying ../diffed-tip.patch
190 190 $ hg --cwd b diff --nodates
191 191 diff -r 80971e65b431 a
192 192 --- a/a
193 193 +++ b/a
194 194 @@ -1,1 +1,2 @@
195 195 line 1
196 196 +line 2
197 197 $ rm -r b
198 198
199 199
200 200 import of malformed plain diff should fail
201 201
202 202 $ hg clone -r0 a b
203 203 adding changesets
204 204 adding manifests
205 205 adding file changes
206 206 added 1 changesets with 2 changes to 2 files
207 207 updating to branch default
208 208 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 209 $ sed 's/1,1/foo/' < diffed-tip.patch > broken.patch
210 210 $ hg --cwd b import -mpatch ../broken.patch
211 211 applying ../broken.patch
212 212 abort: bad hunk #1
213 213 [255]
214 214 $ rm -r b
215 215
216 216
217 217 hg -R repo import
218 218 put the clone in a subdir - having a directory named "a"
219 219 used to hide a bug.
220 220
221 221 $ mkdir dir
222 222 $ hg clone -r0 a dir/b
223 223 adding changesets
224 224 adding manifests
225 225 adding file changes
226 226 added 1 changesets with 2 changes to 2 files
227 227 updating to branch default
228 228 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 229 $ cd dir
230 230 $ hg -R b import ../exported-tip.patch
231 231 applying ../exported-tip.patch
232 232 $ cd ..
233 233 $ rm -r dir
234 234
235 235
236 236 import from stdin
237 237
238 238 $ hg clone -r0 a b
239 239 adding changesets
240 240 adding manifests
241 241 adding file changes
242 242 added 1 changesets with 2 changes to 2 files
243 243 updating to branch default
244 244 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 245 $ hg --cwd b import - < exported-tip.patch
246 246 applying patch from stdin
247 247 $ rm -r b
248 248
249 249
250 250 import two patches in one stream
251 251
252 252 $ hg init b
253 253 $ hg --cwd a export 0:tip | hg --cwd b import -
254 254 applying patch from stdin
255 255 $ hg --cwd a id
256 256 1d4bd90af0e4 tip
257 257 $ hg --cwd b id
258 258 1d4bd90af0e4 tip
259 259 $ rm -r b
260 260
261 261
262 262 override commit message
263 263
264 264 $ hg clone -r0 a b
265 265 adding changesets
266 266 adding manifests
267 267 adding file changes
268 268 added 1 changesets with 2 changes to 2 files
269 269 updating to branch default
270 270 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
271 271 $ hg --cwd b import -m 'override' - < exported-tip.patch
272 272 applying patch from stdin
273 273 $ hg --cwd b tip | grep override
274 274 summary: override
275 275 $ rm -r b
276 276
277 277 $ cat > mkmsg.py <<EOF
278 278 > import email.Message, sys
279 279 > msg = email.Message.Message()
280 280 > patch = open(sys.argv[1], 'rb').read()
281 281 > msg.set_payload('email commit message\n' + patch)
282 282 > msg['Subject'] = 'email patch'
283 283 > msg['From'] = 'email patcher'
284 284 > file(sys.argv[2], 'wb').write(msg.as_string())
285 285 > EOF
286 286
287 287
288 288 plain diff in email, subject, message body
289 289
290 290 $ hg clone -r0 a b
291 291 adding changesets
292 292 adding manifests
293 293 adding file changes
294 294 added 1 changesets with 2 changes to 2 files
295 295 updating to branch default
296 296 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 297 $ python mkmsg.py diffed-tip.patch msg.patch
298 298 $ hg --cwd b import ../msg.patch
299 299 applying ../msg.patch
300 300 $ hg --cwd b tip | grep email
301 301 user: email patcher
302 302 summary: email patch
303 303 $ rm -r b
304 304
305 305
306 306 plain diff in email, no subject, message body
307 307
308 308 $ hg clone -r0 a b
309 309 adding changesets
310 310 adding manifests
311 311 adding file changes
312 312 added 1 changesets with 2 changes to 2 files
313 313 updating to branch default
314 314 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 315 $ grep -v '^Subject:' msg.patch | hg --cwd b import -
316 316 applying patch from stdin
317 317 $ rm -r b
318 318
319 319
320 320 plain diff in email, subject, no message body
321 321
322 322 $ hg clone -r0 a b
323 323 adding changesets
324 324 adding manifests
325 325 adding file changes
326 326 added 1 changesets with 2 changes to 2 files
327 327 updating to branch default
328 328 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 329 $ grep -v '^email ' msg.patch | hg --cwd b import -
330 330 applying patch from stdin
331 331 $ rm -r b
332 332
333 333
334 334 plain diff in email, no subject, no message body, should fail
335 335
336 336 $ hg clone -r0 a b
337 337 adding changesets
338 338 adding manifests
339 339 adding file changes
340 340 added 1 changesets with 2 changes to 2 files
341 341 updating to branch default
342 342 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
343 343 $ egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
344 344 applying patch from stdin
345 345 abort: empty commit message
346 346 [255]
347 347 $ rm -r b
348 348
349 349
350 350 hg export in email, should use patch header
351 351
352 352 $ hg clone -r0 a b
353 353 adding changesets
354 354 adding manifests
355 355 adding file changes
356 356 added 1 changesets with 2 changes to 2 files
357 357 updating to branch default
358 358 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 359 $ python mkmsg.py exported-tip.patch msg.patch
360 360 $ cat msg.patch | hg --cwd b import -
361 361 applying patch from stdin
362 362 $ hg --cwd b tip | grep second
363 363 summary: second change
364 364 $ rm -r b
365 365
366 366
367 367 subject: duplicate detection, removal of [PATCH]
368 368 The '---' tests the gitsendmail handling without proper mail headers
369 369
370 370 $ cat > mkmsg2.py <<EOF
371 371 > import email.Message, sys
372 372 > msg = email.Message.Message()
373 373 > patch = open(sys.argv[1], 'rb').read()
374 374 > msg.set_payload('email patch\n\nnext line\n---\n' + patch)
375 375 > msg['Subject'] = '[PATCH] email patch'
376 376 > msg['From'] = 'email patcher'
377 377 > file(sys.argv[2], 'wb').write(msg.as_string())
378 378 > EOF
379 379
380 380
381 381 plain diff in email, [PATCH] subject, message body with subject
382 382
383 383 $ hg clone -r0 a b
384 384 adding changesets
385 385 adding manifests
386 386 adding file changes
387 387 added 1 changesets with 2 changes to 2 files
388 388 updating to branch default
389 389 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
390 390 $ python mkmsg2.py diffed-tip.patch msg.patch
391 391 $ cat msg.patch | hg --cwd b import -
392 392 applying patch from stdin
393 393 $ hg --cwd b tip --template '{desc}\n'
394 394 email patch
395 395
396 396 next line
397 397 $ rm -r b
398 398
399 399
400 400 Issue963: Parent of working dir incorrect after import of multiple
401 401 patches and rollback
402 402
403 403 We weren't backing up the correct dirstate file when importing many
404 404 patches: import patch1 patch2; rollback
405 405
406 406 $ echo line 3 >> a/a
407 407 $ hg --cwd a ci -m'third change'
408 408 $ hg --cwd a export -o '../patch%R' 1 2
409 409 $ hg clone -qr0 a b
410 410 $ hg --cwd b parents --template 'parent: {rev}\n'
411 411 parent: 0
412 412 $ hg --cwd b import -v ../patch1 ../patch2
413 413 applying ../patch1
414 414 patching file a
415 415 committing files:
416 416 a
417 417 committing manifest
418 418 committing changelog
419 419 created 1d4bd90af0e4
420 420 applying ../patch2
421 421 patching file a
422 422 committing files:
423 423 a
424 424 committing manifest
425 425 committing changelog
426 426 created 6d019af21222
427 427 $ hg --cwd b rollback
428 428 repository tip rolled back to revision 0 (undo import)
429 429 working directory now based on revision 0
430 430 $ hg --cwd b parents --template 'parent: {rev}\n'
431 431 parent: 0
432 432
433 433 Test that "hg rollback" doesn't restore dirstate to one at the
434 434 beginning of the rolled back transaction in not-"parent-gone" case.
435 435
436 436 invoking pretxncommit hook will cause marking '.hg/dirstate' as a file
437 437 to be restored when rolling back, after DirstateTransactionPlan (see wiki
438 438 page for detail).
439 439
440 440 $ hg --cwd b branch -q foobar
441 441 $ hg --cwd b commit -m foobar
442 442 $ hg --cwd b update 0 -q
443 443 $ hg --cwd b import ../patch1 ../patch2 --config hooks.pretxncommit=true
444 444 applying ../patch1
445 445 applying ../patch2
446 446 $ hg --cwd b update -q 1
447 447 $ hg --cwd b rollback -q
448 448 $ hg --cwd b parents --template 'parent: {rev}\n'
449 449 parent: 1
450 450
451 451 $ hg --cwd b update -q -C 0
452 452 $ hg --cwd b --config extensions.strip= strip -q 1
453 453
454 454 Test visibility of in-memory dirstate changes inside transaction to
455 455 external process
456 456
457 457 $ echo foo > a/foo
458 458 $ hg --cwd a commit -A -m 'adding foo' foo
459 459 $ hg --cwd a export -o '../patch%R' 3
460 460
461 461 $ cat > $TESTTMP/checkvisibility.sh <<EOF
462 462 > echo "===="
463 463 > hg parents --template "VISIBLE {rev}:{node|short}\n"
464 464 > hg status -amr
465 465 > # test that pending changes are hidden
466 466 > unset HG_PENDING
467 467 > hg parents --template "ACTUAL {rev}:{node|short}\n"
468 468 > hg status -amr
469 469 > echo "===="
470 470 > EOF
471 471
472 472 == test visibility to external editor
473 473
474 474 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
475 475 ====
476 476 VISIBLE 0:80971e65b431
477 477 ACTUAL 0:80971e65b431
478 478 ====
479 479
480 480 $ HGEDITOR="sh $TESTTMP/checkvisibility.sh" hg --cwd b import -v --edit ../patch1 ../patch2 ../patch3
481 481 applying ../patch1
482 482 patching file a
483 483 ====
484 484 VISIBLE 0:80971e65b431
485 485 M a
486 486 ACTUAL 0:80971e65b431
487 487 M a
488 488 ====
489 489 committing files:
490 490 a
491 491 committing manifest
492 492 committing changelog
493 493 created 1d4bd90af0e4
494 494 applying ../patch2
495 495 patching file a
496 496 ====
497 497 VISIBLE 1:1d4bd90af0e4
498 498 M a
499 499 ACTUAL 0:80971e65b431
500 500 M a
501 501 ====
502 502 committing files:
503 503 a
504 504 committing manifest
505 505 committing changelog
506 506 created 6d019af21222
507 507 applying ../patch3
508 508 patching file foo
509 509 adding foo
510 510 ====
511 511 VISIBLE 2:6d019af21222
512 512 A foo
513 513 ACTUAL 0:80971e65b431
514 514 M a
515 515 ====
516 516 committing files:
517 517 foo
518 518 committing manifest
519 519 committing changelog
520 520 created 55e3f75b2378
521 521
522 522 $ hg --cwd b rollback -q
523 523
524 524 (content of file "a" is already changed and it should be recognized as
525 525 "M", even though dirstate is restored to one before "hg import")
526 526
527 527 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
528 528 ====
529 529 VISIBLE 0:80971e65b431
530 530 M a
531 531 ACTUAL 0:80971e65b431
532 532 M a
533 533 ====
534 534 $ hg --cwd b revert --no-backup a
535 535 $ rm -f b/foo
536 536
537 537 == test visibility to precommit external hook
538 538
539 539 $ cat >> b/.hg/hgrc <<EOF
540 540 > [hooks]
541 541 > precommit.visibility = sh $TESTTMP/checkvisibility.sh
542 542 > EOF
543 543
544 544 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
545 545 ====
546 546 VISIBLE 0:80971e65b431
547 547 ACTUAL 0:80971e65b431
548 548 ====
549 549
550 550 $ hg --cwd b import ../patch1 ../patch2 ../patch3
551 551 applying ../patch1
552 552 ====
553 553 VISIBLE 0:80971e65b431
554 554 M a
555 555 ACTUAL 0:80971e65b431
556 556 M a
557 557 ====
558 558 applying ../patch2
559 559 ====
560 560 VISIBLE 1:1d4bd90af0e4
561 561 M a
562 562 ACTUAL 0:80971e65b431
563 563 M a
564 564 ====
565 565 applying ../patch3
566 566 ====
567 567 VISIBLE 2:6d019af21222
568 568 A foo
569 569 ACTUAL 0:80971e65b431
570 570 M a
571 571 ====
572 572
573 573 $ hg --cwd b rollback -q
574 574 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
575 575 ====
576 576 VISIBLE 0:80971e65b431
577 577 M a
578 578 ACTUAL 0:80971e65b431
579 579 M a
580 580 ====
581 581 $ hg --cwd b revert --no-backup a
582 582 $ rm -f b/foo
583 583
584 584 $ cat >> b/.hg/hgrc <<EOF
585 585 > [hooks]
586 586 > precommit.visibility =
587 587 > EOF
588 588
589 589 == test visibility to pretxncommit external hook
590 590
591 591 $ cat >> b/.hg/hgrc <<EOF
592 592 > [hooks]
593 593 > pretxncommit.visibility = sh $TESTTMP/checkvisibility.sh
594 594 > EOF
595 595
596 596 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
597 597 ====
598 598 VISIBLE 0:80971e65b431
599 599 ACTUAL 0:80971e65b431
600 600 ====
601 601
602 602 $ hg --cwd b import ../patch1 ../patch2 ../patch3
603 603 applying ../patch1
604 604 ====
605 605 VISIBLE 0:80971e65b431
606 606 M a
607 607 ACTUAL 0:80971e65b431
608 608 M a
609 609 ====
610 610 applying ../patch2
611 611 ====
612 612 VISIBLE 1:1d4bd90af0e4
613 613 M a
614 614 ACTUAL 0:80971e65b431
615 615 M a
616 616 ====
617 617 applying ../patch3
618 618 ====
619 619 VISIBLE 2:6d019af21222
620 620 A foo
621 621 ACTUAL 0:80971e65b431
622 622 M a
623 623 ====
624 624
625 625 $ hg --cwd b rollback -q
626 626 $ (cd b && sh "$TESTTMP/checkvisibility.sh")
627 627 ====
628 628 VISIBLE 0:80971e65b431
629 629 M a
630 630 ACTUAL 0:80971e65b431
631 631 M a
632 632 ====
633 633 $ hg --cwd b revert --no-backup a
634 634 $ rm -f b/foo
635 635
636 636 $ cat >> b/.hg/hgrc <<EOF
637 637 > [hooks]
638 638 > pretxncommit.visibility =
639 639 > EOF
640 640
641 641 $ rm -r b
642 642
643 643
644 644 importing a patch in a subdirectory failed at the commit stage
645 645
646 646 $ echo line 2 >> a/d1/d2/a
647 647 $ hg --cwd a ci -u someoneelse -d '1 0' -m'subdir change'
648 648
649 649 hg import in a subdirectory
650 650
651 651 $ hg clone -r0 a b
652 652 adding changesets
653 653 adding manifests
654 654 adding file changes
655 655 added 1 changesets with 2 changes to 2 files
656 656 updating to branch default
657 657 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
658 658 $ hg --cwd a export tip > tmp
659 659 $ sed -e 's/d1\/d2\///' < tmp > subdir-tip.patch
660 660 $ dir=`pwd`
661 661 $ cd b/d1/d2 2>&1 > /dev/null
662 662 $ hg import ../../../subdir-tip.patch
663 663 applying ../../../subdir-tip.patch
664 664 $ cd "$dir"
665 665
666 666 message should be 'subdir change'
667 667 committer should be 'someoneelse'
668 668
669 669 $ hg --cwd b tip
670 670 changeset: 1:3577f5aea227
671 671 tag: tip
672 672 user: someoneelse
673 673 date: Thu Jan 01 00:00:01 1970 +0000
674 674 summary: subdir change
675 675
676 676
677 677 should be empty
678 678
679 679 $ hg --cwd b status
680 680
681 681
682 682 Test fuzziness (ambiguous patch location, fuzz=2)
683 683
684 684 $ hg init fuzzy
685 685 $ cd fuzzy
686 686 $ echo line1 > a
687 687 $ echo line0 >> a
688 688 $ echo line3 >> a
689 689 $ hg ci -Am adda
690 690 adding a
691 691 $ echo line1 > a
692 692 $ echo line2 >> a
693 693 $ echo line0 >> a
694 694 $ echo line3 >> a
695 695 $ hg ci -m change a
696 696 $ hg export tip > fuzzy-tip.patch
697 697 $ hg up -C 0
698 698 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
699 699 $ echo line1 > a
700 700 $ echo line0 >> a
701 701 $ echo line1 >> a
702 702 $ echo line0 >> a
703 703 $ hg ci -m brancha
704 704 created new head
705 705 $ hg import --config patch.fuzz=0 -v fuzzy-tip.patch
706 706 applying fuzzy-tip.patch
707 707 patching file a
708 708 Hunk #1 FAILED at 0
709 709 1 out of 1 hunks FAILED -- saving rejects to file a.rej
710 710 abort: patch failed to apply
711 711 [255]
712 712 $ hg import --no-commit -v fuzzy-tip.patch
713 713 applying fuzzy-tip.patch
714 714 patching file a
715 715 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
716 716 applied to working directory
717 717 $ hg revert -a
718 718 reverting a
719 719
720 720
721 721 import with --no-commit should have written .hg/last-message.txt
722 722
723 723 $ cat .hg/last-message.txt
724 724 change (no-eol)
725 725
726 726
727 727 test fuzziness with eol=auto
728 728
729 729 $ hg --config patch.eol=auto import --no-commit -v fuzzy-tip.patch
730 730 applying fuzzy-tip.patch
731 731 patching file a
732 732 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
733 733 applied to working directory
734 734 $ cd ..
735 735
736 736
737 737 Test hunk touching empty files (issue906)
738 738
739 739 $ hg init empty
740 740 $ cd empty
741 741 $ touch a
742 742 $ touch b1
743 743 $ touch c1
744 744 $ echo d > d
745 745 $ hg ci -Am init
746 746 adding a
747 747 adding b1
748 748 adding c1
749 749 adding d
750 750 $ echo a > a
751 751 $ echo b > b1
752 752 $ hg mv b1 b2
753 753 $ echo c > c1
754 754 $ hg copy c1 c2
755 755 $ rm d
756 756 $ touch d
757 757 $ hg diff --git
758 758 diff --git a/a b/a
759 759 --- a/a
760 760 +++ b/a
761 761 @@ -0,0 +1,1 @@
762 762 +a
763 763 diff --git a/b1 b/b2
764 764 rename from b1
765 765 rename to b2
766 766 --- a/b1
767 767 +++ b/b2
768 768 @@ -0,0 +1,1 @@
769 769 +b
770 770 diff --git a/c1 b/c1
771 771 --- a/c1
772 772 +++ b/c1
773 773 @@ -0,0 +1,1 @@
774 774 +c
775 775 diff --git a/c1 b/c2
776 776 copy from c1
777 777 copy to c2
778 778 --- a/c1
779 779 +++ b/c2
780 780 @@ -0,0 +1,1 @@
781 781 +c
782 782 diff --git a/d b/d
783 783 --- a/d
784 784 +++ b/d
785 785 @@ -1,1 +0,0 @@
786 786 -d
787 787 $ hg ci -m empty
788 788 $ hg export --git tip > empty.diff
789 789 $ hg up -C 0
790 790 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
791 791 $ hg import empty.diff
792 792 applying empty.diff
793 793 $ for name in a b1 b2 c1 c2 d; do
794 794 > echo % $name file
795 795 > test -f $name && cat $name
796 796 > done
797 797 % a file
798 798 a
799 799 % b1 file
800 800 % b2 file
801 801 b
802 802 % c1 file
803 803 c
804 804 % c2 file
805 805 c
806 806 % d file
807 807 $ cd ..
808 808
809 809
810 810 Test importing a patch ending with a binary file removal
811 811
812 812 $ hg init binaryremoval
813 813 $ cd binaryremoval
814 814 $ echo a > a
815 815 $ $PYTHON -c "file('b', 'wb').write('a\x00b')"
816 816 $ hg ci -Am addall
817 817 adding a
818 818 adding b
819 819 $ hg rm a
820 820 $ hg rm b
821 821 $ hg st
822 822 R a
823 823 R b
824 824 $ hg ci -m remove
825 825 $ hg export --git . > remove.diff
826 826 $ cat remove.diff | grep git
827 827 diff --git a/a b/a
828 828 diff --git a/b b/b
829 829 $ hg up -C 0
830 830 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
831 831 $ hg import remove.diff
832 832 applying remove.diff
833 833 $ hg manifest
834 834 $ cd ..
835 835
836 836
837 837 Issue927: test update+rename with common name
838 838
839 839 $ hg init t
840 840 $ cd t
841 841 $ touch a
842 842 $ hg ci -Am t
843 843 adding a
844 844 $ echo a > a
845 845
846 846 Here, bfile.startswith(afile)
847 847
848 848 $ hg copy a a2
849 849 $ hg ci -m copya
850 850 $ hg export --git tip > copy.diff
851 851 $ hg up -C 0
852 852 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
853 853 $ hg import copy.diff
854 854 applying copy.diff
855 855
856 856 a should contain an 'a'
857 857
858 858 $ cat a
859 859 a
860 860
861 861 and a2 should have duplicated it
862 862
863 863 $ cat a2
864 864 a
865 865 $ cd ..
866 866
867 867
868 868 test -p0
869 869
870 870 $ hg init p0
871 871 $ cd p0
872 872 $ echo a > a
873 873 $ hg ci -Am t
874 874 adding a
875 875 $ hg import -p foo
876 876 abort: invalid value 'foo' for option -p, expected int
877 877 [255]
878 878 $ hg import -p0 - << EOF
879 879 > foobar
880 880 > --- a Sat Apr 12 22:43:58 2008 -0400
881 881 > +++ a Sat Apr 12 22:44:05 2008 -0400
882 882 > @@ -1,1 +1,1 @@
883 883 > -a
884 884 > +bb
885 885 > EOF
886 886 applying patch from stdin
887 887 $ hg status
888 888 $ cat a
889 889 bb
890 890
891 891 test --prefix
892 892
893 893 $ mkdir -p dir/dir2
894 894 $ echo b > dir/dir2/b
895 895 $ hg ci -Am b
896 896 adding dir/dir2/b
897 897 $ hg import -p2 --prefix dir - << EOF
898 898 > foobar
899 899 > --- drop1/drop2/dir2/b
900 900 > +++ drop1/drop2/dir2/b
901 901 > @@ -1,1 +1,1 @@
902 902 > -b
903 903 > +cc
904 904 > EOF
905 905 applying patch from stdin
906 906 $ hg status
907 907 $ cat dir/dir2/b
908 908 cc
909 909 $ cd ..
910 910
911 911
912 912 test paths outside repo root
913 913
914 914 $ mkdir outside
915 915 $ touch outside/foo
916 916 $ hg init inside
917 917 $ cd inside
918 918 $ hg import - <<EOF
919 919 > diff --git a/a b/b
920 920 > rename from ../outside/foo
921 921 > rename to bar
922 922 > EOF
923 923 applying patch from stdin
924 924 abort: path contains illegal component: ../outside/foo (glob)
925 925 [255]
926 926 $ cd ..
927 927
928 928
929 929 test import with similarity and git and strip (issue295 et al.)
930 930
931 931 $ hg init sim
932 932 $ cd sim
933 933 $ echo 'this is a test' > a
934 934 $ hg ci -Ama
935 935 adding a
936 936 $ cat > ../rename.diff <<EOF
937 937 > diff --git a/foo/a b/foo/a
938 938 > deleted file mode 100644
939 939 > --- a/foo/a
940 940 > +++ /dev/null
941 941 > @@ -1,1 +0,0 @@
942 942 > -this is a test
943 943 > diff --git a/foo/b b/foo/b
944 944 > new file mode 100644
945 945 > --- /dev/null
946 946 > +++ b/foo/b
947 947 > @@ -0,0 +1,2 @@
948 948 > +this is a test
949 949 > +foo
950 950 > EOF
951 951 $ hg import --no-commit -v -s 1 ../rename.diff -p2
952 952 applying ../rename.diff
953 953 patching file a
954 954 patching file b
955 955 adding b
956 956 recording removal of a as rename to b (88% similar)
957 957 applied to working directory
958 958 $ hg st -C
959 959 A b
960 960 a
961 961 R a
962 962 $ hg revert -a
963 963 undeleting a
964 964 forgetting b
965 965 $ rm b
966 966 $ hg import --no-commit -v -s 100 ../rename.diff -p2
967 967 applying ../rename.diff
968 968 patching file a
969 969 patching file b
970 970 adding b
971 971 applied to working directory
972 972 $ hg st -C
973 973 A b
974 974 R a
975 975 $ cd ..
976 976
977 977
978 978 Issue1495: add empty file from the end of patch
979 979
980 980 $ hg init addemptyend
981 981 $ cd addemptyend
982 982 $ touch a
983 983 $ hg addremove
984 984 adding a
985 985 $ hg ci -m "commit"
986 986 $ cat > a.patch <<EOF
987 987 > add a, b
988 988 > diff --git a/a b/a
989 989 > --- a/a
990 990 > +++ b/a
991 991 > @@ -0,0 +1,1 @@
992 992 > +a
993 993 > diff --git a/b b/b
994 994 > new file mode 100644
995 995 > EOF
996 996 $ hg import --no-commit a.patch
997 997 applying a.patch
998 998
999 999 apply a good patch followed by an empty patch (mainly to ensure
1000 1000 that dirstate is *not* updated when import crashes)
1001 1001 $ hg update -q -C .
1002 1002 $ rm b
1003 1003 $ touch empty.patch
1004 1004 $ hg import a.patch empty.patch
1005 1005 applying a.patch
1006 1006 applying empty.patch
1007 1007 transaction abort!
1008 1008 rollback completed
1009 1009 abort: empty.patch: no diffs found
1010 1010 [255]
1011 1011 $ hg tip --template '{rev} {desc|firstline}\n'
1012 1012 0 commit
1013 1013 $ hg -q status
1014 1014 M a
1015 1015 $ cd ..
1016 1016
1017 1017 create file when source is not /dev/null
1018 1018
1019 1019 $ cat > create.patch <<EOF
1020 1020 > diff -Naur proj-orig/foo proj-new/foo
1021 1021 > --- proj-orig/foo 1969-12-31 16:00:00.000000000 -0800
1022 1022 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
1023 1023 > @@ -0,0 +1,1 @@
1024 1024 > +a
1025 1025 > EOF
1026 1026
1027 1027 some people have patches like the following too
1028 1028
1029 1029 $ cat > create2.patch <<EOF
1030 1030 > diff -Naur proj-orig/foo proj-new/foo
1031 1031 > --- proj-orig/foo.orig 1969-12-31 16:00:00.000000000 -0800
1032 1032 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
1033 1033 > @@ -0,0 +1,1 @@
1034 1034 > +a
1035 1035 > EOF
1036 1036 $ hg init oddcreate
1037 1037 $ cd oddcreate
1038 1038 $ hg import --no-commit ../create.patch
1039 1039 applying ../create.patch
1040 1040 $ cat foo
1041 1041 a
1042 1042 $ rm foo
1043 1043 $ hg revert foo
1044 1044 $ hg import --no-commit ../create2.patch
1045 1045 applying ../create2.patch
1046 1046 $ cat foo
1047 1047 a
1048 1048
1049 1049 $ cd ..
1050 1050
1051 1051 Issue1859: first line mistaken for email headers
1052 1052
1053 1053 $ hg init emailconfusion
1054 1054 $ cd emailconfusion
1055 1055 $ cat > a.patch <<EOF
1056 1056 > module: summary
1057 1057 >
1058 1058 > description
1059 1059 >
1060 1060 >
1061 1061 > diff -r 000000000000 -r 9b4c1e343b55 test.txt
1062 1062 > --- /dev/null
1063 1063 > +++ b/a
1064 1064 > @@ -0,0 +1,1 @@
1065 1065 > +a
1066 1066 > EOF
1067 1067 $ hg import -d '0 0' a.patch
1068 1068 applying a.patch
1069 1069 $ hg parents -v
1070 1070 changeset: 0:5a681217c0ad
1071 1071 tag: tip
1072 1072 user: test
1073 1073 date: Thu Jan 01 00:00:00 1970 +0000
1074 1074 files: a
1075 1075 description:
1076 1076 module: summary
1077 1077
1078 1078 description
1079 1079
1080 1080
1081 1081 $ cd ..
1082 1082
1083 1083
1084 1084 in commit message
1085 1085
1086 1086 $ hg init commitconfusion
1087 1087 $ cd commitconfusion
1088 1088 $ cat > a.patch <<EOF
1089 1089 > module: summary
1090 1090 >
1091 1091 > --- description
1092 1092 >
1093 1093 > diff --git a/a b/a
1094 1094 > new file mode 100644
1095 1095 > --- /dev/null
1096 1096 > +++ b/a
1097 1097 > @@ -0,0 +1,1 @@
1098 1098 > +a
1099 1099 > EOF
1100 1100 > hg import -d '0 0' a.patch
1101 1101 > hg parents -v
1102 1102 > cd ..
1103 1103 >
1104 1104 > echo '% tricky header splitting'
1105 1105 > cat > trickyheaders.patch <<EOF
1106 1106 > From: User A <user@a>
1107 1107 > Subject: [PATCH] from: tricky!
1108 1108 >
1109 1109 > # HG changeset patch
1110 1110 > # User User B
1111 1111 > # Date 1266264441 18000
1112 1112 > # Branch stable
1113 1113 > # Node ID f2be6a1170ac83bf31cb4ae0bad00d7678115bc0
1114 1114 > # Parent 0000000000000000000000000000000000000000
1115 1115 > from: tricky!
1116 1116 >
1117 1117 > That is not a header.
1118 1118 >
1119 1119 > diff -r 000000000000 -r f2be6a1170ac foo
1120 1120 > --- /dev/null
1121 1121 > +++ b/foo
1122 1122 > @@ -0,0 +1,1 @@
1123 1123 > +foo
1124 1124 > EOF
1125 1125 applying a.patch
1126 1126 changeset: 0:f34d9187897d
1127 1127 tag: tip
1128 1128 user: test
1129 1129 date: Thu Jan 01 00:00:00 1970 +0000
1130 1130 files: a
1131 1131 description:
1132 1132 module: summary
1133 1133
1134 1134
1135 1135 % tricky header splitting
1136 1136
1137 1137 $ hg init trickyheaders
1138 1138 $ cd trickyheaders
1139 1139 $ hg import -d '0 0' ../trickyheaders.patch
1140 1140 applying ../trickyheaders.patch
1141 1141 $ hg export --git tip
1142 1142 # HG changeset patch
1143 1143 # User User B
1144 1144 # Date 0 0
1145 1145 # Thu Jan 01 00:00:00 1970 +0000
1146 1146 # Node ID eb56ab91903632294ac504838508cb370c0901d2
1147 1147 # Parent 0000000000000000000000000000000000000000
1148 1148 from: tricky!
1149 1149
1150 1150 That is not a header.
1151 1151
1152 1152 diff --git a/foo b/foo
1153 1153 new file mode 100644
1154 1154 --- /dev/null
1155 1155 +++ b/foo
1156 1156 @@ -0,0 +1,1 @@
1157 1157 +foo
1158 1158 $ cd ..
1159 1159
1160 1160
1161 1161 Issue2102: hg export and hg import speak different languages
1162 1162
1163 1163 $ hg init issue2102
1164 1164 $ cd issue2102
1165 1165 $ mkdir -p src/cmd/gc
1166 1166 $ touch src/cmd/gc/mksys.bash
1167 1167 $ hg ci -Am init
1168 1168 adding src/cmd/gc/mksys.bash
1169 1169 $ hg import - <<EOF
1170 1170 > # HG changeset patch
1171 1171 > # User Rob Pike
1172 1172 > # Date 1216685449 25200
1173 1173 > # Node ID 03aa2b206f499ad6eb50e6e207b9e710d6409c98
1174 1174 > # Parent 93d10138ad8df586827ca90b4ddb5033e21a3a84
1175 1175 > help management of empty pkg and lib directories in perforce
1176 1176 >
1177 1177 > R=gri
1178 1178 > DELTA=4 (4 added, 0 deleted, 0 changed)
1179 1179 > OCL=13328
1180 1180 > CL=13328
1181 1181 >
1182 1182 > diff --git a/lib/place-holder b/lib/place-holder
1183 1183 > new file mode 100644
1184 1184 > --- /dev/null
1185 1185 > +++ b/lib/place-holder
1186 1186 > @@ -0,0 +1,2 @@
1187 1187 > +perforce does not maintain empty directories.
1188 1188 > +this file helps.
1189 1189 > diff --git a/pkg/place-holder b/pkg/place-holder
1190 1190 > new file mode 100644
1191 1191 > --- /dev/null
1192 1192 > +++ b/pkg/place-holder
1193 1193 > @@ -0,0 +1,2 @@
1194 1194 > +perforce does not maintain empty directories.
1195 1195 > +this file helps.
1196 1196 > diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
1197 1197 > old mode 100644
1198 1198 > new mode 100755
1199 1199 > EOF
1200 1200 applying patch from stdin
1201 1201
1202 1202 #if execbit
1203 1203
1204 1204 $ hg sum
1205 1205 parent: 1:d59915696727 tip
1206 1206 help management of empty pkg and lib directories in perforce
1207 1207 branch: default
1208 1208 commit: (clean)
1209 1209 update: (current)
1210 1210 phases: 2 draft
1211 1211
1212 1212 $ hg diff --git -c tip
1213 1213 diff --git a/lib/place-holder b/lib/place-holder
1214 1214 new file mode 100644
1215 1215 --- /dev/null
1216 1216 +++ b/lib/place-holder
1217 1217 @@ -0,0 +1,2 @@
1218 1218 +perforce does not maintain empty directories.
1219 1219 +this file helps.
1220 1220 diff --git a/pkg/place-holder b/pkg/place-holder
1221 1221 new file mode 100644
1222 1222 --- /dev/null
1223 1223 +++ b/pkg/place-holder
1224 1224 @@ -0,0 +1,2 @@
1225 1225 +perforce does not maintain empty directories.
1226 1226 +this file helps.
1227 1227 diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
1228 1228 old mode 100644
1229 1229 new mode 100755
1230 1230
1231 1231 #else
1232 1232
1233 1233 $ hg sum
1234 1234 parent: 1:28f089cc9ccc tip
1235 1235 help management of empty pkg and lib directories in perforce
1236 1236 branch: default
1237 1237 commit: (clean)
1238 1238 update: (current)
1239 1239 phases: 2 draft
1240 1240
1241 1241 $ hg diff --git -c tip
1242 1242 diff --git a/lib/place-holder b/lib/place-holder
1243 1243 new file mode 100644
1244 1244 --- /dev/null
1245 1245 +++ b/lib/place-holder
1246 1246 @@ -0,0 +1,2 @@
1247 1247 +perforce does not maintain empty directories.
1248 1248 +this file helps.
1249 1249 diff --git a/pkg/place-holder b/pkg/place-holder
1250 1250 new file mode 100644
1251 1251 --- /dev/null
1252 1252 +++ b/pkg/place-holder
1253 1253 @@ -0,0 +1,2 @@
1254 1254 +perforce does not maintain empty directories.
1255 1255 +this file helps.
1256 1256
1257 1257 /* The mode change for mksys.bash is missing here, because on platforms */
1258 1258 /* that don't support execbits, mode changes in patches are ignored when */
1259 1259 /* they are imported. This is obviously also the reason for why the hash */
1260 1260 /* in the created changeset is different to the one you see above the */
1261 1261 /* #else clause */
1262 1262
1263 1263 #endif
1264 1264 $ cd ..
1265 1265
1266 1266
1267 1267 diff lines looking like headers
1268 1268
1269 1269 $ hg init difflineslikeheaders
1270 1270 $ cd difflineslikeheaders
1271 1271 $ echo a >a
1272 1272 $ echo b >b
1273 1273 $ echo c >c
1274 1274 $ hg ci -Am1
1275 1275 adding a
1276 1276 adding b
1277 1277 adding c
1278 1278
1279 1279 $ echo "key: value" >>a
1280 1280 $ echo "key: value" >>b
1281 1281 $ echo "foo" >>c
1282 1282 $ hg ci -m2
1283 1283
1284 1284 $ hg up -C 0
1285 1285 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1286 1286 $ hg diff --git -c1 >want
1287 1287 $ hg diff -c1 | hg import --no-commit -
1288 1288 applying patch from stdin
1289 1289 $ hg diff --git >have
1290 1290 $ diff want have
1291 1291 $ cd ..
1292 1292
1293 1293 import a unified diff with no lines of context (diff -U0)
1294 1294
1295 1295 $ hg init diffzero
1296 1296 $ cd diffzero
1297 1297 $ cat > f << EOF
1298 1298 > c2
1299 1299 > c4
1300 1300 > c5
1301 1301 > EOF
1302 1302 $ hg commit -Am0
1303 1303 adding f
1304 1304
1305 1305 $ hg import --no-commit - << EOF
1306 1306 > # HG changeset patch
1307 1307 > # User test
1308 1308 > # Date 0 0
1309 1309 > # Node ID f4974ab632f3dee767567b0576c0ec9a4508575c
1310 1310 > # Parent 8679a12a975b819fae5f7ad3853a2886d143d794
1311 1311 > 1
1312 1312 > diff -r 8679a12a975b -r f4974ab632f3 f
1313 1313 > --- a/f Thu Jan 01 00:00:00 1970 +0000
1314 1314 > +++ b/f Thu Jan 01 00:00:00 1970 +0000
1315 1315 > @@ -0,0 +1,1 @@
1316 1316 > +c1
1317 1317 > @@ -1,0 +3,1 @@
1318 1318 > +c3
1319 1319 > @@ -3,1 +4,0 @@
1320 1320 > -c5
1321 1321 > EOF
1322 1322 applying patch from stdin
1323 1323
1324 1324 $ cat f
1325 1325 c1
1326 1326 c2
1327 1327 c3
1328 1328 c4
1329 1329
1330 1330 $ cd ..
1331 1331
1332 1332 no segfault while importing a unified diff which start line is zero but chunk
1333 1333 size is non-zero
1334 1334
1335 1335 $ hg init startlinezero
1336 1336 $ cd startlinezero
1337 1337 $ echo foo > foo
1338 1338 $ hg commit -Amfoo
1339 1339 adding foo
1340 1340
1341 1341 $ hg import --no-commit - << EOF
1342 1342 > diff a/foo b/foo
1343 1343 > --- a/foo
1344 1344 > +++ b/foo
1345 1345 > @@ -0,1 +0,1 @@
1346 1346 > foo
1347 1347 > EOF
1348 1348 applying patch from stdin
1349 1349
1350 1350 $ cd ..
1351 1351
1352 1352 Test corner case involving fuzz and skew
1353 1353
1354 1354 $ hg init morecornercases
1355 1355 $ cd morecornercases
1356 1356
1357 1357 $ cat > 01-no-context-beginning-of-file.diff <<EOF
1358 1358 > diff --git a/a b/a
1359 1359 > --- a/a
1360 1360 > +++ b/a
1361 1361 > @@ -1,0 +1,1 @@
1362 1362 > +line
1363 1363 > EOF
1364 1364
1365 1365 $ cat > 02-no-context-middle-of-file.diff <<EOF
1366 1366 > diff --git a/a b/a
1367 1367 > --- a/a
1368 1368 > +++ b/a
1369 1369 > @@ -1,1 +1,1 @@
1370 1370 > -2
1371 1371 > +add some skew
1372 1372 > @@ -2,0 +2,1 @@
1373 1373 > +line
1374 1374 > EOF
1375 1375
1376 1376 $ cat > 03-no-context-end-of-file.diff <<EOF
1377 1377 > diff --git a/a b/a
1378 1378 > --- a/a
1379 1379 > +++ b/a
1380 1380 > @@ -10,0 +10,1 @@
1381 1381 > +line
1382 1382 > EOF
1383 1383
1384 1384 $ cat > 04-middle-of-file-completely-fuzzed.diff <<EOF
1385 1385 > diff --git a/a b/a
1386 1386 > --- a/a
1387 1387 > +++ b/a
1388 1388 > @@ -1,1 +1,1 @@
1389 1389 > -2
1390 1390 > +add some skew
1391 1391 > @@ -2,2 +2,3 @@
1392 1392 > not matching, should fuzz
1393 1393 > ... a bit
1394 1394 > +line
1395 1395 > EOF
1396 1396
1397 1397 $ cat > a <<EOF
1398 1398 > 1
1399 1399 > 2
1400 1400 > 3
1401 1401 > 4
1402 1402 > EOF
1403 1403 $ hg ci -Am adda a
1404 1404 $ for p in *.diff; do
1405 1405 > hg import -v --no-commit $p
1406 1406 > cat a
1407 1407 > hg revert -aqC a
1408 1408 > # patch -p1 < $p
1409 1409 > # cat a
1410 1410 > # hg revert -aC a
1411 1411 > done
1412 1412 applying 01-no-context-beginning-of-file.diff
1413 1413 patching file a
1414 1414 applied to working directory
1415 1415 1
1416 1416 line
1417 1417 2
1418 1418 3
1419 1419 4
1420 1420 applying 02-no-context-middle-of-file.diff
1421 1421 patching file a
1422 1422 Hunk #1 succeeded at 2 (offset 1 lines).
1423 1423 Hunk #2 succeeded at 4 (offset 1 lines).
1424 1424 applied to working directory
1425 1425 1
1426 1426 add some skew
1427 1427 3
1428 1428 line
1429 1429 4
1430 1430 applying 03-no-context-end-of-file.diff
1431 1431 patching file a
1432 1432 Hunk #1 succeeded at 5 (offset -6 lines).
1433 1433 applied to working directory
1434 1434 1
1435 1435 2
1436 1436 3
1437 1437 4
1438 1438 line
1439 1439 applying 04-middle-of-file-completely-fuzzed.diff
1440 1440 patching file a
1441 1441 Hunk #1 succeeded at 2 (offset 1 lines).
1442 1442 Hunk #2 succeeded at 5 with fuzz 2 (offset 1 lines).
1443 1443 applied to working directory
1444 1444 1
1445 1445 add some skew
1446 1446 3
1447 1447 4
1448 1448 line
1449 1449 $ cd ..
1450 1450
1451 1451 Test partial application
1452 1452 ------------------------
1453 1453
1454 1454 prepare a stack of patches depending on each other
1455 1455
1456 1456 $ hg init partial
1457 1457 $ cd partial
1458 1458 $ cat << EOF > a
1459 1459 > one
1460 1460 > two
1461 1461 > three
1462 1462 > four
1463 1463 > five
1464 1464 > six
1465 1465 > seven
1466 1466 > EOF
1467 1467 $ hg add a
1468 1468 $ echo 'b' > b
1469 1469 $ hg add b
1470 1470 $ hg commit -m 'initial' -u Babar
1471 1471 $ cat << EOF > a
1472 1472 > one
1473 1473 > two
1474 1474 > 3
1475 1475 > four
1476 1476 > five
1477 1477 > six
1478 1478 > seven
1479 1479 > EOF
1480 1480 $ hg commit -m 'three' -u Celeste
1481 1481 $ cat << EOF > a
1482 1482 > one
1483 1483 > two
1484 1484 > 3
1485 1485 > 4
1486 1486 > five
1487 1487 > six
1488 1488 > seven
1489 1489 > EOF
1490 1490 $ hg commit -m 'four' -u Rataxes
1491 1491 $ cat << EOF > a
1492 1492 > one
1493 1493 > two
1494 1494 > 3
1495 1495 > 4
1496 1496 > 5
1497 1497 > six
1498 1498 > seven
1499 1499 > EOF
1500 1500 $ echo bb >> b
1501 1501 $ hg commit -m 'five' -u Arthur
1502 1502 $ echo 'Babar' > jungle
1503 1503 $ hg add jungle
1504 1504 $ hg ci -m 'jungle' -u Zephir
1505 1505 $ echo 'Celeste' >> jungle
1506 1506 $ hg ci -m 'extended jungle' -u Cornelius
1507 1507 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1508 1508 @ extended jungle [Cornelius] 1: +1/-0
1509 1509 |
1510 1510 o jungle [Zephir] 1: +1/-0
1511 1511 |
1512 1512 o five [Arthur] 2: +2/-1
1513 1513 |
1514 1514 o four [Rataxes] 1: +1/-1
1515 1515 |
1516 1516 o three [Celeste] 1: +1/-1
1517 1517 |
1518 1518 o initial [Babar] 2: +8/-0
1519 1519
1520 Adding those config options should not change the output of diffstat. Bugfix #4755.
1521
1522 $ hg log -r . --template '{diffstat}\n'
1523 1: +1/-0
1524 $ hg log -r . --template '{diffstat}\n' --config diff.git=1 \
1525 > --config diff.noprefix=1
1526 1: +1/-0
1520 1527
1521 1528 Importing with some success and some errors:
1522 1529
1523 1530 $ hg update --rev 'desc(initial)'
1524 1531 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1525 1532 $ hg export --rev 'desc(five)' | hg import --partial -
1526 1533 applying patch from stdin
1527 1534 patching file a
1528 1535 Hunk #1 FAILED at 1
1529 1536 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1530 1537 patch applied partially
1531 1538 (fix the .rej files and run `hg commit --amend`)
1532 1539 [1]
1533 1540
1534 1541 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1535 1542 @ five [Arthur] 1: +1/-0
1536 1543 |
1537 1544 | o extended jungle [Cornelius] 1: +1/-0
1538 1545 | |
1539 1546 | o jungle [Zephir] 1: +1/-0
1540 1547 | |
1541 1548 | o five [Arthur] 2: +2/-1
1542 1549 | |
1543 1550 | o four [Rataxes] 1: +1/-1
1544 1551 | |
1545 1552 | o three [Celeste] 1: +1/-1
1546 1553 |/
1547 1554 o initial [Babar] 2: +8/-0
1548 1555
1549 1556 $ hg export
1550 1557 # HG changeset patch
1551 1558 # User Arthur
1552 1559 # Date 0 0
1553 1560 # Thu Jan 01 00:00:00 1970 +0000
1554 1561 # Node ID 26e6446bb2526e2be1037935f5fca2b2706f1509
1555 1562 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1556 1563 five
1557 1564
1558 1565 diff -r 8e4f0351909e -r 26e6446bb252 b
1559 1566 --- a/b Thu Jan 01 00:00:00 1970 +0000
1560 1567 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1561 1568 @@ -1,1 +1,2 @@
1562 1569 b
1563 1570 +bb
1564 1571 $ hg status -c .
1565 1572 C a
1566 1573 C b
1567 1574 $ ls
1568 1575 a
1569 1576 a.rej
1570 1577 b
1571 1578
1572 1579 Importing with zero success:
1573 1580
1574 1581 $ hg update --rev 'desc(initial)'
1575 1582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1576 1583 $ hg export --rev 'desc(four)' | hg import --partial -
1577 1584 applying patch from stdin
1578 1585 patching file a
1579 1586 Hunk #1 FAILED at 0
1580 1587 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1581 1588 patch applied partially
1582 1589 (fix the .rej files and run `hg commit --amend`)
1583 1590 [1]
1584 1591
1585 1592 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1586 1593 @ four [Rataxes] 0: +0/-0
1587 1594 |
1588 1595 | o five [Arthur] 1: +1/-0
1589 1596 |/
1590 1597 | o extended jungle [Cornelius] 1: +1/-0
1591 1598 | |
1592 1599 | o jungle [Zephir] 1: +1/-0
1593 1600 | |
1594 1601 | o five [Arthur] 2: +2/-1
1595 1602 | |
1596 1603 | o four [Rataxes] 1: +1/-1
1597 1604 | |
1598 1605 | o three [Celeste] 1: +1/-1
1599 1606 |/
1600 1607 o initial [Babar] 2: +8/-0
1601 1608
1602 1609 $ hg export
1603 1610 # HG changeset patch
1604 1611 # User Rataxes
1605 1612 # Date 0 0
1606 1613 # Thu Jan 01 00:00:00 1970 +0000
1607 1614 # Node ID cb9b1847a74d9ad52e93becaf14b98dbcc274e1e
1608 1615 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1609 1616 four
1610 1617
1611 1618 $ hg status -c .
1612 1619 C a
1613 1620 C b
1614 1621 $ ls
1615 1622 a
1616 1623 a.rej
1617 1624 b
1618 1625
1619 1626 Importing with unknown file:
1620 1627
1621 1628 $ hg update --rev 'desc(initial)'
1622 1629 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1623 1630 $ hg export --rev 'desc("extended jungle")' | hg import --partial -
1624 1631 applying patch from stdin
1625 1632 unable to find 'jungle' for patching
1626 1633 (use '--prefix' to apply patch relative to the current directory)
1627 1634 1 out of 1 hunks FAILED -- saving rejects to file jungle.rej
1628 1635 patch applied partially
1629 1636 (fix the .rej files and run `hg commit --amend`)
1630 1637 [1]
1631 1638
1632 1639 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1633 1640 @ extended jungle [Cornelius] 0: +0/-0
1634 1641 |
1635 1642 | o four [Rataxes] 0: +0/-0
1636 1643 |/
1637 1644 | o five [Arthur] 1: +1/-0
1638 1645 |/
1639 1646 | o extended jungle [Cornelius] 1: +1/-0
1640 1647 | |
1641 1648 | o jungle [Zephir] 1: +1/-0
1642 1649 | |
1643 1650 | o five [Arthur] 2: +2/-1
1644 1651 | |
1645 1652 | o four [Rataxes] 1: +1/-1
1646 1653 | |
1647 1654 | o three [Celeste] 1: +1/-1
1648 1655 |/
1649 1656 o initial [Babar] 2: +8/-0
1650 1657
1651 1658 $ hg export
1652 1659 # HG changeset patch
1653 1660 # User Cornelius
1654 1661 # Date 0 0
1655 1662 # Thu Jan 01 00:00:00 1970 +0000
1656 1663 # Node ID 1fb1f86bef43c5a75918178f8d23c29fb0a7398d
1657 1664 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1658 1665 extended jungle
1659 1666
1660 1667 $ hg status -c .
1661 1668 C a
1662 1669 C b
1663 1670 $ ls
1664 1671 a
1665 1672 a.rej
1666 1673 b
1667 1674 jungle.rej
1668 1675
1669 1676 Importing multiple failing patches:
1670 1677
1671 1678 $ hg update --rev 'desc(initial)'
1672 1679 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1673 1680 $ echo 'B' > b # just to make another commit
1674 1681 $ hg commit -m "a new base"
1675 1682 created new head
1676 1683 $ hg export --rev 'desc("four") + desc("extended jungle")' | hg import --partial -
1677 1684 applying patch from stdin
1678 1685 patching file a
1679 1686 Hunk #1 FAILED at 0
1680 1687 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1681 1688 patch applied partially
1682 1689 (fix the .rej files and run `hg commit --amend`)
1683 1690 [1]
1684 1691 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1685 1692 @ four [Rataxes] 0: +0/-0
1686 1693 |
1687 1694 o a new base [test] 1: +1/-1
1688 1695 |
1689 1696 | o extended jungle [Cornelius] 0: +0/-0
1690 1697 |/
1691 1698 | o four [Rataxes] 0: +0/-0
1692 1699 |/
1693 1700 | o five [Arthur] 1: +1/-0
1694 1701 |/
1695 1702 | o extended jungle [Cornelius] 1: +1/-0
1696 1703 | |
1697 1704 | o jungle [Zephir] 1: +1/-0
1698 1705 | |
1699 1706 | o five [Arthur] 2: +2/-1
1700 1707 | |
1701 1708 | o four [Rataxes] 1: +1/-1
1702 1709 | |
1703 1710 | o three [Celeste] 1: +1/-1
1704 1711 |/
1705 1712 o initial [Babar] 2: +8/-0
1706 1713
1707 1714 $ hg export
1708 1715 # HG changeset patch
1709 1716 # User Rataxes
1710 1717 # Date 0 0
1711 1718 # Thu Jan 01 00:00:00 1970 +0000
1712 1719 # Node ID a9d7b6d0ffbb4eb12b7d5939250fcd42e8930a1d
1713 1720 # Parent f59f8d2e95a8ca5b1b4ca64320140da85f3b44fd
1714 1721 four
1715 1722
1716 1723 $ hg status -c .
1717 1724 C a
1718 1725 C b
1719 1726
1720 1727 Importing some extra header
1721 1728 ===========================
1722 1729
1723 1730 $ cat > $TESTTMP/parseextra.py <<EOF
1724 1731 > import mercurial.patch
1725 1732 > import mercurial.cmdutil
1726 1733 >
1727 1734 > def processfoo(repo, data, extra, opts):
1728 1735 > if 'foo' in data:
1729 1736 > extra['foo'] = data['foo']
1730 1737 > def postimport(ctx):
1731 1738 > if 'foo' in ctx.extra():
1732 1739 > ctx.repo().ui.write('imported-foo: %s\n' % ctx.extra()['foo'])
1733 1740 >
1734 1741 > mercurial.patch.patchheadermap.append(('Foo', 'foo'))
1735 1742 > mercurial.cmdutil.extrapreimport.append('foo')
1736 1743 > mercurial.cmdutil.extrapreimportmap['foo'] = processfoo
1737 1744 > mercurial.cmdutil.extrapostimport.append('foo')
1738 1745 > mercurial.cmdutil.extrapostimportmap['foo'] = postimport
1739 1746 > EOF
1740 1747 $ cat >> $HGRCPATH <<EOF
1741 1748 > [extensions]
1742 1749 > parseextra=$TESTTMP/parseextra.py
1743 1750 > EOF
1744 1751 $ hg up -C tip
1745 1752 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1746 1753 $ cat > $TESTTMP/foo.patch <<EOF
1747 1754 > # HG changeset patch
1748 1755 > # User Rataxes
1749 1756 > # Date 0 0
1750 1757 > # Thu Jan 01 00:00:00 1970 +0000
1751 1758 > # Foo bar
1752 1759 > height
1753 1760 >
1754 1761 > --- a/a Thu Jan 01 00:00:00 1970 +0000
1755 1762 > +++ b/a Wed Oct 07 09:17:44 2015 +0000
1756 1763 > @@ -5,3 +5,4 @@
1757 1764 > five
1758 1765 > six
1759 1766 > seven
1760 1767 > +heigt
1761 1768 > EOF
1762 1769 $ hg import $TESTTMP/foo.patch
1763 1770 applying $TESTTMP/foo.patch
1764 1771 imported-foo: bar
1765 1772 $ hg log --debug -r . | grep extra
1766 1773 extra: branch=default
1767 1774 extra: foo=bar
1768 1775
1769 1776 Warn the user that paths are relative to the root of
1770 1777 repository when file not found for patching
1771 1778
1772 1779 $ mkdir filedir
1773 1780 $ echo "file1" >> filedir/file1
1774 1781 $ hg add filedir/file1
1775 1782 $ hg commit -m "file1"
1776 1783 $ cd filedir
1777 1784 $ hg import -p 2 - <<EOF
1778 1785 > # HG changeset patch
1779 1786 > # User test
1780 1787 > # Date 0 0
1781 1788 > file2
1782 1789 >
1783 1790 > diff --git a/filedir/file1 b/filedir/file1
1784 1791 > --- a/filedir/file1
1785 1792 > +++ b/filedir/file1
1786 1793 > @@ -1,1 +1,2 @@
1787 1794 > file1
1788 1795 > +file2
1789 1796 > EOF
1790 1797 applying patch from stdin
1791 1798 unable to find 'file1' for patching
1792 1799 (use '--prefix' to apply patch relative to the current directory)
1793 1800 1 out of 1 hunks FAILED -- saving rejects to file file1.rej
1794 1801 abort: patch failed to apply
1795 1802 [255]
1796 1803
1797 1804 test import crash (issue5375)
1798 1805 $ cd ..
1799 1806 $ hg init repo
1800 1807 $ cd repo
1801 1808 $ printf "diff --git a/a b/b\nrename from a\nrename to b" | hg import -
1802 1809 applying patch from stdin
1803 1810 a not tracked!
1804 1811 abort: source file 'a' does not exist
1805 1812 [255]
General Comments 0
You need to be logged in to leave comments. Login now