##// END OF EJS Templates
fix handling of files of unsupported type in the walk code...
Benoit Boissinot -
r1487:2bc6cd62 default
parent child Browse files
Show More
@@ -1,400 +1,411 b''
1 """
1 """
2 dirstate.py - working directory tracking for mercurial
2 dirstate.py - working directory tracking for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
8 """
8 """
9
9
10 import struct, os
10 import struct, os
11 from node import *
11 from node import *
12 from i18n import gettext as _
12 from i18n import gettext as _
13 from demandload import *
13 from demandload import *
14 demandload(globals(), "time bisect stat util re errno")
14 demandload(globals(), "time bisect stat util re errno")
15
15
16 class dirstate:
16 class dirstate:
17 def __init__(self, opener, ui, root):
17 def __init__(self, opener, ui, root):
18 self.opener = opener
18 self.opener = opener
19 self.root = root
19 self.root = root
20 self.dirty = 0
20 self.dirty = 0
21 self.ui = ui
21 self.ui = ui
22 self.map = None
22 self.map = None
23 self.pl = None
23 self.pl = None
24 self.copies = {}
24 self.copies = {}
25 self.ignorefunc = None
25 self.ignorefunc = None
26 self.blockignore = False
26 self.blockignore = False
27
27
28 def wjoin(self, f):
28 def wjoin(self, f):
29 return os.path.join(self.root, f)
29 return os.path.join(self.root, f)
30
30
31 def getcwd(self):
31 def getcwd(self):
32 cwd = os.getcwd()
32 cwd = os.getcwd()
33 if cwd == self.root: return ''
33 if cwd == self.root: return ''
34 return cwd[len(self.root) + 1:]
34 return cwd[len(self.root) + 1:]
35
35
36 def hgignore(self):
36 def hgignore(self):
37 '''return the contents of .hgignore as a list of patterns.
37 '''return the contents of .hgignore as a list of patterns.
38
38
39 trailing white space is dropped.
39 trailing white space is dropped.
40 the escape character is backslash.
40 the escape character is backslash.
41 comments start with #.
41 comments start with #.
42 empty lines are skipped.
42 empty lines are skipped.
43
43
44 lines can be of the following formats:
44 lines can be of the following formats:
45
45
46 syntax: regexp # defaults following lines to non-rooted regexps
46 syntax: regexp # defaults following lines to non-rooted regexps
47 syntax: glob # defaults following lines to non-rooted globs
47 syntax: glob # defaults following lines to non-rooted globs
48 re:pattern # non-rooted regular expression
48 re:pattern # non-rooted regular expression
49 glob:pattern # non-rooted glob
49 glob:pattern # non-rooted glob
50 pattern # pattern of the current default type'''
50 pattern # pattern of the current default type'''
51 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
51 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
52 def parselines(fp):
52 def parselines(fp):
53 for line in fp:
53 for line in fp:
54 escape = False
54 escape = False
55 for i in xrange(len(line)):
55 for i in xrange(len(line)):
56 if escape: escape = False
56 if escape: escape = False
57 elif line[i] == '\\': escape = True
57 elif line[i] == '\\': escape = True
58 elif line[i] == '#': break
58 elif line[i] == '#': break
59 line = line[:i].rstrip()
59 line = line[:i].rstrip()
60 if line: yield line
60 if line: yield line
61 pats = []
61 pats = []
62 try:
62 try:
63 fp = open(self.wjoin('.hgignore'))
63 fp = open(self.wjoin('.hgignore'))
64 syntax = 'relre:'
64 syntax = 'relre:'
65 for line in parselines(fp):
65 for line in parselines(fp):
66 if line.startswith('syntax:'):
66 if line.startswith('syntax:'):
67 s = line[7:].strip()
67 s = line[7:].strip()
68 try:
68 try:
69 syntax = syntaxes[s]
69 syntax = syntaxes[s]
70 except KeyError:
70 except KeyError:
71 self.ui.warn(_("ignoring invalid syntax '%s'\n") % s)
71 self.ui.warn(_("ignoring invalid syntax '%s'\n") % s)
72 continue
72 continue
73 pat = syntax + line
73 pat = syntax + line
74 for s in syntaxes.values():
74 for s in syntaxes.values():
75 if line.startswith(s):
75 if line.startswith(s):
76 pat = line
76 pat = line
77 break
77 break
78 pats.append(pat)
78 pats.append(pat)
79 except IOError: pass
79 except IOError: pass
80 return pats
80 return pats
81
81
82 def ignore(self, fn):
82 def ignore(self, fn):
83 '''default match function used by dirstate and localrepository.
83 '''default match function used by dirstate and localrepository.
84 this honours the .hgignore file, and nothing more.'''
84 this honours the .hgignore file, and nothing more.'''
85 if self.blockignore:
85 if self.blockignore:
86 return False
86 return False
87 if not self.ignorefunc:
87 if not self.ignorefunc:
88 ignore = self.hgignore()
88 ignore = self.hgignore()
89 if ignore:
89 if ignore:
90 files, self.ignorefunc, anypats = util.matcher(self.root,
90 files, self.ignorefunc, anypats = util.matcher(self.root,
91 inc=ignore)
91 inc=ignore)
92 else:
92 else:
93 self.ignorefunc = util.never
93 self.ignorefunc = util.never
94 return self.ignorefunc(fn)
94 return self.ignorefunc(fn)
95
95
96 def __del__(self):
96 def __del__(self):
97 if self.dirty:
97 if self.dirty:
98 self.write()
98 self.write()
99
99
100 def __getitem__(self, key):
100 def __getitem__(self, key):
101 try:
101 try:
102 return self.map[key]
102 return self.map[key]
103 except TypeError:
103 except TypeError:
104 self.read()
104 self.read()
105 return self[key]
105 return self[key]
106
106
107 def __contains__(self, key):
107 def __contains__(self, key):
108 if not self.map: self.read()
108 if not self.map: self.read()
109 return key in self.map
109 return key in self.map
110
110
111 def parents(self):
111 def parents(self):
112 if not self.pl:
112 if not self.pl:
113 self.read()
113 self.read()
114 return self.pl
114 return self.pl
115
115
116 def markdirty(self):
116 def markdirty(self):
117 if not self.dirty:
117 if not self.dirty:
118 self.dirty = 1
118 self.dirty = 1
119
119
120 def setparents(self, p1, p2=nullid):
120 def setparents(self, p1, p2=nullid):
121 if not self.pl:
121 if not self.pl:
122 self.read()
122 self.read()
123 self.markdirty()
123 self.markdirty()
124 self.pl = p1, p2
124 self.pl = p1, p2
125
125
126 def state(self, key):
126 def state(self, key):
127 try:
127 try:
128 return self[key][0]
128 return self[key][0]
129 except KeyError:
129 except KeyError:
130 return "?"
130 return "?"
131
131
132 def read(self):
132 def read(self):
133 if self.map is not None: return self.map
133 if self.map is not None: return self.map
134
134
135 self.map = {}
135 self.map = {}
136 self.pl = [nullid, nullid]
136 self.pl = [nullid, nullid]
137 try:
137 try:
138 st = self.opener("dirstate").read()
138 st = self.opener("dirstate").read()
139 if not st: return
139 if not st: return
140 except: return
140 except: return
141
141
142 self.pl = [st[:20], st[20: 40]]
142 self.pl = [st[:20], st[20: 40]]
143
143
144 pos = 40
144 pos = 40
145 while pos < len(st):
145 while pos < len(st):
146 e = struct.unpack(">cllll", st[pos:pos+17])
146 e = struct.unpack(">cllll", st[pos:pos+17])
147 l = e[4]
147 l = e[4]
148 pos += 17
148 pos += 17
149 f = st[pos:pos + l]
149 f = st[pos:pos + l]
150 if '\0' in f:
150 if '\0' in f:
151 f, c = f.split('\0')
151 f, c = f.split('\0')
152 self.copies[f] = c
152 self.copies[f] = c
153 self.map[f] = e[:4]
153 self.map[f] = e[:4]
154 pos += l
154 pos += l
155
155
156 def copy(self, source, dest):
156 def copy(self, source, dest):
157 self.read()
157 self.read()
158 self.markdirty()
158 self.markdirty()
159 self.copies[dest] = source
159 self.copies[dest] = source
160
160
161 def copied(self, file):
161 def copied(self, file):
162 return self.copies.get(file, None)
162 return self.copies.get(file, None)
163
163
164 def update(self, files, state, **kw):
164 def update(self, files, state, **kw):
165 ''' current states:
165 ''' current states:
166 n normal
166 n normal
167 m needs merging
167 m needs merging
168 r marked for removal
168 r marked for removal
169 a marked for addition'''
169 a marked for addition'''
170
170
171 if not files: return
171 if not files: return
172 self.read()
172 self.read()
173 self.markdirty()
173 self.markdirty()
174 for f in files:
174 for f in files:
175 if state == "r":
175 if state == "r":
176 self.map[f] = ('r', 0, 0, 0)
176 self.map[f] = ('r', 0, 0, 0)
177 else:
177 else:
178 s = os.lstat(os.path.join(self.root, f))
178 s = os.lstat(os.path.join(self.root, f))
179 st_size = kw.get('st_size', s.st_size)
179 st_size = kw.get('st_size', s.st_size)
180 st_mtime = kw.get('st_mtime', s.st_mtime)
180 st_mtime = kw.get('st_mtime', s.st_mtime)
181 self.map[f] = (state, s.st_mode, st_size, st_mtime)
181 self.map[f] = (state, s.st_mode, st_size, st_mtime)
182 if self.copies.has_key(f):
182 if self.copies.has_key(f):
183 del self.copies[f]
183 del self.copies[f]
184
184
185 def forget(self, files):
185 def forget(self, files):
186 if not files: return
186 if not files: return
187 self.read()
187 self.read()
188 self.markdirty()
188 self.markdirty()
189 for f in files:
189 for f in files:
190 try:
190 try:
191 del self.map[f]
191 del self.map[f]
192 except KeyError:
192 except KeyError:
193 self.ui.warn(_("not in dirstate: %s!\n") % f)
193 self.ui.warn(_("not in dirstate: %s!\n") % f)
194 pass
194 pass
195
195
196 def clear(self):
196 def clear(self):
197 self.map = {}
197 self.map = {}
198 self.markdirty()
198 self.markdirty()
199
199
200 def write(self):
200 def write(self):
201 st = self.opener("dirstate", "w")
201 st = self.opener("dirstate", "w")
202 st.write("".join(self.pl))
202 st.write("".join(self.pl))
203 for f, e in self.map.items():
203 for f, e in self.map.items():
204 c = self.copied(f)
204 c = self.copied(f)
205 if c:
205 if c:
206 f = f + "\0" + c
206 f = f + "\0" + c
207 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
207 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
208 st.write(e + f)
208 st.write(e + f)
209 self.dirty = 0
209 self.dirty = 0
210
210
211 def filterfiles(self, files):
211 def filterfiles(self, files):
212 ret = {}
212 ret = {}
213 unknown = []
213 unknown = []
214
214
215 for x in files:
215 for x in files:
216 if x is '.':
216 if x is '.':
217 return self.map.copy()
217 return self.map.copy()
218 if x not in self.map:
218 if x not in self.map:
219 unknown.append(x)
219 unknown.append(x)
220 else:
220 else:
221 ret[x] = self.map[x]
221 ret[x] = self.map[x]
222
222
223 if not unknown:
223 if not unknown:
224 return ret
224 return ret
225
225
226 b = self.map.keys()
226 b = self.map.keys()
227 b.sort()
227 b.sort()
228 blen = len(b)
228 blen = len(b)
229
229
230 for x in unknown:
230 for x in unknown:
231 bs = bisect.bisect(b, x)
231 bs = bisect.bisect(b, x)
232 if bs != 0 and b[bs-1] == x:
232 if bs != 0 and b[bs-1] == x:
233 ret[x] = self.map[x]
233 ret[x] = self.map[x]
234 continue
234 continue
235 while bs < blen:
235 while bs < blen:
236 s = b[bs]
236 s = b[bs]
237 if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/':
237 if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/':
238 ret[s] = self.map[s]
238 ret[s] = self.map[s]
239 else:
239 else:
240 break
240 break
241 bs += 1
241 bs += 1
242 return ret
242 return ret
243
243
244 def supported_type(self, f, st, verbose=True):
245 if stat.S_ISREG(st.st_mode):
246 return True
247 if verbose:
248 kind = 'unknown'
249 if stat.S_ISCHR(st.st_mode): kind = _('character device')
250 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
251 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
252 elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
253 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
254 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
255 self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
256 util.pathto(self.getcwd(), f),
257 kind))
258 return False
259
244 def statwalk(self, files=None, match=util.always, dc=None):
260 def statwalk(self, files=None, match=util.always, dc=None):
245 self.read()
261 self.read()
246
262
247 # walk all files by default
263 # walk all files by default
248 if not files:
264 if not files:
249 files = [self.root]
265 files = [self.root]
250 if not dc:
266 if not dc:
251 dc = self.map.copy()
267 dc = self.map.copy()
252 elif not dc:
268 elif not dc:
253 dc = self.filterfiles(files)
269 dc = self.filterfiles(files)
254
270
255 def statmatch(file, stat):
271 def statmatch(file, stat):
256 file = util.pconvert(file)
272 file = util.pconvert(file)
257 if file not in dc and self.ignore(file):
273 if file not in dc and self.ignore(file):
258 return False
274 return False
259 return match(file)
275 return match(file)
260
276
261 return self.walkhelper(files=files, statmatch=statmatch, dc=dc)
277 return self.walkhelper(files=files, statmatch=statmatch, dc=dc)
262
278
263 def walk(self, files=None, match=util.always, dc=None):
279 def walk(self, files=None, match=util.always, dc=None):
264 # filter out the stat
280 # filter out the stat
265 for src, f, st in self.statwalk(files, match, dc):
281 for src, f, st in self.statwalk(files, match, dc):
266 yield src, f
282 yield src, f
267
283
268 # walk recursively through the directory tree, finding all files
284 # walk recursively through the directory tree, finding all files
269 # matched by the statmatch function
285 # matched by the statmatch function
270 #
286 #
271 # results are yielded in a tuple (src, filename, st), where src
287 # results are yielded in a tuple (src, filename, st), where src
272 # is one of:
288 # is one of:
273 # 'f' the file was found in the directory tree
289 # 'f' the file was found in the directory tree
274 # 'm' the file was only in the dirstate and not in the tree
290 # 'm' the file was only in the dirstate and not in the tree
275 # and st is the stat result if the file was found in the directory.
291 # and st is the stat result if the file was found in the directory.
276 #
292 #
277 # dc is an optional arg for the current dirstate. dc is not modified
293 # dc is an optional arg for the current dirstate. dc is not modified
278 # directly by this function, but might be modified by your statmatch call.
294 # directly by this function, but might be modified by your statmatch call.
279 #
295 #
280 def walkhelper(self, files, statmatch, dc):
296 def walkhelper(self, files, statmatch, dc):
281 def supported_type(f, st):
282 if stat.S_ISREG(st.st_mode):
283 return True
284 else:
285 kind = 'unknown'
286 if stat.S_ISCHR(st.st_mode): kind = _('character device')
287 elif stat.S_ISBLK(st.st_mode): kind = _('block device')
288 elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
289 elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
290 elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
291 elif stat.S_ISDIR(st.st_mode): kind = _('directory')
292 self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
293 util.pathto(self.getcwd(), f),
294 kind))
295 return False
296
297 # recursion free walker, faster than os.walk.
297 # recursion free walker, faster than os.walk.
298 def findfiles(s):
298 def findfiles(s):
299 retfiles = []
299 retfiles = []
300 work = [s]
300 work = [s]
301 while work:
301 while work:
302 top = work.pop()
302 top = work.pop()
303 names = os.listdir(top)
303 names = os.listdir(top)
304 names.sort()
304 names.sort()
305 # nd is the top of the repository dir tree
305 # nd is the top of the repository dir tree
306 nd = util.normpath(top[len(self.root) + 1:])
306 nd = util.normpath(top[len(self.root) + 1:])
307 if nd == '.': nd = ''
307 if nd == '.': nd = ''
308 for f in names:
308 for f in names:
309 np = os.path.join(nd, f)
309 np = os.path.join(nd, f)
310 if seen(np):
310 if seen(np):
311 continue
311 continue
312 p = os.path.join(top, f)
312 p = os.path.join(top, f)
313 # don't trip over symlinks
313 # don't trip over symlinks
314 st = os.lstat(p)
314 st = os.lstat(p)
315 if stat.S_ISDIR(st.st_mode):
315 if stat.S_ISDIR(st.st_mode):
316 ds = os.path.join(nd, f +'/')
316 ds = os.path.join(nd, f +'/')
317 if statmatch(ds, st):
317 if statmatch(ds, st):
318 work.append(p)
318 work.append(p)
319 elif statmatch(np, st) and supported_type(np, st):
319 if statmatch(np, st) and np in dc:
320 yield util.pconvert(np), st
320 yield 'm', util.pconvert(np), st
321
321 elif statmatch(np, st):
322 if self.supported_type(np, st):
323 yield 'f', util.pconvert(np), st
324 elif np in dc:
325 yield 'm', util.pconvert(np), st
322
326
323 known = {'.hg': 1}
327 known = {'.hg': 1}
324 def seen(fn):
328 def seen(fn):
325 if fn in known: return True
329 if fn in known: return True
326 known[fn] = 1
330 known[fn] = 1
327
331
328 # step one, find all files that match our criteria
332 # step one, find all files that match our criteria
329 files.sort()
333 files.sort()
330 for ff in util.unique(files):
334 for ff in util.unique(files):
331 f = os.path.join(self.root, ff)
335 f = os.path.join(self.root, ff)
332 try:
336 try:
333 st = os.lstat(f)
337 st = os.lstat(f)
334 except OSError, inst:
338 except OSError, inst:
335 if ff not in dc: self.ui.warn('%s: %s\n' % (
339 if ff not in dc: self.ui.warn('%s: %s\n' % (
336 util.pathto(self.getcwd(), ff),
340 util.pathto(self.getcwd(), ff),
337 inst.strerror))
341 inst.strerror))
338 continue
342 continue
339 if stat.S_ISDIR(st.st_mode):
343 if stat.S_ISDIR(st.st_mode):
340 cmp0 = (lambda x, y: cmp(x[0], y[0]))
344 cmp1 = (lambda x, y: cmp(x[1], y[1]))
341 sorted = [ x for x in findfiles(f) ]
345 sorted = [ x for x in findfiles(f) ]
342 sorted.sort(cmp0)
346 sorted.sort(cmp1)
343 for fl, stl in sorted:
347 for e in sorted:
344 yield 'f', fl, stl
348 yield e
345 else:
349 else:
346 ff = util.normpath(ff)
350 ff = util.normpath(ff)
347 if seen(ff):
351 if seen(ff):
348 continue
352 continue
349 found = False
350 self.blockignore = True
353 self.blockignore = True
351 if statmatch(ff, st) and supported_type(ff, st):
354 if statmatch(ff, st):
352 found = True
355 if self.supported_type(ff, st):
356 yield 'f', ff, st
357 elif ff in dc:
358 yield 'm', ff, st
353 self.blockignore = False
359 self.blockignore = False
354 if found:
355 yield 'f', ff, st
356
360
357 # step two run through anything left in the dc hash and yield
361 # step two run through anything left in the dc hash and yield
358 # if we haven't already seen it
362 # if we haven't already seen it
359 ks = dc.keys()
363 ks = dc.keys()
360 ks.sort()
364 ks.sort()
361 for k in ks:
365 for k in ks:
362 if not seen(k) and (statmatch(k, None)):
366 if not seen(k) and (statmatch(k, None)):
363 yield 'm', k, None
367 yield 'm', k, None
364
368
365 def changes(self, files=None, match=util.always):
369 def changes(self, files=None, match=util.always):
366 lookup, modified, added, unknown = [], [], [], []
370 lookup, modified, added, unknown = [], [], [], []
367 removed, deleted = [], []
371 removed, deleted = [], []
368
372
369 for src, fn, st in self.statwalk(files, match):
373 for src, fn, st in self.statwalk(files, match):
370 try:
374 try:
371 type, mode, size, time = self[fn]
375 type, mode, size, time = self[fn]
372 except KeyError:
376 except KeyError:
373 unknown.append(fn)
377 unknown.append(fn)
374 continue
378 continue
375 if src == 'm':
379 if src == 'm':
380 nonexistent = True
381 if not st:
376 try:
382 try:
377 st = os.stat(fn)
383 st = os.lstat(fn)
378 except OSError, inst:
384 except OSError, inst:
385 if inst.errno != errno.ENOENT:
386 raise
387 st = None
388 # We need to re-check that it is a valid file
389 if st and self.supported_type(fn, st):
390 nonexistent = False
379 # XXX: what to do with file no longer present in the fs
391 # XXX: what to do with file no longer present in the fs
380 # who are not removed in the dirstate ?
392 # who are not removed in the dirstate ?
381 if inst.errno != errno.ENOENT:
393 if nonexistent:
382 raise
383 deleted.append(fn)
394 deleted.append(fn)
384 continue
395 continue
385 # check the common case first
396 # check the common case first
386 if type == 'n':
397 if type == 'n':
387 if not st:
398 if not st:
388 st = os.stat(fn)
399 st = os.stat(fn)
389 if size != st.st_size or (mode ^ st.st_mode) & 0100:
400 if size != st.st_size or (mode ^ st.st_mode) & 0100:
390 modified.append(fn)
401 modified.append(fn)
391 elif time != st.st_mtime:
402 elif time != st.st_mtime:
392 lookup.append(fn)
403 lookup.append(fn)
393 elif type == 'm':
404 elif type == 'm':
394 modified.append(fn)
405 modified.append(fn)
395 elif type == 'a':
406 elif type == 'a':
396 added.append(fn)
407 added.append(fn)
397 elif type == 'r':
408 elif type == 'r':
398 removed.append(fn)
409 removed.append(fn)
399
410
400 return (lookup, modified, added, removed + deleted, unknown)
411 return (lookup, modified, added, removed + deleted, unknown)
@@ -1,24 +1,32 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 hg init
3 hg init
4 echo 123 > a
4 echo 123 > a
5 echo 123 > c
5 echo 123 > c
6 hg add a c
6 hg add a c
7 hg commit -m "first" -d "0 0" a c
7 hg commit -m "first" -d "0 0" a c
8 echo 123 > b
8 echo 123 > b
9 echo %% should show b unknown
9 hg status
10 hg status
10 echo 12 > c
11 echo 12 > c
12 echo %% should show b unknown and c modified
11 hg status
13 hg status
12 hg add b
14 hg add b
15 echo %% should show b added and c modified
13 hg status
16 hg status
14 hg rm a
17 hg rm a
18 echo %% should show a removed, b added and c modified
15 hg status
19 hg status
16 hg revert a
20 hg revert a
21 echo %% should show b added and c modified
17 hg status
22 hg status
18 hg revert b
23 hg revert b
24 echo %% should show b unknown and c modified
19 hg status
25 hg status
20 hg revert c
26 hg revert c
27 echo %% should show b unknown
21 hg status
28 hg status
29 echo %% should show a b and c
22 ls
30 ls
23
31
24 true
32 true
@@ -1,16 +1,24 b''
1 %% should show b unknown
1 ? b
2 ? b
3 %% should show b unknown and c modified
2 M c
4 M c
3 ? b
5 ? b
6 %% should show b added and c modified
4 M c
7 M c
5 A b
8 A b
9 %% should show a removed, b added and c modified
6 M c
10 M c
7 A b
11 A b
8 R a
12 R a
13 %% should show b added and c modified
9 M c
14 M c
10 A b
15 A b
16 %% should show b unknown and c modified
11 M c
17 M c
12 ? b
18 ? b
19 %% should show b unknown
13 ? b
20 ? b
21 %% should show a b and c
14 a
22 a
15 b
23 b
16 c
24 c
@@ -1,6 +1,15 b''
1 bar: unsupported file type (type is symbolic link)
1 bar: unsupported file type (type is symbolic link)
2 adding foo
2 adding foo
3 bar: unsupported file type (type is symbolic link)
3 bar: unsupported file type (type is symbolic link)
4 bar: unsupported file type (type is symbolic link)
4 bar: unsupported file type (type is symbolic link)
5 adding bomb
5 adding bomb
6 bar: unsupported file type (type is symbolic link)
6 bar: unsupported file type (type is symbolic link)
7 adding a.c
8 adding dir/a.o
9 adding dir/b.o
10 a.c: unsupported file type (type is fifo)
11 dir/b.o: unsupported file type (type is symbolic link)
12 R a.c
13 R dir/a.o
14 R dir/b.o
15 ? .hgignore
General Comments 0
You need to be logged in to leave comments. Login now