##// END OF EJS Templates
check-code: fix check for trailing whitespace on continued lines too...
Mads Kiilerich -
r17347:2da47de3 default
parent child Browse files
Show More
@@ -1,450 +1,450
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 import re, glob, os, sys
11 11 import keyword
12 12 import optparse
13 13
14 14 def repquote(m):
15 15 t = re.sub(r"\w", "x", m.group('text'))
16 16 t = re.sub(r"[^\s\nx]", "o", t)
17 17 return m.group('quote') + t + m.group('quote')
18 18
19 19 def reppython(m):
20 20 comment = m.group('comment')
21 21 if comment:
22 22 return "#" * len(comment)
23 23 return repquote(m)
24 24
25 25 def repcomment(m):
26 26 return m.group(1) + "#" * len(m.group(2))
27 27
28 28 def repccomment(m):
29 29 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
30 30 return m.group(1) + t + "*/"
31 31
32 32 def repcallspaces(m):
33 33 t = re.sub(r"\n\s+", "\n", m.group(2))
34 34 return m.group(1) + t
35 35
36 36 def repinclude(m):
37 37 return m.group(1) + "<foo>"
38 38
39 39 def rephere(m):
40 40 t = re.sub(r"\S", "x", m.group(2))
41 41 return m.group(1) + t
42 42
43 43
44 44 testpats = [
45 45 [
46 46 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
47 47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
48 48 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
49 49 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
50 50 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
51 51 (r'echo -n', "don't use 'echo -n', use printf"),
52 52 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
53 53 (r'head -c', "don't use 'head -c', use 'dd'"),
54 54 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
55 55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
56 56 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
57 57 (r'printf.*\\x', "don't use printf \\x, use Python"),
58 58 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
59 59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
60 60 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
61 61 "use egrep for extended grep syntax"),
62 62 (r'/bin/', "don't use explicit paths for tools"),
63 63 (r'[^\n]\Z', "no trailing newline"),
64 64 (r'export.*=', "don't export and assign at once"),
65 65 (r'^source\b', "don't use 'source', use '.'"),
66 66 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
67 67 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
68 68 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
69 69 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
70 70 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
71 71 (r'^alias\b.*=', "don't use alias, use a function"),
72 72 (r'if\s*!', "don't use '!' to negate exit status"),
73 73 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
74 74 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
75 75 (r'^( *)\t', "don't use tabs to indent"),
76 76 ],
77 77 # warnings
78 78 [
79 79 (r'^function', "don't use 'function', use old style"),
80 80 (r'^diff.*-\w*N', "don't use 'diff -N'"),
81 81 (r'\$PWD', "don't use $PWD, use `pwd`"),
82 82 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
83 83 ]
84 84 ]
85 85
86 86 testfilters = [
87 87 (r"( *)(#([^\n]*\S)?)", repcomment),
88 88 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
89 89 ]
90 90
91 91 uprefix = r"^ \$ "
92 92 utestpats = [
93 93 [
94 (r'^(\S.*|| \$ .*)[ \t]\n', "trailing whitespace on non-output"),
94 (r'^(\S.*|| [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
95 95 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
96 96 "use regex test output patterns instead of sed"),
97 97 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
98 98 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
99 99 (uprefix + r'.*\|\| echo.*(fail|error)',
100 100 "explicit exit code checks unnecessary"),
101 101 (uprefix + r'set -e', "don't use set -e"),
102 102 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
103 103 (r'^ saved backup bundle to \$TESTTMP.*\.hg$',
104 104 "use (glob) to match Windows paths too"),
105 105 ],
106 106 # warnings
107 107 []
108 108 ]
109 109
110 110 for i in [0, 1]:
111 111 for p, m in testpats[i]:
112 112 if p.startswith(r'^'):
113 113 p = r"^ [$>] (%s)" % p[1:]
114 114 else:
115 115 p = r"^ [$>] .*(%s)" % p
116 116 utestpats[i].append((p, m))
117 117
118 118 utestfilters = [
119 119 (r"( *)(#([^\n]*\S)?)", repcomment),
120 120 ]
121 121
122 122 pypats = [
123 123 [
124 124 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
125 125 "tuple parameter unpacking not available in Python 3+"),
126 126 (r'lambda\s*\(.*,.*\)',
127 127 "tuple parameter unpacking not available in Python 3+"),
128 128 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
129 129 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
130 130 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
131 131 (r'^\s*\t', "don't use tabs"),
132 132 (r'\S;\s*\n', "semicolon"),
133 133 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
134 134 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
135 135 (r'\w,\w', "missing whitespace after ,"),
136 136 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
137 137 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
138 138 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
139 139 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Py2.4'),
140 140 (r'.{81}', "line too long"),
141 141 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
142 142 (r'[^\n]\Z', "no trailing newline"),
143 143 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
144 144 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
145 145 # "don't use underbars in identifiers"),
146 146 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
147 147 "don't use camelcase in identifiers"),
148 148 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
149 149 "linebreak after :"),
150 150 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
151 151 (r'class\s[^( \n]+\(\):',
152 152 "class foo() not available in Python 2.4, use class foo(object)"),
153 153 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
154 154 "Python keyword is not a function"),
155 155 (r',]', "unneeded trailing ',' in list"),
156 156 # (r'class\s[A-Z][^\(]*\((?!Exception)',
157 157 # "don't capitalize non-exception classes"),
158 158 # (r'in range\(', "use xrange"),
159 159 # (r'^\s*print\s+', "avoid using print in core and extensions"),
160 160 (r'[\x80-\xff]', "non-ASCII character literal"),
161 161 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
162 162 (r'^\s*with\s+', "with not available in Python 2.4"),
163 163 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
164 164 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
165 165 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
166 166 (r'(?<!def)\s+(any|all|format)\(',
167 167 "any/all/format not available in Python 2.4"),
168 168 (r'(?<!def)\s+(callable)\(',
169 169 "callable not available in Python 3, use getattr(f, '__call__', None)"),
170 170 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
171 171 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
172 172 "gratuitous whitespace after Python keyword"),
173 173 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
174 174 # (r'\s\s=', "gratuitous whitespace before ="),
175 175 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
176 176 "missing whitespace around operator"),
177 177 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
178 178 "missing whitespace around operator"),
179 179 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
180 180 "missing whitespace around operator"),
181 181 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
182 182 "wrong whitespace around ="),
183 183 (r'raise Exception', "don't raise generic exceptions"),
184 184 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
185 185 (r' [=!]=\s+(True|False|None)',
186 186 "comparison with singleton, use 'is' or 'is not' instead"),
187 187 (r'^\s*(while|if) [01]:',
188 188 "use True/False for constant Boolean expression"),
189 189 (r'(?:(?<!def)\s+|\()hasattr',
190 190 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
191 191 (r'opener\([^)]*\).read\(',
192 192 "use opener.read() instead"),
193 193 (r'BaseException', 'not in Py2.4, use Exception'),
194 194 (r'os\.path\.relpath', 'os.path.relpath is not in Py2.5'),
195 195 (r'opener\([^)]*\).write\(',
196 196 "use opener.write() instead"),
197 197 (r'[\s\(](open|file)\([^)]*\)\.read\(',
198 198 "use util.readfile() instead"),
199 199 (r'[\s\(](open|file)\([^)]*\)\.write\(',
200 200 "use util.readfile() instead"),
201 201 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
202 202 "always assign an opened file to a variable, and close it afterwards"),
203 203 (r'[\s\(](open|file)\([^)]*\)\.',
204 204 "always assign an opened file to a variable, and close it afterwards"),
205 205 (r'(?i)descendent', "the proper spelling is descendAnt"),
206 206 (r'\.debug\(\_', "don't mark debug messages for translation"),
207 207 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
208 208 (r'^\s*except\s*:', "warning: naked except clause", r'#.*re-raises'),
209 209 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
210 210 ],
211 211 # warnings
212 212 [
213 213 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
214 214 "warning: unwrapped ui message"),
215 215 ]
216 216 ]
217 217
218 218 pyfilters = [
219 219 (r"""(?msx)(?P<comment>\#.*?$)|
220 220 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
221 221 (?P<text>(([^\\]|\\.)*?))
222 222 (?P=quote))""", reppython),
223 223 ]
224 224
225 225 cpats = [
226 226 [
227 227 (r'//', "don't use //-style comments"),
228 228 (r'^ ', "don't use spaces to indent"),
229 229 (r'\S\t', "don't use tabs except for indent"),
230 230 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
231 231 (r'.{81}', "line too long"),
232 232 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
233 233 (r'return\(', "return is not a function"),
234 234 (r' ;', "no space before ;"),
235 235 (r'\w+\* \w+', "use int *foo, not int* foo"),
236 236 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
237 237 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
238 238 (r'\w,\w', "missing whitespace after ,"),
239 239 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
240 240 (r'^#\s+\w', "use #foo, not # foo"),
241 241 (r'[^\n]\Z', "no trailing newline"),
242 242 (r'^\s*#import\b', "use only #include in standard C code"),
243 243 ],
244 244 # warnings
245 245 []
246 246 ]
247 247
248 248 cfilters = [
249 249 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
250 250 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
251 251 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
252 252 (r'(\()([^)]+\))', repcallspaces),
253 253 ]
254 254
255 255 inutilpats = [
256 256 [
257 257 (r'\bui\.', "don't use ui in util"),
258 258 ],
259 259 # warnings
260 260 []
261 261 ]
262 262
263 263 inrevlogpats = [
264 264 [
265 265 (r'\brepo\.', "don't use repo in revlog"),
266 266 ],
267 267 # warnings
268 268 []
269 269 ]
270 270
271 271 checks = [
272 272 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
273 273 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
274 274 ('c', r'.*\.c$', cfilters, cpats),
275 275 ('unified test', r'.*\.t$', utestfilters, utestpats),
276 276 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
277 277 inrevlogpats),
278 278 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
279 279 inutilpats),
280 280 ]
281 281
282 282 class norepeatlogger(object):
283 283 def __init__(self):
284 284 self._lastseen = None
285 285
286 286 def log(self, fname, lineno, line, msg, blame):
287 287 """print error related a to given line of a given file.
288 288
289 289 The faulty line will also be printed but only once in the case
290 290 of multiple errors.
291 291
292 292 :fname: filename
293 293 :lineno: line number
294 294 :line: actual content of the line
295 295 :msg: error message
296 296 """
297 297 msgid = fname, lineno, line
298 298 if msgid != self._lastseen:
299 299 if blame:
300 300 print "%s:%d (%s):" % (fname, lineno, blame)
301 301 else:
302 302 print "%s:%d:" % (fname, lineno)
303 303 print " > %s" % line
304 304 self._lastseen = msgid
305 305 print " " + msg
306 306
307 307 _defaultlogger = norepeatlogger()
308 308
309 309 def getblame(f):
310 310 lines = []
311 311 for l in os.popen('hg annotate -un %s' % f):
312 312 start, line = l.split(':', 1)
313 313 user, rev = start.split()
314 314 lines.append((line[1:-1], user, rev))
315 315 return lines
316 316
317 317 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
318 318 blame=False, debug=False, lineno=True):
319 319 """checks style and portability of a given file
320 320
321 321 :f: filepath
322 322 :logfunc: function used to report error
323 323 logfunc(filename, linenumber, linecontent, errormessage)
324 324 :maxerr: number of error to display before arborting.
325 325 Set to false (default) to report all errors
326 326
327 327 return True if no error is found, False otherwise.
328 328 """
329 329 blamecache = None
330 330 result = True
331 331 for name, match, filters, pats in checks:
332 332 if debug:
333 333 print name, f
334 334 fc = 0
335 335 if not re.match(match, f):
336 336 if debug:
337 337 print "Skipping %s for %s it doesn't match %s" % (
338 338 name, match, f)
339 339 continue
340 340 fp = open(f)
341 341 pre = post = fp.read()
342 342 fp.close()
343 343 if "no-" + "check-code" in pre:
344 344 if debug:
345 345 print "Skipping %s for %s it has no- and check-code" % (
346 346 name, f)
347 347 break
348 348 for p, r in filters:
349 349 post = re.sub(p, r, post)
350 350 if warnings:
351 351 pats = pats[0] + pats[1]
352 352 else:
353 353 pats = pats[0]
354 354 # print post # uncomment to show filtered version
355 355
356 356 if debug:
357 357 print "Checking %s for %s" % (name, f)
358 358
359 359 prelines = None
360 360 errors = []
361 361 for pat in pats:
362 362 if len(pat) == 3:
363 363 p, msg, ignore = pat
364 364 else:
365 365 p, msg = pat
366 366 ignore = None
367 367
368 368 # fix-up regexes for multiline searches
369 369 po = p
370 370 # \s doesn't match \n
371 371 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
372 372 # [^...] doesn't match newline
373 373 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
374 374
375 375 #print po, '=>', p
376 376
377 377 pos = 0
378 378 n = 0
379 379 for m in re.finditer(p, post, re.MULTILINE):
380 380 if prelines is None:
381 381 prelines = pre.splitlines()
382 382 postlines = post.splitlines(True)
383 383
384 384 start = m.start()
385 385 while n < len(postlines):
386 386 step = len(postlines[n])
387 387 if pos + step > start:
388 388 break
389 389 pos += step
390 390 n += 1
391 391 l = prelines[n]
392 392
393 393 if "check-code" + "-ignore" in l:
394 394 if debug:
395 395 print "Skipping %s for %s:%s (check-code -ignore)" % (
396 396 name, f, n)
397 397 continue
398 398 elif ignore and re.search(ignore, l, re.MULTILINE):
399 399 continue
400 400 bd = ""
401 401 if blame:
402 402 bd = 'working directory'
403 403 if not blamecache:
404 404 blamecache = getblame(f)
405 405 if n < len(blamecache):
406 406 bl, bu, br = blamecache[n]
407 407 if bl == l:
408 408 bd = '%s@%s' % (bu, br)
409 409 errors.append((f, lineno and n + 1, l, msg, bd))
410 410 result = False
411 411
412 412 errors.sort()
413 413 for e in errors:
414 414 logfunc(*e)
415 415 fc += 1
416 416 if maxerr and fc >= maxerr:
417 417 print " (too many errors, giving up)"
418 418 break
419 419
420 420 return result
421 421
422 422 if __name__ == "__main__":
423 423 parser = optparse.OptionParser("%prog [options] [files]")
424 424 parser.add_option("-w", "--warnings", action="store_true",
425 425 help="include warning-level checks")
426 426 parser.add_option("-p", "--per-file", type="int",
427 427 help="max warnings per file")
428 428 parser.add_option("-b", "--blame", action="store_true",
429 429 help="use annotate to generate blame info")
430 430 parser.add_option("", "--debug", action="store_true",
431 431 help="show debug information")
432 432 parser.add_option("", "--nolineno", action="store_false",
433 433 dest='lineno', help="don't show line numbers")
434 434
435 435 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
436 436 lineno=True)
437 437 (options, args) = parser.parse_args()
438 438
439 439 if len(args) == 0:
440 440 check = glob.glob("*")
441 441 else:
442 442 check = args
443 443
444 444 ret = 0
445 445 for f in check:
446 446 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
447 447 blame=options.blame, debug=options.debug,
448 448 lineno=options.lineno):
449 449 ret = 1
450 450 sys.exit(ret)
@@ -1,322 +1,322
1 1 $ HGMERGE=true; export HGMERGE
2 2
3 3 init
4 4
5 5 $ hg init repo
6 6 $ cd repo
7 7
8 8 commit
9 9
10 10 $ echo 'a' > a
11 11 $ hg ci -A -m test -u nobody -d '1 0'
12 12 adding a
13 13
14 14 annotate -c
15 15
16 16 $ hg annotate -c a
17 17 8435f90966e4: a
18 18
19 19 annotate -cl
20 20
21 21 $ hg annotate -cl a
22 22 8435f90966e4:1: a
23 23
24 24 annotate -d
25 25
26 26 $ hg annotate -d a
27 27 Thu Jan 01 00:00:01 1970 +0000: a
28 28
29 29 annotate -n
30 30
31 31 $ hg annotate -n a
32 32 0: a
33 33
34 34 annotate -nl
35 35
36 36 $ hg annotate -nl a
37 37 0:1: a
38 38
39 39 annotate -u
40 40
41 41 $ hg annotate -u a
42 42 nobody: a
43 43
44 44 annotate -cdnu
45 45
46 46 $ hg annotate -cdnu a
47 47 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
48 48
49 49 annotate -cdnul
50 50
51 51 $ hg annotate -cdnul a
52 52 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
53 53
54 54 $ cat <<EOF >>a
55 55 > a
56 56 > a
57 57 > EOF
58 58 $ hg ci -ma1 -d '1 0'
59 59 $ hg cp a b
60 60 $ hg ci -mb -d '1 0'
61 61 $ cat <<EOF >> b
62 62 > b4
63 63 > b5
64 64 > b6
65 65 > EOF
66 66 $ hg ci -mb2 -d '2 0'
67 67
68 68 annotate -n b
69 69
70 70 $ hg annotate -n b
71 71 0: a
72 72 1: a
73 73 1: a
74 74 3: b4
75 75 3: b5
76 76 3: b6
77 77
78 78 annotate --no-follow b
79 79
80 80 $ hg annotate --no-follow b
81 81 2: a
82 82 2: a
83 83 2: a
84 84 3: b4
85 85 3: b5
86 86 3: b6
87 87
88 88 annotate -nl b
89 89
90 90 $ hg annotate -nl b
91 91 0:1: a
92 92 1:2: a
93 93 1:3: a
94 94 3:4: b4
95 95 3:5: b5
96 96 3:6: b6
97 97
98 98 annotate -nf b
99 99
100 100 $ hg annotate -nf b
101 101 0 a: a
102 102 1 a: a
103 103 1 a: a
104 104 3 b: b4
105 105 3 b: b5
106 106 3 b: b6
107 107
108 108 annotate -nlf b
109 109
110 110 $ hg annotate -nlf b
111 111 0 a:1: a
112 112 1 a:2: a
113 113 1 a:3: a
114 114 3 b:4: b4
115 115 3 b:5: b5
116 116 3 b:6: b6
117 117
118 118 $ hg up -C 2
119 119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 120 $ cat <<EOF >> b
121 121 > b4
122 122 > c
123 123 > b5
124 124 > EOF
125 125 $ hg ci -mb2.1 -d '2 0'
126 126 created new head
127 127 $ hg merge
128 128 merging b
129 129 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
130 130 (branch merge, don't forget to commit)
131 131 $ hg ci -mmergeb -d '3 0'
132 132
133 133 annotate after merge
134 134
135 135 $ hg annotate -nf b
136 136 0 a: a
137 137 1 a: a
138 138 1 a: a
139 139 3 b: b4
140 140 4 b: c
141 141 3 b: b5
142 142
143 143 annotate after merge with -l
144 144
145 145 $ hg annotate -nlf b
146 146 0 a:1: a
147 147 1 a:2: a
148 148 1 a:3: a
149 149 3 b:4: b4
150 150 4 b:5: c
151 151 3 b:5: b5
152 152
153 153 $ hg up -C 1
154 154 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
155 155 $ hg cp a b
156 156 $ cat <<EOF > b
157 157 > a
158 158 > z
159 159 > a
160 160 > EOF
161 161 $ hg ci -mc -d '3 0'
162 162 created new head
163 163 $ hg merge
164 164 merging b
165 165 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
166 166 (branch merge, don't forget to commit)
167 167 $ cat <<EOF >> b
168 168 > b4
169 169 > c
170 170 > b5
171 171 > EOF
172 172 $ echo d >> b
173 173 $ hg ci -mmerge2 -d '4 0'
174 174
175 175 annotate after rename merge
176 176
177 177 $ hg annotate -nf b
178 178 0 a: a
179 179 6 b: z
180 180 1 a: a
181 181 3 b: b4
182 182 4 b: c
183 183 3 b: b5
184 184 7 b: d
185 185
186 186 annotate after rename merge with -l
187 187
188 188 $ hg annotate -nlf b
189 189 0 a:1: a
190 190 6 b:2: z
191 191 1 a:3: a
192 192 3 b:4: b4
193 193 4 b:5: c
194 194 3 b:5: b5
195 195 7 b:7: d
196 196
197 197 Issue2807: alignment of line numbers with -l
198 198
199 199 $ echo more >> b
200 200 $ hg ci -mmore -d '5 0'
201 201 $ echo more >> b
202 202 $ hg ci -mmore -d '6 0'
203 203 $ echo more >> b
204 204 $ hg ci -mmore -d '7 0'
205 205 $ hg annotate -nlf b
206 206 0 a: 1: a
207 207 6 b: 2: z
208 208 1 a: 3: a
209 209 3 b: 4: b4
210 210 4 b: 5: c
211 211 3 b: 5: b5
212 212 7 b: 7: d
213 213 8 b: 8: more
214 214 9 b: 9: more
215 215 10 b:10: more
216 216
217 217 linkrev vs rev
218 218
219 219 $ hg annotate -r tip -n a
220 220 0: a
221 221 1: a
222 222 1: a
223 223
224 224 linkrev vs rev with -l
225 225
226 226 $ hg annotate -r tip -nl a
227 227 0:1: a
228 228 1:2: a
229 229 1:3: a
230 230
231 231 Issue589: "undelete" sequence leads to crash
232 232
233 233 annotate was crashing when trying to --follow something
234 234
235 235 like A -> B -> A
236 236
237 237 generate ABA rename configuration
238 238
239 239 $ echo foo > foo
240 240 $ hg add foo
241 241 $ hg ci -m addfoo
242 242 $ hg rename foo bar
243 243 $ hg ci -m renamefoo
244 244 $ hg rename bar foo
245 245 $ hg ci -m renamebar
246 246
247 247 annotate after ABA with follow
248 248
249 249 $ hg annotate --follow foo
250 250 foo: foo
251 251
252 252 missing file
253 253
254 254 $ hg ann nosuchfile
255 255 abort: nosuchfile: no such file in rev e9e6b4fa872f
256 256 [255]
257 257
258 258 annotate file without '\n' on last line
259 259
260 260 $ printf "" > c
261 261 $ hg ci -A -m test -u nobody -d '1 0'
262 262 adding c
263 263 $ hg annotate c
264 264 $ printf "a\nb" > c
265 265 $ hg ci -m test
266 266 $ hg annotate c
267 267 [0-9]+: a (re)
268 268 [0-9]+: b (re)
269 269
270 270 Test annotate with whitespace options
271 271
272 272 $ cd ..
273 273 $ hg init repo-ws
274 274 $ cd repo-ws
275 275 $ cat > a <<EOF
276 276 > aa
277 277 >
278 278 > b b
279 279 > EOF
280 280 $ hg ci -Am "adda"
281 281 adding a
282 $ cat > a <<EOF
282 $ sed 's/EOL$//g' > a <<EOF
283 283 > a a
284 284 >
285 >
285 > EOL
286 286 > b b
287 287 > EOF
288 288 $ hg ci -m "changea"
289 289
290 290 Annotate with no option
291 291
292 292 $ hg annotate a
293 293 1: a a
294 294 0:
295 295 1:
296 296 1: b b
297 297
298 298 Annotate with --ignore-space-change
299 299
300 300 $ hg annotate --ignore-space-change a
301 301 1: a a
302 302 1:
303 303 0:
304 304 0: b b
305 305
306 306 Annotate with --ignore-all-space
307 307
308 308 $ hg annotate --ignore-all-space a
309 309 0: a a
310 310 0:
311 311 1:
312 312 0: b b
313 313
314 314 Annotate with --ignore-blank-lines (similar to no options case)
315 315
316 316 $ hg annotate --ignore-blank-lines a
317 317 1: a a
318 318 0:
319 319 1:
320 320 1: b b
321 321
322 322 $ cd ..
@@ -1,611 +1,611
1 1 $ hg init repo
2 2 $ cd repo
3 3
4 4 New file:
5 5
6 6 $ hg import -d "1000000 0" -mnew - <<EOF
7 7 > diff --git a/new b/new
8 8 > new file mode 100644
9 9 > index 0000000..7898192
10 10 > --- /dev/null
11 11 > +++ b/new
12 12 > @@ -0,0 +1 @@
13 13 > +a
14 14 > EOF
15 15 applying patch from stdin
16 16
17 17 $ hg tip -q
18 18 0:ae3ee40d2079
19 19
20 20 New empty file:
21 21
22 22 $ hg import -d "1000000 0" -mempty - <<EOF
23 23 > diff --git a/empty b/empty
24 24 > new file mode 100644
25 25 > EOF
26 26 applying patch from stdin
27 27
28 28 $ hg tip -q
29 29 1:ab199dc869b5
30 30
31 31 $ hg locate empty
32 32 empty
33 33
34 34 chmod +x:
35 35
36 36 $ hg import -d "1000000 0" -msetx - <<EOF
37 37 > diff --git a/new b/new
38 38 > old mode 100644
39 39 > new mode 100755
40 40 > EOF
41 41 applying patch from stdin
42 42
43 43 #if execbit
44 44 $ hg tip -q
45 45 2:3a34410f282e
46 46 $ test -x new
47 47 $ hg rollback -q
48 48 #else
49 49 $ hg tip -q
50 50 1:ab199dc869b5
51 51 #endif
52 52
53 53 Copy and removing x bit:
54 54
55 55 $ hg import -f -d "1000000 0" -mcopy - <<EOF
56 56 > diff --git a/new b/copy
57 57 > old mode 100755
58 58 > new mode 100644
59 59 > similarity index 100%
60 60 > copy from new
61 61 > copy to copy
62 62 > diff --git a/new b/copyx
63 63 > similarity index 100%
64 64 > copy from new
65 65 > copy to copyx
66 66 > EOF
67 67 applying patch from stdin
68 68
69 69 $ test -f copy
70 70 #if execbit
71 71 $ test ! -x copy
72 72 $ test -x copyx
73 73 $ hg tip -q
74 74 2:21dfaae65c71
75 75 #else
76 76 $ hg tip -q
77 77 2:0efdaa8e3bf3
78 78 #endif
79 79
80 80 $ hg up -qCr1
81 81 $ hg rollback -q
82 82
83 83 Copy (like above but independent of execbit):
84 84
85 85 $ hg import -d "1000000 0" -mcopy - <<EOF
86 86 > diff --git a/new b/copy
87 87 > similarity index 100%
88 88 > copy from new
89 89 > copy to copy
90 90 > diff --git a/new b/copyx
91 91 > similarity index 100%
92 92 > copy from new
93 93 > copy to copyx
94 94 > EOF
95 95 applying patch from stdin
96 96
97 97 $ hg tip -q
98 98 2:0efdaa8e3bf3
99 99 $ test -f copy
100 100
101 101 $ cat copy
102 102 a
103 103
104 104 $ hg cat copy
105 105 a
106 106
107 107 Rename:
108 108
109 109 $ hg import -d "1000000 0" -mrename - <<EOF
110 110 > diff --git a/copy b/rename
111 111 > similarity index 100%
112 112 > rename from copy
113 113 > rename to rename
114 114 > EOF
115 115 applying patch from stdin
116 116
117 117 $ hg tip -q
118 118 3:b1f57753fad2
119 119
120 120 $ hg locate
121 121 copyx
122 122 empty
123 123 new
124 124 rename
125 125
126 126 Delete:
127 127
128 128 $ hg import -d "1000000 0" -mdelete - <<EOF
129 129 > diff --git a/copyx b/copyx
130 130 > deleted file mode 100755
131 131 > index 7898192..0000000
132 132 > --- a/copyx
133 133 > +++ /dev/null
134 134 > @@ -1 +0,0 @@
135 135 > -a
136 136 > EOF
137 137 applying patch from stdin
138 138
139 139 $ hg tip -q
140 140 4:1bd1da94b9b2
141 141
142 142 $ hg locate
143 143 empty
144 144 new
145 145 rename
146 146
147 147 $ test -f copyx
148 148 [1]
149 149
150 150 Regular diff:
151 151
152 152 $ hg import -d "1000000 0" -mregular - <<EOF
153 153 > diff --git a/rename b/rename
154 154 > index 7898192..72e1fe3 100644
155 155 > --- a/rename
156 156 > +++ b/rename
157 157 > @@ -1 +1,5 @@
158 158 > a
159 159 > +a
160 160 > +a
161 161 > +a
162 162 > +a
163 163 > EOF
164 164 applying patch from stdin
165 165
166 166 $ hg tip -q
167 167 5:46fe99cb3035
168 168
169 169 Copy and modify:
170 170
171 171 $ hg import -d "1000000 0" -mcopymod - <<EOF
172 172 > diff --git a/rename b/copy2
173 173 > similarity index 80%
174 174 > copy from rename
175 175 > copy to copy2
176 176 > index 72e1fe3..b53c148 100644
177 177 > --- a/rename
178 178 > +++ b/copy2
179 179 > @@ -1,5 +1,5 @@
180 180 > a
181 181 > a
182 182 > -a
183 183 > +b
184 184 > a
185 185 > a
186 186 > EOF
187 187 applying patch from stdin
188 188
189 189 $ hg tip -q
190 190 6:ffeb3197c12d
191 191
192 192 $ hg cat copy2
193 193 a
194 194 a
195 195 b
196 196 a
197 197 a
198 198
199 199 Rename and modify:
200 200
201 201 $ hg import -d "1000000 0" -mrenamemod - <<EOF
202 202 > diff --git a/copy2 b/rename2
203 203 > similarity index 80%
204 204 > rename from copy2
205 205 > rename to rename2
206 206 > index b53c148..8f81e29 100644
207 207 > --- a/copy2
208 208 > +++ b/rename2
209 209 > @@ -1,5 +1,5 @@
210 210 > a
211 211 > a
212 212 > b
213 213 > -a
214 214 > +c
215 215 > a
216 216 > EOF
217 217 applying patch from stdin
218 218
219 219 $ hg tip -q
220 220 7:401aede9e6bb
221 221
222 222 $ hg locate copy2
223 223 [1]
224 224 $ hg cat rename2
225 225 a
226 226 a
227 227 b
228 228 c
229 229 a
230 230
231 231 One file renamed multiple times:
232 232
233 233 $ hg import -d "1000000 0" -mmultirenames - <<EOF
234 234 > diff --git a/rename2 b/rename3
235 235 > rename from rename2
236 236 > rename to rename3
237 237 > diff --git a/rename2 b/rename3-2
238 238 > rename from rename2
239 239 > rename to rename3-2
240 240 > EOF
241 241 applying patch from stdin
242 242
243 243 $ hg tip -q
244 244 8:2ef727e684e8
245 245
246 246 $ hg log -vr. --template '{rev} {files} / {file_copies}\n'
247 247 8 rename2 rename3 rename3-2 / rename3 (rename2)rename3-2 (rename2)
248 248
249 249 $ hg locate rename2 rename3 rename3-2
250 250 rename3
251 251 rename3-2
252 252
253 253 $ hg cat rename3
254 254 a
255 255 a
256 256 b
257 257 c
258 258 a
259 259
260 260 $ hg cat rename3-2
261 261 a
262 262 a
263 263 b
264 264 c
265 265 a
266 266
267 267 $ echo foo > foo
268 268 $ hg add foo
269 269 $ hg ci -m 'add foo'
270 270
271 271 Binary files and regular patch hunks:
272 272
273 273 $ hg import -d "1000000 0" -m binaryregular - <<EOF
274 274 > diff --git a/binary b/binary
275 275 > new file mode 100644
276 276 > index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
277 277 > GIT binary patch
278 278 > literal 4
279 279 > Lc\${NkU|;|M00aO5
280 280 >
281 281 > diff --git a/foo b/foo2
282 282 > rename from foo
283 283 > rename to foo2
284 284 > EOF
285 285 applying patch from stdin
286 286
287 287 $ hg tip -q
288 288 10:27377172366e
289 289
290 290 $ cat foo2
291 291 foo
292 292
293 293 $ hg manifest --debug | grep binary
294 294 045c85ba38952325e126c70962cc0f9d9077bc67 644 binary
295 295
296 296 Multiple binary files:
297 297
298 298 $ hg import -d "1000000 0" -m multibinary - <<EOF
299 299 > diff --git a/mbinary1 b/mbinary1
300 300 > new file mode 100644
301 301 > index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
302 302 > GIT binary patch
303 303 > literal 4
304 304 > Lc\${NkU|;|M00aO5
305 305 >
306 306 > diff --git a/mbinary2 b/mbinary2
307 307 > new file mode 100644
308 308 > index 0000000000000000000000000000000000000000..112363ac1917b417ffbd7f376ca786a1e5fa7490
309 309 > GIT binary patch
310 310 > literal 5
311 311 > Mc\${NkU|\`?^000jF3jhEB
312 312 >
313 313 > EOF
314 314 applying patch from stdin
315 315
316 316 $ hg tip -q
317 317 11:18b73a84b4ab
318 318
319 319 $ hg manifest --debug | grep mbinary
320 320 045c85ba38952325e126c70962cc0f9d9077bc67 644 mbinary1
321 321 a874b471193996e7cb034bb301cac7bdaf3e3f46 644 mbinary2
322 322
323 323 Filenames with spaces:
324 324
325 $ hg import -d "1000000 0" -m spaces - <<EOF
325 $ sed 's,EOL$,,g' <<EOF | hg import -d "1000000 0" -m spaces -
326 326 > diff --git a/foo bar b/foo bar
327 327 > new file mode 100644
328 328 > index 0000000..257cc56
329 329 > --- /dev/null
330 > +++ b/foo bar
330 > +++ b/foo bar EOL
331 331 > @@ -0,0 +1 @@
332 332 > +foo
333 333 > EOF
334 334 applying patch from stdin
335 335
336 336 $ hg tip -q
337 337 12:47500ce1614e
338 338
339 339 $ cat "foo bar"
340 340 foo
341 341
342 342 Copy then modify the original file:
343 343
344 344 $ hg import -d "1000000 0" -m copy-mod-orig - <<EOF
345 345 > diff --git a/foo2 b/foo2
346 346 > index 257cc56..fe08ec6 100644
347 347 > --- a/foo2
348 348 > +++ b/foo2
349 349 > @@ -1 +1,2 @@
350 350 > foo
351 351 > +new line
352 352 > diff --git a/foo2 b/foo3
353 353 > similarity index 100%
354 354 > copy from foo2
355 355 > copy to foo3
356 356 > EOF
357 357 applying patch from stdin
358 358
359 359 $ hg tip -q
360 360 13:6757efb07ea9
361 361
362 362 $ cat foo3
363 363 foo
364 364
365 365 Move text file and patch as binary
366 366
367 367 $ echo a > text2
368 368 $ hg ci -Am0
369 369 adding text2
370 370 $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
371 371 > diff --git a/text2 b/binary2
372 372 > rename from text2
373 373 > rename to binary2
374 374 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
375 375 > GIT binary patch
376 376 > literal 5
377 377 > Mc$`b*O5$Pw00T?_*Z=?k
378 378 >
379 379 > EOF
380 380 applying patch from stdin
381 381
382 382 $ cat binary2
383 383 a
384 384 b
385 385 \x00 (no-eol) (esc)
386 386
387 387 $ hg st --copies --change .
388 388 A binary2
389 389 text2
390 390 R text2
391 391
392 392 Invalid base85 content
393 393
394 394 $ hg rollback
395 395 repository tip rolled back to revision 14 (undo import)
396 396 working directory now based on revision 14
397 397 $ hg revert -aq
398 398 $ hg import -d "1000000 0" -m invalid-binary - <<"EOF"
399 399 > diff --git a/text2 b/binary2
400 400 > rename from text2
401 401 > rename to binary2
402 402 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
403 403 > GIT binary patch
404 404 > literal 5
405 405 > Mc$`b*O.$Pw00T?_*Z=?k
406 406 >
407 407 > EOF
408 408 applying patch from stdin
409 409 abort: could not decode "binary2" binary patch: bad base85 character at position 6
410 410 [255]
411 411
412 412 $ hg revert -aq
413 413 $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
414 414 > diff --git a/text2 b/binary2
415 415 > rename from text2
416 416 > rename to binary2
417 417 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
418 418 > GIT binary patch
419 419 > literal 6
420 420 > Mc$`b*O5$Pw00T?_*Z=?k
421 421 >
422 422 > EOF
423 423 applying patch from stdin
424 424 abort: "binary2" length is 5 bytes, should be 6
425 425 [255]
426 426
427 427 $ hg revert -aq
428 428 $ hg import -d "1000000 0" -m rename-as-binary - <<"EOF"
429 429 > diff --git a/text2 b/binary2
430 430 > rename from text2
431 431 > rename to binary2
432 432 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
433 433 > GIT binary patch
434 434 > Mc$`b*O5$Pw00T?_*Z=?k
435 435 >
436 436 > EOF
437 437 applying patch from stdin
438 438 abort: could not extract "binary2" binary data
439 439 [255]
440 440
441 441 Simulate a copy/paste turning LF into CRLF (issue2870)
442 442
443 443 $ hg revert -aq
444 444 $ cat > binary.diff <<"EOF"
445 445 > diff --git a/text2 b/binary2
446 446 > rename from text2
447 447 > rename to binary2
448 448 > index 78981922613b2afb6025042ff6bd878ac1994e85..10efcb362e9f3b3420fcfbfc0e37f3dc16e29757
449 449 > GIT binary patch
450 450 > literal 5
451 451 > Mc$`b*O5$Pw00T?_*Z=?k
452 452 >
453 453 > EOF
454 454 >>> fp = file('binary.diff', 'rb')
455 455 >>> data = fp.read()
456 456 >>> fp.close()
457 457 >>> file('binary.diff', 'wb').write(data.replace('\n', '\r\n'))
458 458 $ rm binary2
459 459 $ hg import --no-commit binary.diff
460 460 applying binary.diff
461 461
462 462 $ cd ..
463 463
464 464 Consecutive import with renames (issue2459)
465 465
466 466 $ hg init issue2459
467 467 $ cd issue2459
468 468 $ hg import --no-commit --force - <<EOF
469 469 > diff --git a/a b/a
470 470 > new file mode 100644
471 471 > EOF
472 472 applying patch from stdin
473 473 $ hg import --no-commit --force - <<EOF
474 474 > diff --git a/a b/b
475 475 > rename from a
476 476 > rename to b
477 477 > EOF
478 478 applying patch from stdin
479 479 a has not been committed yet, so no copy data will be stored for b.
480 480 $ hg debugstate
481 481 a 0 -1 unset b
482 482 $ hg ci -m done
483 483 $ cd ..
484 484
485 485 Renames and strip
486 486
487 487 $ hg init renameandstrip
488 488 $ cd renameandstrip
489 489 $ echo a > a
490 490 $ hg ci -Am adda
491 491 adding a
492 492 $ hg import --no-commit -p2 - <<EOF
493 493 > diff --git a/foo/a b/foo/b
494 494 > rename from foo/a
495 495 > rename to foo/b
496 496 > EOF
497 497 applying patch from stdin
498 498 $ hg st --copies
499 499 A b
500 500 a
501 501 R a
502 502
503 503 Renames, similarity and git diff
504 504
505 505 $ hg revert -aC
506 506 undeleting a
507 507 forgetting b
508 508 $ rm b
509 509 $ hg import --similarity 90 --no-commit - <<EOF
510 510 > diff --git a/a b/b
511 511 > rename from a
512 512 > rename to b
513 513 > EOF
514 514 applying patch from stdin
515 515 $ hg st --copies
516 516 A b
517 517 a
518 518 R a
519 519 $ cd ..
520 520
521 521 Pure copy with existing destination
522 522
523 523 $ hg init copytoexisting
524 524 $ cd copytoexisting
525 525 $ echo a > a
526 526 $ echo b > b
527 527 $ hg ci -Am add
528 528 adding a
529 529 adding b
530 530 $ hg import --no-commit - <<EOF
531 531 > diff --git a/a b/b
532 532 > copy from a
533 533 > copy to b
534 534 > EOF
535 535 applying patch from stdin
536 536 abort: cannot create b: destination already exists
537 537 [255]
538 538 $ cat b
539 539 b
540 540
541 541 Copy and changes with existing destination
542 542
543 543 $ hg import --no-commit - <<EOF
544 544 > diff --git a/a b/b
545 545 > copy from a
546 546 > copy to b
547 547 > --- a/a
548 548 > +++ b/b
549 549 > @@ -1,1 +1,2 @@
550 550 > a
551 551 > +b
552 552 > EOF
553 553 applying patch from stdin
554 554 cannot create b: destination already exists
555 555 1 out of 1 hunks FAILED -- saving rejects to file b.rej
556 556 abort: patch failed to apply
557 557 [255]
558 558 $ cat b
559 559 b
560 560
561 561 #if symlink
562 562
563 563 $ ln -s b linkb
564 564 $ hg add linkb
565 565 $ hg ci -m addlinkb
566 566 $ hg import --no-commit - <<EOF
567 567 > diff --git a/linkb b/linkb
568 568 > deleted file mode 120000
569 569 > --- a/linkb
570 570 > +++ /dev/null
571 571 > @@ -1,1 +0,0 @@
572 572 > -badhunk
573 573 > \ No newline at end of file
574 574 > EOF
575 575 applying patch from stdin
576 576 patching file linkb
577 577 Hunk #1 FAILED at 0
578 578 1 out of 1 hunks FAILED -- saving rejects to file linkb.rej
579 579 abort: patch failed to apply
580 580 [255]
581 581 $ hg st
582 582 ? b.rej
583 583 ? linkb.rej
584 584
585 585 #endif
586 586
587 587 Test corner case involving copies and multiple hunks (issue3384)
588 588
589 589 $ hg revert -qa
590 590 $ hg import --no-commit - <<EOF
591 591 > diff --git a/a b/c
592 592 > copy from a
593 593 > copy to c
594 594 > --- a/a
595 595 > +++ b/c
596 596 > @@ -1,1 +1,2 @@
597 597 > a
598 598 > +a
599 599 > @@ -2,1 +2,2 @@
600 600 > a
601 601 > +a
602 602 > diff --git a/a b/a
603 603 > --- a/a
604 604 > +++ b/a
605 605 > @@ -1,1 +1,2 @@
606 606 > a
607 607 > +b
608 608 > EOF
609 609 applying patch from stdin
610 610
611 611 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now