##// END OF EJS Templates
tests: cat error messages are different on Solaris
Danek Duvall -
r21930:a5168eb9 stable
parent child Browse files
Show More
@@ -1,575 +1,577 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # check-code - a style and portability checker for Mercurial
4 4 #
5 5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 """style and portability checker for Mercurial
11 11
12 12 when a rule triggers wrong, do one of the following (prefer one from top):
13 13 * do the work-around the rule suggests
14 14 * doublecheck that it is a false match
15 15 * improve the rule pattern
16 16 * add an ignore pattern to the rule (3rd arg) which matches your good line
17 17 (you can append a short comment and match this, like: #re-raises, # no-py24)
18 18 * change the pattern to a warning and list the exception in test-check-code-hg
19 19 * ONLY use no--check-code for skipping entire files from external sources
20 20 """
21 21
22 22 import re, glob, os, sys
23 23 import keyword
24 24 import optparse
25 25 try:
26 26 import re2
27 27 except ImportError:
28 28 re2 = None
29 29
30 30 def compilere(pat, multiline=False):
31 31 if multiline:
32 32 pat = '(?m)' + pat
33 33 if re2:
34 34 try:
35 35 return re2.compile(pat)
36 36 except re2.error:
37 37 pass
38 38 return re.compile(pat)
39 39
40 40 def repquote(m):
41 41 fromc = '.:'
42 42 tochr = 'pq'
43 43 def encodechr(i):
44 44 if i > 255:
45 45 return 'u'
46 46 c = chr(i)
47 47 if c in ' \n':
48 48 return c
49 49 if c.isalpha():
50 50 return 'x'
51 51 if c.isdigit():
52 52 return 'n'
53 53 try:
54 54 return tochr[fromc.find(c)]
55 55 except (ValueError, IndexError):
56 56 return 'o'
57 57 t = m.group('text')
58 58 tt = ''.join(encodechr(i) for i in xrange(256))
59 59 t = t.translate(tt)
60 60 return m.group('quote') + t + m.group('quote')
61 61
62 62 def reppython(m):
63 63 comment = m.group('comment')
64 64 if comment:
65 65 l = len(comment.rstrip())
66 66 return "#" * l + comment[l:]
67 67 return repquote(m)
68 68
69 69 def repcomment(m):
70 70 return m.group(1) + "#" * len(m.group(2))
71 71
72 72 def repccomment(m):
73 73 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
74 74 return m.group(1) + t + "*/"
75 75
76 76 def repcallspaces(m):
77 77 t = re.sub(r"\n\s+", "\n", m.group(2))
78 78 return m.group(1) + t
79 79
80 80 def repinclude(m):
81 81 return m.group(1) + "<foo>"
82 82
83 83 def rephere(m):
84 84 t = re.sub(r"\S", "x", m.group(2))
85 85 return m.group(1) + t
86 86
87 87
88 88 testpats = [
89 89 [
90 90 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
91 91 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
92 92 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
93 93 (r'(?<!hg )grep.*-a', "don't use 'grep -a', use in-line python"),
94 94 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
95 95 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
96 96 (r'echo -n', "don't use 'echo -n', use printf"),
97 97 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
98 98 (r'head -c', "don't use 'head -c', use 'dd'"),
99 99 (r'tail -n', "don't use the '-n' option to tail, just use '-<num>'"),
100 100 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
101 101 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
102 102 (r'printf.*[^\\]\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
103 103 (r'printf.*[^\\]\\x', "don't use printf \\x, use Python"),
104 104 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
105 105 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
106 106 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
107 107 "use egrep for extended grep syntax"),
108 108 (r'/bin/', "don't use explicit paths for tools"),
109 109 (r'[^\n]\Z', "no trailing newline"),
110 110 (r'export.*=', "don't export and assign at once"),
111 111 (r'^source\b', "don't use 'source', use '.'"),
112 112 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
113 113 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
114 114 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
115 115 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
116 116 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
117 117 (r'^alias\b.*=', "don't use alias, use a function"),
118 118 (r'if\s*!', "don't use '!' to negate exit status"),
119 119 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
120 120 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
121 121 (r'^( *)\t', "don't use tabs to indent"),
122 122 (r'sed (-e )?\'(\d+|/[^/]*/)i(?!\\\n)',
123 123 "put a backslash-escaped newline after sed 'i' command"),
124 124 (r'^diff *-\w*u.*$\n(^ \$ |^$)', "prefix diff -u with cmp"),
125 125 ],
126 126 # warnings
127 127 [
128 128 (r'^function', "don't use 'function', use old style"),
129 129 (r'^diff.*-\w*N', "don't use 'diff -N'"),
130 130 (r'\$PWD|\${PWD}', "don't use $PWD, use `pwd`"),
131 131 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
132 132 (r'kill (`|\$\()', "don't use kill, use killdaemons.py")
133 133 ]
134 134 ]
135 135
136 136 testfilters = [
137 137 (r"( *)(#([^\n]*\S)?)", repcomment),
138 138 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
139 139 ]
140 140
141 141 winglobmsg = "use (glob) to match Windows paths too"
142 142 uprefix = r"^ \$ "
143 143 utestpats = [
144 144 [
145 145 (r'^(\S.*|| [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
146 146 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
147 147 "use regex test output patterns instead of sed"),
148 148 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
149 149 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
150 150 (uprefix + r'.*\|\| echo.*(fail|error)',
151 151 "explicit exit code checks unnecessary"),
152 152 (uprefix + r'set -e', "don't use set -e"),
153 153 (uprefix + r'(\s|fi\b|done\b)', "use > for continued lines"),
154 154 (uprefix + r'.*:\.\S*/', "x:.y in a path does not work on msys, rewrite "
155 155 "as x://.y, or see `hg log -k msys` for alternatives", r'-\S+:\.|' #-Rxxx
156 156 'hg pull -q file:../test'), # in test-pull.t which is skipped on windows
157 157 (r'^ saved backup bundle to \$TESTTMP.*\.hg$', winglobmsg),
158 158 (r'^ changeset .* references (corrupted|missing) \$TESTTMP/.*[^)]$',
159 159 winglobmsg),
160 160 (r'^ pulling from \$TESTTMP/.*[^)]$', winglobmsg,
161 161 '\$TESTTMP/unix-repo$'), # in test-issue1802.t which skipped on windows
162 162 (r'^ reverting .*/.*[^)]$', winglobmsg),
163 163 (r'^ cloning subrepo \S+/.*[^)]$', winglobmsg),
164 164 (r'^ pushing to \$TESTTMP/.*[^)]$', winglobmsg),
165 165 (r'^ pushing subrepo \S+/\S+ to.*[^)]$', winglobmsg),
166 166 (r'^ moving \S+/.*[^)]$', winglobmsg),
167 167 (r'^ no changes made to subrepo since.*/.*[^)]$', winglobmsg),
168 168 (r'^ .*: largefile \S+ not available from file:.*/.*[^)]$', winglobmsg),
169 169 (r'^ .*file://\$TESTTMP',
170 170 'write "file:/*/$TESTTMP" + (glob) to match on windows too'),
171 (r'^ (cat|find): .*: No such file or directory',
172 'use test -f to test for file existence'),
171 173 ],
172 174 # warnings
173 175 [
174 176 (r'^ [^*?/\n]* \(glob\)$',
175 177 "glob match with no glob character (?*/)"),
176 178 ]
177 179 ]
178 180
179 181 for i in [0, 1]:
180 182 for p, m in testpats[i]:
181 183 if p.startswith(r'^'):
182 184 p = r"^ [$>] (%s)" % p[1:]
183 185 else:
184 186 p = r"^ [$>] .*(%s)" % p
185 187 utestpats[i].append((p, m))
186 188
187 189 utestfilters = [
188 190 (r"<<(\S+)((.|\n)*?\n > \1)", rephere),
189 191 (r"( *)(#([^\n]*\S)?)", repcomment),
190 192 ]
191 193
192 194 pypats = [
193 195 [
194 196 (r'\([^)]*\*\w[^()]+\w+=', "can't pass varargs with keyword in Py2.5"),
195 197 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
196 198 "tuple parameter unpacking not available in Python 3+"),
197 199 (r'lambda\s*\(.*,.*\)',
198 200 "tuple parameter unpacking not available in Python 3+"),
199 201 (r'import (.+,[^.]+\.[^.]+|[^.]+\.[^.]+,)',
200 202 '2to3 can\'t always rewrite "import qux, foo.bar", '
201 203 'use "import foo.bar" on its own line instead.'),
202 204 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
203 205 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
204 206 (r'dict\(.*=', 'dict() is different in Py2 and 3 and is slower than {}',
205 207 'dict-from-generator'),
206 208 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
207 209 (r'\s<>\s', '<> operator is not available in Python 3+, use !='),
208 210 (r'^\s*\t', "don't use tabs"),
209 211 (r'\S;\s*\n', "semicolon"),
210 212 (r'[^_]_\([ \t\n]*(?:"[^"]+"[ \t\n+]*)+%', "don't use % inside _()"),
211 213 (r"[^_]_\([ \t\n]*(?:'[^']+'[ \t\n+]*)+%", "don't use % inside _()"),
212 214 (r'(\w|\)),\w', "missing whitespace after ,"),
213 215 (r'(\w|\))[+/*\-<>]\w', "missing whitespace in expression"),
214 216 (r'^\s+(\w|\.)+=\w[^,()\n]*$', "missing whitespace in assignment"),
215 217 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
216 218 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Python 2.4'),
217 219 (r'(?<!def)(\s+|^|\()next\(.+\)',
218 220 'no next(foo) in Python 2.4 and 2.5, use foo.next() instead'),
219 221 (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
220 222 r'((?:\n|\1\s.*\n)+?)\1finally:',
221 223 'no yield inside try/finally in Python 2.4'),
222 224 (r'.{81}', "line too long"),
223 225 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
224 226 (r'[^\n]\Z', "no trailing newline"),
225 227 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
226 228 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
227 229 # "don't use underbars in identifiers"),
228 230 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
229 231 "don't use camelcase in identifiers"),
230 232 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
231 233 "linebreak after :"),
232 234 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
233 235 (r'class\s[^( \n]+\(\):',
234 236 "class foo() not available in Python 2.4, use class foo(object)"),
235 237 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
236 238 "Python keyword is not a function"),
237 239 (r',]', "unneeded trailing ',' in list"),
238 240 # (r'class\s[A-Z][^\(]*\((?!Exception)',
239 241 # "don't capitalize non-exception classes"),
240 242 # (r'in range\(', "use xrange"),
241 243 # (r'^\s*print\s+', "avoid using print in core and extensions"),
242 244 (r'[\x80-\xff]', "non-ASCII character literal"),
243 245 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
244 246 (r'^\s*with\s+', "with not available in Python 2.4"),
245 247 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
246 248 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
247 249 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
248 250 (r'(?<!def)\s+(any|all|format)\(',
249 251 "any/all/format not available in Python 2.4", 'no-py24'),
250 252 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
251 253 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
252 254 "gratuitous whitespace after Python keyword"),
253 255 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
254 256 # (r'\s\s=', "gratuitous whitespace before ="),
255 257 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
256 258 "missing whitespace around operator"),
257 259 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
258 260 "missing whitespace around operator"),
259 261 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
260 262 "missing whitespace around operator"),
261 263 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
262 264 "wrong whitespace around ="),
263 265 (r'\([^()]*( =[^=]|[^<>!=]= )',
264 266 "no whitespace around = for named parameters"),
265 267 (r'raise Exception', "don't raise generic exceptions"),
266 268 (r'raise [^,(]+, (\([^\)]+\)|[^,\(\)]+)$',
267 269 "don't use old-style two-argument raise, use Exception(message)"),
268 270 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
269 271 (r' [=!]=\s+(True|False|None)',
270 272 "comparison with singleton, use 'is' or 'is not' instead"),
271 273 (r'^\s*(while|if) [01]:',
272 274 "use True/False for constant Boolean expression"),
273 275 (r'(?:(?<!def)\s+|\()hasattr',
274 276 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
275 277 (r'opener\([^)]*\).read\(',
276 278 "use opener.read() instead"),
277 279 (r'BaseException', 'not in Python 2.4, use Exception'),
278 280 (r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
279 281 (r'opener\([^)]*\).write\(',
280 282 "use opener.write() instead"),
281 283 (r'[\s\(](open|file)\([^)]*\)\.read\(',
282 284 "use util.readfile() instead"),
283 285 (r'[\s\(](open|file)\([^)]*\)\.write\(',
284 286 "use util.writefile() instead"),
285 287 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
286 288 "always assign an opened file to a variable, and close it afterwards"),
287 289 (r'[\s\(](open|file)\([^)]*\)\.',
288 290 "always assign an opened file to a variable, and close it afterwards"),
289 291 (r'(?i)descendent', "the proper spelling is descendAnt"),
290 292 (r'\.debug\(\_', "don't mark debug messages for translation"),
291 293 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
292 294 (r'^\s*except\s*:', "naked except clause", r'#.*re-raises'),
293 295 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
294 296 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
295 297 "missing _() in ui message (use () to hide false-positives)"),
296 298 (r'release\(.*wlock, .*lock\)', "wrong lock release order"),
297 299 ],
298 300 # warnings
299 301 [
300 302 (r'(^| )pp +xxxxqq[ \n][^\n]', "add two newlines after '.. note::'"),
301 303 ]
302 304 ]
303 305
304 306 pyfilters = [
305 307 (r"""(?msx)(?P<comment>\#.*?$)|
306 308 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
307 309 (?P<text>(([^\\]|\\.)*?))
308 310 (?P=quote))""", reppython),
309 311 ]
310 312
311 313 txtfilters = []
312 314
313 315 txtpats = [
314 316 [
315 317 ('\s$', 'trailing whitespace'),
316 318 ('.. note::[ \n][^\n]', 'add two newlines after note::')
317 319 ],
318 320 []
319 321 ]
320 322
321 323 cpats = [
322 324 [
323 325 (r'//', "don't use //-style comments"),
324 326 (r'^ ', "don't use spaces to indent"),
325 327 (r'\S\t', "don't use tabs except for indent"),
326 328 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
327 329 (r'.{81}', "line too long"),
328 330 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
329 331 (r'return\(', "return is not a function"),
330 332 (r' ;', "no space before ;"),
331 333 (r'[)][{]', "space between ) and {"),
332 334 (r'\w+\* \w+', "use int *foo, not int* foo"),
333 335 (r'\W\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
334 336 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
335 337 (r'\w,\w', "missing whitespace after ,"),
336 338 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
337 339 (r'^#\s+\w', "use #foo, not # foo"),
338 340 (r'[^\n]\Z', "no trailing newline"),
339 341 (r'^\s*#import\b', "use only #include in standard C code"),
340 342 ],
341 343 # warnings
342 344 []
343 345 ]
344 346
345 347 cfilters = [
346 348 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
347 349 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
348 350 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
349 351 (r'(\()([^)]+\))', repcallspaces),
350 352 ]
351 353
352 354 inutilpats = [
353 355 [
354 356 (r'\bui\.', "don't use ui in util"),
355 357 ],
356 358 # warnings
357 359 []
358 360 ]
359 361
360 362 inrevlogpats = [
361 363 [
362 364 (r'\brepo\.', "don't use repo in revlog"),
363 365 ],
364 366 # warnings
365 367 []
366 368 ]
367 369
368 370 webtemplatefilters = []
369 371
370 372 webtemplatepats = [
371 373 [],
372 374 [
373 375 (r'{desc(\|(?!websub|firstline)[^\|]*)+}',
374 376 'follow desc keyword with either firstline or websub'),
375 377 ]
376 378 ]
377 379
378 380 checks = [
379 381 ('python', r'.*\.(py|cgi)$', r'^#!.*python', pyfilters, pypats),
380 382 ('test script', r'(.*/)?test-[^.~]*$', '', testfilters, testpats),
381 383 ('c', r'.*\.[ch]$', '', cfilters, cpats),
382 384 ('unified test', r'.*\.t$', '', utestfilters, utestpats),
383 385 ('layering violation repo in revlog', r'mercurial/revlog\.py', '',
384 386 pyfilters, inrevlogpats),
385 387 ('layering violation ui in util', r'mercurial/util\.py', '', pyfilters,
386 388 inutilpats),
387 389 ('txt', r'.*\.txt$', '', txtfilters, txtpats),
388 390 ('web template', r'mercurial/templates/.*\.tmpl', '',
389 391 webtemplatefilters, webtemplatepats),
390 392 ]
391 393
392 394 def _preparepats():
393 395 for c in checks:
394 396 failandwarn = c[-1]
395 397 for pats in failandwarn:
396 398 for i, pseq in enumerate(pats):
397 399 # fix-up regexes for multi-line searches
398 400 p = pseq[0]
399 401 # \s doesn't match \n
400 402 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
401 403 # [^...] doesn't match newline
402 404 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
403 405
404 406 pats[i] = (re.compile(p, re.MULTILINE),) + pseq[1:]
405 407 filters = c[3]
406 408 for i, flt in enumerate(filters):
407 409 filters[i] = re.compile(flt[0]), flt[1]
408 410 _preparepats()
409 411
410 412 class norepeatlogger(object):
411 413 def __init__(self):
412 414 self._lastseen = None
413 415
414 416 def log(self, fname, lineno, line, msg, blame):
415 417 """print error related a to given line of a given file.
416 418
417 419 The faulty line will also be printed but only once in the case
418 420 of multiple errors.
419 421
420 422 :fname: filename
421 423 :lineno: line number
422 424 :line: actual content of the line
423 425 :msg: error message
424 426 """
425 427 msgid = fname, lineno, line
426 428 if msgid != self._lastseen:
427 429 if blame:
428 430 print "%s:%d (%s):" % (fname, lineno, blame)
429 431 else:
430 432 print "%s:%d:" % (fname, lineno)
431 433 print " > %s" % line
432 434 self._lastseen = msgid
433 435 print " " + msg
434 436
435 437 _defaultlogger = norepeatlogger()
436 438
437 439 def getblame(f):
438 440 lines = []
439 441 for l in os.popen('hg annotate -un %s' % f):
440 442 start, line = l.split(':', 1)
441 443 user, rev = start.split()
442 444 lines.append((line[1:-1], user, rev))
443 445 return lines
444 446
445 447 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
446 448 blame=False, debug=False, lineno=True):
447 449 """checks style and portability of a given file
448 450
449 451 :f: filepath
450 452 :logfunc: function used to report error
451 453 logfunc(filename, linenumber, linecontent, errormessage)
452 454 :maxerr: number of error to display before aborting.
453 455 Set to false (default) to report all errors
454 456
455 457 return True if no error is found, False otherwise.
456 458 """
457 459 blamecache = None
458 460 result = True
459 461
460 462 try:
461 463 fp = open(f)
462 464 except IOError, e:
463 465 print "Skipping %s, %s" % (f, str(e).split(':', 1)[0])
464 466 return result
465 467 pre = post = fp.read()
466 468 fp.close()
467 469
468 470 for name, match, magic, filters, pats in checks:
469 471 if debug:
470 472 print name, f
471 473 fc = 0
472 474 if not (re.match(match, f) or (magic and re.search(magic, f))):
473 475 if debug:
474 476 print "Skipping %s for %s it doesn't match %s" % (
475 477 name, match, f)
476 478 continue
477 479 if "no-" "check-code" in pre:
478 480 print "Skipping %s it has no-" "check-code" % f
479 481 return "Skip" # skip checking this file
480 482 for p, r in filters:
481 483 post = re.sub(p, r, post)
482 484 nerrs = len(pats[0]) # nerr elements are errors
483 485 if warnings:
484 486 pats = pats[0] + pats[1]
485 487 else:
486 488 pats = pats[0]
487 489 # print post # uncomment to show filtered version
488 490
489 491 if debug:
490 492 print "Checking %s for %s" % (name, f)
491 493
492 494 prelines = None
493 495 errors = []
494 496 for i, pat in enumerate(pats):
495 497 if len(pat) == 3:
496 498 p, msg, ignore = pat
497 499 else:
498 500 p, msg = pat
499 501 ignore = None
500 502 if i >= nerrs:
501 503 msg = "warning: " + msg
502 504
503 505 pos = 0
504 506 n = 0
505 507 for m in p.finditer(post):
506 508 if prelines is None:
507 509 prelines = pre.splitlines()
508 510 postlines = post.splitlines(True)
509 511
510 512 start = m.start()
511 513 while n < len(postlines):
512 514 step = len(postlines[n])
513 515 if pos + step > start:
514 516 break
515 517 pos += step
516 518 n += 1
517 519 l = prelines[n]
518 520
519 521 if ignore and re.search(ignore, l, re.MULTILINE):
520 522 if debug:
521 523 print "Skipping %s for %s:%s (ignore pattern)" % (
522 524 name, f, n)
523 525 continue
524 526 bd = ""
525 527 if blame:
526 528 bd = 'working directory'
527 529 if not blamecache:
528 530 blamecache = getblame(f)
529 531 if n < len(blamecache):
530 532 bl, bu, br = blamecache[n]
531 533 if bl == l:
532 534 bd = '%s@%s' % (bu, br)
533 535
534 536 errors.append((f, lineno and n + 1, l, msg, bd))
535 537 result = False
536 538
537 539 errors.sort()
538 540 for e in errors:
539 541 logfunc(*e)
540 542 fc += 1
541 543 if maxerr and fc >= maxerr:
542 544 print " (too many errors, giving up)"
543 545 break
544 546
545 547 return result
546 548
547 549 if __name__ == "__main__":
548 550 parser = optparse.OptionParser("%prog [options] [files]")
549 551 parser.add_option("-w", "--warnings", action="store_true",
550 552 help="include warning-level checks")
551 553 parser.add_option("-p", "--per-file", type="int",
552 554 help="max warnings per file")
553 555 parser.add_option("-b", "--blame", action="store_true",
554 556 help="use annotate to generate blame info")
555 557 parser.add_option("", "--debug", action="store_true",
556 558 help="show debug information")
557 559 parser.add_option("", "--nolineno", action="store_false",
558 560 dest='lineno', help="don't show line numbers")
559 561
560 562 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
561 563 lineno=True)
562 564 (options, args) = parser.parse_args()
563 565
564 566 if len(args) == 0:
565 567 check = glob.glob("*")
566 568 else:
567 569 check = args
568 570
569 571 ret = 0
570 572 for f in check:
571 573 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
572 574 blame=options.blame, debug=options.debug,
573 575 lineno=options.lineno):
574 576 ret = 1
575 577 sys.exit(ret)
@@ -1,346 +1,345 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ initrepo ()
9 9 > {
10 10 > hg init r
11 11 > cd r
12 12 > for x in a b c d e f ; do
13 13 > echo $x > $x
14 14 > hg add $x
15 15 > hg ci -m $x
16 16 > done
17 17 > }
18 18
19 19 $ initrepo
20 20
21 21 log before edit
22 22 $ hg log --graph
23 23 @ changeset: 5:652413bf663e
24 24 | tag: tip
25 25 | user: test
26 26 | date: Thu Jan 01 00:00:00 1970 +0000
27 27 | summary: f
28 28 |
29 29 o changeset: 4:e860deea161a
30 30 | user: test
31 31 | date: Thu Jan 01 00:00:00 1970 +0000
32 32 | summary: e
33 33 |
34 34 o changeset: 3:055a42cdd887
35 35 | user: test
36 36 | date: Thu Jan 01 00:00:00 1970 +0000
37 37 | summary: d
38 38 |
39 39 o changeset: 2:177f92b77385
40 40 | user: test
41 41 | date: Thu Jan 01 00:00:00 1970 +0000
42 42 | summary: c
43 43 |
44 44 o changeset: 1:d2ae7f538514
45 45 | user: test
46 46 | date: Thu Jan 01 00:00:00 1970 +0000
47 47 | summary: b
48 48 |
49 49 o changeset: 0:cb9a9f314b8b
50 50 user: test
51 51 date: Thu Jan 01 00:00:00 1970 +0000
52 52 summary: a
53 53
54 54
55 55 edit the history
56 56 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
57 57 > pick 177f92b77385 c
58 58 > pick 055a42cdd887 d
59 59 > edit e860deea161a e
60 60 > pick 652413bf663e f
61 61 > EOF
62 62 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
63 63 Make changes as needed, you may commit or record as needed now.
64 64 When you are finished, run hg histedit --continue to resume.
65 65
66 66 Go at a random point and try to continue
67 67
68 68 $ hg id -n
69 69 3+
70 70 $ hg up 0
71 71 abort: histedit in progress
72 72 (use 'hg histedit --continue' or 'hg histedit --abort')
73 73 [255]
74 74
75 75 commit, then edit the revision
76 76 $ hg ci -m 'wat'
77 77 created new head
78 78 $ echo a > e
79 79 $ HGEDITOR='echo foobaz > ' hg histedit --continue 2>&1 | fixbundle
80 80 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 81 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 82
83 83 $ hg log --graph
84 84 @ changeset: 6:b5f70786f9b0
85 85 | tag: tip
86 86 | user: test
87 87 | date: Thu Jan 01 00:00:00 1970 +0000
88 88 | summary: f
89 89 |
90 90 o changeset: 5:a5e1ba2f7afb
91 91 | user: test
92 92 | date: Thu Jan 01 00:00:00 1970 +0000
93 93 | summary: foobaz
94 94 |
95 95 o changeset: 4:1a60820cd1f6
96 96 | user: test
97 97 | date: Thu Jan 01 00:00:00 1970 +0000
98 98 | summary: wat
99 99 |
100 100 o changeset: 3:055a42cdd887
101 101 | user: test
102 102 | date: Thu Jan 01 00:00:00 1970 +0000
103 103 | summary: d
104 104 |
105 105 o changeset: 2:177f92b77385
106 106 | user: test
107 107 | date: Thu Jan 01 00:00:00 1970 +0000
108 108 | summary: c
109 109 |
110 110 o changeset: 1:d2ae7f538514
111 111 | user: test
112 112 | date: Thu Jan 01 00:00:00 1970 +0000
113 113 | summary: b
114 114 |
115 115 o changeset: 0:cb9a9f314b8b
116 116 user: test
117 117 date: Thu Jan 01 00:00:00 1970 +0000
118 118 summary: a
119 119
120 120
121 121 $ hg cat e
122 122 a
123 123
124 124 check histedit_source
125 125
126 126 $ hg log --debug --rev 5
127 127 changeset: 5:a5e1ba2f7afb899ef1581cea528fd885d2fca70d
128 128 phase: draft
129 129 parent: 4:1a60820cd1f6004a362aa622ebc47d59bc48eb34
130 130 parent: -1:0000000000000000000000000000000000000000
131 131 manifest: 5:5ad3be8791f39117565557781f5464363b918a45
132 132 user: test
133 133 date: Thu Jan 01 00:00:00 1970 +0000
134 134 files: e
135 135 extra: branch=default
136 136 extra: histedit_source=e860deea161a2f77de56603b340ebbb4536308ae
137 137 description:
138 138 foobaz
139 139
140 140
141 141
142 142 $ hg histedit tip --commands - 2>&1 <<EOF| fixbundle
143 143 > edit b5f70786f9b0 f
144 144 > EOF
145 145 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
146 146 Make changes as needed, you may commit or record as needed now.
147 147 When you are finished, run hg histedit --continue to resume.
148 148 $ hg status
149 149 A f
150 150
151 151 $ hg summary
152 152 parent: 5:a5e1ba2f7afb
153 153 foobaz
154 154 branch: default
155 155 commit: 1 added (new branch head)
156 156 update: 1 new changesets (update)
157 157 hist: 1 remaining (histedit --continue)
158 158
159 159 (test also that editor is invoked if histedit is continued for
160 160 "edit" action)
161 161
162 162 $ HGEDITOR='cat' hg histedit --continue
163 163 f
164 164
165 165
166 166 HG: Enter commit message. Lines beginning with 'HG:' are removed.
167 167 HG: Leave message empty to abort commit.
168 168 HG: --
169 169 HG: user: test
170 170 HG: branch 'default'
171 171 HG: added f
172 172 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
173 173 saved backup bundle to $TESTTMP/r/.hg/strip-backup/b5f70786f9b0-backup.hg (glob)
174 174
175 175 $ hg status
176 176
177 177 log after edit
178 178 $ hg log --limit 1
179 179 changeset: 6:a107ee126658
180 180 tag: tip
181 181 user: test
182 182 date: Thu Jan 01 00:00:00 1970 +0000
183 183 summary: f
184 184
185 185
186 186 say we'll change the message, but don't.
187 187 $ cat > ../edit.sh <<EOF
188 188 > cat "\$1" | sed s/pick/mess/ > tmp
189 189 > mv tmp "\$1"
190 190 > EOF
191 191 $ HGEDITOR="sh ../edit.sh" hg histedit tip 2>&1 | fixbundle
192 192 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
193 193 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
194 194 $ hg status
195 195 $ hg log --limit 1
196 196 changeset: 6:1fd3b2fe7754
197 197 tag: tip
198 198 user: test
199 199 date: Thu Jan 01 00:00:00 1970 +0000
200 200 summary: f
201 201
202 202
203 203 modify the message
204 204
205 205 check saving last-message.txt, at first
206 206
207 207 $ cat > $TESTTMP/commitfailure.py <<EOF
208 208 > from mercurial import util
209 209 > def reposetup(ui, repo):
210 210 > class commitfailure(repo.__class__):
211 211 > def commit(self, *args, **kwargs):
212 212 > raise util.Abort('emulating unexpected abort')
213 213 > repo.__class__ = commitfailure
214 214 > EOF
215 215 $ cat >> .hg/hgrc <<EOF
216 216 > [extensions]
217 217 > # this failure occurs before editor invocation
218 218 > commitfailure = $TESTTMP/commitfailure.py
219 219 > EOF
220 220
221 221 $ cat > $TESTTMP/editor.sh <<EOF
222 222 > echo "==== before editing"
223 223 > cat \$1
224 224 > echo "===="
225 225 > echo "check saving last-message.txt" >> \$1
226 226 > EOF
227 227
228 228 (test that editor is not invoked before transaction starting)
229 229
230 230 $ rm -f .hg/last-message.txt
231 231 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF | fixbundle
232 232 > mess 1fd3b2fe7754 f
233 233 > EOF
234 234 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
235 235 abort: emulating unexpected abort
236 $ cat .hg/last-message.txt
237 cat: .hg/last-message.txt: No such file or directory
236 $ test -f .hg/last-message.txt
238 237 [1]
239 238
240 239 $ cat >> .hg/hgrc <<EOF
241 240 > [extensions]
242 241 > commitfailure = !
243 242 > EOF
244 243 $ hg histedit --abort -q
245 244
246 245 (test that editor is invoked and commit message is saved into
247 246 "last-message.txt")
248 247
249 248 $ cat >> .hg/hgrc <<EOF
250 249 > [hooks]
251 250 > # this failure occurs after editor invocation
252 251 > pretxncommit.unexpectedabort = false
253 252 > EOF
254 253
255 254 $ hg status --rev '1fd3b2fe7754^1' --rev 1fd3b2fe7754
256 255 A f
257 256
258 257 $ rm -f .hg/last-message.txt
259 258 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF
260 259 > mess 1fd3b2fe7754 f
261 260 > EOF
262 261 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
263 262 adding f
264 263 ==== before editing
265 264 f
266 265
267 266
268 267 HG: Enter commit message. Lines beginning with 'HG:' are removed.
269 268 HG: Leave message empty to abort commit.
270 269 HG: --
271 270 HG: user: test
272 271 HG: branch 'default'
273 272 HG: added f
274 273 ====
275 274 transaction abort!
276 275 rollback completed
277 276 note: commit message saved in .hg/last-message.txt
278 277 abort: pretxncommit.unexpectedabort hook exited with status 1
279 278 [255]
280 279 $ cat .hg/last-message.txt
281 280 f
282 281
283 282
284 283 check saving last-message.txt
285 284
286 285 (test also that editor is invoked if histedit is continued for "message"
287 286 action)
288 287
289 288 $ HGEDITOR=cat hg histedit --continue
290 289 f
291 290
292 291
293 292 HG: Enter commit message. Lines beginning with 'HG:' are removed.
294 293 HG: Leave message empty to abort commit.
295 294 HG: --
296 295 HG: user: test
297 296 HG: branch 'default'
298 297 HG: added f
299 298 transaction abort!
300 299 rollback completed
301 300 note: commit message saved in .hg/last-message.txt
302 301 abort: pretxncommit.unexpectedabort hook exited with status 1
303 302 [255]
304 303
305 304 $ cat >> .hg/hgrc <<EOF
306 305 > [hooks]
307 306 > pretxncommit.unexpectedabort =
308 307 > EOF
309 308 $ hg histedit --abort -q
310 309
311 310 then, check "modify the message" itself
312 311
313 312 $ hg histedit tip --commands - 2>&1 << EOF | fixbundle
314 313 > mess 1fd3b2fe7754 f
315 314 > EOF
316 315 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
317 316 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
318 317 $ hg status
319 318 $ hg log --limit 1
320 319 changeset: 6:62feedb1200e
321 320 tag: tip
322 321 user: test
323 322 date: Thu Jan 01 00:00:00 1970 +0000
324 323 summary: f
325 324
326 325
327 326 rollback should not work after a histedit
328 327 $ hg rollback
329 328 no rollback information available
330 329 [1]
331 330
332 331 $ cd ..
333 332 $ hg clone -qr0 r r0
334 333 $ cd r0
335 334 $ hg phase -fdr0
336 335 $ hg histedit --commands - 0 2>&1 << EOF
337 336 > edit cb9a9f314b8b a > $EDITED
338 337 > EOF
339 338 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
340 339 adding a
341 340 Make changes as needed, you may commit or record as needed now.
342 341 When you are finished, run hg histedit --continue to resume.
343 342 [1]
344 343 $ HGEDITOR=true hg histedit --continue
345 344 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
346 345 saved backup bundle to $TESTTMP/r0/.hg/strip-backup/cb9a9f314b8b-backup.hg (glob)
@@ -1,370 +1,369 b''
1 1
2 2 $ echo "[extensions]" >> $HGRCPATH
3 3 $ echo "largefiles =" >> $HGRCPATH
4 4
5 5 Create the repository outside $HOME since largefiles write to
6 6 $HOME/.cache/largefiles.
7 7
8 8 $ hg init test
9 9 $ cd test
10 10 $ echo "root" > root
11 11 $ hg add root
12 12 $ hg commit -m "Root commit"
13 13
14 14 $ echo "large" > foo
15 15 $ hg add --large foo
16 16 $ hg commit -m "Add foo as a largefile"
17 17
18 18 $ hg update -r 0
19 19 getting changed largefiles
20 20 0 largefiles updated, 1 removed
21 21 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
22 22
23 23 $ echo "normal" > foo
24 24 $ hg add foo
25 25 $ hg commit -m "Add foo as normal file"
26 26 created new head
27 27
28 28 Normal file in the working copy, keeping the normal version:
29 29
30 30 $ echo "n" | hg merge --config ui.interactive=Yes
31 31 remote turned local normal file foo into a largefile
32 32 use (l)argefile or keep (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
33 33 (branch merge, don't forget to commit)
34 34 getting changed largefiles
35 35 0 largefiles updated, 0 removed
36 36
37 37 $ hg status
38 38 $ cat foo
39 39 normal
40 40
41 41 Normal file in the working copy, keeping the largefile version:
42 42
43 43 $ hg update -q -C
44 44 $ echo "l" | hg merge --config ui.interactive=Yes
45 45 remote turned local normal file foo into a largefile
46 46 use (l)argefile or keep (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
47 47 (branch merge, don't forget to commit)
48 48 getting changed largefiles
49 49 1 largefiles updated, 0 removed
50 50
51 51 $ hg status
52 52 M foo
53 53
54 54 $ hg diff --nodates
55 55 diff -r fa129ab6b5a7 .hglf/foo
56 56 --- /dev/null
57 57 +++ b/.hglf/foo
58 58 @@ -0,0 +1,1 @@
59 59 +7f7097b041ccf68cc5561e9600da4655d21c6d18
60 60 diff -r fa129ab6b5a7 foo
61 61 --- a/foo
62 62 +++ /dev/null
63 63 @@ -1,1 +0,0 @@
64 64 -normal
65 65
66 66 $ cat foo
67 67 large
68 68
69 69 Largefile in the working copy, keeping the normal version:
70 70
71 71 $ hg update -q -C -r 1
72 72 $ echo "n" | hg merge --config ui.interactive=Yes
73 73 remote turned local largefile foo into a normal file
74 74 keep (l)argefile or use (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
75 75 (branch merge, don't forget to commit)
76 76 getting changed largefiles
77 77 0 largefiles updated, 0 removed
78 78
79 79 $ hg status
80 80 M foo
81 81
82 82 $ hg diff --nodates
83 83 diff -r ff521236428a .hglf/foo
84 84 --- a/.hglf/foo
85 85 +++ /dev/null
86 86 @@ -1,1 +0,0 @@
87 87 -7f7097b041ccf68cc5561e9600da4655d21c6d18
88 88 diff -r ff521236428a foo
89 89 --- /dev/null
90 90 +++ b/foo
91 91 @@ -0,0 +1,1 @@
92 92 +normal
93 93
94 94 $ cat foo
95 95 normal
96 96
97 97 Largefile in the working copy, keeping the largefile version:
98 98
99 99 $ hg update -q -C -r 1
100 100 $ echo "l" | hg merge --config ui.interactive=Yes
101 101 remote turned local largefile foo into a normal file
102 102 keep (l)argefile or use (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
103 103 (branch merge, don't forget to commit)
104 104 getting changed largefiles
105 105 1 largefiles updated, 0 removed
106 106
107 107 $ hg status
108 108
109 109 $ cat foo
110 110 large
111 111
112 112 Whatever ... commit something so we can invoke merge when updating
113 113
114 114 $ hg commit -m '3: Merge'
115 115
116 116 Updating from largefile to normal - no reason to prompt
117 117
118 118 $ hg up -r 2
119 119 getting changed largefiles
120 120 0 largefiles updated, 0 removed
121 121 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
122 122 $ cat foo
123 123 normal
124 124
125 125 (the update above used to leave the working dir in a very weird state - clean it
126 126 $ hg up -qr null
127 127 $ hg up -qr 2
128 128 )
129 129
130 130 Updating from normal to largefile - no reason to prompt
131 131
132 132 $ hg up -r 3
133 133 getting changed largefiles
134 134 1 largefiles updated, 0 removed
135 135 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
136 136 $ cat foo
137 137 large
138 138
139 139 $ cd ..
140 140
141 141
142 142 Systematic testing of merges involving largefiles:
143 143
144 144 Ancestor: normal Parent: normal= Parent: large result: large
145 145 Ancestor: normal Parent: normal2 Parent: large result: ?
146 146 Ancestor: large Parent: large= Parent: normal result: normal
147 147 Ancestor: large Parent: large2 Parent: normal result: ?
148 148
149 149 All cases should try merging both ways.
150 150 "=" means same file content.
151 151
152 152 Prepare test repo:
153 153
154 154 $ hg init merges
155 155 $ cd merges
156 156 $ touch f1
157 157 $ hg ci -Aqm "0-root" --config extensions.largefiles=!
158 158
159 159 Ensure that .hg/largefiles isn't created before largefiles are added
160 160 #if unix-permissions
161 161 $ chmod 555 .hg
162 162 #endif
163 163 $ hg status
164 164 #if unix-permissions
165 165 $ chmod 755 .hg
166 166 #endif
167 167
168 $ find .hg/largefiles
169 find: `.hg/largefiles': No such file or directory
168 $ test -f .hg/largefiles
170 169 [1]
171 170
172 171 ancestor is "normal":
173 172 $ echo normal > f
174 173 $ hg ci -Aqm "1-normal-ancestor"
175 174 $ touch f2
176 175 $ hg ci -Aqm "2-normal-unchanged"
177 176 $ hg tag -l "normal="
178 177 $ echo normal2 > f
179 178 $ hg ci -m "3-normal2"
180 179 $ hg tag -l "normal2"
181 180 $ hg up -qr 1
182 181 $ hg rm f
183 182 $ echo large > f
184 183 $ hg add --large f
185 184 $ hg ci -qm "4-normal-to-large"
186 185 $ hg tag -l "large"
187 186
188 187 $ hg up -qr null
189 188
190 189 ancestor is "large":
191 190 $ echo large > f
192 191 $ hg add --large f
193 192 $ hg ci -qm "5-large-ancestor"
194 193 $ touch f2
195 194 $ hg ci -Aqm "6-large-unchanged"
196 195 $ hg tag -l "large="
197 196 $ echo large2 > f
198 197 $ hg ci -m "7-large2"
199 198 $ hg tag -l "large2"
200 199 $ hg up -qr 5
201 200 $ hg rm f
202 201 $ echo normal > f
203 202 $ hg ci -qAm "8-large-to-normal"
204 203 $ hg tag -l "normal"
205 204
206 205 Ancestor: normal Parent: normal= Parent: large result: large
207 206
208 207 $ hg up -Cqr normal=
209 208 $ hg merge -r large
210 209 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
211 210 (branch merge, don't forget to commit)
212 211 getting changed largefiles
213 212 1 largefiles updated, 0 removed
214 213 $ cat f
215 214 large
216 215
217 216 swap
218 217
219 218 $ hg up -Cqr large
220 219 $ hg merge -r normal=
221 220 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
222 221 (branch merge, don't forget to commit)
223 222 getting changed largefiles
224 223 0 largefiles updated, 0 removed
225 224 $ cat f
226 225 large
227 226
228 227 Ancestor: normal Parent: normal2 Parent: large result: ?
229 228 (annoying extra prompt ... but it do not do any serious harm)
230 229
231 230 $ hg up -Cqr normal2
232 231 $ hg merge -r large
233 232 local changed f which remote deleted
234 233 use (c)hanged version or (d)elete? c
235 234 remote turned local normal file f into a largefile
236 235 use (l)argefile or keep (n)ormal file? l
237 236 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
238 237 (branch merge, don't forget to commit)
239 238 getting changed largefiles
240 239 1 largefiles updated, 0 removed
241 240 $ cat f
242 241 large
243 242
244 243 $ hg up -Cqr normal2
245 244 $ ( echo c; echo n ) | hg merge -r large --config ui.interactive=Yes
246 245 local changed f which remote deleted
247 246 use (c)hanged version or (d)elete? remote turned local normal file f into a largefile
248 247 use (l)argefile or keep (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
249 248 (branch merge, don't forget to commit)
250 249 getting changed largefiles
251 250 0 largefiles updated, 0 removed
252 251 $ cat f
253 252 normal2
254 253
255 254 $ hg up -Cqr normal2
256 255 $ echo d | hg merge -r large --config ui.interactive=Yes
257 256 local changed f which remote deleted
258 257 use (c)hanged version or (d)elete? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
259 258 (branch merge, don't forget to commit)
260 259 getting changed largefiles
261 260 1 largefiles updated, 0 removed
262 261 $ cat f
263 262 large
264 263
265 264 swap
266 265
267 266 $ hg up -Cqr large
268 267 $ hg merge -r normal2
269 268 remote changed f which local deleted
270 269 use (c)hanged version or leave (d)eleted? c
271 270 remote turned local largefile f into a normal file
272 271 keep (l)argefile or use (n)ormal file? l
273 272 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
274 273 (branch merge, don't forget to commit)
275 274 getting changed largefiles
276 275 1 largefiles updated, 0 removed
277 276 $ cat f
278 277 large
279 278
280 279 $ hg up -Cqr large
281 280 $ ( echo c; echo n ) | hg merge -r normal2 --config ui.interactive=Yes
282 281 remote changed f which local deleted
283 282 use (c)hanged version or leave (d)eleted? remote turned local largefile f into a normal file
284 283 keep (l)argefile or use (n)ormal file? 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
285 284 (branch merge, don't forget to commit)
286 285 getting changed largefiles
287 286 0 largefiles updated, 0 removed
288 287 $ cat f
289 288 normal2
290 289
291 290 $ hg up -Cqr large
292 291 $ echo d | hg merge -r normal2 --config ui.interactive=Yes
293 292 remote changed f which local deleted
294 293 use (c)hanged version or leave (d)eleted? 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
295 294 (branch merge, don't forget to commit)
296 295 getting changed largefiles
297 296 0 largefiles updated, 0 removed
298 297 $ cat f
299 298 large
300 299
301 300 Ancestor: large Parent: large= Parent: normal result: normal
302 301
303 302 $ hg up -Cqr large=
304 303 $ hg merge -r normal
305 304 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
306 305 (branch merge, don't forget to commit)
307 306 getting changed largefiles
308 307 0 largefiles updated, 0 removed
309 308 $ cat f
310 309 normal
311 310
312 311 swap
313 312
314 313 $ hg up -Cqr normal
315 314 $ hg merge -r large=
316 315 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
317 316 (branch merge, don't forget to commit)
318 317 $ cat f
319 318 normal
320 319
321 320 Ancestor: large Parent: large2 Parent: normal result: ?
322 321 (annoying extra prompt ... but it do not do any serious harm)
323 322
324 323 $ hg up -Cqr large2
325 324 $ hg merge -r normal
326 325 local changed .hglf/f which remote deleted
327 326 use (c)hanged version or (d)elete? c
328 327 remote turned local largefile f into a normal file
329 328 keep (l)argefile or use (n)ormal file? l
330 329 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
331 330 (branch merge, don't forget to commit)
332 331 getting changed largefiles
333 332 1 largefiles updated, 0 removed
334 333 $ cat f
335 334 large2
336 335
337 336 $ hg up -Cqr large2
338 337 $ echo d | hg merge -r normal --config ui.interactive=Yes
339 338 local changed .hglf/f which remote deleted
340 339 use (c)hanged version or (d)elete? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
341 340 (branch merge, don't forget to commit)
342 341 getting changed largefiles
343 342 0 largefiles updated, 0 removed
344 343 $ cat f
345 344 normal
346 345
347 346 swap
348 347
349 348 $ hg up -Cqr normal
350 349 $ hg merge -r large2
351 350 remote changed .hglf/f which local deleted
352 351 use (c)hanged version or leave (d)eleted? c
353 352 remote turned local normal file f into a largefile
354 353 use (l)argefile or keep (n)ormal file? l
355 354 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
356 355 (branch merge, don't forget to commit)
357 356 getting changed largefiles
358 357 1 largefiles updated, 0 removed
359 358 $ cat f
360 359 large2
361 360
362 361 $ hg up -Cqr normal
363 362 $ echo d | hg merge -r large2 --config ui.interactive=Yes
364 363 remote changed .hglf/f which local deleted
365 364 use (c)hanged version or leave (d)eleted? 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 365 (branch merge, don't forget to commit)
367 366 $ cat f
368 367 normal
369 368
370 369 $ cd ..
@@ -1,262 +1,261 b''
1 1 $ echo "[extensions]" >> $HGRCPATH
2 2 $ echo "mq=" >> $HGRCPATH
3 3 $ echo "[mq]" >> $HGRCPATH
4 4 $ echo "git=keep" >> $HGRCPATH
5 5 $ echo "[diff]" >> $HGRCPATH
6 6 $ echo "nodates=1" >> $HGRCPATH
7 7
8 8 init:
9 9
10 10 $ hg init repo
11 11 $ cd repo
12 12 $ echo a > a
13 13 $ hg ci -Am adda
14 14 adding a
15 15 $ echo a >> a
16 16 $ hg qnew -f p1
17 17 $ echo b >> a
18 18 $ hg qnew -f p2
19 19 $ echo c >> a
20 20 $ hg qnew -f p3
21 21
22 22 Fold in the middle of the queue:
23 23 (this tests also that editor is not invoked if '--edit' is not
24 24 specified)
25 25
26 26 $ hg qpop p1
27 27 popping p3
28 28 popping p2
29 29 now at: p1
30 30
31 31 $ hg qdiff
32 32 diff -r 07f494440405 a
33 33 --- a/a
34 34 +++ b/a
35 35 @@ -1,1 +1,2 @@
36 36 a
37 37 +a
38 38
39 39 $ HGEDITOR=cat hg qfold p2
40 40 $ grep git .hg/patches/p1 && echo 'git patch found!'
41 41 [1]
42 42
43 43 $ hg qser
44 44 p1
45 45 p3
46 46
47 47 $ hg qdiff
48 48 diff -r 07f494440405 a
49 49 --- a/a
50 50 +++ b/a
51 51 @@ -1,1 +1,3 @@
52 52 a
53 53 +a
54 54 +b
55 55
56 56 Fold with local changes:
57 57
58 58 $ echo d >> a
59 59 $ hg qfold p3
60 60 abort: local changes found, refresh first
61 61 [255]
62 62
63 63 $ hg diff -c .
64 64 diff -r 07f494440405 -r ???????????? a (glob)
65 65 --- a/a
66 66 +++ b/a
67 67 @@ -1,1 +1,3 @@
68 68 a
69 69 +a
70 70 +b
71 71
72 72 $ hg revert -a --no-backup
73 73 reverting a
74 74
75 75 Fold git patch into a regular patch, expect git patch:
76 76
77 77 $ echo a >> a
78 78 $ hg qnew -f regular
79 79 $ hg cp a aa
80 80 $ hg qnew --git -f git
81 81
82 82 $ hg qpop
83 83 popping git
84 84 now at: regular
85 85
86 86 $ hg qfold git
87 87
88 88 $ cat .hg/patches/regular
89 89 # HG changeset patch
90 90 # Parent ???????????????????????????????????????? (glob)
91 91
92 92 diff --git a/a b/a
93 93 --- a/a
94 94 +++ b/a
95 95 @@ -1,3 +1,4 @@
96 96 a
97 97 a
98 98 b
99 99 +a
100 100 diff --git a/a b/aa
101 101 copy from a
102 102 copy to aa
103 103 --- a/a
104 104 +++ b/aa
105 105 @@ -1,3 +1,4 @@
106 106 a
107 107 a
108 108 b
109 109 +a
110 110
111 111 $ hg qpop
112 112 popping regular
113 113 now at: p1
114 114
115 115 $ hg qdel regular
116 116
117 117 Fold regular patch into a git patch, expect git patch:
118 118
119 119 $ hg cp a aa
120 120 $ hg qnew --git -f git
121 121 $ echo b >> aa
122 122 $ hg qnew -f regular
123 123
124 124 $ hg qpop
125 125 popping regular
126 126 now at: git
127 127
128 128 $ hg qfold regular
129 129
130 130 $ cat .hg/patches/git
131 131 # HG changeset patch
132 132 # Parent ???????????????????????????????????????? (glob)
133 133
134 134 diff --git a/a b/aa
135 135 copy from a
136 136 copy to aa
137 137 --- a/a
138 138 +++ b/aa
139 139 @@ -1,3 +1,4 @@
140 140 a
141 141 a
142 142 b
143 143 +b
144 144
145 145 Test saving last-message.txt:
146 146
147 147 $ hg qrefresh -m "original message"
148 148
149 149 $ cat > $TESTTMP/commitfailure.py <<EOF
150 150 > from mercurial import util
151 151 > def reposetup(ui, repo):
152 152 > class commitfailure(repo.__class__):
153 153 > def commit(self, *args, **kwargs):
154 154 > raise util.Abort('emulating unexpected abort')
155 155 > repo.__class__ = commitfailure
156 156 > EOF
157 157
158 158 $ cat >> .hg/hgrc <<EOF
159 159 > [extensions]
160 160 > # this failure occurs before editor invocation
161 161 > commitfailure = $TESTTMP/commitfailure.py
162 162 > EOF
163 163
164 164 $ cat > $TESTTMP/editor.sh << EOF
165 165 > echo "==== before editing"
166 166 > cat \$1
167 167 > echo "===="
168 168 > (echo; echo "test saving last-message.txt") >> \$1
169 169 > EOF
170 170
171 171 $ hg qapplied
172 172 p1
173 173 git
174 174 $ hg tip --template "{files}\n"
175 175 aa
176 176
177 177 (test that editor is not invoked before transaction starting,
178 178 and that combination of '--edit' and '--message' doesn't abort execution)
179 179
180 180 $ rm -f .hg/last-message.txt
181 181 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qfold -e -m MESSAGE p3
182 182 refresh interrupted while patch was popped! (revert --all, qpush to recover)
183 183 abort: emulating unexpected abort
184 184 [255]
185 $ cat .hg/last-message.txt
186 cat: .hg/last-message.txt: No such file or directory
185 $ test -f .hg/last-message.txt
187 186 [1]
188 187
189 188 (reset applied patches and directory status)
190 189
191 190 $ cat >> .hg/hgrc <<EOF
192 191 > [extensions]
193 192 > # this failure occurs after editor invocation
194 193 > commitfailure = !
195 194 > EOF
196 195
197 196 $ hg qapplied
198 197 p1
199 198 $ hg status -A aa
200 199 ? aa
201 200 $ rm aa
202 201 $ hg status -m
203 202 M a
204 203 $ hg revert --no-backup -q a
205 204 $ hg qpush -q git
206 205 now at: git
207 206
208 207 (test that editor is invoked and commit message is saved into
209 208 "last-message.txt")
210 209
211 210 $ cat >> .hg/hgrc <<EOF
212 211 > [hooks]
213 212 > # this failure occurs after editor invocation
214 213 > pretxncommit.unexpectedabort = false
215 214 > EOF
216 215
217 216 $ rm -f .hg/last-message.txt
218 217 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qfold -e p3
219 218 ==== before editing
220 219 original message
221 220
222 221
223 222 HG: Enter commit message. Lines beginning with 'HG:' are removed.
224 223 HG: Leave message empty to use default message.
225 224 HG: --
226 225 HG: user: test
227 226 HG: branch 'default'
228 227 HG: added aa
229 228 HG: changed a
230 229 ====
231 230 transaction abort!
232 231 rollback completed
233 232 note: commit message saved in .hg/last-message.txt
234 233 refresh interrupted while patch was popped! (revert --all, qpush to recover)
235 234 abort: pretxncommit.unexpectedabort hook exited with status 1
236 235 [255]
237 236 $ cat .hg/last-message.txt
238 237 original message
239 238
240 239
241 240
242 241 test saving last-message.txt
243 242
244 243 (confirm whether files listed up in the commit message editing are correct)
245 244
246 245 $ cat >> .hg/hgrc <<EOF
247 246 > [hooks]
248 247 > pretxncommit.unexpectedabort =
249 248 > EOF
250 249 $ hg status -u | while read f; do rm ${f}; done
251 250 $ hg revert --no-backup -q --all
252 251 $ hg qpush -q git
253 252 now at: git
254 253 $ hg qpush -q --move p3
255 254 now at: p3
256 255
257 256 $ hg status --rev "git^1" --rev . -arm
258 257 M a
259 258 A aa
260 259
261 260 $ cd ..
262 261
@@ -1,344 +1,343 b''
1 1
2 2 $ catpatch() {
3 3 > cat $1 | sed -e "s/^\(# Parent \).*/\1/"
4 4 > }
5 5 $ echo "[extensions]" >> $HGRCPATH
6 6 $ echo "mq=" >> $HGRCPATH
7 7 $ runtest() {
8 8 > hg init mq
9 9 > cd mq
10 10 >
11 11 > echo a > a
12 12 > hg ci -Ama
13 13 >
14 14 > echo '% qnew should refuse bad patch names'
15 15 > hg qnew series
16 16 > hg qnew status
17 17 > hg qnew guards
18 18 > hg qnew .
19 19 > hg qnew ..
20 20 > hg qnew .hgignore
21 21 > hg qnew .mqfoo
22 22 > hg qnew 'foo#bar'
23 23 > hg qnew 'foo:bar'
24 24 >
25 25 > hg qinit -c
26 26 >
27 27 > echo '% qnew with name containing slash'
28 28 > hg qnew foo/
29 29 > hg qnew foo/bar.patch
30 30 > hg qnew foo
31 31 > hg qseries
32 32 > hg qpop
33 33 > hg qdelete foo/bar.patch
34 34 >
35 35 > echo '% qnew with uncommitted changes'
36 36 > echo a > somefile
37 37 > hg add somefile
38 38 > hg qnew uncommitted.patch
39 39 > hg st
40 40 > hg qseries
41 41 >
42 42 > echo '% qnew implies add'
43 43 > hg -R .hg/patches st
44 44 >
45 45 > echo '% qnew missing'
46 46 > hg qnew missing.patch missing
47 47 >
48 48 > echo '% qnew -m'
49 49 > hg qnew -m 'foo bar' mtest.patch
50 50 > catpatch .hg/patches/mtest.patch
51 51 >
52 52 > echo '% qnew twice'
53 53 > hg qnew first.patch
54 54 > hg qnew first.patch
55 55 >
56 56 > touch ../first.patch
57 57 > hg qimport ../first.patch
58 58 >
59 59 > echo '% qnew -f from a subdirectory'
60 60 > hg qpop -a
61 61 > mkdir d
62 62 > cd d
63 63 > echo b > b
64 64 > hg ci -Am t
65 65 > echo b >> b
66 66 > hg st
67 67 > hg qnew -g -f p
68 68 > catpatch ../.hg/patches/p
69 69 >
70 70 > echo '% qnew -u with no username configured'
71 71 > HGUSER= hg qnew -u blue red
72 72 > catpatch ../.hg/patches/red
73 73 >
74 74 > echo '% qnew -e -u with no username configured'
75 75 > HGUSER= hg qnew -e -u chartreuse fucsia
76 76 > catpatch ../.hg/patches/fucsia
77 77 >
78 78 > echo '% fail when trying to import a merge'
79 79 > hg init merge
80 80 > cd merge
81 81 > touch a
82 82 > hg ci -Am null
83 83 > echo a >> a
84 84 > hg ci -m a
85 85 > hg up -r 0
86 86 > echo b >> a
87 87 > hg ci -m b
88 88 > hg merge -f 1
89 89 > hg resolve --mark a
90 90 > hg qnew -f merge
91 91 >
92 92 > cd ../../..
93 93 > rm -r mq
94 94 > }
95 95
96 96 plain headers
97 97
98 98 $ echo "[mq]" >> $HGRCPATH
99 99 $ echo "plain=true" >> $HGRCPATH
100 100 $ mkdir sandbox
101 101 $ (cd sandbox ; runtest)
102 102 adding a
103 103 % qnew should refuse bad patch names
104 104 abort: "series" cannot be used as the name of a patch
105 105 abort: "status" cannot be used as the name of a patch
106 106 abort: "guards" cannot be used as the name of a patch
107 107 abort: "." cannot be used as the name of a patch
108 108 abort: ".." cannot be used as the name of a patch
109 109 abort: patch name cannot begin with ".hg"
110 110 abort: patch name cannot begin with ".mq"
111 111 abort: "#" cannot be used in the name of a patch
112 112 abort: ":" cannot be used in the name of a patch
113 113 % qnew with name containing slash
114 114 abort: path ends in directory separator: foo/ (glob)
115 115 abort: "foo" already exists as a directory
116 116 foo/bar.patch
117 117 popping foo/bar.patch
118 118 patch queue now empty
119 119 % qnew with uncommitted changes
120 120 uncommitted.patch
121 121 % qnew implies add
122 122 A .hgignore
123 123 A series
124 124 A uncommitted.patch
125 125 % qnew missing
126 126 abort: missing: * (glob)
127 127 % qnew -m
128 128 foo bar
129 129
130 130 % qnew twice
131 131 abort: patch "first.patch" already exists
132 132 abort: patch "first.patch" already exists
133 133 % qnew -f from a subdirectory
134 134 popping first.patch
135 135 popping mtest.patch
136 136 popping uncommitted.patch
137 137 patch queue now empty
138 138 adding d/b
139 139 M d/b
140 140 diff --git a/d/b b/d/b
141 141 --- a/d/b
142 142 +++ b/d/b
143 143 @@ -1,1 +1,2 @@
144 144 b
145 145 +b
146 146 % qnew -u with no username configured
147 147 From: blue
148 148
149 149 % qnew -e -u with no username configured
150 150 From: chartreuse
151 151
152 152 % fail when trying to import a merge
153 153 adding a
154 154 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 155 created new head
156 156 merging a
157 157 warning: conflicts during merge.
158 158 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
159 159 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
160 160 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
161 161 no more unresolved files
162 162 abort: cannot manage merge changesets
163 163 $ rm -r sandbox
164 164
165 165 hg headers
166 166
167 167 $ echo "plain=false" >> $HGRCPATH
168 168 $ mkdir sandbox
169 169 $ (cd sandbox ; runtest)
170 170 adding a
171 171 % qnew should refuse bad patch names
172 172 abort: "series" cannot be used as the name of a patch
173 173 abort: "status" cannot be used as the name of a patch
174 174 abort: "guards" cannot be used as the name of a patch
175 175 abort: "." cannot be used as the name of a patch
176 176 abort: ".." cannot be used as the name of a patch
177 177 abort: patch name cannot begin with ".hg"
178 178 abort: patch name cannot begin with ".mq"
179 179 abort: "#" cannot be used in the name of a patch
180 180 abort: ":" cannot be used in the name of a patch
181 181 % qnew with name containing slash
182 182 abort: path ends in directory separator: foo/ (glob)
183 183 abort: "foo" already exists as a directory
184 184 foo/bar.patch
185 185 popping foo/bar.patch
186 186 patch queue now empty
187 187 % qnew with uncommitted changes
188 188 uncommitted.patch
189 189 % qnew implies add
190 190 A .hgignore
191 191 A series
192 192 A uncommitted.patch
193 193 % qnew missing
194 194 abort: missing: * (glob)
195 195 % qnew -m
196 196 # HG changeset patch
197 197 # Parent
198 198 foo bar
199 199
200 200 % qnew twice
201 201 abort: patch "first.patch" already exists
202 202 abort: patch "first.patch" already exists
203 203 % qnew -f from a subdirectory
204 204 popping first.patch
205 205 popping mtest.patch
206 206 popping uncommitted.patch
207 207 patch queue now empty
208 208 adding d/b
209 209 M d/b
210 210 # HG changeset patch
211 211 # Parent
212 212 diff --git a/d/b b/d/b
213 213 --- a/d/b
214 214 +++ b/d/b
215 215 @@ -1,1 +1,2 @@
216 216 b
217 217 +b
218 218 % qnew -u with no username configured
219 219 # HG changeset patch
220 220 # Parent
221 221 # User blue
222 222 % qnew -e -u with no username configured
223 223 # HG changeset patch
224 224 # Parent
225 225 # User chartreuse
226 226 % fail when trying to import a merge
227 227 adding a
228 228 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 229 created new head
230 230 merging a
231 231 warning: conflicts during merge.
232 232 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
233 233 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
234 234 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
235 235 no more unresolved files
236 236 abort: cannot manage merge changesets
237 237 $ rm -r sandbox
238 238
239 239 Test saving last-message.txt
240 240
241 241 $ hg init repo
242 242 $ cd repo
243 243
244 244 $ cat > $TESTTMP/commitfailure.py <<EOF
245 245 > from mercurial import util
246 246 > def reposetup(ui, repo):
247 247 > class commitfailure(repo.__class__):
248 248 > def commit(self, *args, **kwargs):
249 249 > raise util.Abort('emulating unexpected abort')
250 250 > repo.__class__ = commitfailure
251 251 > EOF
252 252 $ cat >> .hg/hgrc <<EOF
253 253 > [extensions]
254 254 > # this failure occurs before editor invocation
255 255 > commitfailure = $TESTTMP/commitfailure.py
256 256 > EOF
257 257
258 258 $ cat > $TESTTMP/editor.sh << EOF
259 259 > echo "==== before editing"
260 260 > cat \$1
261 261 > echo "===="
262 262 > echo "test saving last-message.txt" >> \$1
263 263 > EOF
264 264
265 265 (test that editor is not invoked before transaction starting)
266 266
267 267 $ rm -f .hg/last-message.txt
268 268 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qnew -e patch
269 269 abort: emulating unexpected abort
270 270 [255]
271 $ cat .hg/last-message.txt
272 cat: .hg/last-message.txt: No such file or directory
271 $ test -f .hg/last-message.txt
273 272 [1]
274 273
275 274 (test that editor is invoked and commit message is saved into
276 275 "last-message.txt")
277 276
278 277 $ cat >> .hg/hgrc <<EOF
279 278 > [extensions]
280 279 > commitfailure = !
281 280 > [hooks]
282 281 > # this failure occurs after editor invocation
283 282 > pretxncommit.unexpectedabort = false
284 283 > EOF
285 284
286 285 $ rm -f .hg/last-message.txt
287 286 $ hg status
288 287 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qnew -e patch
289 288 ==== before editing
290 289
291 290
292 291 HG: Enter commit message. Lines beginning with 'HG:' are removed.
293 292 HG: Leave message empty to use default message.
294 293 HG: --
295 294 HG: user: test
296 295 HG: branch 'default'
297 296 HG: no files changed
298 297 ====
299 298 transaction abort!
300 299 rollback completed
301 300 note: commit message saved in .hg/last-message.txt
302 301 abort: pretxncommit.unexpectedabort hook exited with status 1
303 302 [255]
304 303 $ cat .hg/last-message.txt
305 304
306 305
307 306 test saving last-message.txt
308 307
309 308 $ cat >> .hg/hgrc <<EOF
310 309 > [hooks]
311 310 > pretxncommit.unexpectedabort =
312 311 > EOF
313 312
314 313 #if unix-permissions
315 314
316 315 Test handling default message with the patch filename with tail whitespaces
317 316
318 317 $ cat > $TESTTMP/editor.sh << EOF
319 318 > echo "==== before editing"
320 319 > cat \$1
321 320 > echo "===="
322 321 > echo "[mq]: patch " > \$1
323 322 > EOF
324 323
325 324 $ rm -f .hg/last-message.txt
326 325 $ hg status
327 326 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qnew -e "patch "
328 327 ==== before editing
329 328
330 329
331 330 HG: Enter commit message. Lines beginning with 'HG:' are removed.
332 331 HG: Leave message empty to use default message.
333 332 HG: --
334 333 HG: user: test
335 334 HG: branch 'default'
336 335 HG: no files changed
337 336 ====
338 337 $ cat ".hg/patches/patch "
339 338 # HG changeset patch
340 339 # Parent 0000000000000000000000000000000000000000
341 340
342 341 $ cd ..
343 342
344 343 #endif
@@ -1,192 +1,191 b''
1 1 Environment setup for MQ
2 2
3 3 $ echo "[extensions]" >> $HGRCPATH
4 4 $ echo "mq=" >> $HGRCPATH
5 5 $ hg init
6 6 $ hg qinit
7 7
8 8 Should fail if no patches applied
9 9 (this tests also that editor is not invoked if '--edit' is not
10 10 specified)
11 11
12 12 $ hg qrefresh
13 13 no patches applied
14 14 [1]
15 15 $ hg qrefresh -e
16 16 no patches applied
17 17 [1]
18 18 $ hg qnew -m "First commit message" first-patch
19 19 $ echo aaaa > file
20 20 $ hg add file
21 21 $ HGEDITOR=cat hg qrefresh
22 22
23 23 Should display 'First commit message'
24 24
25 25 $ hg log -l1 --template "{desc}\n"
26 26 First commit message
27 27
28 28 Testing changing message with -m
29 29 (this tests also that '--edit' can be used with '--message', and
30 30 that '[committemplate] changeset' definition and commit log specific
31 31 template keyword 'extramsg' work well)
32 32
33 33 $ cat >> .hg/hgrc <<EOF
34 34 > [committemplate]
35 35 > changeset = HG: this is customized commit template
36 36 > {desc}\n\n
37 37 > HG: Enter commit message. Lines beginning with 'HG:' are removed.
38 38 > HG: {extramsg}
39 39 > HG: --
40 40 > HG: user: {author}
41 41 > HG: branch '{branch}'\n{file_adds %
42 42 > "HG: added {file}\n" }{file_mods %
43 43 > "HG: changed {file}\n" }{file_dels %
44 44 > "HG: removed {file}\n" }{if(files, "",
45 45 > "HG: no files changed\n")}
46 46 > EOF
47 47
48 48 $ echo bbbb > file
49 49 $ HGEDITOR=cat hg qrefresh -m "Second commit message" -e
50 50 HG: this is customized commit template
51 51 Second commit message
52 52
53 53
54 54 HG: Enter commit message. Lines beginning with 'HG:' are removed.
55 55 HG: Leave message empty to use default message.
56 56 HG: --
57 57 HG: user: test
58 58 HG: branch 'default'
59 59 HG: added file
60 60
61 61 $ cat >> .hg/hgrc <<EOF
62 62 > # disable customizing for subsequent tests
63 63 > [committemplate]
64 64 > changeset =
65 65 > EOF
66 66
67 67 Should display 'Second commit message'
68 68
69 69 $ hg log -l1 --template "{desc}\n"
70 70 Second commit message
71 71
72 72 Testing changing message with -l
73 73
74 74 $ echo "Third commit message" > logfile
75 75 $ echo " This is the 3rd log message" >> logfile
76 76 $ echo bbbb > file
77 77 $ hg qrefresh -l logfile
78 78
79 79 Should display 'Third commit message\\\n This is the 3rd log message'
80 80
81 81 $ hg log -l1 --template "{desc}\n"
82 82 Third commit message
83 83 This is the 3rd log message
84 84
85 85 Testing changing message with -l-
86 86
87 87 $ hg qnew -m "First commit message" second-patch
88 88 $ echo aaaa > file2
89 89 $ hg add file2
90 90 $ echo bbbb > file2
91 91 $ (echo "Fifth commit message"; echo " This is the 5th log message") | hg qrefresh -l-
92 92
93 93 Should display 'Fifth commit message\\\n This is the 5th log message'
94 94
95 95 $ hg log -l1 --template "{desc}\n"
96 96 Fifth commit message
97 97 This is the 5th log message
98 98
99 99 Test saving last-message.txt:
100 100
101 101 $ cat > $TESTTMP/editor.sh << EOF
102 102 > echo "==== before editing"
103 103 > cat \$1
104 104 > echo "===="
105 105 > (echo; echo "test saving last-message.txt") >> \$1
106 106 > EOF
107 107
108 108 $ cat > $TESTTMP/commitfailure.py <<EOF
109 109 > from mercurial import util
110 110 > def reposetup(ui, repo):
111 111 > class commitfailure(repo.__class__):
112 112 > def commit(self, *args, **kwargs):
113 113 > raise util.Abort('emulating unexpected abort')
114 114 > repo.__class__ = commitfailure
115 115 > EOF
116 116
117 117 $ cat >> .hg/hgrc <<EOF
118 118 > [extensions]
119 119 > # this failure occurs before editor invocation
120 120 > commitfailure = $TESTTMP/commitfailure.py
121 121 > EOF
122 122
123 123 $ hg qapplied
124 124 first-patch
125 125 second-patch
126 126 $ hg tip --template "{files}\n"
127 127 file2
128 128
129 129 (test that editor is not invoked before transaction starting)
130 130
131 131 $ rm -f .hg/last-message.txt
132 132 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qrefresh -e
133 133 refresh interrupted while patch was popped! (revert --all, qpush to recover)
134 134 abort: emulating unexpected abort
135 135 [255]
136 $ cat .hg/last-message.txt
137 cat: .hg/last-message.txt: No such file or directory
136 $ test -f .hg/last-message.txt
138 137 [1]
139 138
140 139 (reset applied patches and directory status)
141 140
142 141 $ cat >> .hg/hgrc <<EOF
143 142 > [extensions]
144 143 > commitfailure = !
145 144 > EOF
146 145
147 146 $ hg qapplied
148 147 first-patch
149 148 $ hg status -A file2
150 149 ? file2
151 150 $ rm file2
152 151 $ hg qpush -q second-patch
153 152 now at: second-patch
154 153
155 154 (test that editor is invoked and commit message is saved into
156 155 "last-message.txt")
157 156
158 157 $ cat >> .hg/hgrc <<EOF
159 158 > [hooks]
160 159 > # this failure occurs after editor invocation
161 160 > pretxncommit.unexpectedabort = false
162 161 > EOF
163 162
164 163 $ rm -f .hg/last-message.txt
165 164 $ hg status --rev "second-patch^1" -arm
166 165 A file2
167 166 $ HGEDITOR="sh $TESTTMP/editor.sh" hg qrefresh -e
168 167 ==== before editing
169 168 Fifth commit message
170 169 This is the 5th log message
171 170
172 171
173 172 HG: Enter commit message. Lines beginning with 'HG:' are removed.
174 173 HG: Leave message empty to use default message.
175 174 HG: --
176 175 HG: user: test
177 176 HG: branch 'default'
178 177 HG: added file2
179 178 ====
180 179 transaction abort!
181 180 rollback completed
182 181 note: commit message saved in .hg/last-message.txt
183 182 refresh interrupted while patch was popped! (revert --all, qpush to recover)
184 183 abort: pretxncommit.unexpectedabort hook exited with status 1
185 184 [255]
186 185 $ cat .hg/last-message.txt
187 186 Fifth commit message
188 187 This is the 5th log message
189 188
190 189
191 190
192 191 test saving last-message.txt
@@ -1,688 +1,686 b''
1 1 $ "$TESTDIR/hghave" svn15 || exit 80
2 2
3 3 $ SVNREPOPATH=`pwd`/svn-repo
4 4 #if windows
5 5 $ SVNREPOURL=file:///`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
6 6 #else
7 7 $ SVNREPOURL=file://`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
8 8 #endif
9 9
10 10 create subversion repo
11 11
12 12 $ WCROOT="`pwd`/svn-wc"
13 13 $ svnadmin create svn-repo
14 14 $ svn co "$SVNREPOURL" svn-wc
15 15 Checked out revision 0.
16 16 $ cd svn-wc
17 17 $ mkdir src
18 18 $ echo alpha > src/alpha
19 19 $ svn add src
20 20 A src
21 21 A src/alpha (glob)
22 22 $ mkdir externals
23 23 $ echo other > externals/other
24 24 $ svn add externals
25 25 A externals
26 26 A externals/other (glob)
27 27 $ svn ci -m 'Add alpha'
28 28 Adding externals
29 29 Adding externals/other (glob)
30 30 Adding src
31 31 Adding src/alpha (glob)
32 32 Transmitting file data ..
33 33 Committed revision 1.
34 34 $ svn up -q
35 35 $ echo "externals -r1 $SVNREPOURL/externals" > extdef
36 36 $ svn propset -F extdef svn:externals src
37 37 property 'svn:externals' set on 'src'
38 38 $ svn ci -m 'Setting externals'
39 39 Sending src
40 40
41 41 Committed revision 2.
42 42 $ cd ..
43 43
44 44 create hg repo
45 45
46 46 $ mkdir sub
47 47 $ cd sub
48 48 $ hg init t
49 49 $ cd t
50 50
51 51 first revision, no sub
52 52
53 53 $ echo a > a
54 54 $ hg ci -Am0
55 55 adding a
56 56
57 57 add first svn sub with leading whitespaces
58 58
59 59 $ echo "s = [svn] $SVNREPOURL/src" >> .hgsub
60 60 $ echo "subdir/s = [svn] $SVNREPOURL/src" >> .hgsub
61 61 $ svn co --quiet "$SVNREPOURL"/src s
62 62 $ mkdir subdir
63 63 $ svn co --quiet "$SVNREPOURL"/src subdir/s
64 64 $ hg add .hgsub
65 65 $ hg ci -m1
66 66
67 67 make sure we avoid empty commits (issue2445)
68 68
69 69 $ hg sum
70 70 parent: 1:* tip (glob)
71 71 1
72 72 branch: default
73 73 commit: (clean)
74 74 update: (current)
75 75 $ hg ci -moops
76 76 nothing changed
77 77 [1]
78 78
79 79 debugsub
80 80
81 81 $ hg debugsub
82 82 path s
83 83 source file://*/svn-repo/src (glob)
84 84 revision 2
85 85 path subdir/s
86 86 source file://*/svn-repo/src (glob)
87 87 revision 2
88 88
89 89 change file in svn and hg, commit
90 90
91 91 $ echo a >> a
92 92 $ echo alpha >> s/alpha
93 93 $ hg sum
94 94 parent: 1:* tip (glob)
95 95 1
96 96 branch: default
97 97 commit: 1 modified, 1 subrepos
98 98 update: (current)
99 99 $ hg commit --subrepos -m 'Message!' | grep -v Updating
100 100 committing subrepository s
101 101 Sending*s/alpha (glob)
102 102 Transmitting file data .
103 103 Committed revision 3.
104 104
105 105 Fetching external item into '*s/externals'* (glob)
106 106 External at revision 1.
107 107
108 108 At revision 3.
109 109 $ hg debugsub
110 110 path s
111 111 source file://*/svn-repo/src (glob)
112 112 revision 3
113 113 path subdir/s
114 114 source file://*/svn-repo/src (glob)
115 115 revision 2
116 116
117 117 missing svn file, commit should fail
118 118
119 119 $ rm s/alpha
120 120 $ hg commit --subrepos -m 'abort on missing file'
121 121 committing subrepository s
122 122 abort: cannot commit missing svn entries (in subrepo s)
123 123 [255]
124 124 $ svn revert s/alpha > /dev/null
125 125
126 126 add an unrelated revision in svn and update the subrepo to without
127 127 bringing any changes.
128 128
129 129 $ svn mkdir "$SVNREPOURL/unrelated" -m 'create unrelated'
130 130
131 131 Committed revision 4.
132 132 $ svn up -q s
133 133 $ hg sum
134 134 parent: 2:* tip (glob)
135 135 Message!
136 136 branch: default
137 137 commit: (clean)
138 138 update: (current)
139 139
140 140 $ echo a > s/a
141 141
142 142 should be empty despite change to s/a
143 143
144 144 $ hg st
145 145
146 146 add a commit from svn
147 147
148 148 $ cd "$WCROOT/src"
149 149 $ svn up -q
150 150 $ echo xyz >> alpha
151 151 $ svn propset svn:mime-type 'text/xml' alpha
152 152 property 'svn:mime-type' set on 'alpha'
153 153 $ svn ci -m 'amend a from svn'
154 154 Sending *alpha (glob)
155 155 Transmitting file data .
156 156 Committed revision 5.
157 157 $ cd ../../sub/t
158 158
159 159 this commit from hg will fail
160 160
161 161 $ echo zzz >> s/alpha
162 162 $ (hg ci --subrepos -m 'amend alpha from hg' 2>&1; echo "[$?]") | grep -vi 'out of date'
163 163 committing subrepository s
164 164 abort: svn:*Commit failed (details follow): (glob)
165 165 [255]
166 166 $ svn revert -q s/alpha
167 167
168 168 this commit fails because of meta changes
169 169
170 170 $ svn propset svn:mime-type 'text/html' s/alpha
171 171 property 'svn:mime-type' set on 's/alpha' (glob)
172 172 $ (hg ci --subrepos -m 'amend alpha from hg' 2>&1; echo "[$?]") | grep -vi 'out of date'
173 173 committing subrepository s
174 174 abort: svn:*Commit failed (details follow): (glob)
175 175 [255]
176 176 $ svn revert -q s/alpha
177 177
178 178 this commit fails because of externals changes
179 179
180 180 $ echo zzz > s/externals/other
181 181 $ hg ci --subrepos -m 'amend externals from hg'
182 182 committing subrepository s
183 183 abort: cannot commit svn externals (in subrepo s)
184 184 [255]
185 185 $ hg diff --subrepos -r 1:2 | grep -v diff
186 186 --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
187 187 +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
188 188 @@ -1,2 +1,2 @@
189 189 -2 s
190 190 +3 s
191 191 2 subdir/s
192 192 --- a/a Thu Jan 01 00:00:00 1970 +0000
193 193 +++ b/a Thu Jan 01 00:00:00 1970 +0000
194 194 @@ -1,1 +1,2 @@
195 195 a
196 196 +a
197 197 $ svn revert -q s/externals/other
198 198
199 199 this commit fails because of externals meta changes
200 200
201 201 $ svn propset svn:mime-type 'text/html' s/externals/other
202 202 property 'svn:mime-type' set on 's/externals/other' (glob)
203 203 $ hg ci --subrepos -m 'amend externals from hg'
204 204 committing subrepository s
205 205 abort: cannot commit svn externals (in subrepo s)
206 206 [255]
207 207 $ svn revert -q s/externals/other
208 208
209 209 clone
210 210
211 211 $ cd ..
212 212 $ hg clone t tc
213 213 updating to branch default
214 214 A tc/s/alpha (glob)
215 215 U tc/s (glob)
216 216
217 217 Fetching external item into 'tc/s/externals'* (glob)
218 218 A tc/s/externals/other (glob)
219 219 Checked out external at revision 1.
220 220
221 221 Checked out revision 3.
222 222 A tc/subdir/s/alpha (glob)
223 223 U tc/subdir/s (glob)
224 224
225 225 Fetching external item into 'tc/subdir/s/externals'* (glob)
226 226 A tc/subdir/s/externals/other (glob)
227 227 Checked out external at revision 1.
228 228
229 229 Checked out revision 2.
230 230 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 231 $ cd tc
232 232
233 233 debugsub in clone
234 234
235 235 $ hg debugsub
236 236 path s
237 237 source file://*/svn-repo/src (glob)
238 238 revision 3
239 239 path subdir/s
240 240 source file://*/svn-repo/src (glob)
241 241 revision 2
242 242
243 243 verify subrepo is contained within the repo directory
244 244
245 245 $ python -c "import os.path; print os.path.exists('s')"
246 246 True
247 247
248 248 update to nullrev (must delete the subrepo)
249 249
250 250 $ hg up null
251 251 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
252 252 $ ls
253 253
254 254 Check hg update --clean
255 255 $ cd "$TESTTMP/sub/t"
256 256 $ cd s
257 257 $ echo c0 > alpha
258 258 $ echo c1 > f1
259 259 $ echo c1 > f2
260 260 $ svn add f1 -q
261 261 $ svn status | sort
262 262
263 263 ? * a (glob)
264 264 ? * f2 (glob)
265 265 A * f1 (glob)
266 266 M * alpha (glob)
267 267 Performing status on external item at 'externals'* (glob)
268 268 X * externals (glob)
269 269 $ cd ../..
270 270 $ hg -R t update -C
271 271
272 272 Fetching external item into 't/s/externals'* (glob)
273 273 Checked out external at revision 1.
274 274
275 275 Checked out revision 3.
276 276 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
277 277 $ cd t/s
278 278 $ svn status | sort
279 279
280 280 ? * a (glob)
281 281 ? * f1 (glob)
282 282 ? * f2 (glob)
283 283 Performing status on external item at 'externals'* (glob)
284 284 X * externals (glob)
285 285
286 286 Sticky subrepositories, no changes
287 287 $ cd "$TESTTMP/sub/t"
288 288 $ hg id -n
289 289 2
290 290 $ cd s
291 291 $ svnversion
292 292 3
293 293 $ cd ..
294 294 $ hg update 1
295 295 U *s/alpha (glob)
296 296
297 297 Fetching external item into '*s/externals'* (glob)
298 298 Checked out external at revision 1.
299 299
300 300 Checked out revision 2.
301 301 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
302 302 $ hg id -n
303 303 1
304 304 $ cd s
305 305 $ svnversion
306 306 2
307 307 $ cd ..
308 308
309 309 Sticky subrepositories, file changes
310 310 $ touch s/f1
311 311 $ cd s
312 312 $ svn add f1
313 313 A f1
314 314 $ cd ..
315 315 $ hg id -n
316 316 1+
317 317 $ cd s
318 318 $ svnversion
319 319 2M
320 320 $ cd ..
321 321 $ hg update tip
322 322 subrepository s diverged (local revision: 2, remote revision: 3)
323 323 (M)erge, keep (l)ocal or keep (r)emote? m
324 324 subrepository sources for s differ
325 325 use (l)ocal source (2) or (r)emote source (3)?
326 326 l
327 327 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
328 328 $ hg id -n
329 329 2+
330 330 $ cd s
331 331 $ svnversion
332 332 2M
333 333 $ cd ..
334 334 $ hg update --clean tip
335 335 U *s/alpha (glob)
336 336
337 337 Fetching external item into '*s/externals'* (glob)
338 338 Checked out external at revision 1.
339 339
340 340 Checked out revision 3.
341 341 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
342 342
343 343 Sticky subrepository, revision updates
344 344 $ hg id -n
345 345 2
346 346 $ cd s
347 347 $ svnversion
348 348 3
349 349 $ cd ..
350 350 $ cd s
351 351 $ svn update -qr 1
352 352 $ cd ..
353 353 $ hg update 1
354 354 subrepository s diverged (local revision: 3, remote revision: 2)
355 355 (M)erge, keep (l)ocal or keep (r)emote? m
356 356 subrepository sources for s differ (in checked out version)
357 357 use (l)ocal source (1) or (r)emote source (2)?
358 358 l
359 359 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
360 360 $ hg id -n
361 361 1+
362 362 $ cd s
363 363 $ svnversion
364 364 1
365 365 $ cd ..
366 366
367 367 Sticky subrepository, file changes and revision updates
368 368 $ touch s/f1
369 369 $ cd s
370 370 $ svn add f1
371 371 A f1
372 372 $ svnversion
373 373 1M
374 374 $ cd ..
375 375 $ hg id -n
376 376 1+
377 377 $ hg update tip
378 378 subrepository s diverged (local revision: 3, remote revision: 3)
379 379 (M)erge, keep (l)ocal or keep (r)emote? m
380 380 subrepository sources for s differ
381 381 use (l)ocal source (1) or (r)emote source (3)?
382 382 l
383 383 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
384 384 $ hg id -n
385 385 2+
386 386 $ cd s
387 387 $ svnversion
388 388 1M
389 389 $ cd ..
390 390
391 391 Sticky repository, update --clean
392 392 $ hg update --clean tip | grep -v 's[/\]externals[/\]other'
393 393 U *s/alpha (glob)
394 394 U *s (glob)
395 395
396 396 Fetching external item into '*s/externals'* (glob)
397 397 Checked out external at revision 1.
398 398
399 399 Checked out revision 3.
400 400 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
401 401 $ hg id -n
402 402 2
403 403 $ cd s
404 404 $ svnversion
405 405 3
406 406 $ cd ..
407 407
408 408 Test subrepo already at intended revision:
409 409 $ cd s
410 410 $ svn update -qr 2
411 411 $ cd ..
412 412 $ hg update 1
413 413 subrepository s diverged (local revision: 3, remote revision: 2)
414 414 (M)erge, keep (l)ocal or keep (r)emote? m
415 415 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
416 416 $ hg id -n
417 417 1+
418 418 $ cd s
419 419 $ svnversion
420 420 2
421 421 $ cd ..
422 422
423 423 Test case where subversion would fail to update the subrepo because there
424 424 are unknown directories being replaced by tracked ones (happens with rebase).
425 425
426 426 $ cd "$WCROOT/src"
427 427 $ mkdir dir
428 428 $ echo epsilon.py > dir/epsilon.py
429 429 $ svn add dir
430 430 A dir
431 431 A dir/epsilon.py (glob)
432 432 $ svn ci -m 'Add dir/epsilon.py'
433 433 Adding *dir (glob)
434 434 Adding *dir/epsilon.py (glob)
435 435 Transmitting file data .
436 436 Committed revision 6.
437 437 $ cd ../..
438 438 $ hg init rebaserepo
439 439 $ cd rebaserepo
440 440 $ svn co -r5 --quiet "$SVNREPOURL"/src s
441 441 $ echo "s = [svn] $SVNREPOURL/src" >> .hgsub
442 442 $ hg add .hgsub
443 443 $ hg ci -m addsub
444 444 $ echo a > a
445 445 $ hg ci -Am adda
446 446 adding a
447 447 $ hg up 0
448 448 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
449 449 $ svn up -qr6 s
450 450 $ hg ci -m updatesub
451 451 created new head
452 452 $ echo pyc > s/dir/epsilon.pyc
453 453 $ hg up 1
454 454 D *s/dir (glob)
455 455
456 456 Fetching external item into '*s/externals'* (glob)
457 457 Checked out external at revision 1.
458 458
459 459 Checked out revision 5.
460 460 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
461 461 $ hg up -q 2
462 462
463 463 Modify one of the externals to point to a different path so we can
464 464 test having obstructions when switching branches on checkout:
465 465 $ hg checkout tip
466 466 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
467 467 $ echo "obstruct = [svn] $SVNREPOURL/externals" >> .hgsub
468 468 $ svn co -r5 --quiet "$SVNREPOURL"/externals obstruct
469 469 $ hg commit -m 'Start making obstructed working copy'
470 470 $ hg book other
471 471 $ hg co -r 'p1(tip)'
472 472 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
473 473 (leaving bookmark other)
474 474 $ echo "obstruct = [svn] $SVNREPOURL/src" >> .hgsub
475 475 $ svn co -r5 --quiet "$SVNREPOURL"/src obstruct
476 476 $ hg commit -m 'Other branch which will be obstructed'
477 477 created new head
478 478
479 479 Switching back to the head where we have another path mapped to the
480 480 same subrepo should work if the subrepo is clean.
481 481 $ hg co other
482 482 A *obstruct/other (glob)
483 483 Checked out revision 1.
484 484 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
485 485 (activating bookmark other)
486 486
487 487 This is surprising, but is also correct based on the current code:
488 488 $ echo "updating should (maybe) fail" > obstruct/other
489 489 $ hg co tip
490 490 abort: uncommitted changes
491 491 (commit or update --clean to discard changes)
492 492 [255]
493 493
494 494 Point to a Subversion branch which has since been deleted and recreated
495 495 First, create that condition in the repository.
496 496
497 497 $ hg ci --subrepos -m cleanup | grep -v Updating
498 498 committing subrepository obstruct
499 499 Sending obstruct/other (glob)
500 500 Transmitting file data .
501 501 Committed revision 7.
502 502 At revision 7.
503 503 $ svn mkdir -m "baseline" $SVNREPOURL/trunk
504 504
505 505 Committed revision 8.
506 506 $ svn copy -m "initial branch" $SVNREPOURL/trunk $SVNREPOURL/branch
507 507
508 508 Committed revision 9.
509 509 $ svn co --quiet "$SVNREPOURL"/branch tempwc
510 510 $ cd tempwc
511 511 $ echo "something old" > somethingold
512 512 $ svn add somethingold
513 513 A somethingold
514 514 $ svn ci -m 'Something old'
515 515 Adding somethingold
516 516 Transmitting file data .
517 517 Committed revision 10.
518 518 $ svn rm -m "remove branch" $SVNREPOURL/branch
519 519
520 520 Committed revision 11.
521 521 $ svn copy -m "recreate branch" $SVNREPOURL/trunk $SVNREPOURL/branch
522 522
523 523 Committed revision 12.
524 524 $ svn up -q
525 525 $ echo "something new" > somethingnew
526 526 $ svn add somethingnew
527 527 A somethingnew
528 528 $ svn ci -m 'Something new'
529 529 Adding somethingnew
530 530 Transmitting file data .
531 531 Committed revision 13.
532 532 $ cd ..
533 533 $ rm -rf tempwc
534 534 $ svn co "$SVNREPOURL/branch"@10 recreated
535 535 A recreated/somethingold (glob)
536 536 Checked out revision 10.
537 537 $ echo "recreated = [svn] $SVNREPOURL/branch" >> .hgsub
538 538 $ hg ci -m addsub
539 539 $ cd recreated
540 540 $ svn up -q
541 541 $ cd ..
542 542 $ hg ci -m updatesub
543 543 $ hg up -r-2
544 544 D *recreated/somethingnew (glob)
545 545 A *recreated/somethingold (glob)
546 546 Checked out revision 10.
547 547 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
548 548 (leaving bookmark other)
549 549 $ test -f recreated/somethingold
550 550
551 551 Test archive
552 552
553 553 $ hg archive -S ../archive-all --debug
554 554 archiving: 0/2 files (0.00%)
555 555 archiving: .hgsub 1/2 files (50.00%)
556 556 archiving: .hgsubstate 2/2 files (100.00%)
557 557 archiving (obstruct): 0/1 files (0.00%)
558 558 archiving (obstruct): 1/1 files (100.00%)
559 559 archiving (recreated): 0/1 files (0.00%)
560 560 archiving (recreated): 1/1 files (100.00%)
561 561 archiving (s): 0/2 files (0.00%)
562 562 archiving (s): 1/2 files (50.00%)
563 563 archiving (s): 2/2 files (100.00%)
564 564
565 565 $ hg archive -S ../archive-exclude --debug -X **old
566 566 archiving: 0/2 files (0.00%)
567 567 archiving: .hgsub 1/2 files (50.00%)
568 568 archiving: .hgsubstate 2/2 files (100.00%)
569 569 archiving (obstruct): 0/1 files (0.00%)
570 570 archiving (obstruct): 1/1 files (100.00%)
571 571 archiving (recreated): 0 files
572 572 archiving (s): 0/2 files (0.00%)
573 573 archiving (s): 1/2 files (50.00%)
574 574 archiving (s): 2/2 files (100.00%)
575 575 $ find ../archive-exclude | sort
576 576 ../archive-exclude
577 577 ../archive-exclude/.hg_archival.txt
578 578 ../archive-exclude/.hgsub
579 579 ../archive-exclude/.hgsubstate
580 580 ../archive-exclude/obstruct
581 581 ../archive-exclude/obstruct/other
582 582 ../archive-exclude/s
583 583 ../archive-exclude/s/alpha
584 584 ../archive-exclude/s/dir
585 585 ../archive-exclude/s/dir/epsilon.py
586 586
587 587 Test forgetting files, not implemented in svn subrepo, used to
588 588 traceback
589 589
590 590 #if no-windows
591 591 $ hg forget 'notafile*'
592 592 notafile*: No such file or directory
593 593 [1]
594 594 #else
595 595 $ hg forget 'notafile'
596 596 notafile: * (glob)
597 597 [1]
598 598 #endif
599 599
600 600 Test a subrepo referencing a just moved svn path. Last commit rev will
601 601 be different from the revision, and the path will be different as
602 602 well.
603 603
604 604 $ cd "$WCROOT"
605 605 $ svn up > /dev/null
606 606 $ mkdir trunk/subdir branches
607 607 $ echo a > trunk/subdir/a
608 608 $ svn add trunk/subdir branches
609 609 A trunk/subdir (glob)
610 610 A trunk/subdir/a (glob)
611 611 A branches
612 612 $ svn ci -m addsubdir
613 613 Adding branches
614 614 Adding trunk/subdir (glob)
615 615 Adding trunk/subdir/a (glob)
616 616 Transmitting file data .
617 617 Committed revision 14.
618 618 $ svn cp -m branchtrunk $SVNREPOURL/trunk $SVNREPOURL/branches/somebranch
619 619
620 620 Committed revision 15.
621 621 $ cd ..
622 622
623 623 $ hg init repo2
624 624 $ cd repo2
625 625 $ svn co $SVNREPOURL/branches/somebranch/subdir
626 626 A subdir/a (glob)
627 627 Checked out revision 15.
628 628 $ echo "subdir = [svn] $SVNREPOURL/branches/somebranch/subdir" > .hgsub
629 629 $ hg add .hgsub
630 630 $ hg ci -m addsub
631 631 $ hg up null
632 632 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
633 633 $ hg up
634 634 A *subdir/a (glob)
635 635 Checked out revision 15.
636 636 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
637 637 $ cd ..
638 638
639 639 Test sanitizing ".hg/hgrc" in subrepo
640 640
641 641 $ cd sub/t
642 642 $ hg update -q -C tip
643 643 $ cd s
644 644 $ mkdir .hg
645 645 $ echo '.hg/hgrc in svn repo' > .hg/hgrc
646 646 $ mkdir -p sub/.hg
647 647 $ echo 'sub/.hg/hgrc in svn repo' > sub/.hg/hgrc
648 648 $ svn add .hg sub
649 649 A .hg
650 650 A .hg/hgrc (glob)
651 651 A sub
652 652 A sub/.hg (glob)
653 653 A sub/.hg/hgrc (glob)
654 654 $ svn ci -m 'add .hg/hgrc to be sanitized at hg update'
655 655 Adding .hg
656 656 Adding .hg/hgrc (glob)
657 657 Adding sub
658 658 Adding sub/.hg (glob)
659 659 Adding sub/.hg/hgrc (glob)
660 660 Transmitting file data ..
661 661 Committed revision 16.
662 662 $ svn up -q
663 663 $ cd ..
664 664 $ hg commit -S -m 'commit with svn revision including .hg/hgrc'
665 665 $ grep ' s$' .hgsubstate
666 666 16 s
667 667 $ cd ..
668 668
669 669 $ hg -R tc pull -u -q 2>&1 | sort
670 670 warning: removing potentially hostile 'hgrc' in '$TESTTMP/sub/tc/s/.hg' (glob)
671 671 warning: removing potentially hostile 'hgrc' in '$TESTTMP/sub/tc/s/sub/.hg' (glob)
672 672 $ cd tc
673 673 $ grep ' s$' .hgsubstate
674 674 16 s
675 $ cat s/.hg/hgrc
676 cat: s/.hg/hgrc: No such file or directory
675 $ test -f s/.hg/hgrc
677 676 [1]
678 $ cat s/sub/.hg/hgrc
679 cat: s/sub/.hg/hgrc: No such file or directory
677 $ test -f s/sub/.hg/hgrc
680 678 [1]
681 679
682 680 Test that sanitizing is omitted in meta data area:
683 681
684 682 $ mkdir s/.svn/.hg
685 683 $ echo '.hg/hgrc in svn metadata area' > s/.svn/.hg/hgrc
686 684 $ hg update -q -C '.^1'
687 685
688 686 $ cd ../..
@@ -1,606 +1,605 b''
1 1 $ hg init test
2 2 $ cd test
3 3
4 4 $ echo a > a
5 5 $ hg add a
6 6 $ hg commit -m "test"
7 7 $ hg history
8 8 changeset: 0:acb14030fe0a
9 9 tag: tip
10 10 user: test
11 11 date: Thu Jan 01 00:00:00 1970 +0000
12 12 summary: test
13 13
14 14
15 15 $ hg tag ' '
16 16 abort: tag names cannot consist entirely of whitespace
17 17 [255]
18 18
19 19 (this tests also that editor is not invoked, if '--edit' is not
20 20 specified)
21 21
22 22 $ HGEDITOR=cat hg tag "bleah"
23 23 $ hg history
24 24 changeset: 1:d4f0d2909abc
25 25 tag: tip
26 26 user: test
27 27 date: Thu Jan 01 00:00:00 1970 +0000
28 28 summary: Added tag bleah for changeset acb14030fe0a
29 29
30 30 changeset: 0:acb14030fe0a
31 31 tag: bleah
32 32 user: test
33 33 date: Thu Jan 01 00:00:00 1970 +0000
34 34 summary: test
35 35
36 36
37 37 $ echo foo >> .hgtags
38 38 $ hg tag "bleah2"
39 39 abort: working copy of .hgtags is changed (please commit .hgtags manually)
40 40 [255]
41 41
42 42 $ hg revert .hgtags
43 43 $ hg tag -r 0 x y z y y z
44 44 abort: tag names must be unique
45 45 [255]
46 46 $ hg tag tap nada dot tip
47 47 abort: the name 'tip' is reserved
48 48 [255]
49 49 $ hg tag .
50 50 abort: the name '.' is reserved
51 51 [255]
52 52 $ hg tag null
53 53 abort: the name 'null' is reserved
54 54 [255]
55 55 $ hg tag "bleah"
56 56 abort: tag 'bleah' already exists (use -f to force)
57 57 [255]
58 58 $ hg tag "blecch" "bleah"
59 59 abort: tag 'bleah' already exists (use -f to force)
60 60 [255]
61 61
62 62 $ hg tag --remove "blecch"
63 63 abort: tag 'blecch' does not exist
64 64 [255]
65 65 $ hg tag --remove "bleah" "blecch" "blough"
66 66 abort: tag 'blecch' does not exist
67 67 [255]
68 68
69 69 $ hg tag -r 0 "bleah0"
70 70 $ hg tag -l -r 1 "bleah1"
71 71 $ hg tag gack gawk gorp
72 72 $ hg tag -f gack
73 73 $ hg tag --remove gack gorp
74 74
75 75 $ hg tag "bleah "
76 76 abort: tag 'bleah' already exists (use -f to force)
77 77 [255]
78 78 $ hg tag " bleah"
79 79 abort: tag 'bleah' already exists (use -f to force)
80 80 [255]
81 81 $ hg tag " bleah"
82 82 abort: tag 'bleah' already exists (use -f to force)
83 83 [255]
84 84 $ hg tag -r 0 " bleahbleah "
85 85 $ hg tag -r 0 " bleah bleah "
86 86
87 87 $ cat .hgtags
88 88 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
89 89 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
90 90 336fccc858a4eb69609a291105009e484a6b6b8d gack
91 91 336fccc858a4eb69609a291105009e484a6b6b8d gawk
92 92 336fccc858a4eb69609a291105009e484a6b6b8d gorp
93 93 336fccc858a4eb69609a291105009e484a6b6b8d gack
94 94 799667b6f2d9b957f73fa644a918c2df22bab58f gack
95 95 799667b6f2d9b957f73fa644a918c2df22bab58f gack
96 96 0000000000000000000000000000000000000000 gack
97 97 336fccc858a4eb69609a291105009e484a6b6b8d gorp
98 98 0000000000000000000000000000000000000000 gorp
99 99 acb14030fe0a21b60322c440ad2d20cf7685a376 bleahbleah
100 100 acb14030fe0a21b60322c440ad2d20cf7685a376 bleah bleah
101 101
102 102 $ cat .hg/localtags
103 103 d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
104 104
105 105 tagging on a non-head revision
106 106
107 107 $ hg update 0
108 108 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
109 109 $ hg tag -l localblah
110 110 $ hg tag "foobar"
111 111 abort: not at a branch head (use -f to force)
112 112 [255]
113 113 $ hg tag -f "foobar"
114 114 $ cat .hgtags
115 115 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
116 116 $ cat .hg/localtags
117 117 d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
118 118 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
119 119
120 120 $ hg tag -l 'xx
121 121 > newline'
122 122 abort: '\n' cannot be used in a name
123 123 [255]
124 124 $ hg tag -l 'xx:xx'
125 125 abort: ':' cannot be used in a name
126 126 [255]
127 127
128 128 cloning local tags
129 129
130 130 $ cd ..
131 131 $ hg -R test log -r0:5
132 132 changeset: 0:acb14030fe0a
133 133 tag: bleah
134 134 tag: bleah bleah
135 135 tag: bleah0
136 136 tag: bleahbleah
137 137 tag: foobar
138 138 tag: localblah
139 139 user: test
140 140 date: Thu Jan 01 00:00:00 1970 +0000
141 141 summary: test
142 142
143 143 changeset: 1:d4f0d2909abc
144 144 tag: bleah1
145 145 user: test
146 146 date: Thu Jan 01 00:00:00 1970 +0000
147 147 summary: Added tag bleah for changeset acb14030fe0a
148 148
149 149 changeset: 2:336fccc858a4
150 150 tag: gawk
151 151 user: test
152 152 date: Thu Jan 01 00:00:00 1970 +0000
153 153 summary: Added tag bleah0 for changeset acb14030fe0a
154 154
155 155 changeset: 3:799667b6f2d9
156 156 user: test
157 157 date: Thu Jan 01 00:00:00 1970 +0000
158 158 summary: Added tag gack, gawk, gorp for changeset 336fccc858a4
159 159
160 160 changeset: 4:154eeb7c0138
161 161 user: test
162 162 date: Thu Jan 01 00:00:00 1970 +0000
163 163 summary: Added tag gack for changeset 799667b6f2d9
164 164
165 165 changeset: 5:b4bb47aaff09
166 166 user: test
167 167 date: Thu Jan 01 00:00:00 1970 +0000
168 168 summary: Removed tag gack, gorp
169 169
170 170 $ hg clone -q -rbleah1 test test1
171 171 $ hg -R test1 parents --style=compact
172 172 1[tip] d4f0d2909abc 1970-01-01 00:00 +0000 test
173 173 Added tag bleah for changeset acb14030fe0a
174 174
175 175 $ hg clone -q -r5 test#bleah1 test2
176 176 $ hg -R test2 parents --style=compact
177 177 5[tip] b4bb47aaff09 1970-01-01 00:00 +0000 test
178 178 Removed tag gack, gorp
179 179
180 180 $ hg clone -q -U test#bleah1 test3
181 181 $ hg -R test3 parents --style=compact
182 182
183 183 $ cd test
184 184
185 185 Issue601: hg tag doesn't do the right thing if .hgtags or localtags
186 186 doesn't end with EOL
187 187
188 188 $ python << EOF
189 189 > f = file('.hg/localtags'); last = f.readlines()[-1][:-1]; f.close()
190 190 > f = file('.hg/localtags', 'w'); f.write(last); f.close()
191 191 > EOF
192 192 $ cat .hg/localtags; echo
193 193 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
194 194 $ hg tag -l localnewline
195 195 $ cat .hg/localtags; echo
196 196 acb14030fe0a21b60322c440ad2d20cf7685a376 localblah
197 197 c2899151f4e76890c602a2597a650a72666681bf localnewline
198 198
199 199
200 200 $ python << EOF
201 201 > f = file('.hgtags'); last = f.readlines()[-1][:-1]; f.close()
202 202 > f = file('.hgtags', 'w'); f.write(last); f.close()
203 203 > EOF
204 204 $ hg ci -m'broken manual edit of .hgtags'
205 205 $ cat .hgtags; echo
206 206 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
207 207 $ hg tag newline
208 208 $ cat .hgtags; echo
209 209 acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
210 210 a0eea09de1eeec777b46f2085260a373b2fbc293 newline
211 211
212 212
213 213 tag and branch using same name
214 214
215 215 $ hg branch tag-and-branch-same-name
216 216 marked working directory as branch tag-and-branch-same-name
217 217 (branches are permanent and global, did you want a bookmark?)
218 218 $ hg ci -m"discouraged"
219 219 $ hg tag tag-and-branch-same-name
220 220 warning: tag tag-and-branch-same-name conflicts with existing branch name
221 221
222 222 test custom commit messages
223 223
224 224 $ cat > editor.sh << '__EOF__'
225 225 > echo "==== before editing"
226 226 > cat "$1"
227 227 > echo "===="
228 228 > echo "custom tag message" > "$1"
229 229 > echo "second line" >> "$1"
230 230 > __EOF__
231 231
232 232 at first, test saving last-message.txt
233 233
234 234 (test that editor is not invoked before transaction starting)
235 235
236 236 $ cat > .hg/hgrc << '__EOF__'
237 237 > [hooks]
238 238 > # this failure occurs before editor invocation
239 239 > pretag.test-saving-lastmessage = false
240 240 > __EOF__
241 241 $ rm -f .hg/last-message.txt
242 242 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
243 243 abort: pretag.test-saving-lastmessage hook exited with status 1
244 244 [255]
245 $ cat .hg/last-message.txt
246 cat: .hg/last-message.txt: No such file or directory
245 $ test -f .hg/last-message.txt
247 246 [1]
248 247
249 248 (test that editor is invoked and commit message is saved into
250 249 "last-message.txt")
251 250
252 251 $ cat >> .hg/hgrc << '__EOF__'
253 252 > [hooks]
254 253 > pretag.test-saving-lastmessage =
255 254 > # this failure occurs after editor invocation
256 255 > pretxncommit.unexpectedabort = false
257 256 > __EOF__
258 257
259 258 (this tests also that editor is invoked, if '--edit' is specified,
260 259 regardless of '--message')
261 260
262 261 $ rm -f .hg/last-message.txt
263 262 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e -m "foo bar"
264 263 ==== before editing
265 264 foo bar
266 265
267 266
268 267 HG: Enter commit message. Lines beginning with 'HG:' are removed.
269 268 HG: Leave message empty to abort commit.
270 269 HG: --
271 270 HG: user: test
272 271 HG: branch 'tag-and-branch-same-name'
273 272 HG: changed .hgtags
274 273 ====
275 274 transaction abort!
276 275 rollback completed
277 276 note: commit message saved in .hg/last-message.txt
278 277 abort: pretxncommit.unexpectedabort hook exited with status 1
279 278 [255]
280 279 $ cat .hg/last-message.txt
281 280 custom tag message
282 281 second line
283 282
284 283 $ cat >> .hg/hgrc << '__EOF__'
285 284 > [hooks]
286 285 > pretxncommit.unexpectedabort =
287 286 > __EOF__
288 287 $ hg status .hgtags
289 288 M .hgtags
290 289 $ hg revert --no-backup -q .hgtags
291 290
292 291 then, test custom commit message itself
293 292
294 293 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg tag custom-tag -e
295 294 ==== before editing
296 295 Added tag custom-tag for changeset 75a534207be6
297 296
298 297
299 298 HG: Enter commit message. Lines beginning with 'HG:' are removed.
300 299 HG: Leave message empty to abort commit.
301 300 HG: --
302 301 HG: user: test
303 302 HG: branch 'tag-and-branch-same-name'
304 303 HG: changed .hgtags
305 304 ====
306 305 $ hg log -l1 --template "{desc}\n"
307 306 custom tag message
308 307 second line
309 308
310 309
311 310 local tag with .hgtags modified
312 311
313 312 $ hg tag hgtags-modified
314 313 $ hg rollback
315 314 repository tip rolled back to revision 13 (undo commit)
316 315 working directory now based on revision 13
317 316 $ hg st
318 317 M .hgtags
319 318 ? .hgtags.orig
320 319 ? editor.sh
321 320 $ hg tag --local baz
322 321 $ hg revert --no-backup .hgtags
323 322
324 323
325 324 tagging when at named-branch-head that's not a topo-head
326 325
327 326 $ hg up default
328 327 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 328 $ hg merge -t internal:local
330 329 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
331 330 (branch merge, don't forget to commit)
332 331 $ hg ci -m 'merge named branch'
333 332 $ hg up 13
334 333 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 334 $ hg tag new-topo-head
336 335
337 336 tagging on null rev
338 337
339 338 $ hg up null
340 339 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
341 340 $ hg tag nullrev
342 341 abort: not at a branch head (use -f to force)
343 342 [255]
344 343
345 344 $ hg init empty
346 345 $ hg tag -R empty nullrev
347 346 abort: cannot tag null revision
348 347 [255]
349 348
350 349 $ hg tag -R empty -r 00000000000 -f nulltag
351 350 abort: cannot tag null revision
352 351 [255]
353 352
354 353 $ cd ..
355 354
356 355 tagging on an uncommitted merge (issue2542)
357 356
358 357 $ hg init repo-tag-uncommitted-merge
359 358 $ cd repo-tag-uncommitted-merge
360 359 $ echo c1 > f1
361 360 $ hg ci -Am0
362 361 adding f1
363 362 $ echo c2 > f2
364 363 $ hg ci -Am1
365 364 adding f2
366 365 $ hg co -q 0
367 366 $ hg branch b1
368 367 marked working directory as branch b1
369 368 (branches are permanent and global, did you want a bookmark?)
370 369 $ hg ci -m2
371 370 $ hg up default
372 371 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 372 $ hg merge b1
374 373 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 374 (branch merge, don't forget to commit)
376 375
377 376 $ hg tag t1
378 377 abort: uncommitted merge
379 378 [255]
380 379 $ hg status
381 380 $ hg tag --rev 1 t2
382 381 abort: uncommitted merge
383 382 [255]
384 383 $ hg tag --rev 1 --local t3
385 384 $ hg tags -v
386 385 tip 2:2a156e8887cc
387 386 t3 1:c3adabd1a5f4 local
388 387
389 388 $ cd ..
390 389
391 390 commit hook on tag used to be run without write lock - issue3344
392 391
393 392 $ hg init repo-tag
394 393 $ touch repo-tag/test
395 394 $ hg -R repo-tag commit -A -m "test"
396 395 adding test
397 396 $ hg init repo-tag-target
398 397 $ hg -R repo-tag --config hooks.commit="\"hg\" push \"`pwd`/repo-tag-target\"" tag tag
399 398 pushing to $TESTTMP/repo-tag-target (glob)
400 399 searching for changes
401 400 adding changesets
402 401 adding manifests
403 402 adding file changes
404 403 added 2 changesets with 2 changes to 2 files
405 404
406 405 automatically merge resolvable tag conflicts (i.e. tags that differ in rank)
407 406 create two clones with some different tags as well as some common tags
408 407 check that we can merge tags that differ in rank
409 408
410 409 $ hg init repo-automatic-tag-merge
411 410 $ cd repo-automatic-tag-merge
412 411 $ echo c0 > f0
413 412 $ hg ci -A -m0
414 413 adding f0
415 414 $ hg tag tbase
416 415 $ cd ..
417 416 $ hg clone repo-automatic-tag-merge repo-automatic-tag-merge-clone
418 417 updating to branch default
419 418 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 419 $ cd repo-automatic-tag-merge-clone
421 420 $ echo c1 > f1
422 421 $ hg ci -A -m1
423 422 adding f1
424 423 $ hg tag t1 t2 t3
425 424 $ hg tag --remove t2
426 425 $ hg tag t5
427 426 $ echo c2 > f2
428 427 $ hg ci -A -m2
429 428 adding f2
430 429 $ hg tag -f t3
431 430
432 431 $ cd ../repo-automatic-tag-merge
433 432 $ echo c3 > f3
434 433 $ hg ci -A -m3
435 434 adding f3
436 435 $ hg tag -f t4 t5 t6
437 436 $ hg tag --remove t5
438 437 $ echo c4 > f4
439 438 $ hg ci -A -m4
440 439 adding f4
441 440 $ hg tag t2
442 441 $ hg tag -f t6
443 442
444 443 $ cd ../repo-automatic-tag-merge-clone
445 444 $ hg pull
446 445 pulling from $TESTTMP/repo-automatic-tag-merge (glob)
447 446 searching for changes
448 447 adding changesets
449 448 adding manifests
450 449 adding file changes
451 450 added 6 changesets with 6 changes to 3 files (+1 heads)
452 451 (run 'hg heads' to see heads, 'hg merge' to merge)
453 452 $ hg merge --tool internal:tagmerge
454 453 merging .hgtags
455 454 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
456 455 (branch merge, don't forget to commit)
457 456 $ hg status
458 457 M .hgtags
459 458 M f3
460 459 M f4
461 460 $ hg resolve -l
462 461 R .hgtags
463 462 $ cat .hgtags
464 463 9aa4e1292a27a248f8d07339bed9931d54907be7 t4
465 464 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
466 465 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
467 466 09af2ce14077a94effef208b49a718f4836d4338 t6
468 467 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
469 468 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
470 469 929bca7b18d067cbf3844c3896319a940059d748 t2
471 470 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
472 471 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
473 472 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
474 473 0000000000000000000000000000000000000000 t2
475 474 875517b4806a848f942811a315a5bce30804ae85 t5
476 475 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
477 476 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
478 477 0000000000000000000000000000000000000000 t5
479 478 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
480 479 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
481 480
482 481 check that the merge tried to minimize the diff witht he first merge parent
483 482
484 483 $ hg diff --git -r 'p1()' .hgtags
485 484 diff --git a/.hgtags b/.hgtags
486 485 --- a/.hgtags
487 486 +++ b/.hgtags
488 487 @@ -1,9 +1,17 @@
489 488 +9aa4e1292a27a248f8d07339bed9931d54907be7 t4
490 489 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
491 490 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6
492 491 +09af2ce14077a94effef208b49a718f4836d4338 t6
493 492 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
494 493 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
495 494 +929bca7b18d067cbf3844c3896319a940059d748 t2
496 495 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
497 496 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
498 497 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
499 498 0000000000000000000000000000000000000000 t2
500 499 875517b4806a848f942811a315a5bce30804ae85 t5
501 500 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
502 501 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5
503 502 +0000000000000000000000000000000000000000 t5
504 503 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
505 504 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
506 505
507 506 detect merge tag conflicts
508 507
509 508 $ hg update -C -r tip
510 509 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
511 510 $ hg tag t7
512 511 $ hg update -C -r 'first(sort(head()))'
513 512 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
514 513 $ printf "%s %s\n" `hg log -r . --template "{node} t7"` >> .hgtags
515 514 $ hg commit -m "manually add conflicting t7 tag"
516 515 $ hg merge --tool internal:tagmerge
517 516 merging .hgtags
518 517 automatic .hgtags merge failed
519 518 the following 1 tags are in conflict: t7
520 519 automatic tag merging of .hgtags failed! (use 'hg resolve --tool internal:merge' or another merge tool of your choice)
521 520 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
522 521 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
523 522 [1]
524 523 $ hg resolve -l
525 524 U .hgtags
526 525 $ cat .hgtags
527 526 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
528 527 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
529 528 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
530 529 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
531 530 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
532 531 0000000000000000000000000000000000000000 t2
533 532 875517b4806a848f942811a315a5bce30804ae85 t5
534 533 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
535 534 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
536 535 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
537 536
538 537 $ cd ..
539 538
540 539 handle the loss of tags
541 540
542 541 $ hg clone repo-automatic-tag-merge-clone repo-merge-lost-tags
543 542 updating to branch default
544 543 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
545 544 $ cd repo-merge-lost-tags
546 545 $ echo c5 > f5
547 546 $ hg ci -A -m5
548 547 adding f5
549 548 $ hg tag -f t7
550 549 $ hg update -r 'p1(t7)'
551 550 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
552 551 $ printf '' > .hgtags
553 552 $ hg commit -m 'delete all tags'
554 553 created new head
555 554 $ hg update -r 'max(t7::)'
556 555 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
557 556 $ hg merge -r tip --tool internal:tagmerge
558 557 merging .hgtags
559 558 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
560 559 (branch merge, don't forget to commit)
561 560 $ hg resolve -l
562 561 R .hgtags
563 562 $ cat .hgtags
564 563 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
565 564 0000000000000000000000000000000000000000 tbase
566 565 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
567 566 0000000000000000000000000000000000000000 t1
568 567 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
569 568 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
570 569 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
571 570 0000000000000000000000000000000000000000 t2
572 571 875517b4806a848f942811a315a5bce30804ae85 t5
573 572 0000000000000000000000000000000000000000 t5
574 573 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
575 574 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
576 575 0000000000000000000000000000000000000000 t3
577 576 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
578 577 0000000000000000000000000000000000000000 t7
579 578 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
580 579 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
581 580
582 581 also check that we minimize the diff with the 1st merge parent
583 582
584 583 $ hg diff --git -r 'p1()' .hgtags
585 584 diff --git a/.hgtags b/.hgtags
586 585 --- a/.hgtags
587 586 +++ b/.hgtags
588 587 @@ -1,12 +1,17 @@
589 588 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
590 589 +0000000000000000000000000000000000000000 tbase
591 590 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
592 591 +0000000000000000000000000000000000000000 t1
593 592 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
594 593 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
595 594 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
596 595 0000000000000000000000000000000000000000 t2
597 596 875517b4806a848f942811a315a5bce30804ae85 t5
598 597 +0000000000000000000000000000000000000000 t5
599 598 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
600 599 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
601 600 +0000000000000000000000000000000000000000 t3
602 601 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
603 602 +0000000000000000000000000000000000000000 t7
604 603 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
605 604 fd3a9e394ce3afb354a496323bf68ac1755a30de t7
606 605
General Comments 0
You need to be logged in to leave comments. Login now