##// END OF EJS Templates
keyword: suppress keyword expansion while 'hg backout' for internal merge...
FUJIWARA Katsunori -
r21706:5c64c338 stable
parent child Browse files
Show More
@@ -1,736 +1,736 b''
1 1 # keyword.py - $Keyword$ expansion for Mercurial
2 2 #
3 3 # Copyright 2007-2012 Christian Ebert <blacktrash@gmx.net>
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 # $Id$
9 9 #
10 10 # Keyword expansion hack against the grain of a Distributed SCM
11 11 #
12 12 # There are many good reasons why this is not needed in a distributed
13 13 # SCM, still it may be useful in very small projects based on single
14 14 # files (like LaTeX packages), that are mostly addressed to an
15 15 # audience not running a version control system.
16 16 #
17 17 # For in-depth discussion refer to
18 18 # <http://mercurial.selenic.com/wiki/KeywordPlan>.
19 19 #
20 20 # Keyword expansion is based on Mercurial's changeset template mappings.
21 21 #
22 22 # Binary files are not touched.
23 23 #
24 24 # Files to act upon/ignore are specified in the [keyword] section.
25 25 # Customized keyword template mappings in the [keywordmaps] section.
26 26 #
27 27 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
28 28
29 29 '''expand keywords in tracked files
30 30
31 31 This extension expands RCS/CVS-like or self-customized $Keywords$ in
32 32 tracked text files selected by your configuration.
33 33
34 34 Keywords are only expanded in local repositories and not stored in the
35 35 change history. The mechanism can be regarded as a convenience for the
36 36 current user or for archive distribution.
37 37
38 38 Keywords expand to the changeset data pertaining to the latest change
39 39 relative to the working directory parent of each file.
40 40
41 41 Configuration is done in the [keyword], [keywordset] and [keywordmaps]
42 42 sections of hgrc files.
43 43
44 44 Example::
45 45
46 46 [keyword]
47 47 # expand keywords in every python file except those matching "x*"
48 48 **.py =
49 49 x* = ignore
50 50
51 51 [keywordset]
52 52 # prefer svn- over cvs-like default keywordmaps
53 53 svn = True
54 54
55 55 .. note::
56 56
57 57 The more specific you are in your filename patterns the less you
58 58 lose speed in huge repositories.
59 59
60 60 For [keywordmaps] template mapping and expansion demonstration and
61 61 control run :hg:`kwdemo`. See :hg:`help templates` for a list of
62 62 available templates and filters.
63 63
64 64 Three additional date template filters are provided:
65 65
66 66 :``utcdate``: "2006/09/18 15:13:13"
67 67 :``svnutcdate``: "2006-09-18 15:13:13Z"
68 68 :``svnisodate``: "2006-09-18 08:13:13 -700 (Mon, 18 Sep 2006)"
69 69
70 70 The default template mappings (view with :hg:`kwdemo -d`) can be
71 71 replaced with customized keywords and templates. Again, run
72 72 :hg:`kwdemo` to control the results of your configuration changes.
73 73
74 74 Before changing/disabling active keywords, you must run :hg:`kwshrink`
75 75 to avoid storing expanded keywords in the change history.
76 76
77 77 To force expansion after enabling it, or a configuration change, run
78 78 :hg:`kwexpand`.
79 79
80 80 Expansions spanning more than one line and incremental expansions,
81 81 like CVS' $Log$, are not supported. A keyword template map "Log =
82 82 {desc}" expands to the first line of the changeset description.
83 83 '''
84 84
85 85 from mercurial import commands, context, cmdutil, dispatch, filelog, extensions
86 86 from mercurial import localrepo, match, patch, templatefilters, templater, util
87 87 from mercurial import scmutil, pathutil
88 88 from mercurial.hgweb import webcommands
89 89 from mercurial.i18n import _
90 90 import os, re, shutil, tempfile
91 91
92 92 commands.optionalrepo += ' kwdemo'
93 93 commands.inferrepo += ' kwexpand kwfiles kwshrink'
94 94
95 95 cmdtable = {}
96 96 command = cmdutil.command(cmdtable)
97 97 testedwith = 'internal'
98 98
99 99 # hg commands that do not act on keywords
100 100 nokwcommands = ('add addremove annotate bundle export grep incoming init log'
101 101 ' outgoing push tip verify convert email glog')
102 102
103 103 # hg commands that trigger expansion only when writing to working dir,
104 104 # not when reading filelog, and unexpand when reading from working dir
105 105 restricted = ('merge kwexpand kwshrink record qrecord resolve transplant'
106 ' unshelve rebase graft')
106 ' unshelve rebase graft backout')
107 107
108 108 # names of extensions using dorecord
109 109 recordextensions = 'record'
110 110
111 111 colortable = {
112 112 'kwfiles.enabled': 'green bold',
113 113 'kwfiles.deleted': 'cyan bold underline',
114 114 'kwfiles.enabledunknown': 'green',
115 115 'kwfiles.ignored': 'bold',
116 116 'kwfiles.ignoredunknown': 'none'
117 117 }
118 118
119 119 # date like in cvs' $Date
120 120 def utcdate(text):
121 121 ''':utcdate: Date. Returns a UTC-date in this format: "2009/08/18 11:00:13".
122 122 '''
123 123 return util.datestr((util.parsedate(text)[0], 0), '%Y/%m/%d %H:%M:%S')
124 124 # date like in svn's $Date
125 125 def svnisodate(text):
126 126 ''':svnisodate: Date. Returns a date in this format: "2009-08-18 13:00:13
127 127 +0200 (Tue, 18 Aug 2009)".
128 128 '''
129 129 return util.datestr(text, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
130 130 # date like in svn's $Id
131 131 def svnutcdate(text):
132 132 ''':svnutcdate: Date. Returns a UTC-date in this format: "2009-08-18
133 133 11:00:13Z".
134 134 '''
135 135 return util.datestr((util.parsedate(text)[0], 0), '%Y-%m-%d %H:%M:%SZ')
136 136
137 137 templatefilters.filters.update({'utcdate': utcdate,
138 138 'svnisodate': svnisodate,
139 139 'svnutcdate': svnutcdate})
140 140
141 141 # make keyword tools accessible
142 142 kwtools = {'templater': None, 'hgcmd': ''}
143 143
144 144 def _defaultkwmaps(ui):
145 145 '''Returns default keywordmaps according to keywordset configuration.'''
146 146 templates = {
147 147 'Revision': '{node|short}',
148 148 'Author': '{author|user}',
149 149 }
150 150 kwsets = ({
151 151 'Date': '{date|utcdate}',
152 152 'RCSfile': '{file|basename},v',
153 153 'RCSFile': '{file|basename},v', # kept for backwards compatibility
154 154 # with hg-keyword
155 155 'Source': '{root}/{file},v',
156 156 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
157 157 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
158 158 }, {
159 159 'Date': '{date|svnisodate}',
160 160 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}',
161 161 'LastChangedRevision': '{node|short}',
162 162 'LastChangedBy': '{author|user}',
163 163 'LastChangedDate': '{date|svnisodate}',
164 164 })
165 165 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
166 166 return templates
167 167
168 168 def _shrinktext(text, subfunc):
169 169 '''Helper for keyword expansion removal in text.
170 170 Depending on subfunc also returns number of substitutions.'''
171 171 return subfunc(r'$\1$', text)
172 172
173 173 def _preselect(wstatus, changed):
174 174 '''Retrieves modified and added files from a working directory state
175 175 and returns the subset of each contained in given changed files
176 176 retrieved from a change context.'''
177 177 modified, added = wstatus[:2]
178 178 modified = [f for f in modified if f in changed]
179 179 added = [f for f in added if f in changed]
180 180 return modified, added
181 181
182 182
183 183 class kwtemplater(object):
184 184 '''
185 185 Sets up keyword templates, corresponding keyword regex, and
186 186 provides keyword substitution functions.
187 187 '''
188 188
189 189 def __init__(self, ui, repo, inc, exc):
190 190 self.ui = ui
191 191 self.repo = repo
192 192 self.match = match.match(repo.root, '', [], inc, exc)
193 193 self.restrict = kwtools['hgcmd'] in restricted.split()
194 194 self.postcommit = False
195 195
196 196 kwmaps = self.ui.configitems('keywordmaps')
197 197 if kwmaps: # override default templates
198 198 self.templates = dict((k, templater.parsestring(v, False))
199 199 for k, v in kwmaps)
200 200 else:
201 201 self.templates = _defaultkwmaps(self.ui)
202 202
203 203 @util.propertycache
204 204 def escape(self):
205 205 '''Returns bar-separated and escaped keywords.'''
206 206 return '|'.join(map(re.escape, self.templates.keys()))
207 207
208 208 @util.propertycache
209 209 def rekw(self):
210 210 '''Returns regex for unexpanded keywords.'''
211 211 return re.compile(r'\$(%s)\$' % self.escape)
212 212
213 213 @util.propertycache
214 214 def rekwexp(self):
215 215 '''Returns regex for expanded keywords.'''
216 216 return re.compile(r'\$(%s): [^$\n\r]*? \$' % self.escape)
217 217
218 218 def substitute(self, data, path, ctx, subfunc):
219 219 '''Replaces keywords in data with expanded template.'''
220 220 def kwsub(mobj):
221 221 kw = mobj.group(1)
222 222 ct = cmdutil.changeset_templater(self.ui, self.repo, False, None,
223 223 self.templates[kw], '', False)
224 224 self.ui.pushbuffer()
225 225 ct.show(ctx, root=self.repo.root, file=path)
226 226 ekw = templatefilters.firstline(self.ui.popbuffer())
227 227 return '$%s: %s $' % (kw, ekw)
228 228 return subfunc(kwsub, data)
229 229
230 230 def linkctx(self, path, fileid):
231 231 '''Similar to filelog.linkrev, but returns a changectx.'''
232 232 return self.repo.filectx(path, fileid=fileid).changectx()
233 233
234 234 def expand(self, path, node, data):
235 235 '''Returns data with keywords expanded.'''
236 236 if not self.restrict and self.match(path) and not util.binary(data):
237 237 ctx = self.linkctx(path, node)
238 238 return self.substitute(data, path, ctx, self.rekw.sub)
239 239 return data
240 240
241 241 def iskwfile(self, cand, ctx):
242 242 '''Returns subset of candidates which are configured for keyword
243 243 expansion but are not symbolic links.'''
244 244 return [f for f in cand if self.match(f) and 'l' not in ctx.flags(f)]
245 245
246 246 def overwrite(self, ctx, candidates, lookup, expand, rekw=False):
247 247 '''Overwrites selected files expanding/shrinking keywords.'''
248 248 if self.restrict or lookup or self.postcommit: # exclude kw_copy
249 249 candidates = self.iskwfile(candidates, ctx)
250 250 if not candidates:
251 251 return
252 252 kwcmd = self.restrict and lookup # kwexpand/kwshrink
253 253 if self.restrict or expand and lookup:
254 254 mf = ctx.manifest()
255 255 if self.restrict or rekw:
256 256 re_kw = self.rekw
257 257 else:
258 258 re_kw = self.rekwexp
259 259 if expand:
260 260 msg = _('overwriting %s expanding keywords\n')
261 261 else:
262 262 msg = _('overwriting %s shrinking keywords\n')
263 263 for f in candidates:
264 264 if self.restrict:
265 265 data = self.repo.file(f).read(mf[f])
266 266 else:
267 267 data = self.repo.wread(f)
268 268 if util.binary(data):
269 269 continue
270 270 if expand:
271 271 if lookup:
272 272 ctx = self.linkctx(f, mf[f])
273 273 data, found = self.substitute(data, f, ctx, re_kw.subn)
274 274 elif self.restrict:
275 275 found = re_kw.search(data)
276 276 else:
277 277 data, found = _shrinktext(data, re_kw.subn)
278 278 if found:
279 279 self.ui.note(msg % f)
280 280 fp = self.repo.wopener(f, "wb", atomictemp=True)
281 281 fp.write(data)
282 282 fp.close()
283 283 if kwcmd:
284 284 self.repo.dirstate.normal(f)
285 285 elif self.postcommit:
286 286 self.repo.dirstate.normallookup(f)
287 287
288 288 def shrink(self, fname, text):
289 289 '''Returns text with all keyword substitutions removed.'''
290 290 if self.match(fname) and not util.binary(text):
291 291 return _shrinktext(text, self.rekwexp.sub)
292 292 return text
293 293
294 294 def shrinklines(self, fname, lines):
295 295 '''Returns lines with keyword substitutions removed.'''
296 296 if self.match(fname):
297 297 text = ''.join(lines)
298 298 if not util.binary(text):
299 299 return _shrinktext(text, self.rekwexp.sub).splitlines(True)
300 300 return lines
301 301
302 302 def wread(self, fname, data):
303 303 '''If in restricted mode returns data read from wdir with
304 304 keyword substitutions removed.'''
305 305 if self.restrict:
306 306 return self.shrink(fname, data)
307 307 return data
308 308
309 309 class kwfilelog(filelog.filelog):
310 310 '''
311 311 Subclass of filelog to hook into its read, add, cmp methods.
312 312 Keywords are "stored" unexpanded, and processed on reading.
313 313 '''
314 314 def __init__(self, opener, kwt, path):
315 315 super(kwfilelog, self).__init__(opener, path)
316 316 self.kwt = kwt
317 317 self.path = path
318 318
319 319 def read(self, node):
320 320 '''Expands keywords when reading filelog.'''
321 321 data = super(kwfilelog, self).read(node)
322 322 if self.renamed(node):
323 323 return data
324 324 return self.kwt.expand(self.path, node, data)
325 325
326 326 def add(self, text, meta, tr, link, p1=None, p2=None):
327 327 '''Removes keyword substitutions when adding to filelog.'''
328 328 text = self.kwt.shrink(self.path, text)
329 329 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
330 330
331 331 def cmp(self, node, text):
332 332 '''Removes keyword substitutions for comparison.'''
333 333 text = self.kwt.shrink(self.path, text)
334 334 return super(kwfilelog, self).cmp(node, text)
335 335
336 336 def _status(ui, repo, wctx, kwt, *pats, **opts):
337 337 '''Bails out if [keyword] configuration is not active.
338 338 Returns status of working directory.'''
339 339 if kwt:
340 340 return repo.status(match=scmutil.match(wctx, pats, opts), clean=True,
341 341 unknown=opts.get('unknown') or opts.get('all'))
342 342 if ui.configitems('keyword'):
343 343 raise util.Abort(_('[keyword] patterns cannot match'))
344 344 raise util.Abort(_('no [keyword] patterns configured'))
345 345
346 346 def _kwfwrite(ui, repo, expand, *pats, **opts):
347 347 '''Selects files and passes them to kwtemplater.overwrite.'''
348 348 wctx = repo[None]
349 349 if len(wctx.parents()) > 1:
350 350 raise util.Abort(_('outstanding uncommitted merge'))
351 351 kwt = kwtools['templater']
352 352 wlock = repo.wlock()
353 353 try:
354 354 status = _status(ui, repo, wctx, kwt, *pats, **opts)
355 355 modified, added, removed, deleted, unknown, ignored, clean = status
356 356 if modified or added or removed or deleted:
357 357 raise util.Abort(_('outstanding uncommitted changes'))
358 358 kwt.overwrite(wctx, clean, True, expand)
359 359 finally:
360 360 wlock.release()
361 361
362 362 @command('kwdemo',
363 363 [('d', 'default', None, _('show default keyword template maps')),
364 364 ('f', 'rcfile', '',
365 365 _('read maps from rcfile'), _('FILE'))],
366 366 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...'))
367 367 def demo(ui, repo, *args, **opts):
368 368 '''print [keywordmaps] configuration and an expansion example
369 369
370 370 Show current, custom, or default keyword template maps and their
371 371 expansions.
372 372
373 373 Extend the current configuration by specifying maps as arguments
374 374 and using -f/--rcfile to source an external hgrc file.
375 375
376 376 Use -d/--default to disable current configuration.
377 377
378 378 See :hg:`help templates` for information on templates and filters.
379 379 '''
380 380 def demoitems(section, items):
381 381 ui.write('[%s]\n' % section)
382 382 for k, v in sorted(items):
383 383 ui.write('%s = %s\n' % (k, v))
384 384
385 385 fn = 'demo.txt'
386 386 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
387 387 ui.note(_('creating temporary repository at %s\n') % tmpdir)
388 388 repo = localrepo.localrepository(repo.baseui, tmpdir, True)
389 389 ui.setconfig('keyword', fn, '', 'keyword')
390 390 svn = ui.configbool('keywordset', 'svn')
391 391 # explicitly set keywordset for demo output
392 392 ui.setconfig('keywordset', 'svn', svn, 'keyword')
393 393
394 394 uikwmaps = ui.configitems('keywordmaps')
395 395 if args or opts.get('rcfile'):
396 396 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
397 397 if uikwmaps:
398 398 ui.status(_('\textending current template maps\n'))
399 399 if opts.get('default') or not uikwmaps:
400 400 if svn:
401 401 ui.status(_('\toverriding default svn keywordset\n'))
402 402 else:
403 403 ui.status(_('\toverriding default cvs keywordset\n'))
404 404 if opts.get('rcfile'):
405 405 ui.readconfig(opts.get('rcfile'))
406 406 if args:
407 407 # simulate hgrc parsing
408 408 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
409 409 fp = repo.opener('hgrc', 'w')
410 410 fp.writelines(rcmaps)
411 411 fp.close()
412 412 ui.readconfig(repo.join('hgrc'))
413 413 kwmaps = dict(ui.configitems('keywordmaps'))
414 414 elif opts.get('default'):
415 415 if svn:
416 416 ui.status(_('\n\tconfiguration using default svn keywordset\n'))
417 417 else:
418 418 ui.status(_('\n\tconfiguration using default cvs keywordset\n'))
419 419 kwmaps = _defaultkwmaps(ui)
420 420 if uikwmaps:
421 421 ui.status(_('\tdisabling current template maps\n'))
422 422 for k, v in kwmaps.iteritems():
423 423 ui.setconfig('keywordmaps', k, v, 'keyword')
424 424 else:
425 425 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
426 426 if uikwmaps:
427 427 kwmaps = dict(uikwmaps)
428 428 else:
429 429 kwmaps = _defaultkwmaps(ui)
430 430
431 431 uisetup(ui)
432 432 reposetup(ui, repo)
433 433 ui.write('[extensions]\nkeyword =\n')
434 434 demoitems('keyword', ui.configitems('keyword'))
435 435 demoitems('keywordset', ui.configitems('keywordset'))
436 436 demoitems('keywordmaps', kwmaps.iteritems())
437 437 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
438 438 repo.wopener.write(fn, keywords)
439 439 repo[None].add([fn])
440 440 ui.note(_('\nkeywords written to %s:\n') % fn)
441 441 ui.note(keywords)
442 442 wlock = repo.wlock()
443 443 try:
444 444 repo.dirstate.setbranch('demobranch')
445 445 finally:
446 446 wlock.release()
447 447 for name, cmd in ui.configitems('hooks'):
448 448 if name.split('.', 1)[0].find('commit') > -1:
449 449 repo.ui.setconfig('hooks', name, '', 'keyword')
450 450 msg = _('hg keyword configuration and expansion example')
451 451 ui.note(("hg ci -m '%s'\n" % msg))
452 452 repo.commit(text=msg)
453 453 ui.status(_('\n\tkeywords expanded\n'))
454 454 ui.write(repo.wread(fn))
455 455 shutil.rmtree(tmpdir, ignore_errors=True)
456 456
457 457 @command('kwexpand', commands.walkopts, _('hg kwexpand [OPTION]... [FILE]...'))
458 458 def expand(ui, repo, *pats, **opts):
459 459 '''expand keywords in the working directory
460 460
461 461 Run after (re)enabling keyword expansion.
462 462
463 463 kwexpand refuses to run if given files contain local changes.
464 464 '''
465 465 # 3rd argument sets expansion to True
466 466 _kwfwrite(ui, repo, True, *pats, **opts)
467 467
468 468 @command('kwfiles',
469 469 [('A', 'all', None, _('show keyword status flags of all files')),
470 470 ('i', 'ignore', None, _('show files excluded from expansion')),
471 471 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
472 472 ] + commands.walkopts,
473 473 _('hg kwfiles [OPTION]... [FILE]...'))
474 474 def files(ui, repo, *pats, **opts):
475 475 '''show files configured for keyword expansion
476 476
477 477 List which files in the working directory are matched by the
478 478 [keyword] configuration patterns.
479 479
480 480 Useful to prevent inadvertent keyword expansion and to speed up
481 481 execution by including only files that are actual candidates for
482 482 expansion.
483 483
484 484 See :hg:`help keyword` on how to construct patterns both for
485 485 inclusion and exclusion of files.
486 486
487 487 With -A/--all and -v/--verbose the codes used to show the status
488 488 of files are::
489 489
490 490 K = keyword expansion candidate
491 491 k = keyword expansion candidate (not tracked)
492 492 I = ignored
493 493 i = ignored (not tracked)
494 494 '''
495 495 kwt = kwtools['templater']
496 496 wctx = repo[None]
497 497 status = _status(ui, repo, wctx, kwt, *pats, **opts)
498 498 cwd = pats and repo.getcwd() or ''
499 499 modified, added, removed, deleted, unknown, ignored, clean = status
500 500 files = []
501 501 if not opts.get('unknown') or opts.get('all'):
502 502 files = sorted(modified + added + clean)
503 503 kwfiles = kwt.iskwfile(files, wctx)
504 504 kwdeleted = kwt.iskwfile(deleted, wctx)
505 505 kwunknown = kwt.iskwfile(unknown, wctx)
506 506 if not opts.get('ignore') or opts.get('all'):
507 507 showfiles = kwfiles, kwdeleted, kwunknown
508 508 else:
509 509 showfiles = [], [], []
510 510 if opts.get('all') or opts.get('ignore'):
511 511 showfiles += ([f for f in files if f not in kwfiles],
512 512 [f for f in unknown if f not in kwunknown])
513 513 kwlabels = 'enabled deleted enabledunknown ignored ignoredunknown'.split()
514 514 kwstates = zip(kwlabels, 'K!kIi', showfiles)
515 515 fm = ui.formatter('kwfiles', opts)
516 516 fmt = '%.0s%s\n'
517 517 if opts.get('all') or ui.verbose:
518 518 fmt = '%s %s\n'
519 519 for kwstate, char, filenames in kwstates:
520 520 label = 'kwfiles.' + kwstate
521 521 for f in filenames:
522 522 fm.startitem()
523 523 fm.write('kwstatus path', fmt, char,
524 524 repo.pathto(f, cwd), label=label)
525 525 fm.end()
526 526
527 527 @command('kwshrink', commands.walkopts, _('hg kwshrink [OPTION]... [FILE]...'))
528 528 def shrink(ui, repo, *pats, **opts):
529 529 '''revert expanded keywords in the working directory
530 530
531 531 Must be run before changing/disabling active keywords.
532 532
533 533 kwshrink refuses to run if given files contain local changes.
534 534 '''
535 535 # 3rd argument sets expansion to False
536 536 _kwfwrite(ui, repo, False, *pats, **opts)
537 537
538 538
539 539 def uisetup(ui):
540 540 ''' Monkeypatches dispatch._parse to retrieve user command.'''
541 541
542 542 def kwdispatch_parse(orig, ui, args):
543 543 '''Monkeypatch dispatch._parse to obtain running hg command.'''
544 544 cmd, func, args, options, cmdoptions = orig(ui, args)
545 545 kwtools['hgcmd'] = cmd
546 546 return cmd, func, args, options, cmdoptions
547 547
548 548 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
549 549
550 550 def reposetup(ui, repo):
551 551 '''Sets up repo as kwrepo for keyword substitution.
552 552 Overrides file method to return kwfilelog instead of filelog
553 553 if file matches user configuration.
554 554 Wraps commit to overwrite configured files with updated
555 555 keyword substitutions.
556 556 Monkeypatches patch and webcommands.'''
557 557
558 558 try:
559 559 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
560 560 or '.hg' in util.splitpath(repo.root)
561 561 or repo._url.startswith('bundle:')):
562 562 return
563 563 except AttributeError:
564 564 pass
565 565
566 566 inc, exc = [], ['.hg*']
567 567 for pat, opt in ui.configitems('keyword'):
568 568 if opt != 'ignore':
569 569 inc.append(pat)
570 570 else:
571 571 exc.append(pat)
572 572 if not inc:
573 573 return
574 574
575 575 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
576 576
577 577 class kwrepo(repo.__class__):
578 578 def file(self, f):
579 579 if f[0] == '/':
580 580 f = f[1:]
581 581 return kwfilelog(self.sopener, kwt, f)
582 582
583 583 def wread(self, filename):
584 584 data = super(kwrepo, self).wread(filename)
585 585 return kwt.wread(filename, data)
586 586
587 587 def commit(self, *args, **opts):
588 588 # use custom commitctx for user commands
589 589 # other extensions can still wrap repo.commitctx directly
590 590 self.commitctx = self.kwcommitctx
591 591 try:
592 592 return super(kwrepo, self).commit(*args, **opts)
593 593 finally:
594 594 del self.commitctx
595 595
596 596 def kwcommitctx(self, ctx, error=False):
597 597 n = super(kwrepo, self).commitctx(ctx, error)
598 598 # no lock needed, only called from repo.commit() which already locks
599 599 if not kwt.postcommit:
600 600 restrict = kwt.restrict
601 601 kwt.restrict = True
602 602 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
603 603 False, True)
604 604 kwt.restrict = restrict
605 605 return n
606 606
607 607 def rollback(self, dryrun=False, force=False):
608 608 wlock = self.wlock()
609 609 try:
610 610 if not dryrun:
611 611 changed = self['.'].files()
612 612 ret = super(kwrepo, self).rollback(dryrun, force)
613 613 if not dryrun:
614 614 ctx = self['.']
615 615 modified, added = _preselect(self[None].status(), changed)
616 616 kwt.overwrite(ctx, modified, True, True)
617 617 kwt.overwrite(ctx, added, True, False)
618 618 return ret
619 619 finally:
620 620 wlock.release()
621 621
622 622 # monkeypatches
623 623 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None):
624 624 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
625 625 rejects or conflicts due to expanded keywords in working dir.'''
626 626 orig(self, ui, gp, backend, store, eolmode)
627 627 # shrink keywords read from working dir
628 628 self.lines = kwt.shrinklines(self.fname, self.lines)
629 629
630 630 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
631 631 opts=None, prefix=''):
632 632 '''Monkeypatch patch.diff to avoid expansion.'''
633 633 kwt.restrict = True
634 634 return orig(repo, node1, node2, match, changes, opts, prefix)
635 635
636 636 def kwweb_skip(orig, web, req, tmpl):
637 637 '''Wraps webcommands.x turning off keyword expansion.'''
638 638 kwt.match = util.never
639 639 return orig(web, req, tmpl)
640 640
641 641 def kw_amend(orig, ui, repo, commitfunc, old, extra, pats, opts):
642 642 '''Wraps cmdutil.amend expanding keywords after amend.'''
643 643 wlock = repo.wlock()
644 644 try:
645 645 kwt.postcommit = True
646 646 newid = orig(ui, repo, commitfunc, old, extra, pats, opts)
647 647 if newid != old.node():
648 648 ctx = repo[newid]
649 649 kwt.restrict = True
650 650 kwt.overwrite(ctx, ctx.files(), False, True)
651 651 kwt.restrict = False
652 652 return newid
653 653 finally:
654 654 wlock.release()
655 655
656 656 def kw_copy(orig, ui, repo, pats, opts, rename=False):
657 657 '''Wraps cmdutil.copy so that copy/rename destinations do not
658 658 contain expanded keywords.
659 659 Note that the source of a regular file destination may also be a
660 660 symlink:
661 661 hg cp sym x -> x is symlink
662 662 cp sym x; hg cp -A sym x -> x is file (maybe expanded keywords)
663 663 For the latter we have to follow the symlink to find out whether its
664 664 target is configured for expansion and we therefore must unexpand the
665 665 keywords in the destination.'''
666 666 wlock = repo.wlock()
667 667 try:
668 668 orig(ui, repo, pats, opts, rename)
669 669 if opts.get('dry_run'):
670 670 return
671 671 wctx = repo[None]
672 672 cwd = repo.getcwd()
673 673
674 674 def haskwsource(dest):
675 675 '''Returns true if dest is a regular file and configured for
676 676 expansion or a symlink which points to a file configured for
677 677 expansion. '''
678 678 source = repo.dirstate.copied(dest)
679 679 if 'l' in wctx.flags(source):
680 680 source = pathutil.canonpath(repo.root, cwd,
681 681 os.path.realpath(source))
682 682 return kwt.match(source)
683 683
684 684 candidates = [f for f in repo.dirstate.copies() if
685 685 'l' not in wctx.flags(f) and haskwsource(f)]
686 686 kwt.overwrite(wctx, candidates, False, False)
687 687 finally:
688 688 wlock.release()
689 689
690 690 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
691 691 '''Wraps record.dorecord expanding keywords after recording.'''
692 692 wlock = repo.wlock()
693 693 try:
694 694 # record returns 0 even when nothing has changed
695 695 # therefore compare nodes before and after
696 696 kwt.postcommit = True
697 697 ctx = repo['.']
698 698 wstatus = repo[None].status()
699 699 ret = orig(ui, repo, commitfunc, *pats, **opts)
700 700 recctx = repo['.']
701 701 if ctx != recctx:
702 702 modified, added = _preselect(wstatus, recctx.files())
703 703 kwt.restrict = False
704 704 kwt.overwrite(recctx, modified, False, True)
705 705 kwt.overwrite(recctx, added, False, True, True)
706 706 kwt.restrict = True
707 707 return ret
708 708 finally:
709 709 wlock.release()
710 710
711 711 def kwfilectx_cmp(orig, self, fctx):
712 712 # keyword affects data size, comparing wdir and filelog size does
713 713 # not make sense
714 714 if (fctx._filerev is None and
715 715 (self._repo._encodefilterpats or
716 716 kwt.match(fctx.path()) and 'l' not in fctx.flags() or
717 717 self.size() - 4 == fctx.size()) or
718 718 self.size() == fctx.size()):
719 719 return self._filelog.cmp(self._filenode, fctx.data())
720 720 return True
721 721
722 722 extensions.wrapfunction(context.filectx, 'cmp', kwfilectx_cmp)
723 723 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
724 724 extensions.wrapfunction(patch, 'diff', kw_diff)
725 725 extensions.wrapfunction(cmdutil, 'amend', kw_amend)
726 726 extensions.wrapfunction(cmdutil, 'copy', kw_copy)
727 727 for c in 'annotate changeset rev filediff diff'.split():
728 728 extensions.wrapfunction(webcommands, c, kwweb_skip)
729 729 for name in recordextensions.split():
730 730 try:
731 731 record = extensions.find(name)
732 732 extensions.wrapfunction(record, 'dorecord', kw_dorecord)
733 733 except KeyError:
734 734 pass
735 735
736 736 repo.__class__ = kwrepo
@@ -1,1261 +1,1274 b''
1 1 $ cat <<EOF >> $HGRCPATH
2 2 > [extensions]
3 3 > keyword =
4 4 > mq =
5 5 > notify =
6 6 > record =
7 7 > transplant =
8 8 > [ui]
9 9 > interactive = true
10 10 > EOF
11 11
12 12 hide outer repo
13 13 $ hg init
14 14
15 15 Run kwdemo before [keyword] files are set up
16 16 as it would succeed without uisetup otherwise
17 17
18 18 $ hg --quiet kwdemo
19 19 [extensions]
20 20 keyword =
21 21 [keyword]
22 22 demo.txt =
23 23 [keywordset]
24 24 svn = False
25 25 [keywordmaps]
26 26 Author = {author|user}
27 27 Date = {date|utcdate}
28 28 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
29 29 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
30 30 RCSFile = {file|basename},v
31 31 RCSfile = {file|basename},v
32 32 Revision = {node|short}
33 33 Source = {root}/{file},v
34 34 $Author: test $
35 35 $Date: ????/??/?? ??:??:?? $ (glob)
36 36 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
37 37 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
38 38 $RCSFile: demo.txt,v $
39 39 $RCSfile: demo.txt,v $
40 40 $Revision: ???????????? $ (glob)
41 41 $Source: */demo.txt,v $ (glob)
42 42
43 43 $ hg --quiet kwdemo "Branch = {branches}"
44 44 [extensions]
45 45 keyword =
46 46 [keyword]
47 47 demo.txt =
48 48 [keywordset]
49 49 svn = False
50 50 [keywordmaps]
51 51 Branch = {branches}
52 52 $Branch: demobranch $
53 53
54 54 $ cat <<EOF >> $HGRCPATH
55 55 > [keyword]
56 56 > ** =
57 57 > b = ignore
58 58 > i = ignore
59 59 > [hooks]
60 60 > EOF
61 61 $ cp $HGRCPATH $HGRCPATH.nohooks
62 62 > cat <<EOF >> $HGRCPATH
63 63 > commit=
64 64 > commit.test=cp a hooktest
65 65 > EOF
66 66
67 67 $ hg init Test-bndl
68 68 $ cd Test-bndl
69 69
70 70 kwshrink should exit silently in empty/invalid repo
71 71
72 72 $ hg kwshrink
73 73
74 74 Symlinks cannot be created on Windows.
75 75 A bundle to test this was made with:
76 76 hg init t
77 77 cd t
78 78 echo a > a
79 79 ln -s a sym
80 80 hg add sym
81 81 hg ci -m addsym -u mercurial
82 82 hg bundle --base null ../test-keyword.hg
83 83
84 84 $ hg pull -u "$TESTDIR"/bundles/test-keyword.hg
85 85 pulling from *test-keyword.hg (glob)
86 86 requesting all changes
87 87 adding changesets
88 88 adding manifests
89 89 adding file changes
90 90 added 1 changesets with 1 changes to 1 files
91 91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 92
93 93 $ echo 'expand $Id$' > a
94 94 $ echo 'do not process $Id:' >> a
95 95 $ echo 'xxx $' >> a
96 96 $ echo 'ignore $Id$' > b
97 97
98 98 Output files as they were created
99 99
100 100 $ cat a b
101 101 expand $Id$
102 102 do not process $Id:
103 103 xxx $
104 104 ignore $Id$
105 105
106 106 no kwfiles
107 107
108 108 $ hg kwfiles
109 109
110 110 untracked candidates
111 111
112 112 $ hg -v kwfiles --unknown
113 113 k a
114 114
115 115 Add files and check status
116 116
117 117 $ hg addremove
118 118 adding a
119 119 adding b
120 120 $ hg status
121 121 A a
122 122 A b
123 123
124 124
125 125 Default keyword expansion including commit hook
126 126 Interrupted commit should not change state or run commit hook
127 127
128 128 $ hg --debug commit
129 129 abort: empty commit message
130 130 [255]
131 131 $ hg status
132 132 A a
133 133 A b
134 134
135 135 Commit with several checks
136 136
137 137 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
138 138 a
139 139 b
140 140 overwriting a expanding keywords
141 141 running hook commit.test: cp a hooktest
142 142 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
143 143 $ hg status
144 144 ? hooktest
145 145 $ hg debugrebuildstate
146 146 $ hg --quiet identify
147 147 ef63ca68695b
148 148
149 149 cat files in working directory with keywords expanded
150 150
151 151 $ cat a b
152 152 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
153 153 do not process $Id:
154 154 xxx $
155 155 ignore $Id$
156 156
157 157 hg cat files and symlink, no expansion
158 158
159 159 $ hg cat sym a b && echo
160 160 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
161 161 do not process $Id:
162 162 xxx $
163 163 ignore $Id$
164 164 a
165 165
166 166 $ diff a hooktest
167 167
168 168 $ cp $HGRCPATH.nohooks $HGRCPATH
169 169 $ rm hooktest
170 170
171 171 hg status of kw-ignored binary file starting with '\1\n'
172 172
173 173 >>> open("i", "wb").write("\1\nfoo")
174 174 $ hg -q commit -Am metasep i
175 175 $ hg status
176 176 >>> open("i", "wb").write("\1\nbar")
177 177 $ hg status
178 178 M i
179 179 $ hg -q commit -m "modify metasep" i
180 180 $ hg status --rev 2:3
181 181 M i
182 182 $ touch empty
183 183 $ hg -q commit -A -m "another file"
184 184 $ hg status -A --rev 3:4 i
185 185 C i
186 186
187 187 $ hg -q strip -n 2
188 188
189 189 Test hook execution
190 190
191 191 bundle
192 192
193 193 $ hg bundle --base null ../kw.hg
194 194 2 changesets found
195 195 $ cd ..
196 196 $ hg init Test
197 197 $ cd Test
198 198
199 199 Notify on pull to check whether keywords stay as is in email
200 200 ie. if patch.diff wrapper acts as it should
201 201
202 202 $ cat <<EOF >> $HGRCPATH
203 203 > [hooks]
204 204 > incoming.notify = python:hgext.notify.hook
205 205 > [notify]
206 206 > sources = pull
207 207 > diffstat = False
208 208 > maxsubject = 15
209 209 > [reposubs]
210 210 > * = Test
211 211 > EOF
212 212
213 213 Pull from bundle and trigger notify
214 214
215 215 $ hg pull -u ../kw.hg
216 216 pulling from ../kw.hg
217 217 requesting all changes
218 218 adding changesets
219 219 adding manifests
220 220 adding file changes
221 221 added 2 changesets with 3 changes to 3 files
222 222 Content-Type: text/plain; charset="us-ascii"
223 223 MIME-Version: 1.0
224 224 Content-Transfer-Encoding: 7bit
225 225 Date: * (glob)
226 226 Subject: changeset in...
227 227 From: mercurial
228 228 X-Hg-Notification: changeset a2392c293916
229 229 Message-Id: <hg.a2392c293916*> (glob)
230 230 To: Test
231 231
232 232 changeset a2392c293916 in $TESTTMP/Test (glob)
233 233 details: $TESTTMP/Test?cmd=changeset;node=a2392c293916
234 234 description:
235 235 addsym
236 236
237 237 diffs (6 lines):
238 238
239 239 diff -r 000000000000 -r a2392c293916 sym
240 240 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
241 241 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
242 242 @@ -0,0 +1,1 @@
243 243 +a
244 244 \ No newline at end of file
245 245 Content-Type: text/plain; charset="us-ascii"
246 246 MIME-Version: 1.0
247 247 Content-Transfer-Encoding: 7bit
248 248 Date:* (glob)
249 249 Subject: changeset in...
250 250 From: User Name <user@example.com>
251 251 X-Hg-Notification: changeset ef63ca68695b
252 252 Message-Id: <hg.ef63ca68695b*> (glob)
253 253 To: Test
254 254
255 255 changeset ef63ca68695b in $TESTTMP/Test (glob)
256 256 details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
257 257 description:
258 258 absym
259 259
260 260 diffs (12 lines):
261 261
262 262 diff -r a2392c293916 -r ef63ca68695b a
263 263 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
264 264 +++ b/a Thu Jan 01 00:00:00 1970 +0000
265 265 @@ -0,0 +1,3 @@
266 266 +expand $Id$
267 267 +do not process $Id:
268 268 +xxx $
269 269 diff -r a2392c293916 -r ef63ca68695b b
270 270 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
271 271 +++ b/b Thu Jan 01 00:00:00 1970 +0000
272 272 @@ -0,0 +1,1 @@
273 273 +ignore $Id$
274 274 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 275
276 276 $ cp $HGRCPATH.nohooks $HGRCPATH
277 277
278 278 Touch files and check with status
279 279
280 280 $ touch a b
281 281 $ hg status
282 282
283 283 Update and expand
284 284
285 285 $ rm sym a b
286 286 $ hg update -C
287 287 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 288 $ cat a b
289 289 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
290 290 do not process $Id:
291 291 xxx $
292 292 ignore $Id$
293 293
294 294 Check whether expansion is filewise and file mode is preserved
295 295
296 296 $ echo '$Id$' > c
297 297 $ echo 'tests for different changenodes' >> c
298 298 #if unix-permissions
299 299 $ chmod 600 c
300 300 $ ls -l c | cut -b 1-10
301 301 -rw-------
302 302 #endif
303 303
304 304 commit file c
305 305
306 306 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
307 307 adding c
308 308 #if unix-permissions
309 309 $ ls -l c | cut -b 1-10
310 310 -rw-------
311 311 #endif
312 312
313 313 force expansion
314 314
315 315 $ hg -v kwexpand
316 316 overwriting a expanding keywords
317 317 overwriting c expanding keywords
318 318
319 319 compare changenodes in a and c
320 320
321 321 $ cat a c
322 322 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
323 323 do not process $Id:
324 324 xxx $
325 325 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
326 326 tests for different changenodes
327 327
328 328 record
329 329
330 330 $ echo '$Id$' > r
331 331 $ hg add r
332 332
333 333 record chunk
334 334
335 335 >>> lines = open('a', 'rb').readlines()
336 336 >>> lines.insert(1, 'foo\n')
337 337 >>> lines.append('bar\n')
338 338 >>> open('a', 'wb').writelines(lines)
339 339 $ hg record -d '10 1' -m rectest a<<EOF
340 340 > y
341 341 > y
342 342 > n
343 343 > EOF
344 344 diff --git a/a b/a
345 345 2 hunks, 2 lines changed
346 346 examine changes to 'a'? [Ynesfdaq?]
347 347 @@ -1,3 +1,4 @@
348 348 expand $Id$
349 349 +foo
350 350 do not process $Id:
351 351 xxx $
352 352 record change 1/2 to 'a'? [Ynesfdaq?]
353 353 @@ -2,2 +3,3 @@
354 354 do not process $Id:
355 355 xxx $
356 356 +bar
357 357 record change 2/2 to 'a'? [Ynesfdaq?]
358 358
359 359 $ hg identify
360 360 5f5eb23505c3+ tip
361 361 $ hg status
362 362 M a
363 363 A r
364 364
365 365 Cat modified file a
366 366
367 367 $ cat a
368 368 expand $Id: a,v 5f5eb23505c3 1970/01/01 00:00:10 test $
369 369 foo
370 370 do not process $Id:
371 371 xxx $
372 372 bar
373 373
374 374 Diff remaining chunk
375 375
376 376 $ hg diff a
377 377 diff -r 5f5eb23505c3 a
378 378 --- a/a Thu Jan 01 00:00:09 1970 -0000
379 379 +++ b/a * (glob)
380 380 @@ -2,3 +2,4 @@
381 381 foo
382 382 do not process $Id:
383 383 xxx $
384 384 +bar
385 385
386 386 $ hg rollback
387 387 repository tip rolled back to revision 2 (undo commit)
388 388 working directory now based on revision 2
389 389
390 390 Record all chunks in file a
391 391
392 392 $ echo foo > msg
393 393
394 394 - do not use "hg record -m" here!
395 395
396 396 $ hg record -l msg -d '11 1' a<<EOF
397 397 > y
398 398 > y
399 399 > y
400 400 > EOF
401 401 diff --git a/a b/a
402 402 2 hunks, 2 lines changed
403 403 examine changes to 'a'? [Ynesfdaq?]
404 404 @@ -1,3 +1,4 @@
405 405 expand $Id$
406 406 +foo
407 407 do not process $Id:
408 408 xxx $
409 409 record change 1/2 to 'a'? [Ynesfdaq?]
410 410 @@ -2,2 +3,3 @@
411 411 do not process $Id:
412 412 xxx $
413 413 +bar
414 414 record change 2/2 to 'a'? [Ynesfdaq?]
415 415
416 416 File a should be clean
417 417
418 418 $ hg status -A a
419 419 C a
420 420
421 421 rollback and revert expansion
422 422
423 423 $ cat a
424 424 expand $Id: a,v 78e0a02d76aa 1970/01/01 00:00:11 test $
425 425 foo
426 426 do not process $Id:
427 427 xxx $
428 428 bar
429 429 $ hg --verbose rollback
430 430 repository tip rolled back to revision 2 (undo commit)
431 431 working directory now based on revision 2
432 432 overwriting a expanding keywords
433 433 $ hg status a
434 434 M a
435 435 $ cat a
436 436 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
437 437 foo
438 438 do not process $Id:
439 439 xxx $
440 440 bar
441 441 $ echo '$Id$' > y
442 442 $ echo '$Id$' > z
443 443 $ hg add y
444 444 $ hg commit -Am "rollback only" z
445 445 $ cat z
446 446 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
447 447 $ hg --verbose rollback
448 448 repository tip rolled back to revision 2 (undo commit)
449 449 working directory now based on revision 2
450 450 overwriting z shrinking keywords
451 451
452 452 Only z should be overwritten
453 453
454 454 $ hg status a y z
455 455 M a
456 456 A y
457 457 A z
458 458 $ cat z
459 459 $Id$
460 460 $ hg forget y z
461 461 $ rm y z
462 462
463 463 record added file alone
464 464
465 465 $ hg -v record -l msg -d '12 2' r<<EOF
466 466 > y
467 467 > EOF
468 468 diff --git a/r b/r
469 469 new file mode 100644
470 470 examine changes to 'r'? [Ynesfdaq?]
471 471 r
472 472 committed changeset 3:82a2f715724d
473 473 overwriting r expanding keywords
474 474 - status call required for dirstate.normallookup() check
475 475 $ hg status r
476 476 $ hg --verbose rollback
477 477 repository tip rolled back to revision 2 (undo commit)
478 478 working directory now based on revision 2
479 479 overwriting r shrinking keywords
480 480 $ hg forget r
481 481 $ rm msg r
482 482 $ hg update -C
483 483 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
484 484
485 485 record added keyword ignored file
486 486
487 487 $ echo '$Id$' > i
488 488 $ hg add i
489 489 $ hg --verbose record -d '13 1' -m recignored<<EOF
490 490 > y
491 491 > EOF
492 492 diff --git a/i b/i
493 493 new file mode 100644
494 494 examine changes to 'i'? [Ynesfdaq?]
495 495 i
496 496 committed changeset 3:9f40ceb5a072
497 497 $ cat i
498 498 $Id$
499 499 $ hg -q rollback
500 500 $ hg forget i
501 501 $ rm i
502 502
503 503 amend
504 504
505 505 $ echo amend >> a
506 506 $ echo amend >> b
507 507 $ hg -q commit -d '14 1' -m 'prepare amend'
508 508
509 509 $ hg --debug commit --amend -d '15 1' -m 'amend without changes' | grep keywords
510 510 invalid branchheads cache (served): tip differs
511 511 overwriting a expanding keywords
512 512 $ hg -q id
513 513 67d8c481a6be
514 514 $ head -1 a
515 515 expand $Id: a,v 67d8c481a6be 1970/01/01 00:00:15 test $
516 516
517 517 $ hg -q strip -n tip
518 518
519 519 Test patch queue repo
520 520
521 521 $ hg init --mq
522 522 $ hg qimport -r tip -n mqtest.diff
523 523 $ hg commit --mq -m mqtest
524 524
525 525 Keywords should not be expanded in patch
526 526
527 527 $ cat .hg/patches/mqtest.diff
528 528 # HG changeset patch
529 529 # User User Name <user@example.com>
530 530 # Date 1 0
531 531 # Thu Jan 01 00:00:01 1970 +0000
532 532 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
533 533 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
534 534 cndiff
535 535
536 536 diff -r ef63ca68695b -r 40a904bbbe4c c
537 537 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
538 538 +++ b/c Thu Jan 01 00:00:01 1970 +0000
539 539 @@ -0,0 +1,2 @@
540 540 +$Id$
541 541 +tests for different changenodes
542 542
543 543 $ hg qpop
544 544 popping mqtest.diff
545 545 patch queue now empty
546 546
547 547 qgoto, implying qpush, should expand
548 548
549 549 $ hg qgoto mqtest.diff
550 550 applying mqtest.diff
551 551 now at: mqtest.diff
552 552 $ cat c
553 553 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
554 554 tests for different changenodes
555 555 $ hg cat c
556 556 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
557 557 tests for different changenodes
558 558
559 559 Keywords should not be expanded in filelog
560 560
561 561 $ hg --config 'extensions.keyword=!' cat c
562 562 $Id$
563 563 tests for different changenodes
564 564
565 565 qpop and move on
566 566
567 567 $ hg qpop
568 568 popping mqtest.diff
569 569 patch queue now empty
570 570
571 571 Copy and show added kwfiles
572 572
573 573 $ hg cp a c
574 574 $ hg kwfiles
575 575 a
576 576 c
577 577
578 578 Commit and show expansion in original and copy
579 579
580 580 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
581 581 invalid branchheads cache (served): tip differs
582 582 c
583 583 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
584 584 invalid branchheads cache (served): tip differs
585 585 overwriting c expanding keywords
586 586 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
587 587 $ cat a c
588 588 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
589 589 do not process $Id:
590 590 xxx $
591 591 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
592 592 do not process $Id:
593 593 xxx $
594 594
595 595 Touch copied c and check its status
596 596
597 597 $ touch c
598 598 $ hg status
599 599
600 600 Copy kwfile to keyword ignored file unexpanding keywords
601 601
602 602 $ hg --verbose copy a i
603 603 copying a to i
604 604 overwriting i shrinking keywords
605 605 $ head -n 1 i
606 606 expand $Id$
607 607 $ hg forget i
608 608 $ rm i
609 609
610 610 Copy ignored file to ignored file: no overwriting
611 611
612 612 $ hg --verbose copy b i
613 613 copying b to i
614 614 $ hg forget i
615 615 $ rm i
616 616
617 617 cp symlink file; hg cp -A symlink file (part1)
618 618 - copied symlink points to kwfile: overwrite
619 619
620 620 #if symlink
621 621 $ cp sym i
622 622 $ ls -l i
623 623 -rw-r--r--* (glob)
624 624 $ head -1 i
625 625 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
626 626 $ hg copy --after --verbose sym i
627 627 copying sym to i
628 628 overwriting i shrinking keywords
629 629 $ head -1 i
630 630 expand $Id$
631 631 $ hg forget i
632 632 $ rm i
633 633 #endif
634 634
635 635 Test different options of hg kwfiles
636 636
637 637 $ hg kwfiles
638 638 a
639 639 c
640 640 $ hg -v kwfiles --ignore
641 641 I b
642 642 I sym
643 643 $ hg kwfiles --all
644 644 K a
645 645 K c
646 646 I b
647 647 I sym
648 648
649 649 Diff specific revision
650 650
651 651 $ hg diff --rev 1
652 652 diff -r ef63ca68695b c
653 653 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
654 654 +++ b/c * (glob)
655 655 @@ -0,0 +1,3 @@
656 656 +expand $Id$
657 657 +do not process $Id:
658 658 +xxx $
659 659
660 660 Status after rollback:
661 661
662 662 $ hg rollback
663 663 repository tip rolled back to revision 1 (undo commit)
664 664 working directory now based on revision 1
665 665 $ hg status
666 666 A c
667 667 $ hg update --clean
668 668 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
669 669
670 670 #if symlink
671 671
672 672 cp symlink file; hg cp -A symlink file (part2)
673 673 - copied symlink points to kw ignored file: do not overwrite
674 674
675 675 $ cat a > i
676 676 $ ln -s i symignored
677 677 $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
678 678 $ cp symignored x
679 679 $ hg copy --after --verbose symignored x
680 680 copying symignored to x
681 681 $ head -n 1 x
682 682 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
683 683 $ hg forget x
684 684 $ rm x
685 685
686 686 $ hg rollback
687 687 repository tip rolled back to revision 1 (undo commit)
688 688 working directory now based on revision 1
689 689 $ hg update --clean
690 690 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
691 691 $ rm i symignored
692 692
693 693 #endif
694 694
695 695 Custom keywordmaps as argument to kwdemo
696 696
697 697 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
698 698 [extensions]
699 699 keyword =
700 700 [keyword]
701 701 ** =
702 702 b = ignore
703 703 demo.txt =
704 704 i = ignore
705 705 [keywordset]
706 706 svn = False
707 707 [keywordmaps]
708 708 Xinfo = {author}: {desc}
709 709 $Xinfo: test: hg keyword configuration and expansion example $
710 710
711 711 Configure custom keywordmaps
712 712
713 713 $ cat <<EOF >>$HGRCPATH
714 714 > [keywordmaps]
715 715 > Id = {file} {node|short} {date|rfc822date} {author|user}
716 716 > Xinfo = {author}: {desc}
717 717 > EOF
718 718
719 719 Cat and hg cat files before custom expansion
720 720
721 721 $ cat a b
722 722 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
723 723 do not process $Id:
724 724 xxx $
725 725 ignore $Id$
726 726 $ hg cat sym a b && echo
727 727 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
728 728 do not process $Id:
729 729 xxx $
730 730 ignore $Id$
731 731 a
732 732
733 733 Write custom keyword and prepare multi-line commit message
734 734
735 735 $ echo '$Xinfo$' >> a
736 736 $ cat <<EOF >> log
737 737 > firstline
738 738 > secondline
739 739 > EOF
740 740
741 741 Interrupted commit should not change state
742 742
743 743 $ hg commit
744 744 abort: empty commit message
745 745 [255]
746 746 $ hg status
747 747 M a
748 748 ? c
749 749 ? log
750 750
751 751 Commit with multi-line message and custom expansion
752 752
753 753 |Note:
754 754 |
755 755 | After the last rollback, the "served" branchheads cache became invalid, but
756 756 | all changesets in the repo were public. For filtering this means:
757 757 | "immutable" == "served" == ΓΈ.
758 758 |
759 759 | As the "served" cache is invalid, we fall back to the "immutable" cache. But
760 760 | no update is needed between "immutable" and "served" and the "served" cache
761 761 | is not updated on disk. The on-disk version therefore stays invalid for some
762 762 | time. This explains why the "served" branchheads cache is detected as
763 763 | invalid here.
764 764
765 765 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
766 766 invalid branchheads cache (served): tip differs
767 767 a
768 768 invalid branchheads cache (served): tip differs
769 769 overwriting a expanding keywords
770 770 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
771 771 $ rm log
772 772
773 773 Stat, verify and show custom expansion (firstline)
774 774
775 775 $ hg status
776 776 ? c
777 777 $ hg verify
778 778 checking changesets
779 779 checking manifests
780 780 crosschecking files in changesets and manifests
781 781 checking files
782 782 3 files, 3 changesets, 4 total revisions
783 783 $ cat a b
784 784 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
785 785 do not process $Id:
786 786 xxx $
787 787 $Xinfo: User Name <user@example.com>: firstline $
788 788 ignore $Id$
789 789 $ hg cat sym a b && echo
790 790 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
791 791 do not process $Id:
792 792 xxx $
793 793 $Xinfo: User Name <user@example.com>: firstline $
794 794 ignore $Id$
795 795 a
796 796
797 797 annotate
798 798
799 799 $ hg annotate a
800 800 1: expand $Id$
801 801 1: do not process $Id:
802 802 1: xxx $
803 803 2: $Xinfo$
804 804
805 805 remove with status checks
806 806
807 807 $ hg debugrebuildstate
808 808 $ hg remove a
809 809 $ hg --debug commit -m rma
810 810 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
811 811 $ hg status
812 812 ? c
813 813
814 814 Rollback, revert, and check expansion
815 815
816 816 $ hg rollback
817 817 repository tip rolled back to revision 2 (undo commit)
818 818 working directory now based on revision 2
819 819 $ hg status
820 820 R a
821 821 ? c
822 822 $ hg revert --no-backup --rev tip a
823 823 $ cat a
824 824 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
825 825 do not process $Id:
826 826 xxx $
827 827 $Xinfo: User Name <user@example.com>: firstline $
828 828
829 829 Clone to test global and local configurations
830 830
831 831 $ cd ..
832 832
833 833 Expansion in destination with global configuration
834 834
835 835 $ hg --quiet clone Test globalconf
836 836 $ cat globalconf/a
837 837 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
838 838 do not process $Id:
839 839 xxx $
840 840 $Xinfo: User Name <user@example.com>: firstline $
841 841
842 842 No expansion in destination with local configuration in origin only
843 843
844 844 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
845 845 $ cat localconf/a
846 846 expand $Id$
847 847 do not process $Id:
848 848 xxx $
849 849 $Xinfo$
850 850
851 851 Clone to test incoming
852 852
853 853 $ hg clone -r1 Test Test-a
854 854 adding changesets
855 855 adding manifests
856 856 adding file changes
857 857 added 2 changesets with 3 changes to 3 files
858 858 updating to branch default
859 859 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
860 860 $ cd Test-a
861 861 $ cat <<EOF >> .hg/hgrc
862 862 > [paths]
863 863 > default = ../Test
864 864 > EOF
865 865 $ hg incoming
866 866 comparing with $TESTTMP/Test (glob)
867 867 searching for changes
868 868 changeset: 2:bb948857c743
869 869 tag: tip
870 870 user: User Name <user@example.com>
871 871 date: Thu Jan 01 00:00:02 1970 +0000
872 872 summary: firstline
873 873
874 874 Imported patch should not be rejected
875 875
876 876 >>> import re
877 877 >>> text = re.sub(r'(Id.*)', r'\1 rejecttest', open('a').read())
878 878 >>> open('a', 'wb').write(text)
879 879 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
880 880 a
881 881 overwriting a expanding keywords
882 882 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
883 883 $ hg export -o ../rejecttest.diff tip
884 884 $ cd ../Test
885 885 $ hg import ../rejecttest.diff
886 886 applying ../rejecttest.diff
887 887 $ cat a b
888 888 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
889 889 do not process $Id: rejecttest
890 890 xxx $
891 891 $Xinfo: User Name <user@example.com>: rejects? $
892 892 ignore $Id$
893 893
894 894 $ hg rollback
895 895 repository tip rolled back to revision 2 (undo import)
896 896 working directory now based on revision 2
897 897 $ hg update --clean
898 898 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
899 899
900 900 kwexpand/kwshrink on selected files
901 901
902 902 $ mkdir x
903 903 $ hg copy a x/a
904 904 $ hg --verbose kwshrink a
905 905 overwriting a shrinking keywords
906 906 - sleep required for dirstate.normal() check
907 907 $ sleep 1
908 908 $ hg status a
909 909 $ hg --verbose kwexpand a
910 910 overwriting a expanding keywords
911 911 $ hg status a
912 912
913 913 kwexpand x/a should abort
914 914
915 915 $ hg --verbose kwexpand x/a
916 916 abort: outstanding uncommitted changes
917 917 [255]
918 918 $ cd x
919 919 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
920 920 x/a
921 921 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
922 922 overwriting x/a expanding keywords
923 923 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
924 924 $ cat a
925 925 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
926 926 do not process $Id:
927 927 xxx $
928 928 $Xinfo: User Name <user@example.com>: xa $
929 929
930 930 kwshrink a inside directory x
931 931
932 932 $ hg --verbose kwshrink a
933 933 overwriting x/a shrinking keywords
934 934 $ cat a
935 935 expand $Id$
936 936 do not process $Id:
937 937 xxx $
938 938 $Xinfo$
939 939 $ cd ..
940 940
941 941 kwexpand nonexistent
942 942
943 943 $ hg kwexpand nonexistent
944 944 nonexistent:* (glob)
945 945
946 946
947 947 #if serve
948 948 hg serve
949 949 - expand with hgweb file
950 950 - no expansion with hgweb annotate/changeset/filediff
951 951 - check errors
952 952
953 953 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
954 954 $ cat hg.pid >> $DAEMON_PIDS
955 955 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
956 956 200 Script output follows
957 957
958 958 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
959 959 do not process $Id:
960 960 xxx $
961 961 $Xinfo: User Name <user@example.com>: firstline $
962 962 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
963 963 200 Script output follows
964 964
965 965
966 966 user@1: expand $Id$
967 967 user@1: do not process $Id:
968 968 user@1: xxx $
969 969 user@2: $Xinfo$
970 970
971 971
972 972
973 973
974 974 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
975 975 200 Script output follows
976 976
977 977
978 978 # HG changeset patch
979 979 # User User Name <user@example.com>
980 980 # Date 3 0
981 981 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
982 982 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
983 983 xa
984 984
985 985 diff -r bb948857c743 -r b4560182a3f9 x/a
986 986 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
987 987 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
988 988 @@ -0,0 +1,4 @@
989 989 +expand $Id$
990 990 +do not process $Id:
991 991 +xxx $
992 992 +$Xinfo$
993 993
994 994 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
995 995 200 Script output follows
996 996
997 997
998 998 diff -r ef63ca68695b -r bb948857c743 a
999 999 --- a/a Thu Jan 01 00:00:00 1970 +0000
1000 1000 +++ b/a Thu Jan 01 00:00:02 1970 +0000
1001 1001 @@ -1,3 +1,4 @@
1002 1002 expand $Id$
1003 1003 do not process $Id:
1004 1004 xxx $
1005 1005 +$Xinfo$
1006 1006
1007 1007
1008 1008
1009 1009
1010 1010 $ cat errors.log
1011 1011 #endif
1012 1012
1013 1013 Prepare merge and resolve tests
1014 1014
1015 1015 $ echo '$Id$' > m
1016 1016 $ hg add m
1017 1017 $ hg commit -m 4kw
1018 1018 $ echo foo >> m
1019 1019 $ hg commit -m 5foo
1020 1020
1021 1021 simplemerge
1022 1022
1023 1023 $ hg update 4
1024 1024 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1025 1025 $ echo foo >> m
1026 1026 $ hg commit -m 6foo
1027 1027 created new head
1028 1028 $ hg merge
1029 1029 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1030 1030 (branch merge, don't forget to commit)
1031 1031 $ hg commit -m simplemerge
1032 1032 $ cat m
1033 1033 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
1034 1034 foo
1035 1035
1036 1036 conflict: keyword should stay outside conflict zone
1037 1037
1038 1038 $ hg update 4
1039 1039 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1040 1040 $ echo bar >> m
1041 1041 $ hg commit -m 8bar
1042 1042 created new head
1043 1043 $ hg merge
1044 1044 merging m
1045 1045 warning: conflicts during merge.
1046 1046 merging m incomplete! (edit conflicts, then use 'hg resolve --mark')
1047 1047 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1048 1048 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1049 1049 [1]
1050 1050 $ cat m
1051 1051 $Id$
1052 1052 <<<<<<< local
1053 1053 bar
1054 1054 =======
1055 1055 foo
1056 1056 >>>>>>> other
1057 1057
1058 1058 resolve to local
1059 1059
1060 1060 $ HGMERGE=internal:local hg resolve -a
1061 1061 $ hg commit -m localresolve
1062 1062 $ cat m
1063 1063 $Id: m 800511b3a22d Thu, 01 Jan 1970 00:00:00 +0000 test $
1064 1064 bar
1065 1065
1066 1066 Test restricted mode with transplant -b
1067 1067
1068 1068 $ hg update 6
1069 1069 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1070 1070 $ hg branch foo
1071 1071 marked working directory as branch foo
1072 1072 (branches are permanent and global, did you want a bookmark?)
1073 1073 $ mv a a.bak
1074 1074 $ echo foobranch > a
1075 1075 $ cat a.bak >> a
1076 1076 $ rm a.bak
1077 1077 $ hg commit -m 9foobranch
1078 1078 $ hg update default
1079 1079 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1080 1080 $ hg -y transplant -b foo tip
1081 1081 applying 4aa30d025d50
1082 1082 4aa30d025d50 transplanted to e00abbf63521
1083 1083
1084 1084 Expansion in changeset but not in file
1085 1085
1086 1086 $ hg tip -p
1087 1087 changeset: 11:e00abbf63521
1088 1088 tag: tip
1089 1089 parent: 9:800511b3a22d
1090 1090 user: test
1091 1091 date: Thu Jan 01 00:00:00 1970 +0000
1092 1092 summary: 9foobranch
1093 1093
1094 1094 diff -r 800511b3a22d -r e00abbf63521 a
1095 1095 --- a/a Thu Jan 01 00:00:00 1970 +0000
1096 1096 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1097 1097 @@ -1,3 +1,4 @@
1098 1098 +foobranch
1099 1099 expand $Id$
1100 1100 do not process $Id:
1101 1101 xxx $
1102 1102
1103 1103 $ head -n 2 a
1104 1104 foobranch
1105 1105 expand $Id: a e00abbf63521 Thu, 01 Jan 1970 00:00:00 +0000 test $
1106 1106
1107 1107 Turn off expansion
1108 1108
1109 1109 $ hg -q rollback
1110 1110 $ hg -q update -C
1111 1111
1112 1112 kwshrink with unknown file u
1113 1113
1114 1114 $ cp a u
1115 1115 $ hg --verbose kwshrink
1116 1116 overwriting a shrinking keywords
1117 1117 overwriting m shrinking keywords
1118 1118 overwriting x/a shrinking keywords
1119 1119
1120 1120 Keywords shrunk in working directory, but not yet disabled
1121 1121 - cat shows unexpanded keywords
1122 1122 - hg cat shows expanded keywords
1123 1123
1124 1124 $ cat a b
1125 1125 expand $Id$
1126 1126 do not process $Id:
1127 1127 xxx $
1128 1128 $Xinfo$
1129 1129 ignore $Id$
1130 1130 $ hg cat sym a b && echo
1131 1131 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
1132 1132 do not process $Id:
1133 1133 xxx $
1134 1134 $Xinfo: User Name <user@example.com>: firstline $
1135 1135 ignore $Id$
1136 1136 a
1137 1137
1138 1138 Now disable keyword expansion
1139 1139
1140 1140 $ cp $HGRCPATH $HGRCPATH.backup
1141 1141 $ rm "$HGRCPATH"
1142 1142 $ cat a b
1143 1143 expand $Id$
1144 1144 do not process $Id:
1145 1145 xxx $
1146 1146 $Xinfo$
1147 1147 ignore $Id$
1148 1148 $ hg cat sym a b && echo
1149 1149 expand $Id$
1150 1150 do not process $Id:
1151 1151 xxx $
1152 1152 $Xinfo$
1153 1153 ignore $Id$
1154 1154 a
1155 1155
1156 1156 enable keyword expansion again
1157 1157
1158 1158 $ cat $HGRCPATH.backup >> $HGRCPATH
1159 1159
1160 1160 Test restricted mode with unshelve
1161 1161
1162 1162 $ cat <<EOF >> $HGRCPATH
1163 1163 > [extensions]
1164 1164 > shelve =
1165 1165 > EOF
1166 1166
1167 1167 $ echo xxxx >> a
1168 1168 $ hg diff
1169 1169 diff -r 800511b3a22d a
1170 1170 --- a/a Thu Jan 01 00:00:00 1970 +0000
1171 1171 +++ b/a * (glob)
1172 1172 @@ -2,3 +2,4 @@
1173 1173 do not process $Id:
1174 1174 xxx $
1175 1175 $Xinfo$
1176 1176 +xxxx
1177 1177 $ hg shelve -q --name tmp
1178 1178 $ hg shelve --list --patch
1179 1179 tmp (*) changes to 'localresolve' (glob)
1180 1180
1181 1181 diff --git a/a b/a
1182 1182 --- a/a
1183 1183 +++ b/a
1184 1184 @@ -2,3 +2,4 @@
1185 1185 do not process $Id:
1186 1186 xxx $
1187 1187 $Xinfo$
1188 1188 +xxxx
1189 1189
1190 1190 $ hg update -q -C 10
1191 1191 $ hg unshelve -q tmp
1192 1192 $ hg diff
1193 1193 diff -r 4aa30d025d50 a
1194 1194 --- a/a Thu Jan 01 00:00:00 1970 +0000
1195 1195 +++ b/a * (glob)
1196 1196 @@ -3,3 +3,4 @@
1197 1197 do not process $Id:
1198 1198 xxx $
1199 1199 $Xinfo$
1200 1200 +xxxx
1201 1201
1202 1202 Test restricted mode with rebase
1203 1203
1204 1204 $ cat <<EOF >> $HGRCPATH
1205 1205 > [extensions]
1206 1206 > rebase =
1207 1207 > EOF
1208 1208
1209 1209 $ hg update -q -C 9
1210 1210
1211 1211 $ echo xxxx >> a
1212 1212 $ hg commit -m '#11'
1213 1213 $ hg diff -c 11
1214 1214 diff -r 800511b3a22d -r b07670694489 a
1215 1215 --- a/a Thu Jan 01 00:00:00 1970 +0000
1216 1216 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1217 1217 @@ -2,3 +2,4 @@
1218 1218 do not process $Id:
1219 1219 xxx $
1220 1220 $Xinfo$
1221 1221 +xxxx
1222 1222
1223 1223 $ hg diff -c 10
1224 1224 diff -r 27d48ee14f67 -r 4aa30d025d50 a
1225 1225 --- a/a Thu Jan 01 00:00:00 1970 +0000
1226 1226 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1227 1227 @@ -1,3 +1,4 @@
1228 1228 +foobranch
1229 1229 expand $Id$
1230 1230 do not process $Id:
1231 1231 xxx $
1232 1232
1233 1233 $ hg rebase -q -s 10 -d 11 --keep
1234 1234 $ hg diff -r 9 -r 12 a
1235 1235 diff -r 800511b3a22d -r 1939b927726c a
1236 1236 --- a/a Thu Jan 01 00:00:00 1970 +0000
1237 1237 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1238 1238 @@ -1,4 +1,6 @@
1239 1239 +foobranch
1240 1240 expand $Id$
1241 1241 do not process $Id:
1242 1242 xxx $
1243 1243 $Xinfo$
1244 1244 +xxxx
1245 1245
1246 1246 Test restricted mode with graft
1247 1247
1248 1248 $ hg graft -q 10
1249 1249 $ hg diff -r 9 -r 13 a
1250 1250 diff -r 800511b3a22d -r 01a68de1003a a
1251 1251 --- a/a Thu Jan 01 00:00:00 1970 +0000
1252 1252 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1253 1253 @@ -1,4 +1,6 @@
1254 1254 +foobranch
1255 1255 expand $Id$
1256 1256 do not process $Id:
1257 1257 xxx $
1258 1258 $Xinfo$
1259 1259 +xxxx
1260 1260
1261 Test restricted mode with backout
1262
1263 $ hg backout -q 11
1264 $ hg diff a
1265 diff -r 01a68de1003a a
1266 --- a/a Thu Jan 01 00:00:00 1970 +0000
1267 +++ b/a * (glob)
1268 @@ -3,4 +3,3 @@
1269 do not process $Id:
1270 xxx $
1271 $Xinfo$
1272 -xxxx
1273
1261 1274 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now