##// END OF EJS Templates
status: put added files that have disappeared in the deleted list...
Alexis S. L. Carvalho -
r6110:81e20e01 default
parent child Browse files
Show More
@@ -1,595 +1,595 b''
1 """
1 """
2 dirstate.py - working directory tracking for mercurial
2 dirstate.py - working directory tracking for mercurial
3
3
4 Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 Copyright 2005-2007 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 from node import *
10 from node import *
11 from i18n import _
11 from i18n import _
12 import struct, os, time, bisect, stat, strutil, util, re, errno, ignore
12 import struct, os, time, bisect, stat, strutil, util, re, errno, ignore
13 import cStringIO, osutil
13 import cStringIO, osutil
14
14
15 _unknown = ('?', 0, 0, 0)
15 _unknown = ('?', 0, 0, 0)
16 _format = ">cllll"
16 _format = ">cllll"
17
17
18 class dirstate(object):
18 class dirstate(object):
19
19
20 def __init__(self, opener, ui, root):
20 def __init__(self, opener, ui, root):
21 self._opener = opener
21 self._opener = opener
22 self._root = root
22 self._root = root
23 self._dirty = False
23 self._dirty = False
24 self._dirtypl = False
24 self._dirtypl = False
25 self._ui = ui
25 self._ui = ui
26
26
27 def __getattr__(self, name):
27 def __getattr__(self, name):
28 if name == '_map':
28 if name == '_map':
29 self._read()
29 self._read()
30 return self._map
30 return self._map
31 elif name == '_copymap':
31 elif name == '_copymap':
32 self._read()
32 self._read()
33 return self._copymap
33 return self._copymap
34 elif name == '_branch':
34 elif name == '_branch':
35 try:
35 try:
36 self._branch = (self._opener("branch").read().strip()
36 self._branch = (self._opener("branch").read().strip()
37 or "default")
37 or "default")
38 except IOError:
38 except IOError:
39 self._branch = "default"
39 self._branch = "default"
40 return self._branch
40 return self._branch
41 elif name == '_pl':
41 elif name == '_pl':
42 self._pl = [nullid, nullid]
42 self._pl = [nullid, nullid]
43 try:
43 try:
44 st = self._opener("dirstate").read(40)
44 st = self._opener("dirstate").read(40)
45 if len(st) == 40:
45 if len(st) == 40:
46 self._pl = st[:20], st[20:40]
46 self._pl = st[:20], st[20:40]
47 except IOError, err:
47 except IOError, err:
48 if err.errno != errno.ENOENT: raise
48 if err.errno != errno.ENOENT: raise
49 return self._pl
49 return self._pl
50 elif name == '_dirs':
50 elif name == '_dirs':
51 self._dirs = {}
51 self._dirs = {}
52 for f in self._map:
52 for f in self._map:
53 if self[f] != 'r':
53 if self[f] != 'r':
54 self._incpath(f)
54 self._incpath(f)
55 return self._dirs
55 return self._dirs
56 elif name == '_ignore':
56 elif name == '_ignore':
57 files = [self._join('.hgignore')]
57 files = [self._join('.hgignore')]
58 for name, path in self._ui.configitems("ui"):
58 for name, path in self._ui.configitems("ui"):
59 if name == 'ignore' or name.startswith('ignore.'):
59 if name == 'ignore' or name.startswith('ignore.'):
60 files.append(os.path.expanduser(path))
60 files.append(os.path.expanduser(path))
61 self._ignore = ignore.ignore(self._root, files, self._ui.warn)
61 self._ignore = ignore.ignore(self._root, files, self._ui.warn)
62 return self._ignore
62 return self._ignore
63 elif name == '_slash':
63 elif name == '_slash':
64 self._slash = self._ui.configbool('ui', 'slash') and os.sep != '/'
64 self._slash = self._ui.configbool('ui', 'slash') and os.sep != '/'
65 return self._slash
65 return self._slash
66 else:
66 else:
67 raise AttributeError, name
67 raise AttributeError, name
68
68
69 def _join(self, f):
69 def _join(self, f):
70 return os.path.join(self._root, f)
70 return os.path.join(self._root, f)
71
71
72 def getcwd(self):
72 def getcwd(self):
73 cwd = os.getcwd()
73 cwd = os.getcwd()
74 if cwd == self._root: return ''
74 if cwd == self._root: return ''
75 # self._root ends with a path separator if self._root is '/' or 'C:\'
75 # self._root ends with a path separator if self._root is '/' or 'C:\'
76 rootsep = self._root
76 rootsep = self._root
77 if not util.endswithsep(rootsep):
77 if not util.endswithsep(rootsep):
78 rootsep += os.sep
78 rootsep += os.sep
79 if cwd.startswith(rootsep):
79 if cwd.startswith(rootsep):
80 return cwd[len(rootsep):]
80 return cwd[len(rootsep):]
81 else:
81 else:
82 # we're outside the repo. return an absolute path.
82 # we're outside the repo. return an absolute path.
83 return cwd
83 return cwd
84
84
85 def pathto(self, f, cwd=None):
85 def pathto(self, f, cwd=None):
86 if cwd is None:
86 if cwd is None:
87 cwd = self.getcwd()
87 cwd = self.getcwd()
88 path = util.pathto(self._root, cwd, f)
88 path = util.pathto(self._root, cwd, f)
89 if self._slash:
89 if self._slash:
90 return util.normpath(path)
90 return util.normpath(path)
91 return path
91 return path
92
92
93 def __getitem__(self, key):
93 def __getitem__(self, key):
94 ''' current states:
94 ''' current states:
95 n normal
95 n normal
96 m needs merging
96 m needs merging
97 r marked for removal
97 r marked for removal
98 a marked for addition
98 a marked for addition
99 ? not tracked'''
99 ? not tracked'''
100 return self._map.get(key, ("?",))[0]
100 return self._map.get(key, ("?",))[0]
101
101
102 def __contains__(self, key):
102 def __contains__(self, key):
103 return key in self._map
103 return key in self._map
104
104
105 def __iter__(self):
105 def __iter__(self):
106 a = self._map.keys()
106 a = self._map.keys()
107 a.sort()
107 a.sort()
108 for x in a:
108 for x in a:
109 yield x
109 yield x
110
110
111 def parents(self):
111 def parents(self):
112 return self._pl
112 return self._pl
113
113
114 def branch(self):
114 def branch(self):
115 return self._branch
115 return self._branch
116
116
117 def setparents(self, p1, p2=nullid):
117 def setparents(self, p1, p2=nullid):
118 self._dirty = self._dirtypl = True
118 self._dirty = self._dirtypl = True
119 self._pl = p1, p2
119 self._pl = p1, p2
120
120
121 def setbranch(self, branch):
121 def setbranch(self, branch):
122 self._branch = branch
122 self._branch = branch
123 self._opener("branch", "w").write(branch + '\n')
123 self._opener("branch", "w").write(branch + '\n')
124
124
125 def _read(self):
125 def _read(self):
126 self._map = {}
126 self._map = {}
127 self._copymap = {}
127 self._copymap = {}
128 if not self._dirtypl:
128 if not self._dirtypl:
129 self._pl = [nullid, nullid]
129 self._pl = [nullid, nullid]
130 try:
130 try:
131 st = self._opener("dirstate").read()
131 st = self._opener("dirstate").read()
132 except IOError, err:
132 except IOError, err:
133 if err.errno != errno.ENOENT: raise
133 if err.errno != errno.ENOENT: raise
134 return
134 return
135 if not st:
135 if not st:
136 return
136 return
137
137
138 if not self._dirtypl:
138 if not self._dirtypl:
139 self._pl = [st[:20], st[20: 40]]
139 self._pl = [st[:20], st[20: 40]]
140
140
141 # deref fields so they will be local in loop
141 # deref fields so they will be local in loop
142 dmap = self._map
142 dmap = self._map
143 copymap = self._copymap
143 copymap = self._copymap
144 unpack = struct.unpack
144 unpack = struct.unpack
145 e_size = struct.calcsize(_format)
145 e_size = struct.calcsize(_format)
146 pos1 = 40
146 pos1 = 40
147 l = len(st)
147 l = len(st)
148
148
149 # the inner loop
149 # the inner loop
150 while pos1 < l:
150 while pos1 < l:
151 pos2 = pos1 + e_size
151 pos2 = pos1 + e_size
152 e = unpack(">cllll", st[pos1:pos2]) # a literal here is faster
152 e = unpack(">cllll", st[pos1:pos2]) # a literal here is faster
153 pos1 = pos2 + e[4]
153 pos1 = pos2 + e[4]
154 f = st[pos2:pos1]
154 f = st[pos2:pos1]
155 if '\0' in f:
155 if '\0' in f:
156 f, c = f.split('\0')
156 f, c = f.split('\0')
157 copymap[f] = c
157 copymap[f] = c
158 dmap[f] = e # we hold onto e[4] because making a subtuple is slow
158 dmap[f] = e # we hold onto e[4] because making a subtuple is slow
159
159
160 def invalidate(self):
160 def invalidate(self):
161 for a in "_map _copymap _branch _pl _dirs _ignore".split():
161 for a in "_map _copymap _branch _pl _dirs _ignore".split():
162 if a in self.__dict__:
162 if a in self.__dict__:
163 delattr(self, a)
163 delattr(self, a)
164 self._dirty = False
164 self._dirty = False
165
165
166 def copy(self, source, dest):
166 def copy(self, source, dest):
167 self._dirty = True
167 self._dirty = True
168 self._copymap[dest] = source
168 self._copymap[dest] = source
169
169
170 def copied(self, file):
170 def copied(self, file):
171 return self._copymap.get(file, None)
171 return self._copymap.get(file, None)
172
172
173 def copies(self):
173 def copies(self):
174 return self._copymap
174 return self._copymap
175
175
176 def _incpath(self, path):
176 def _incpath(self, path):
177 c = path.rfind('/')
177 c = path.rfind('/')
178 if c >= 0:
178 if c >= 0:
179 dirs = self._dirs
179 dirs = self._dirs
180 base = path[:c]
180 base = path[:c]
181 if base not in dirs:
181 if base not in dirs:
182 self._incpath(base)
182 self._incpath(base)
183 dirs[base] = 1
183 dirs[base] = 1
184 else:
184 else:
185 dirs[base] += 1
185 dirs[base] += 1
186
186
187 def _decpath(self, path):
187 def _decpath(self, path):
188 c = path.rfind('/')
188 c = path.rfind('/')
189 if c >= 0:
189 if c >= 0:
190 base = path[:c]
190 base = path[:c]
191 dirs = self._dirs
191 dirs = self._dirs
192 if dirs[base] == 1:
192 if dirs[base] == 1:
193 del dirs[base]
193 del dirs[base]
194 self._decpath(base)
194 self._decpath(base)
195 else:
195 else:
196 dirs[base] -= 1
196 dirs[base] -= 1
197
197
198 def _incpathcheck(self, f):
198 def _incpathcheck(self, f):
199 if '\r' in f or '\n' in f:
199 if '\r' in f or '\n' in f:
200 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames"))
200 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames"))
201 # shadows
201 # shadows
202 if f in self._dirs:
202 if f in self._dirs:
203 raise util.Abort(_('directory %r already in dirstate') % f)
203 raise util.Abort(_('directory %r already in dirstate') % f)
204 for c in strutil.rfindall(f, '/'):
204 for c in strutil.rfindall(f, '/'):
205 d = f[:c]
205 d = f[:c]
206 if d in self._dirs:
206 if d in self._dirs:
207 break
207 break
208 if d in self._map and self[d] != 'r':
208 if d in self._map and self[d] != 'r':
209 raise util.Abort(_('file %r in dirstate clashes with %r') %
209 raise util.Abort(_('file %r in dirstate clashes with %r') %
210 (d, f))
210 (d, f))
211 self._incpath(f)
211 self._incpath(f)
212
212
213 def _changepath(self, f, newstate, relaxed=False):
213 def _changepath(self, f, newstate, relaxed=False):
214 # handle upcoming path changes
214 # handle upcoming path changes
215 oldstate = self[f]
215 oldstate = self[f]
216 if oldstate not in "?r" and newstate in "?r":
216 if oldstate not in "?r" and newstate in "?r":
217 if "_dirs" in self.__dict__:
217 if "_dirs" in self.__dict__:
218 self._decpath(f)
218 self._decpath(f)
219 return
219 return
220 if oldstate in "?r" and newstate not in "?r":
220 if oldstate in "?r" and newstate not in "?r":
221 if relaxed and oldstate == '?':
221 if relaxed and oldstate == '?':
222 # XXX
222 # XXX
223 # in relaxed mode we assume the caller knows
223 # in relaxed mode we assume the caller knows
224 # what it is doing, workaround for updating
224 # what it is doing, workaround for updating
225 # dir-to-file revisions
225 # dir-to-file revisions
226 if "_dirs" in self.__dict__:
226 if "_dirs" in self.__dict__:
227 self._incpath(f)
227 self._incpath(f)
228 return
228 return
229 self._incpathcheck(f)
229 self._incpathcheck(f)
230 return
230 return
231
231
232 def normal(self, f):
232 def normal(self, f):
233 'mark a file normal and clean'
233 'mark a file normal and clean'
234 self._dirty = True
234 self._dirty = True
235 self._changepath(f, 'n', True)
235 self._changepath(f, 'n', True)
236 s = os.lstat(self._join(f))
236 s = os.lstat(self._join(f))
237 self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0)
237 self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0)
238 if f in self._copymap:
238 if f in self._copymap:
239 del self._copymap[f]
239 del self._copymap[f]
240
240
241 def normallookup(self, f):
241 def normallookup(self, f):
242 'mark a file normal, but possibly dirty'
242 'mark a file normal, but possibly dirty'
243 self._dirty = True
243 self._dirty = True
244 self._changepath(f, 'n', True)
244 self._changepath(f, 'n', True)
245 self._map[f] = ('n', 0, -1, -1, 0)
245 self._map[f] = ('n', 0, -1, -1, 0)
246 if f in self._copymap:
246 if f in self._copymap:
247 del self._copymap[f]
247 del self._copymap[f]
248
248
249 def normaldirty(self, f):
249 def normaldirty(self, f):
250 'mark a file normal, but dirty'
250 'mark a file normal, but dirty'
251 self._dirty = True
251 self._dirty = True
252 self._changepath(f, 'n', True)
252 self._changepath(f, 'n', True)
253 self._map[f] = ('n', 0, -2, -1, 0)
253 self._map[f] = ('n', 0, -2, -1, 0)
254 if f in self._copymap:
254 if f in self._copymap:
255 del self._copymap[f]
255 del self._copymap[f]
256
256
257 def add(self, f):
257 def add(self, f):
258 'mark a file added'
258 'mark a file added'
259 self._dirty = True
259 self._dirty = True
260 self._changepath(f, 'a')
260 self._changepath(f, 'a')
261 self._map[f] = ('a', 0, -1, -1, 0)
261 self._map[f] = ('a', 0, -1, -1, 0)
262 if f in self._copymap:
262 if f in self._copymap:
263 del self._copymap[f]
263 del self._copymap[f]
264
264
265 def remove(self, f):
265 def remove(self, f):
266 'mark a file removed'
266 'mark a file removed'
267 self._dirty = True
267 self._dirty = True
268 self._changepath(f, 'r')
268 self._changepath(f, 'r')
269 self._map[f] = ('r', 0, 0, 0, 0)
269 self._map[f] = ('r', 0, 0, 0, 0)
270 if f in self._copymap:
270 if f in self._copymap:
271 del self._copymap[f]
271 del self._copymap[f]
272
272
273 def merge(self, f):
273 def merge(self, f):
274 'mark a file merged'
274 'mark a file merged'
275 self._dirty = True
275 self._dirty = True
276 s = os.lstat(self._join(f))
276 s = os.lstat(self._join(f))
277 self._changepath(f, 'm', True)
277 self._changepath(f, 'm', True)
278 self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0)
278 self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0)
279 if f in self._copymap:
279 if f in self._copymap:
280 del self._copymap[f]
280 del self._copymap[f]
281
281
282 def forget(self, f):
282 def forget(self, f):
283 'forget a file'
283 'forget a file'
284 self._dirty = True
284 self._dirty = True
285 try:
285 try:
286 self._changepath(f, '?')
286 self._changepath(f, '?')
287 del self._map[f]
287 del self._map[f]
288 except KeyError:
288 except KeyError:
289 self._ui.warn(_("not in dirstate: %s\n") % f)
289 self._ui.warn(_("not in dirstate: %s\n") % f)
290
290
291 def clear(self):
291 def clear(self):
292 self._map = {}
292 self._map = {}
293 if "_dirs" in self.__dict__:
293 if "_dirs" in self.__dict__:
294 delattr(self, "_dirs");
294 delattr(self, "_dirs");
295 self._copymap = {}
295 self._copymap = {}
296 self._pl = [nullid, nullid]
296 self._pl = [nullid, nullid]
297 self._dirty = True
297 self._dirty = True
298
298
299 def rebuild(self, parent, files):
299 def rebuild(self, parent, files):
300 self.clear()
300 self.clear()
301 for f in files:
301 for f in files:
302 if files.execf(f):
302 if files.execf(f):
303 self._map[f] = ('n', 0777, -1, 0, 0)
303 self._map[f] = ('n', 0777, -1, 0, 0)
304 else:
304 else:
305 self._map[f] = ('n', 0666, -1, 0, 0)
305 self._map[f] = ('n', 0666, -1, 0, 0)
306 self._pl = (parent, nullid)
306 self._pl = (parent, nullid)
307 self._dirty = True
307 self._dirty = True
308
308
309 def write(self):
309 def write(self):
310 if not self._dirty:
310 if not self._dirty:
311 return
311 return
312 cs = cStringIO.StringIO()
312 cs = cStringIO.StringIO()
313 copymap = self._copymap
313 copymap = self._copymap
314 pack = struct.pack
314 pack = struct.pack
315 write = cs.write
315 write = cs.write
316 write("".join(self._pl))
316 write("".join(self._pl))
317 for f, e in self._map.iteritems():
317 for f, e in self._map.iteritems():
318 if f in copymap:
318 if f in copymap:
319 f = "%s\0%s" % (f, copymap[f])
319 f = "%s\0%s" % (f, copymap[f])
320 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
320 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
321 write(e)
321 write(e)
322 write(f)
322 write(f)
323 st = self._opener("dirstate", "w", atomictemp=True)
323 st = self._opener("dirstate", "w", atomictemp=True)
324 st.write(cs.getvalue())
324 st.write(cs.getvalue())
325 st.rename()
325 st.rename()
326 self._dirty = self._dirtypl = False
326 self._dirty = self._dirtypl = False
327
327
328 def _filter(self, files):
328 def _filter(self, files):
329 ret = {}
329 ret = {}
330 unknown = []
330 unknown = []
331
331
332 for x in files:
332 for x in files:
333 if x == '.':
333 if x == '.':
334 return self._map.copy()
334 return self._map.copy()
335 if x not in self._map:
335 if x not in self._map:
336 unknown.append(x)
336 unknown.append(x)
337 else:
337 else:
338 ret[x] = self._map[x]
338 ret[x] = self._map[x]
339
339
340 if not unknown:
340 if not unknown:
341 return ret
341 return ret
342
342
343 b = self._map.keys()
343 b = self._map.keys()
344 b.sort()
344 b.sort()
345 blen = len(b)
345 blen = len(b)
346
346
347 for x in unknown:
347 for x in unknown:
348 bs = bisect.bisect(b, "%s%s" % (x, '/'))
348 bs = bisect.bisect(b, "%s%s" % (x, '/'))
349 while bs < blen:
349 while bs < blen:
350 s = b[bs]
350 s = b[bs]
351 if len(s) > len(x) and s.startswith(x):
351 if len(s) > len(x) and s.startswith(x):
352 ret[s] = self._map[s]
352 ret[s] = self._map[s]
353 else:
353 else:
354 break
354 break
355 bs += 1
355 bs += 1
356 return ret
356 return ret
357
357
358 def _supported(self, f, mode, verbose=False):
358 def _supported(self, f, mode, verbose=False):
359 if stat.S_ISREG(mode) or stat.S_ISLNK(mode):
359 if stat.S_ISREG(mode) or stat.S_ISLNK(mode):
360 return True
360 return True
361 if verbose:
361 if verbose:
362 kind = 'unknown'
362 kind = 'unknown'
363 if stat.S_ISCHR(mode): kind = _('character device')
363 if stat.S_ISCHR(mode): kind = _('character device')
364 elif stat.S_ISBLK(mode): kind = _('block device')
364 elif stat.S_ISBLK(mode): kind = _('block device')
365 elif stat.S_ISFIFO(mode): kind = _('fifo')
365 elif stat.S_ISFIFO(mode): kind = _('fifo')
366 elif stat.S_ISSOCK(mode): kind = _('socket')
366 elif stat.S_ISSOCK(mode): kind = _('socket')
367 elif stat.S_ISDIR(mode): kind = _('directory')
367 elif stat.S_ISDIR(mode): kind = _('directory')
368 self._ui.warn(_('%s: unsupported file type (type is %s)\n')
368 self._ui.warn(_('%s: unsupported file type (type is %s)\n')
369 % (self.pathto(f), kind))
369 % (self.pathto(f), kind))
370 return False
370 return False
371
371
372 def _dirignore(self, f):
372 def _dirignore(self, f):
373 if self._ignore(f):
373 if self._ignore(f):
374 return True
374 return True
375 for c in strutil.findall(f, '/'):
375 for c in strutil.findall(f, '/'):
376 if self._ignore(f[:c]):
376 if self._ignore(f[:c]):
377 return True
377 return True
378 return False
378 return False
379
379
380 def walk(self, files=None, match=util.always, badmatch=None):
380 def walk(self, files=None, match=util.always, badmatch=None):
381 # filter out the stat
381 # filter out the stat
382 for src, f, st in self.statwalk(files, match, badmatch=badmatch):
382 for src, f, st in self.statwalk(files, match, badmatch=badmatch):
383 yield src, f
383 yield src, f
384
384
385 def statwalk(self, files=None, match=util.always, ignored=False,
385 def statwalk(self, files=None, match=util.always, ignored=False,
386 badmatch=None, directories=False):
386 badmatch=None, directories=False):
387 '''
387 '''
388 walk recursively through the directory tree, finding all files
388 walk recursively through the directory tree, finding all files
389 matched by the match function
389 matched by the match function
390
390
391 results are yielded in a tuple (src, filename, st), where src
391 results are yielded in a tuple (src, filename, st), where src
392 is one of:
392 is one of:
393 'f' the file was found in the directory tree
393 'f' the file was found in the directory tree
394 'd' the file is a directory of the tree
394 'd' the file is a directory of the tree
395 'm' the file was only in the dirstate and not in the tree
395 'm' the file was only in the dirstate and not in the tree
396 'b' file was not found and matched badmatch
396 'b' file was not found and matched badmatch
397
397
398 and st is the stat result if the file was found in the directory.
398 and st is the stat result if the file was found in the directory.
399 '''
399 '''
400
400
401 # walk all files by default
401 # walk all files by default
402 if not files:
402 if not files:
403 files = ['.']
403 files = ['.']
404 dc = self._map.copy()
404 dc = self._map.copy()
405 else:
405 else:
406 files = util.unique(files)
406 files = util.unique(files)
407 dc = self._filter(files)
407 dc = self._filter(files)
408
408
409 def imatch(file_):
409 def imatch(file_):
410 if file_ not in dc and self._ignore(file_):
410 if file_ not in dc and self._ignore(file_):
411 return False
411 return False
412 return match(file_)
412 return match(file_)
413
413
414 ignore = self._ignore
414 ignore = self._ignore
415 dirignore = self._dirignore
415 dirignore = self._dirignore
416 if ignored:
416 if ignored:
417 imatch = match
417 imatch = match
418 ignore = util.never
418 ignore = util.never
419 dirignore = util.never
419 dirignore = util.never
420
420
421 # self._root may end with a path separator when self._root == '/'
421 # self._root may end with a path separator when self._root == '/'
422 common_prefix_len = len(self._root)
422 common_prefix_len = len(self._root)
423 if not util.endswithsep(self._root):
423 if not util.endswithsep(self._root):
424 common_prefix_len += 1
424 common_prefix_len += 1
425
425
426 normpath = util.normpath
426 normpath = util.normpath
427 listdir = osutil.listdir
427 listdir = osutil.listdir
428 lstat = os.lstat
428 lstat = os.lstat
429 bisect_left = bisect.bisect_left
429 bisect_left = bisect.bisect_left
430 isdir = os.path.isdir
430 isdir = os.path.isdir
431 pconvert = util.pconvert
431 pconvert = util.pconvert
432 join = os.path.join
432 join = os.path.join
433 s_isdir = stat.S_ISDIR
433 s_isdir = stat.S_ISDIR
434 supported = self._supported
434 supported = self._supported
435 _join = self._join
435 _join = self._join
436 known = {'.hg': 1}
436 known = {'.hg': 1}
437
437
438 # recursion free walker, faster than os.walk.
438 # recursion free walker, faster than os.walk.
439 def findfiles(s):
439 def findfiles(s):
440 work = [s]
440 work = [s]
441 wadd = work.append
441 wadd = work.append
442 found = []
442 found = []
443 add = found.append
443 add = found.append
444 if directories:
444 if directories:
445 add((normpath(s[common_prefix_len:]), 'd', lstat(s)))
445 add((normpath(s[common_prefix_len:]), 'd', lstat(s)))
446 while work:
446 while work:
447 top = work.pop()
447 top = work.pop()
448 entries = listdir(top, stat=True)
448 entries = listdir(top, stat=True)
449 # nd is the top of the repository dir tree
449 # nd is the top of the repository dir tree
450 nd = normpath(top[common_prefix_len:])
450 nd = normpath(top[common_prefix_len:])
451 if nd == '.':
451 if nd == '.':
452 nd = ''
452 nd = ''
453 else:
453 else:
454 # do not recurse into a repo contained in this
454 # do not recurse into a repo contained in this
455 # one. use bisect to find .hg directory so speed
455 # one. use bisect to find .hg directory so speed
456 # is good on big directory.
456 # is good on big directory.
457 names = [e[0] for e in entries]
457 names = [e[0] for e in entries]
458 hg = bisect_left(names, '.hg')
458 hg = bisect_left(names, '.hg')
459 if hg < len(names) and names[hg] == '.hg':
459 if hg < len(names) and names[hg] == '.hg':
460 if isdir(join(top, '.hg')):
460 if isdir(join(top, '.hg')):
461 continue
461 continue
462 for f, kind, st in entries:
462 for f, kind, st in entries:
463 np = pconvert(join(nd, f))
463 np = pconvert(join(nd, f))
464 if np in known:
464 if np in known:
465 continue
465 continue
466 known[np] = 1
466 known[np] = 1
467 p = join(top, f)
467 p = join(top, f)
468 # don't trip over symlinks
468 # don't trip over symlinks
469 if kind == stat.S_IFDIR:
469 if kind == stat.S_IFDIR:
470 if not ignore(np):
470 if not ignore(np):
471 wadd(p)
471 wadd(p)
472 if directories:
472 if directories:
473 add((np, 'd', st))
473 add((np, 'd', st))
474 if np in dc and match(np):
474 if np in dc and match(np):
475 add((np, 'm', st))
475 add((np, 'm', st))
476 elif imatch(np):
476 elif imatch(np):
477 if supported(np, st.st_mode):
477 if supported(np, st.st_mode):
478 add((np, 'f', st))
478 add((np, 'f', st))
479 elif np in dc:
479 elif np in dc:
480 add((np, 'm', st))
480 add((np, 'm', st))
481 found.sort()
481 found.sort()
482 return found
482 return found
483
483
484 # step one, find all files that match our criteria
484 # step one, find all files that match our criteria
485 files.sort()
485 files.sort()
486 for ff in files:
486 for ff in files:
487 nf = normpath(ff)
487 nf = normpath(ff)
488 f = _join(ff)
488 f = _join(ff)
489 try:
489 try:
490 st = lstat(f)
490 st = lstat(f)
491 except OSError, inst:
491 except OSError, inst:
492 found = False
492 found = False
493 for fn in dc:
493 for fn in dc:
494 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
494 if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
495 found = True
495 found = True
496 break
496 break
497 if not found:
497 if not found:
498 if inst.errno != errno.ENOENT or not badmatch:
498 if inst.errno != errno.ENOENT or not badmatch:
499 self._ui.warn('%s: %s\n' %
499 self._ui.warn('%s: %s\n' %
500 (self.pathto(ff), inst.strerror))
500 (self.pathto(ff), inst.strerror))
501 elif badmatch and badmatch(ff) and imatch(nf):
501 elif badmatch and badmatch(ff) and imatch(nf):
502 yield 'b', ff, None
502 yield 'b', ff, None
503 continue
503 continue
504 if s_isdir(st.st_mode):
504 if s_isdir(st.st_mode):
505 if not dirignore(nf):
505 if not dirignore(nf):
506 for f, src, st in findfiles(f):
506 for f, src, st in findfiles(f):
507 yield src, f, st
507 yield src, f, st
508 else:
508 else:
509 if nf in known:
509 if nf in known:
510 continue
510 continue
511 known[nf] = 1
511 known[nf] = 1
512 if match(nf):
512 if match(nf):
513 if supported(ff, st.st_mode, verbose=True):
513 if supported(ff, st.st_mode, verbose=True):
514 yield 'f', nf, st
514 yield 'f', nf, st
515 elif ff in dc:
515 elif ff in dc:
516 yield 'm', nf, st
516 yield 'm', nf, st
517
517
518 # step two run through anything left in the dc hash and yield
518 # step two run through anything left in the dc hash and yield
519 # if we haven't already seen it
519 # if we haven't already seen it
520 ks = dc.keys()
520 ks = dc.keys()
521 ks.sort()
521 ks.sort()
522 for k in ks:
522 for k in ks:
523 if k in known:
523 if k in known:
524 continue
524 continue
525 known[k] = 1
525 known[k] = 1
526 if imatch(k):
526 if imatch(k):
527 yield 'm', k, None
527 yield 'm', k, None
528
528
529 def status(self, files, match, list_ignored, list_clean):
529 def status(self, files, match, list_ignored, list_clean):
530 lookup, modified, added, unknown, ignored = [], [], [], [], []
530 lookup, modified, added, unknown, ignored = [], [], [], [], []
531 removed, deleted, clean = [], [], []
531 removed, deleted, clean = [], [], []
532
532
533 files = files or []
533 files = files or []
534 _join = self._join
534 _join = self._join
535 lstat = os.lstat
535 lstat = os.lstat
536 cmap = self._copymap
536 cmap = self._copymap
537 dmap = self._map
537 dmap = self._map
538 ladd = lookup.append
538 ladd = lookup.append
539 madd = modified.append
539 madd = modified.append
540 aadd = added.append
540 aadd = added.append
541 uadd = unknown.append
541 uadd = unknown.append
542 iadd = ignored.append
542 iadd = ignored.append
543 radd = removed.append
543 radd = removed.append
544 dadd = deleted.append
544 dadd = deleted.append
545 cadd = clean.append
545 cadd = clean.append
546
546
547 for src, fn, st in self.statwalk(files, match, ignored=list_ignored):
547 for src, fn, st in self.statwalk(files, match, ignored=list_ignored):
548 if fn in dmap:
548 if fn in dmap:
549 type_, mode, size, time, foo = dmap[fn]
549 type_, mode, size, time, foo = dmap[fn]
550 else:
550 else:
551 if (list_ignored or fn in files) and self._dirignore(fn):
551 if (list_ignored or fn in files) and self._dirignore(fn):
552 if list_ignored:
552 if list_ignored:
553 iadd(fn)
553 iadd(fn)
554 else:
554 else:
555 uadd(fn)
555 uadd(fn)
556 continue
556 continue
557 if src == 'm':
557 if src == 'm':
558 nonexistent = True
558 nonexistent = True
559 if not st:
559 if not st:
560 try:
560 try:
561 st = lstat(_join(fn))
561 st = lstat(_join(fn))
562 except OSError, inst:
562 except OSError, inst:
563 if inst.errno not in (errno.ENOENT, errno.ENOTDIR):
563 if inst.errno not in (errno.ENOENT, errno.ENOTDIR):
564 raise
564 raise
565 st = None
565 st = None
566 # We need to re-check that it is a valid file
566 # We need to re-check that it is a valid file
567 if st and self._supported(fn, st.st_mode):
567 if st and self._supported(fn, st.st_mode):
568 nonexistent = False
568 nonexistent = False
569 # XXX: what to do with file no longer present in the fs
569 # XXX: what to do with file no longer present in the fs
570 # who are not removed in the dirstate ?
570 # who are not removed in the dirstate ?
571 if nonexistent and type_ in "nm":
571 if nonexistent and type_ in "nma":
572 dadd(fn)
572 dadd(fn)
573 continue
573 continue
574 # check the common case first
574 # check the common case first
575 if type_ == 'n':
575 if type_ == 'n':
576 if not st:
576 if not st:
577 st = lstat(_join(fn))
577 st = lstat(_join(fn))
578 if (size >= 0 and (size != st.st_size
578 if (size >= 0 and (size != st.st_size
579 or (mode ^ st.st_mode) & 0100)
579 or (mode ^ st.st_mode) & 0100)
580 or size == -2
580 or size == -2
581 or fn in self._copymap):
581 or fn in self._copymap):
582 madd(fn)
582 madd(fn)
583 elif time != int(st.st_mtime):
583 elif time != int(st.st_mtime):
584 ladd(fn)
584 ladd(fn)
585 elif list_clean:
585 elif list_clean:
586 cadd(fn)
586 cadd(fn)
587 elif type_ == 'm':
587 elif type_ == 'm':
588 madd(fn)
588 madd(fn)
589 elif type_ == 'a':
589 elif type_ == 'a':
590 aadd(fn)
590 aadd(fn)
591 elif type_ == 'r':
591 elif type_ == 'r':
592 radd(fn)
592 radd(fn)
593
593
594 return (lookup, modified, added, removed, deleted, unknown, ignored,
594 return (lookup, modified, added, removed, deleted, unknown, ignored,
595 clean)
595 clean)
@@ -1,92 +1,93 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cleanpath()
3 cleanpath()
4 {
4 {
5 sed -e "s:/.*\(/test/.*\):...\1:"
5 sed -e "s:/.*\(/test/.*\):...\1:"
6 }
6 }
7
7
8 echo % commit date test
8 echo % commit date test
9 hg init test
9 hg init test
10 cd test
10 cd test
11 echo foo > foo
11 echo foo > foo
12 hg add foo
12 hg add foo
13 HGEDITOR=true hg commit -m ""
13 HGEDITOR=true hg commit -m ""
14 hg commit -d '0 0' -m commit-1
14 hg commit -d '0 0' -m commit-1
15 echo foo >> foo
15 echo foo >> foo
16 hg commit -d '1 4444444' -m commit-3
16 hg commit -d '1 4444444' -m commit-3
17 hg commit -d '1 15.1' -m commit-4
17 hg commit -d '1 15.1' -m commit-4
18 hg commit -d 'foo bar' -m commit-5
18 hg commit -d 'foo bar' -m commit-5
19 hg commit -d ' 1 4444' -m commit-6
19 hg commit -d ' 1 4444' -m commit-6
20 hg commit -d '111111111111 0' -m commit-7
20 hg commit -d '111111111111 0' -m commit-7
21
21
22 echo % partial commit test
22 echo % commit added file that has been deleted
23 echo bar > bar
23 echo bar > bar
24 hg add bar
24 hg add bar
25 rm bar
25 rm bar
26 hg commit -d "1000000 0" -m commit-8 2>&1 | cleanpath
26 hg commit -d "1000000 0" -m commit-8 2>&1 | cleanpath
27 hg commit -d "1000000 0" -m commit-8 bar 2>&1 | cleanpath
27
28
28 hg -q revert -a --no-backup
29 hg -q revert -a --no-backup
29
30
30 mkdir dir
31 mkdir dir
31 echo boo > dir/file
32 echo boo > dir/file
32 hg add
33 hg add
33 hg -v commit -d '0 0' -m commit-9 dir
34 hg -v commit -d '0 0' -m commit-9 dir
34
35
35 echo > dir.file
36 echo > dir.file
36 hg add
37 hg add
37 hg commit -d '0 0' -m commit-10 dir dir.file 2>&1 | cleanpath
38 hg commit -d '0 0' -m commit-10 dir dir.file 2>&1 | cleanpath
38
39
39 echo >> dir/file
40 echo >> dir/file
40 mkdir bleh
41 mkdir bleh
41 mkdir dir2
42 mkdir dir2
42 cd bleh
43 cd bleh
43 hg commit -d '0 0' -m commit-11 . 2>&1 | cleanpath
44 hg commit -d '0 0' -m commit-11 . 2>&1 | cleanpath
44 hg commit -d '0 0' -m commit-12 ../dir ../dir2 2>&1 | cleanpath
45 hg commit -d '0 0' -m commit-12 ../dir ../dir2 2>&1 | cleanpath
45 hg -v commit -d '0 0' -m commit-13 ../dir
46 hg -v commit -d '0 0' -m commit-13 ../dir
46 cd ..
47 cd ..
47
48
48 hg commit -d '0 0' -m commit-14 does-not-exist 2>&1 | cleanpath
49 hg commit -d '0 0' -m commit-14 does-not-exist 2>&1 | cleanpath
49 ln -s foo baz
50 ln -s foo baz
50 hg commit -d '0 0' -m commit-15 baz 2>&1 | cleanpath
51 hg commit -d '0 0' -m commit-15 baz 2>&1 | cleanpath
51 touch quux
52 touch quux
52 hg commit -d '0 0' -m commit-16 quux 2>&1 | cleanpath
53 hg commit -d '0 0' -m commit-16 quux 2>&1 | cleanpath
53 echo >> dir/file
54 echo >> dir/file
54 hg -v commit -d '0 0' -m commit-17 dir/file
55 hg -v commit -d '0 0' -m commit-17 dir/file
55 cd ..
56 cd ..
56
57
57 echo % partial subdir commit test
58 echo % partial subdir commit test
58 hg init test2
59 hg init test2
59 cd test2
60 cd test2
60 mkdir foo
61 mkdir foo
61 echo foo > foo/foo
62 echo foo > foo/foo
62 mkdir bar
63 mkdir bar
63 echo bar > bar/bar
64 echo bar > bar/bar
64 hg add
65 hg add
65 hg ci -d '1000000 0' -u test -m commit-subdir-1 foo
66 hg ci -d '1000000 0' -u test -m commit-subdir-1 foo
66 hg ci -d '1000001 0' -u test -m commit-subdir-2 bar
67 hg ci -d '1000001 0' -u test -m commit-subdir-2 bar
67 echo % subdir log 1
68 echo % subdir log 1
68 hg log -v foo
69 hg log -v foo
69 echo % subdir log 2
70 echo % subdir log 2
70 hg log -v bar
71 hg log -v bar
71 echo % full log
72 echo % full log
72 hg log -v
73 hg log -v
73 cd ..
74 cd ..
74
75
75 echo % dot and subdir commit test
76 echo % dot and subdir commit test
76 hg init test3
77 hg init test3
77 cd test3
78 cd test3
78 mkdir foo
79 mkdir foo
79 echo foo content > foo/plain-file
80 echo foo content > foo/plain-file
80 hg add foo/plain-file
81 hg add foo/plain-file
81 hg ci -d '1000000 0' -u test -m commit-foo-subdir foo
82 hg ci -d '1000000 0' -u test -m commit-foo-subdir foo
82 echo modified foo content > foo/plain-file
83 echo modified foo content > foo/plain-file
83 hg ci -d '2000000 0' -u test -m commit-foo-dot .
84 hg ci -d '2000000 0' -u test -m commit-foo-dot .
84 echo % full log
85 echo % full log
85 hg log -v
86 hg log -v
86 echo % subdir log
87 echo % subdir log
87 cd foo
88 cd foo
88 hg log .
89 hg log .
89 cd ..
90 cd ..
90 cd ..
91 cd ..
91
92
92 exit 0
93 exit 0
@@ -1,100 +1,100 b''
1 % commit date test
1 % commit date test
2 transaction abort!
2 transaction abort!
3 rollback completed
3 rollback completed
4 abort: empty commit message
4 abort: empty commit message
5 transaction abort!
5 transaction abort!
6 rollback completed
6 rollback completed
7 abort: impossible time zone offset: 4444444
7 abort: impossible time zone offset: 4444444
8 transaction abort!
8 transaction abort!
9 rollback completed
9 rollback completed
10 abort: invalid date: '1\t15.1'
10 abort: invalid date: '1\t15.1'
11 transaction abort!
11 transaction abort!
12 rollback completed
12 rollback completed
13 abort: invalid date: 'foo bar'
13 abort: invalid date: 'foo bar'
14 nothing changed
14 nothing changed
15 % partial commit test
15 % commit added file that has been deleted
16 trouble committing bar!
16 nothing changed
17 abort: No such file or directory: .../test/bar
17 abort: file .../test/bar not found!
18 adding dir/file
18 adding dir/file
19 dir/file
19 dir/file
20 adding dir.file
20 adding dir.file
21 abort: no match under directory .../test/dir!
21 abort: no match under directory .../test/dir!
22 abort: no match under directory .../test/bleh!
22 abort: no match under directory .../test/bleh!
23 abort: no match under directory .../test/dir2!
23 abort: no match under directory .../test/dir2!
24 dir/file
24 dir/file
25 does-not-exist: No such file or directory
25 does-not-exist: No such file or directory
26 abort: file .../test/does-not-exist not found!
26 abort: file .../test/does-not-exist not found!
27 abort: file .../test/baz not tracked!
27 abort: file .../test/baz not tracked!
28 abort: file .../test/quux not tracked!
28 abort: file .../test/quux not tracked!
29 dir/file
29 dir/file
30 % partial subdir commit test
30 % partial subdir commit test
31 adding bar/bar
31 adding bar/bar
32 adding foo/foo
32 adding foo/foo
33 % subdir log 1
33 % subdir log 1
34 changeset: 0:6ef3cb06bb80
34 changeset: 0:6ef3cb06bb80
35 user: test
35 user: test
36 date: Mon Jan 12 13:46:40 1970 +0000
36 date: Mon Jan 12 13:46:40 1970 +0000
37 files: foo/foo
37 files: foo/foo
38 description:
38 description:
39 commit-subdir-1
39 commit-subdir-1
40
40
41
41
42 % subdir log 2
42 % subdir log 2
43 changeset: 1:f2e51572cf5a
43 changeset: 1:f2e51572cf5a
44 tag: tip
44 tag: tip
45 user: test
45 user: test
46 date: Mon Jan 12 13:46:41 1970 +0000
46 date: Mon Jan 12 13:46:41 1970 +0000
47 files: bar/bar
47 files: bar/bar
48 description:
48 description:
49 commit-subdir-2
49 commit-subdir-2
50
50
51
51
52 % full log
52 % full log
53 changeset: 1:f2e51572cf5a
53 changeset: 1:f2e51572cf5a
54 tag: tip
54 tag: tip
55 user: test
55 user: test
56 date: Mon Jan 12 13:46:41 1970 +0000
56 date: Mon Jan 12 13:46:41 1970 +0000
57 files: bar/bar
57 files: bar/bar
58 description:
58 description:
59 commit-subdir-2
59 commit-subdir-2
60
60
61
61
62 changeset: 0:6ef3cb06bb80
62 changeset: 0:6ef3cb06bb80
63 user: test
63 user: test
64 date: Mon Jan 12 13:46:40 1970 +0000
64 date: Mon Jan 12 13:46:40 1970 +0000
65 files: foo/foo
65 files: foo/foo
66 description:
66 description:
67 commit-subdir-1
67 commit-subdir-1
68
68
69
69
70 % dot and subdir commit test
70 % dot and subdir commit test
71 % full log
71 % full log
72 changeset: 1:d9180e04fa8a
72 changeset: 1:d9180e04fa8a
73 tag: tip
73 tag: tip
74 user: test
74 user: test
75 date: Sat Jan 24 03:33:20 1970 +0000
75 date: Sat Jan 24 03:33:20 1970 +0000
76 files: foo/plain-file
76 files: foo/plain-file
77 description:
77 description:
78 commit-foo-dot
78 commit-foo-dot
79
79
80
80
81 changeset: 0:80b572aaf098
81 changeset: 0:80b572aaf098
82 user: test
82 user: test
83 date: Mon Jan 12 13:46:40 1970 +0000
83 date: Mon Jan 12 13:46:40 1970 +0000
84 files: foo/plain-file
84 files: foo/plain-file
85 description:
85 description:
86 commit-foo-subdir
86 commit-foo-subdir
87
87
88
88
89 % subdir log
89 % subdir log
90 changeset: 1:d9180e04fa8a
90 changeset: 1:d9180e04fa8a
91 tag: tip
91 tag: tip
92 user: test
92 user: test
93 date: Sat Jan 24 03:33:20 1970 +0000
93 date: Sat Jan 24 03:33:20 1970 +0000
94 summary: commit-foo-dot
94 summary: commit-foo-dot
95
95
96 changeset: 0:80b572aaf098
96 changeset: 0:80b572aaf098
97 user: test
97 user: test
98 date: Mon Jan 12 13:46:40 1970 +0000
98 date: Mon Jan 12 13:46:40 1970 +0000
99 summary: commit-foo-subdir
99 summary: commit-foo-subdir
100
100
@@ -1,151 +1,151 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 hg init repo
3 hg init repo
4 cd repo
4 cd repo
5 echo 123 > a
5 echo 123 > a
6 echo 123 > c
6 echo 123 > c
7 echo 123 > e
7 echo 123 > e
8 hg add a c e
8 hg add a c e
9 hg commit -m "first" -d "1000000 0" a c e
9 hg commit -m "first" -d "1000000 0" a c e
10 echo 123 > b
10 echo 123 > b
11 echo %% should show b unknown
11 echo %% should show b unknown
12 hg status
12 hg status
13 echo 12 > c
13 echo 12 > c
14 echo %% should show b unknown and c modified
14 echo %% should show b unknown and c modified
15 hg status
15 hg status
16 hg add b
16 hg add b
17 echo %% should show b added and c modified
17 echo %% should show b added and c modified
18 hg status
18 hg status
19 hg rm a
19 hg rm a
20 echo %% should show a removed, b added and c modified
20 echo %% should show a removed, b added and c modified
21 hg status
21 hg status
22 hg revert a
22 hg revert a
23 echo %% should show b added, copy saved, and c modified
23 echo %% should show b added, copy saved, and c modified
24 hg status
24 hg status
25 hg revert b
25 hg revert b
26 echo %% should show b unknown, and c modified
26 echo %% should show b unknown, and c modified
27 hg status
27 hg status
28 hg revert --no-backup c
28 hg revert --no-backup c
29 echo %% should show unknown: b
29 echo %% should show unknown: b
30 hg status
30 hg status
31 hg add b
31 hg add b
32 echo %% should show b added
32 echo %% should show b added
33 hg status b
33 hg status b
34 rm b
34 rm b
35 echo %% should show b added
35 echo %% should show b deleted
36 hg status b
36 hg status b
37 hg revert -v b
37 hg revert -v b
38 echo %% should not find b
38 echo %% should not find b
39 hg status b
39 hg status b
40 echo %% should show a c e
40 echo %% should show a c e
41 ls
41 ls
42 echo %% should verbosely save backup to e.orig
42 echo %% should verbosely save backup to e.orig
43 echo z > e
43 echo z > e
44 hg revert --all -v
44 hg revert --all -v
45 echo %% should say no changes needed
45 echo %% should say no changes needed
46 hg revert a
46 hg revert a
47 echo %% should say file not managed
47 echo %% should say file not managed
48 echo q > q
48 echo q > q
49 hg revert q
49 hg revert q
50 rm q
50 rm q
51 echo %% should say file not found
51 echo %% should say file not found
52 hg revert notfound
52 hg revert notfound
53 touch d
53 touch d
54 hg add d
54 hg add d
55 hg rm a
55 hg rm a
56 hg commit -m "second" -d "1000000 0"
56 hg commit -m "second" -d "1000000 0"
57 echo z > z
57 echo z > z
58 hg add z
58 hg add z
59 hg st
59 hg st
60 echo %% should add a, remove d, forget z
60 echo %% should add a, remove d, forget z
61 hg revert --all -r0
61 hg revert --all -r0
62 echo %% should forget a, undelete d
62 echo %% should forget a, undelete d
63 hg revert --all -rtip
63 hg revert --all -rtip
64 rm a *.orig
64 rm a *.orig
65 echo %% should silently add a
65 echo %% should silently add a
66 hg revert -r0 a
66 hg revert -r0 a
67 hg st a
67 hg st a
68 hg rm d
68 hg rm d
69 hg st d
69 hg st d
70 echo %% should silently keep d removed
70 echo %% should silently keep d removed
71 hg revert -r0 d
71 hg revert -r0 d
72 hg st d
72 hg st d
73
73
74 hg update -C
74 hg update -C
75 chmod +x c
75 chmod +x c
76 hg revert --all
76 hg revert --all
77 echo %% should print non-executable
77 echo %% should print non-executable
78 test -x c || echo non-executable
78 test -x c || echo non-executable
79
79
80 chmod +x c
80 chmod +x c
81 hg commit -d '1000001 0' -m exe
81 hg commit -d '1000001 0' -m exe
82
82
83 chmod -x c
83 chmod -x c
84 hg revert --all
84 hg revert --all
85 echo %% should print executable
85 echo %% should print executable
86 test -x c && echo executable
86 test -x c && echo executable
87
87
88 cd ..
88 cd ..
89
89
90 echo %% issue 241
90 echo %% issue 241
91 hg init a
91 hg init a
92 cd a
92 cd a
93 echo a >> a
93 echo a >> a
94 hg commit -A -d '1 0' -m a
94 hg commit -A -d '1 0' -m a
95 echo a >> a
95 echo a >> a
96 hg commit -d '2 0' -m a
96 hg commit -d '2 0' -m a
97 hg update 0
97 hg update 0
98 mkdir b
98 mkdir b
99 echo b > b/b
99 echo b > b/b
100
100
101 echo % should fail - no arguments
101 echo % should fail - no arguments
102 hg revert -rtip
102 hg revert -rtip
103
103
104 echo % should succeed
104 echo % should succeed
105 hg revert --all -rtip
105 hg revert --all -rtip
106
106
107 echo %% issue332
107 echo %% issue332
108 hg ci -A -m b -d '1000001 0'
108 hg ci -A -m b -d '1000001 0'
109 echo foobar > b/b
109 echo foobar > b/b
110 mkdir newdir
110 mkdir newdir
111 echo foo > newdir/newfile
111 echo foo > newdir/newfile
112 hg add newdir/newfile
112 hg add newdir/newfile
113 hg revert b newdir
113 hg revert b newdir
114 echo foobar > b/b
114 echo foobar > b/b
115 hg revert .
115 hg revert .
116
116
117 echo % reverting a rename target should revert the source
117 echo % reverting a rename target should revert the source
118 hg mv a newa
118 hg mv a newa
119 hg revert newa
119 hg revert newa
120 hg st a newa
120 hg st a newa
121
121
122 cd ..
122 cd ..
123
123
124 hg init ignored
124 hg init ignored
125 cd ignored
125 cd ignored
126 echo '^ignored$' > .hgignore
126 echo '^ignored$' > .hgignore
127 echo '^ignoreddir$' >> .hgignore
127 echo '^ignoreddir$' >> .hgignore
128 echo '^removed$' >> .hgignore
128 echo '^removed$' >> .hgignore
129
129
130 mkdir ignoreddir
130 mkdir ignoreddir
131 touch ignoreddir/file
131 touch ignoreddir/file
132 touch ignoreddir/removed
132 touch ignoreddir/removed
133 touch ignored
133 touch ignored
134 touch removed
134 touch removed
135 echo '%% 4 ignored files (we will add/commit everything)'
135 echo '%% 4 ignored files (we will add/commit everything)'
136 hg st -A -X .hgignore
136 hg st -A -X .hgignore
137 hg ci -qAm 'add files' ignored ignoreddir/file ignoreddir/removed removed
137 hg ci -qAm 'add files' ignored ignoreddir/file ignoreddir/removed removed
138
138
139 echo >> ignored
139 echo >> ignored
140 echo >> ignoreddir/file
140 echo >> ignoreddir/file
141 hg rm removed ignoreddir/removed
141 hg rm removed ignoreddir/removed
142 echo '%% should revert ignored* and undelete *removed'
142 echo '%% should revert ignored* and undelete *removed'
143 hg revert -a --no-backup
143 hg revert -a --no-backup
144 hg st -mardi
144 hg st -mardi
145
145
146 hg up -qC
146 hg up -qC
147 echo >> ignored
147 echo >> ignored
148 hg rm removed
148 hg rm removed
149 echo %% should silently revert the named files
149 echo %% should silently revert the named files
150 hg revert --no-backup ignored removed
150 hg revert --no-backup ignored removed
151 hg st -mardi
151 hg st -mardi
@@ -1,86 +1,86 b''
1 %% should show b unknown
1 %% should show b unknown
2 ? b
2 ? b
3 %% should show b unknown and c modified
3 %% should show b unknown and c modified
4 M c
4 M c
5 ? b
5 ? b
6 %% should show b added and c modified
6 %% should show b added and c modified
7 M c
7 M c
8 A b
8 A b
9 %% should show a removed, b added and c modified
9 %% should show a removed, b added and c modified
10 M c
10 M c
11 A b
11 A b
12 R a
12 R a
13 %% should show b added, copy saved, and c modified
13 %% should show b added, copy saved, and c modified
14 M c
14 M c
15 A b
15 A b
16 %% should show b unknown, and c modified
16 %% should show b unknown, and c modified
17 M c
17 M c
18 ? b
18 ? b
19 %% should show unknown: b
19 %% should show unknown: b
20 ? b
20 ? b
21 %% should show b added
21 %% should show b added
22 A b
22 A b
23 %% should show b added
23 %% should show b deleted
24 A b
24 ! b
25 forgetting b
25 forgetting b
26 %% should not find b
26 %% should not find b
27 b: No such file or directory
27 b: No such file or directory
28 %% should show a c e
28 %% should show a c e
29 a
29 a
30 c
30 c
31 e
31 e
32 %% should verbosely save backup to e.orig
32 %% should verbosely save backup to e.orig
33 saving current version of e as e.orig
33 saving current version of e as e.orig
34 reverting e
34 reverting e
35 %% should say no changes needed
35 %% should say no changes needed
36 no changes needed to a
36 no changes needed to a
37 %% should say file not managed
37 %% should say file not managed
38 file not managed: q
38 file not managed: q
39 %% should say file not found
39 %% should say file not found
40 notfound: No such file in rev 095eacd0c0d7
40 notfound: No such file in rev 095eacd0c0d7
41 A z
41 A z
42 ? e.orig
42 ? e.orig
43 %% should add a, remove d, forget z
43 %% should add a, remove d, forget z
44 adding a
44 adding a
45 removing d
45 removing d
46 forgetting z
46 forgetting z
47 %% should forget a, undelete d
47 %% should forget a, undelete d
48 forgetting a
48 forgetting a
49 undeleting d
49 undeleting d
50 %% should silently add a
50 %% should silently add a
51 A a
51 A a
52 R d
52 R d
53 %% should silently keep d removed
53 %% should silently keep d removed
54 R d
54 R d
55 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
55 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
56 reverting c
56 reverting c
57 %% should print non-executable
57 %% should print non-executable
58 non-executable
58 non-executable
59 reverting c
59 reverting c
60 %% should print executable
60 %% should print executable
61 executable
61 executable
62 %% issue 241
62 %% issue 241
63 adding a
63 adding a
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 % should fail - no arguments
65 % should fail - no arguments
66 abort: no files or directories specified; use --all to revert the whole repo
66 abort: no files or directories specified; use --all to revert the whole repo
67 % should succeed
67 % should succeed
68 reverting a
68 reverting a
69 %% issue332
69 %% issue332
70 adding b/b
70 adding b/b
71 reverting b/b
71 reverting b/b
72 forgetting newdir/newfile
72 forgetting newdir/newfile
73 reverting b/b
73 reverting b/b
74 % reverting a rename target should revert the source
74 % reverting a rename target should revert the source
75 ? newa
75 ? newa
76 %% 4 ignored files (we will add/commit everything)
76 %% 4 ignored files (we will add/commit everything)
77 I ignored
77 I ignored
78 I ignoreddir/file
78 I ignoreddir/file
79 I ignoreddir/removed
79 I ignoreddir/removed
80 I removed
80 I removed
81 %% should revert ignored* and undelete *removed
81 %% should revert ignored* and undelete *removed
82 reverting ignored
82 reverting ignored
83 reverting ignoreddir/file
83 reverting ignoreddir/file
84 undeleting ignoreddir/removed
84 undeleting ignoreddir/removed
85 undeleting removed
85 undeleting removed
86 %% should silently revert the named files
86 %% should silently revert the named files
General Comments 0
You need to be logged in to leave comments. Login now