##// END OF EJS Templates
filectx.ancestor: use fctx._repopath to cache filelogs (issue1035)...
Alexis S. L. Carvalho -
r6286:90a4329a default
parent child Browse files
Show More
@@ -1,622 +1,625
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import nullid, nullrev, short
8 from node import nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import ancestor, bdiff, revlog, util, os, errno
10 import ancestor, bdiff, revlog, util, os, errno
11
11
12 class changectx(object):
12 class changectx(object):
13 """A changecontext object makes access to data related to a particular
13 """A changecontext object makes access to data related to a particular
14 changeset convenient."""
14 changeset convenient."""
15 def __init__(self, repo, changeid=None):
15 def __init__(self, repo, changeid=None):
16 """changeid is a revision number, node, or tag"""
16 """changeid is a revision number, node, or tag"""
17 self._repo = repo
17 self._repo = repo
18
18
19 if not changeid and changeid != 0:
19 if not changeid and changeid != 0:
20 p1, p2 = self._repo.dirstate.parents()
20 p1, p2 = self._repo.dirstate.parents()
21 self._rev = self._repo.changelog.rev(p1)
21 self._rev = self._repo.changelog.rev(p1)
22 if self._rev == -1:
22 if self._rev == -1:
23 changeid = 'tip'
23 changeid = 'tip'
24 else:
24 else:
25 self._node = p1
25 self._node = p1
26 return
26 return
27
27
28 self._node = self._repo.lookup(changeid)
28 self._node = self._repo.lookup(changeid)
29 self._rev = self._repo.changelog.rev(self._node)
29 self._rev = self._repo.changelog.rev(self._node)
30
30
31 def __str__(self):
31 def __str__(self):
32 return short(self.node())
32 return short(self.node())
33
33
34 def __repr__(self):
34 def __repr__(self):
35 return "<changectx %s>" % str(self)
35 return "<changectx %s>" % str(self)
36
36
37 def __eq__(self, other):
37 def __eq__(self, other):
38 try:
38 try:
39 return self._rev == other._rev
39 return self._rev == other._rev
40 except AttributeError:
40 except AttributeError:
41 return False
41 return False
42
42
43 def __ne__(self, other):
43 def __ne__(self, other):
44 return not (self == other)
44 return not (self == other)
45
45
46 def __nonzero__(self):
46 def __nonzero__(self):
47 return self._rev != nullrev
47 return self._rev != nullrev
48
48
49 def __getattr__(self, name):
49 def __getattr__(self, name):
50 if name == '_changeset':
50 if name == '_changeset':
51 self._changeset = self._repo.changelog.read(self.node())
51 self._changeset = self._repo.changelog.read(self.node())
52 return self._changeset
52 return self._changeset
53 elif name == '_manifest':
53 elif name == '_manifest':
54 self._manifest = self._repo.manifest.read(self._changeset[0])
54 self._manifest = self._repo.manifest.read(self._changeset[0])
55 return self._manifest
55 return self._manifest
56 elif name == '_manifestdelta':
56 elif name == '_manifestdelta':
57 md = self._repo.manifest.readdelta(self._changeset[0])
57 md = self._repo.manifest.readdelta(self._changeset[0])
58 self._manifestdelta = md
58 self._manifestdelta = md
59 return self._manifestdelta
59 return self._manifestdelta
60 else:
60 else:
61 raise AttributeError, name
61 raise AttributeError, name
62
62
63 def __contains__(self, key):
63 def __contains__(self, key):
64 return key in self._manifest
64 return key in self._manifest
65
65
66 def __getitem__(self, key):
66 def __getitem__(self, key):
67 return self.filectx(key)
67 return self.filectx(key)
68
68
69 def __iter__(self):
69 def __iter__(self):
70 a = self._manifest.keys()
70 a = self._manifest.keys()
71 a.sort()
71 a.sort()
72 for f in a:
72 for f in a:
73 yield f
73 yield f
74
74
75 def changeset(self): return self._changeset
75 def changeset(self): return self._changeset
76 def manifest(self): return self._manifest
76 def manifest(self): return self._manifest
77
77
78 def rev(self): return self._rev
78 def rev(self): return self._rev
79 def node(self): return self._node
79 def node(self): return self._node
80 def user(self): return self._changeset[1]
80 def user(self): return self._changeset[1]
81 def date(self): return self._changeset[2]
81 def date(self): return self._changeset[2]
82 def files(self): return self._changeset[3]
82 def files(self): return self._changeset[3]
83 def description(self): return self._changeset[4]
83 def description(self): return self._changeset[4]
84 def branch(self): return self._changeset[5].get("branch")
84 def branch(self): return self._changeset[5].get("branch")
85 def extra(self): return self._changeset[5]
85 def extra(self): return self._changeset[5]
86 def tags(self): return self._repo.nodetags(self._node)
86 def tags(self): return self._repo.nodetags(self._node)
87
87
88 def parents(self):
88 def parents(self):
89 """return contexts for each parent changeset"""
89 """return contexts for each parent changeset"""
90 p = self._repo.changelog.parents(self._node)
90 p = self._repo.changelog.parents(self._node)
91 return [changectx(self._repo, x) for x in p]
91 return [changectx(self._repo, x) for x in p]
92
92
93 def children(self):
93 def children(self):
94 """return contexts for each child changeset"""
94 """return contexts for each child changeset"""
95 c = self._repo.changelog.children(self._node)
95 c = self._repo.changelog.children(self._node)
96 return [changectx(self._repo, x) for x in c]
96 return [changectx(self._repo, x) for x in c]
97
97
98 def _fileinfo(self, path):
98 def _fileinfo(self, path):
99 if '_manifest' in self.__dict__:
99 if '_manifest' in self.__dict__:
100 try:
100 try:
101 return self._manifest[path], self._manifest.flags(path)
101 return self._manifest[path], self._manifest.flags(path)
102 except KeyError:
102 except KeyError:
103 raise revlog.LookupError(self._node, path,
103 raise revlog.LookupError(self._node, path,
104 _('not found in manifest'))
104 _('not found in manifest'))
105 if '_manifestdelta' in self.__dict__ or path in self.files():
105 if '_manifestdelta' in self.__dict__ or path in self.files():
106 if path in self._manifestdelta:
106 if path in self._manifestdelta:
107 return self._manifestdelta[path], self._manifestdelta.flags(path)
107 return self._manifestdelta[path], self._manifestdelta.flags(path)
108 node, flag = self._repo.manifest.find(self._changeset[0], path)
108 node, flag = self._repo.manifest.find(self._changeset[0], path)
109 if not node:
109 if not node:
110 raise revlog.LookupError(self._node, path,
110 raise revlog.LookupError(self._node, path,
111 _('not found in manifest'))
111 _('not found in manifest'))
112
112
113 return node, flag
113 return node, flag
114
114
115 def filenode(self, path):
115 def filenode(self, path):
116 return self._fileinfo(path)[0]
116 return self._fileinfo(path)[0]
117
117
118 def fileflags(self, path):
118 def fileflags(self, path):
119 try:
119 try:
120 return self._fileinfo(path)[1]
120 return self._fileinfo(path)[1]
121 except revlog.LookupError:
121 except revlog.LookupError:
122 return ''
122 return ''
123
123
124 def filectx(self, path, fileid=None, filelog=None):
124 def filectx(self, path, fileid=None, filelog=None):
125 """get a file context from this changeset"""
125 """get a file context from this changeset"""
126 if fileid is None:
126 if fileid is None:
127 fileid = self.filenode(path)
127 fileid = self.filenode(path)
128 return filectx(self._repo, path, fileid=fileid,
128 return filectx(self._repo, path, fileid=fileid,
129 changectx=self, filelog=filelog)
129 changectx=self, filelog=filelog)
130
130
131 def filectxs(self):
131 def filectxs(self):
132 """generate a file context for each file in this changeset's
132 """generate a file context for each file in this changeset's
133 manifest"""
133 manifest"""
134 mf = self.manifest()
134 mf = self.manifest()
135 m = mf.keys()
135 m = mf.keys()
136 m.sort()
136 m.sort()
137 for f in m:
137 for f in m:
138 yield self.filectx(f, fileid=mf[f])
138 yield self.filectx(f, fileid=mf[f])
139
139
140 def ancestor(self, c2):
140 def ancestor(self, c2):
141 """
141 """
142 return the ancestor context of self and c2
142 return the ancestor context of self and c2
143 """
143 """
144 n = self._repo.changelog.ancestor(self._node, c2._node)
144 n = self._repo.changelog.ancestor(self._node, c2._node)
145 return changectx(self._repo, n)
145 return changectx(self._repo, n)
146
146
147 class filectx(object):
147 class filectx(object):
148 """A filecontext object makes access to data related to a particular
148 """A filecontext object makes access to data related to a particular
149 filerevision convenient."""
149 filerevision convenient."""
150 def __init__(self, repo, path, changeid=None, fileid=None,
150 def __init__(self, repo, path, changeid=None, fileid=None,
151 filelog=None, changectx=None):
151 filelog=None, changectx=None):
152 """changeid can be a changeset revision, node, or tag.
152 """changeid can be a changeset revision, node, or tag.
153 fileid can be a file revision or node."""
153 fileid can be a file revision or node."""
154 self._repo = repo
154 self._repo = repo
155 self._path = path
155 self._path = path
156
156
157 assert (changeid is not None
157 assert (changeid is not None
158 or fileid is not None
158 or fileid is not None
159 or changectx is not None)
159 or changectx is not None)
160
160
161 if filelog:
161 if filelog:
162 self._filelog = filelog
162 self._filelog = filelog
163
163
164 if changeid is not None:
164 if changeid is not None:
165 self._changeid = changeid
165 self._changeid = changeid
166 if changectx is not None:
166 if changectx is not None:
167 self._changectx = changectx
167 self._changectx = changectx
168 if fileid is not None:
168 if fileid is not None:
169 self._fileid = fileid
169 self._fileid = fileid
170
170
171 def __getattr__(self, name):
171 def __getattr__(self, name):
172 if name == '_changectx':
172 if name == '_changectx':
173 self._changectx = changectx(self._repo, self._changeid)
173 self._changectx = changectx(self._repo, self._changeid)
174 return self._changectx
174 return self._changectx
175 elif name == '_filelog':
175 elif name == '_filelog':
176 self._filelog = self._repo.file(self._path)
176 self._filelog = self._repo.file(self._path)
177 return self._filelog
177 return self._filelog
178 elif name == '_changeid':
178 elif name == '_changeid':
179 if '_changectx' in self.__dict__:
179 if '_changectx' in self.__dict__:
180 self._changeid = self._changectx.rev()
180 self._changeid = self._changectx.rev()
181 else:
181 else:
182 self._changeid = self._filelog.linkrev(self._filenode)
182 self._changeid = self._filelog.linkrev(self._filenode)
183 return self._changeid
183 return self._changeid
184 elif name == '_filenode':
184 elif name == '_filenode':
185 if '_fileid' in self.__dict__:
185 if '_fileid' in self.__dict__:
186 self._filenode = self._filelog.lookup(self._fileid)
186 self._filenode = self._filelog.lookup(self._fileid)
187 else:
187 else:
188 self._filenode = self._changectx.filenode(self._path)
188 self._filenode = self._changectx.filenode(self._path)
189 return self._filenode
189 return self._filenode
190 elif name == '_filerev':
190 elif name == '_filerev':
191 self._filerev = self._filelog.rev(self._filenode)
191 self._filerev = self._filelog.rev(self._filenode)
192 return self._filerev
192 return self._filerev
193 elif name == '_repopath':
194 self._repopath = self._path
195 return self._repopath
193 else:
196 else:
194 raise AttributeError, name
197 raise AttributeError, name
195
198
196 def __nonzero__(self):
199 def __nonzero__(self):
197 try:
200 try:
198 n = self._filenode
201 n = self._filenode
199 return True
202 return True
200 except revlog.LookupError:
203 except revlog.LookupError:
201 # file is missing
204 # file is missing
202 return False
205 return False
203
206
204 def __str__(self):
207 def __str__(self):
205 return "%s@%s" % (self.path(), short(self.node()))
208 return "%s@%s" % (self.path(), short(self.node()))
206
209
207 def __repr__(self):
210 def __repr__(self):
208 return "<filectx %s>" % str(self)
211 return "<filectx %s>" % str(self)
209
212
210 def __eq__(self, other):
213 def __eq__(self, other):
211 try:
214 try:
212 return (self._path == other._path
215 return (self._path == other._path
213 and self._fileid == other._fileid)
216 and self._fileid == other._fileid)
214 except AttributeError:
217 except AttributeError:
215 return False
218 return False
216
219
217 def __ne__(self, other):
220 def __ne__(self, other):
218 return not (self == other)
221 return not (self == other)
219
222
220 def filectx(self, fileid):
223 def filectx(self, fileid):
221 '''opens an arbitrary revision of the file without
224 '''opens an arbitrary revision of the file without
222 opening a new filelog'''
225 opening a new filelog'''
223 return filectx(self._repo, self._path, fileid=fileid,
226 return filectx(self._repo, self._path, fileid=fileid,
224 filelog=self._filelog)
227 filelog=self._filelog)
225
228
226 def filerev(self): return self._filerev
229 def filerev(self): return self._filerev
227 def filenode(self): return self._filenode
230 def filenode(self): return self._filenode
228 def fileflags(self): return self._changectx.fileflags(self._path)
231 def fileflags(self): return self._changectx.fileflags(self._path)
229 def isexec(self): return 'x' in self.fileflags()
232 def isexec(self): return 'x' in self.fileflags()
230 def islink(self): return 'l' in self.fileflags()
233 def islink(self): return 'l' in self.fileflags()
231 def filelog(self): return self._filelog
234 def filelog(self): return self._filelog
232
235
233 def rev(self):
236 def rev(self):
234 if '_changectx' in self.__dict__:
237 if '_changectx' in self.__dict__:
235 return self._changectx.rev()
238 return self._changectx.rev()
236 if '_changeid' in self.__dict__:
239 if '_changeid' in self.__dict__:
237 return self._changectx.rev()
240 return self._changectx.rev()
238 return self._filelog.linkrev(self._filenode)
241 return self._filelog.linkrev(self._filenode)
239
242
240 def linkrev(self): return self._filelog.linkrev(self._filenode)
243 def linkrev(self): return self._filelog.linkrev(self._filenode)
241 def node(self): return self._changectx.node()
244 def node(self): return self._changectx.node()
242 def user(self): return self._changectx.user()
245 def user(self): return self._changectx.user()
243 def date(self): return self._changectx.date()
246 def date(self): return self._changectx.date()
244 def files(self): return self._changectx.files()
247 def files(self): return self._changectx.files()
245 def description(self): return self._changectx.description()
248 def description(self): return self._changectx.description()
246 def branch(self): return self._changectx.branch()
249 def branch(self): return self._changectx.branch()
247 def manifest(self): return self._changectx.manifest()
250 def manifest(self): return self._changectx.manifest()
248 def changectx(self): return self._changectx
251 def changectx(self): return self._changectx
249
252
250 def data(self): return self._filelog.read(self._filenode)
253 def data(self): return self._filelog.read(self._filenode)
251 def path(self): return self._path
254 def path(self): return self._path
252 def size(self): return self._filelog.size(self._filerev)
255 def size(self): return self._filelog.size(self._filerev)
253
256
254 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
257 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
255
258
256 def renamed(self):
259 def renamed(self):
257 """check if file was actually renamed in this changeset revision
260 """check if file was actually renamed in this changeset revision
258
261
259 If rename logged in file revision, we report copy for changeset only
262 If rename logged in file revision, we report copy for changeset only
260 if file revisions linkrev points back to the changeset in question
263 if file revisions linkrev points back to the changeset in question
261 or both changeset parents contain different file revisions.
264 or both changeset parents contain different file revisions.
262 """
265 """
263
266
264 renamed = self._filelog.renamed(self._filenode)
267 renamed = self._filelog.renamed(self._filenode)
265 if not renamed:
268 if not renamed:
266 return renamed
269 return renamed
267
270
268 if self.rev() == self.linkrev():
271 if self.rev() == self.linkrev():
269 return renamed
272 return renamed
270
273
271 name = self.path()
274 name = self.path()
272 fnode = self._filenode
275 fnode = self._filenode
273 for p in self._changectx.parents():
276 for p in self._changectx.parents():
274 try:
277 try:
275 if fnode == p.filenode(name):
278 if fnode == p.filenode(name):
276 return None
279 return None
277 except revlog.LookupError:
280 except revlog.LookupError:
278 pass
281 pass
279 return renamed
282 return renamed
280
283
281 def parents(self):
284 def parents(self):
282 p = self._path
285 p = self._path
283 fl = self._filelog
286 fl = self._filelog
284 pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)]
287 pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)]
285
288
286 r = self._filelog.renamed(self._filenode)
289 r = self._filelog.renamed(self._filenode)
287 if r:
290 if r:
288 pl[0] = (r[0], r[1], None)
291 pl[0] = (r[0], r[1], None)
289
292
290 return [filectx(self._repo, p, fileid=n, filelog=l)
293 return [filectx(self._repo, p, fileid=n, filelog=l)
291 for p,n,l in pl if n != nullid]
294 for p,n,l in pl if n != nullid]
292
295
293 def children(self):
296 def children(self):
294 # hard for renames
297 # hard for renames
295 c = self._filelog.children(self._filenode)
298 c = self._filelog.children(self._filenode)
296 return [filectx(self._repo, self._path, fileid=x,
299 return [filectx(self._repo, self._path, fileid=x,
297 filelog=self._filelog) for x in c]
300 filelog=self._filelog) for x in c]
298
301
299 def annotate(self, follow=False, linenumber=None):
302 def annotate(self, follow=False, linenumber=None):
300 '''returns a list of tuples of (ctx, line) for each line
303 '''returns a list of tuples of (ctx, line) for each line
301 in the file, where ctx is the filectx of the node where
304 in the file, where ctx is the filectx of the node where
302 that line was last changed.
305 that line was last changed.
303 This returns tuples of ((ctx, linenumber), line) for each line,
306 This returns tuples of ((ctx, linenumber), line) for each line,
304 if "linenumber" parameter is NOT "None".
307 if "linenumber" parameter is NOT "None".
305 In such tuples, linenumber means one at the first appearance
308 In such tuples, linenumber means one at the first appearance
306 in the managed file.
309 in the managed file.
307 To reduce annotation cost,
310 To reduce annotation cost,
308 this returns fixed value(False is used) as linenumber,
311 this returns fixed value(False is used) as linenumber,
309 if "linenumber" parameter is "False".'''
312 if "linenumber" parameter is "False".'''
310
313
311 def decorate_compat(text, rev):
314 def decorate_compat(text, rev):
312 return ([rev] * len(text.splitlines()), text)
315 return ([rev] * len(text.splitlines()), text)
313
316
314 def without_linenumber(text, rev):
317 def without_linenumber(text, rev):
315 return ([(rev, False)] * len(text.splitlines()), text)
318 return ([(rev, False)] * len(text.splitlines()), text)
316
319
317 def with_linenumber(text, rev):
320 def with_linenumber(text, rev):
318 size = len(text.splitlines())
321 size = len(text.splitlines())
319 return ([(rev, i) for i in xrange(1, size + 1)], text)
322 return ([(rev, i) for i in xrange(1, size + 1)], text)
320
323
321 decorate = (((linenumber is None) and decorate_compat) or
324 decorate = (((linenumber is None) and decorate_compat) or
322 (linenumber and with_linenumber) or
325 (linenumber and with_linenumber) or
323 without_linenumber)
326 without_linenumber)
324
327
325 def pair(parent, child):
328 def pair(parent, child):
326 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
329 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
327 child[0][b1:b2] = parent[0][a1:a2]
330 child[0][b1:b2] = parent[0][a1:a2]
328 return child
331 return child
329
332
330 getlog = util.cachefunc(lambda x: self._repo.file(x))
333 getlog = util.cachefunc(lambda x: self._repo.file(x))
331 def getctx(path, fileid):
334 def getctx(path, fileid):
332 log = path == self._path and self._filelog or getlog(path)
335 log = path == self._path and self._filelog or getlog(path)
333 return filectx(self._repo, path, fileid=fileid, filelog=log)
336 return filectx(self._repo, path, fileid=fileid, filelog=log)
334 getctx = util.cachefunc(getctx)
337 getctx = util.cachefunc(getctx)
335
338
336 def parents(f):
339 def parents(f):
337 # we want to reuse filectx objects as much as possible
340 # we want to reuse filectx objects as much as possible
338 p = f._path
341 p = f._path
339 if f._filerev is None: # working dir
342 if f._filerev is None: # working dir
340 pl = [(n.path(), n.filerev()) for n in f.parents()]
343 pl = [(n.path(), n.filerev()) for n in f.parents()]
341 else:
344 else:
342 pl = [(p, n) for n in f._filelog.parentrevs(f._filerev)]
345 pl = [(p, n) for n in f._filelog.parentrevs(f._filerev)]
343
346
344 if follow:
347 if follow:
345 r = f.renamed()
348 r = f.renamed()
346 if r:
349 if r:
347 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
350 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
348
351
349 return [getctx(p, n) for p, n in pl if n != nullrev]
352 return [getctx(p, n) for p, n in pl if n != nullrev]
350
353
351 # use linkrev to find the first changeset where self appeared
354 # use linkrev to find the first changeset where self appeared
352 if self.rev() != self.linkrev():
355 if self.rev() != self.linkrev():
353 base = self.filectx(self.filerev())
356 base = self.filectx(self.filerev())
354 else:
357 else:
355 base = self
358 base = self
356
359
357 # find all ancestors
360 # find all ancestors
358 needed = {base: 1}
361 needed = {base: 1}
359 visit = [base]
362 visit = [base]
360 files = [base._path]
363 files = [base._path]
361 while visit:
364 while visit:
362 f = visit.pop(0)
365 f = visit.pop(0)
363 for p in parents(f):
366 for p in parents(f):
364 if p not in needed:
367 if p not in needed:
365 needed[p] = 1
368 needed[p] = 1
366 visit.append(p)
369 visit.append(p)
367 if p._path not in files:
370 if p._path not in files:
368 files.append(p._path)
371 files.append(p._path)
369 else:
372 else:
370 # count how many times we'll use this
373 # count how many times we'll use this
371 needed[p] += 1
374 needed[p] += 1
372
375
373 # sort by revision (per file) which is a topological order
376 # sort by revision (per file) which is a topological order
374 visit = []
377 visit = []
375 for f in files:
378 for f in files:
376 fn = [(n.rev(), n) for n in needed.keys() if n._path == f]
379 fn = [(n.rev(), n) for n in needed.keys() if n._path == f]
377 visit.extend(fn)
380 visit.extend(fn)
378 visit.sort()
381 visit.sort()
379 hist = {}
382 hist = {}
380
383
381 for r, f in visit:
384 for r, f in visit:
382 curr = decorate(f.data(), f)
385 curr = decorate(f.data(), f)
383 for p in parents(f):
386 for p in parents(f):
384 if p != nullid:
387 if p != nullid:
385 curr = pair(hist[p], curr)
388 curr = pair(hist[p], curr)
386 # trim the history of unneeded revs
389 # trim the history of unneeded revs
387 needed[p] -= 1
390 needed[p] -= 1
388 if not needed[p]:
391 if not needed[p]:
389 del hist[p]
392 del hist[p]
390 hist[f] = curr
393 hist[f] = curr
391
394
392 return zip(hist[f][0], hist[f][1].splitlines(1))
395 return zip(hist[f][0], hist[f][1].splitlines(1))
393
396
394 def ancestor(self, fc2):
397 def ancestor(self, fc2):
395 """
398 """
396 find the common ancestor file context, if any, of self, and fc2
399 find the common ancestor file context, if any, of self, and fc2
397 """
400 """
398
401
399 acache = {}
402 acache = {}
400
403
401 # prime the ancestor cache for the working directory
404 # prime the ancestor cache for the working directory
402 for c in (self, fc2):
405 for c in (self, fc2):
403 if c._filerev == None:
406 if c._filerev == None:
404 pl = [(n.path(), n.filenode()) for n in c.parents()]
407 pl = [(n.path(), n.filenode()) for n in c.parents()]
405 acache[(c._path, None)] = pl
408 acache[(c._path, None)] = pl
406
409
407 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
410 flcache = {self._repopath:self._filelog, fc2._repopath:fc2._filelog}
408 def parents(vertex):
411 def parents(vertex):
409 if vertex in acache:
412 if vertex in acache:
410 return acache[vertex]
413 return acache[vertex]
411 f, n = vertex
414 f, n = vertex
412 if f not in flcache:
415 if f not in flcache:
413 flcache[f] = self._repo.file(f)
416 flcache[f] = self._repo.file(f)
414 fl = flcache[f]
417 fl = flcache[f]
415 pl = [(f, p) for p in fl.parents(n) if p != nullid]
418 pl = [(f, p) for p in fl.parents(n) if p != nullid]
416 re = fl.renamed(n)
419 re = fl.renamed(n)
417 if re:
420 if re:
418 pl.append(re)
421 pl.append(re)
419 acache[vertex] = pl
422 acache[vertex] = pl
420 return pl
423 return pl
421
424
422 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
425 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
423 v = ancestor.ancestor(a, b, parents)
426 v = ancestor.ancestor(a, b, parents)
424 if v:
427 if v:
425 f, n = v
428 f, n = v
426 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
429 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
427
430
428 return None
431 return None
429
432
430 class workingctx(changectx):
433 class workingctx(changectx):
431 """A workingctx object makes access to data related to
434 """A workingctx object makes access to data related to
432 the current working directory convenient."""
435 the current working directory convenient."""
433 def __init__(self, repo):
436 def __init__(self, repo):
434 self._repo = repo
437 self._repo = repo
435 self._rev = None
438 self._rev = None
436 self._node = None
439 self._node = None
437
440
438 def __str__(self):
441 def __str__(self):
439 return str(self._parents[0]) + "+"
442 return str(self._parents[0]) + "+"
440
443
441 def __nonzero__(self):
444 def __nonzero__(self):
442 return True
445 return True
443
446
444 def __getattr__(self, name):
447 def __getattr__(self, name):
445 if name == '_parents':
448 if name == '_parents':
446 self._parents = self._repo.parents()
449 self._parents = self._repo.parents()
447 return self._parents
450 return self._parents
448 if name == '_status':
451 if name == '_status':
449 self._status = self._repo.status()
452 self._status = self._repo.status()
450 return self._status
453 return self._status
451 if name == '_manifest':
454 if name == '_manifest':
452 self._buildmanifest()
455 self._buildmanifest()
453 return self._manifest
456 return self._manifest
454 else:
457 else:
455 raise AttributeError, name
458 raise AttributeError, name
456
459
457 def _buildmanifest(self):
460 def _buildmanifest(self):
458 """generate a manifest corresponding to the working directory"""
461 """generate a manifest corresponding to the working directory"""
459
462
460 man = self._parents[0].manifest().copy()
463 man = self._parents[0].manifest().copy()
461 copied = self._repo.dirstate.copies()
464 copied = self._repo.dirstate.copies()
462 is_exec = util.execfunc(self._repo.root,
465 is_exec = util.execfunc(self._repo.root,
463 lambda p: man.execf(copied.get(p,p)))
466 lambda p: man.execf(copied.get(p,p)))
464 is_link = util.linkfunc(self._repo.root,
467 is_link = util.linkfunc(self._repo.root,
465 lambda p: man.linkf(copied.get(p,p)))
468 lambda p: man.linkf(copied.get(p,p)))
466 modified, added, removed, deleted, unknown = self._status[:5]
469 modified, added, removed, deleted, unknown = self._status[:5]
467 for i, l in (("a", added), ("m", modified), ("u", unknown)):
470 for i, l in (("a", added), ("m", modified), ("u", unknown)):
468 for f in l:
471 for f in l:
469 man[f] = man.get(copied.get(f, f), nullid) + i
472 man[f] = man.get(copied.get(f, f), nullid) + i
470 try:
473 try:
471 man.set(f, is_exec(f), is_link(f))
474 man.set(f, is_exec(f), is_link(f))
472 except OSError:
475 except OSError:
473 pass
476 pass
474
477
475 for f in deleted + removed:
478 for f in deleted + removed:
476 if f in man:
479 if f in man:
477 del man[f]
480 del man[f]
478
481
479 self._manifest = man
482 self._manifest = man
480
483
481 def manifest(self): return self._manifest
484 def manifest(self): return self._manifest
482
485
483 def user(self): return self._repo.ui.username()
486 def user(self): return self._repo.ui.username()
484 def date(self): return util.makedate()
487 def date(self): return util.makedate()
485 def description(self): return ""
488 def description(self): return ""
486 def files(self):
489 def files(self):
487 f = self.modified() + self.added() + self.removed()
490 f = self.modified() + self.added() + self.removed()
488 f.sort()
491 f.sort()
489 return f
492 return f
490
493
491 def modified(self): return self._status[0]
494 def modified(self): return self._status[0]
492 def added(self): return self._status[1]
495 def added(self): return self._status[1]
493 def removed(self): return self._status[2]
496 def removed(self): return self._status[2]
494 def deleted(self): return self._status[3]
497 def deleted(self): return self._status[3]
495 def unknown(self): return self._status[4]
498 def unknown(self): return self._status[4]
496 def clean(self): return self._status[5]
499 def clean(self): return self._status[5]
497 def branch(self): return self._repo.dirstate.branch()
500 def branch(self): return self._repo.dirstate.branch()
498
501
499 def tags(self):
502 def tags(self):
500 t = []
503 t = []
501 [t.extend(p.tags()) for p in self.parents()]
504 [t.extend(p.tags()) for p in self.parents()]
502 return t
505 return t
503
506
504 def parents(self):
507 def parents(self):
505 """return contexts for each parent changeset"""
508 """return contexts for each parent changeset"""
506 return self._parents
509 return self._parents
507
510
508 def children(self):
511 def children(self):
509 return []
512 return []
510
513
511 def fileflags(self, path):
514 def fileflags(self, path):
512 if '_manifest' in self.__dict__:
515 if '_manifest' in self.__dict__:
513 try:
516 try:
514 return self._manifest.flags(path)
517 return self._manifest.flags(path)
515 except KeyError:
518 except KeyError:
516 return ''
519 return ''
517
520
518 pnode = self._parents[0].changeset()[0]
521 pnode = self._parents[0].changeset()[0]
519 orig = self._repo.dirstate.copies().get(path, path)
522 orig = self._repo.dirstate.copies().get(path, path)
520 node, flag = self._repo.manifest.find(pnode, orig)
523 node, flag = self._repo.manifest.find(pnode, orig)
521 is_link = util.linkfunc(self._repo.root, lambda p: 'l' in flag)
524 is_link = util.linkfunc(self._repo.root, lambda p: 'l' in flag)
522 is_exec = util.execfunc(self._repo.root, lambda p: 'x' in flag)
525 is_exec = util.execfunc(self._repo.root, lambda p: 'x' in flag)
523 try:
526 try:
524 return (is_link(path) and 'l' or '') + (is_exec(path) and 'e' or '')
527 return (is_link(path) and 'l' or '') + (is_exec(path) and 'e' or '')
525 except OSError:
528 except OSError:
526 pass
529 pass
527
530
528 if not node or path in self.deleted() or path in self.removed():
531 if not node or path in self.deleted() or path in self.removed():
529 return ''
532 return ''
530 return flag
533 return flag
531
534
532 def filectx(self, path, filelog=None):
535 def filectx(self, path, filelog=None):
533 """get a file context from the working directory"""
536 """get a file context from the working directory"""
534 return workingfilectx(self._repo, path, workingctx=self,
537 return workingfilectx(self._repo, path, workingctx=self,
535 filelog=filelog)
538 filelog=filelog)
536
539
537 def ancestor(self, c2):
540 def ancestor(self, c2):
538 """return the ancestor context of self and c2"""
541 """return the ancestor context of self and c2"""
539 return self._parents[0].ancestor(c2) # punt on two parents for now
542 return self._parents[0].ancestor(c2) # punt on two parents for now
540
543
541 class workingfilectx(filectx):
544 class workingfilectx(filectx):
542 """A workingfilectx object makes access to data related to a particular
545 """A workingfilectx object makes access to data related to a particular
543 file in the working directory convenient."""
546 file in the working directory convenient."""
544 def __init__(self, repo, path, filelog=None, workingctx=None):
547 def __init__(self, repo, path, filelog=None, workingctx=None):
545 """changeid can be a changeset revision, node, or tag.
548 """changeid can be a changeset revision, node, or tag.
546 fileid can be a file revision or node."""
549 fileid can be a file revision or node."""
547 self._repo = repo
550 self._repo = repo
548 self._path = path
551 self._path = path
549 self._changeid = None
552 self._changeid = None
550 self._filerev = self._filenode = None
553 self._filerev = self._filenode = None
551
554
552 if filelog:
555 if filelog:
553 self._filelog = filelog
556 self._filelog = filelog
554 if workingctx:
557 if workingctx:
555 self._changectx = workingctx
558 self._changectx = workingctx
556
559
557 def __getattr__(self, name):
560 def __getattr__(self, name):
558 if name == '_changectx':
561 if name == '_changectx':
559 self._changectx = workingctx(self._repo)
562 self._changectx = workingctx(self._repo)
560 return self._changectx
563 return self._changectx
561 elif name == '_repopath':
564 elif name == '_repopath':
562 self._repopath = (self._repo.dirstate.copied(self._path)
565 self._repopath = (self._repo.dirstate.copied(self._path)
563 or self._path)
566 or self._path)
564 return self._repopath
567 return self._repopath
565 elif name == '_filelog':
568 elif name == '_filelog':
566 self._filelog = self._repo.file(self._repopath)
569 self._filelog = self._repo.file(self._repopath)
567 return self._filelog
570 return self._filelog
568 else:
571 else:
569 raise AttributeError, name
572 raise AttributeError, name
570
573
571 def __nonzero__(self):
574 def __nonzero__(self):
572 return True
575 return True
573
576
574 def __str__(self):
577 def __str__(self):
575 return "%s@%s" % (self.path(), self._changectx)
578 return "%s@%s" % (self.path(), self._changectx)
576
579
577 def filectx(self, fileid):
580 def filectx(self, fileid):
578 '''opens an arbitrary revision of the file without
581 '''opens an arbitrary revision of the file without
579 opening a new filelog'''
582 opening a new filelog'''
580 return filectx(self._repo, self._repopath, fileid=fileid,
583 return filectx(self._repo, self._repopath, fileid=fileid,
581 filelog=self._filelog)
584 filelog=self._filelog)
582
585
583 def rev(self):
586 def rev(self):
584 if '_changectx' in self.__dict__:
587 if '_changectx' in self.__dict__:
585 return self._changectx.rev()
588 return self._changectx.rev()
586 return self._filelog.linkrev(self._filenode)
589 return self._filelog.linkrev(self._filenode)
587
590
588 def data(self): return self._repo.wread(self._path)
591 def data(self): return self._repo.wread(self._path)
589 def renamed(self):
592 def renamed(self):
590 rp = self._repopath
593 rp = self._repopath
591 if rp == self._path:
594 if rp == self._path:
592 return None
595 return None
593 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
596 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
594
597
595 def parents(self):
598 def parents(self):
596 '''return parent filectxs, following copies if necessary'''
599 '''return parent filectxs, following copies if necessary'''
597 p = self._path
600 p = self._path
598 rp = self._repopath
601 rp = self._repopath
599 pcl = self._changectx._parents
602 pcl = self._changectx._parents
600 fl = self._filelog
603 fl = self._filelog
601 pl = [(rp, pcl[0]._manifest.get(rp, nullid), fl)]
604 pl = [(rp, pcl[0]._manifest.get(rp, nullid), fl)]
602 if len(pcl) > 1:
605 if len(pcl) > 1:
603 if rp != p:
606 if rp != p:
604 fl = None
607 fl = None
605 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
608 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
606
609
607 return [filectx(self._repo, p, fileid=n, filelog=l)
610 return [filectx(self._repo, p, fileid=n, filelog=l)
608 for p,n,l in pl if n != nullid]
611 for p,n,l in pl if n != nullid]
609
612
610 def children(self):
613 def children(self):
611 return []
614 return []
612
615
613 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
616 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
614 def date(self):
617 def date(self):
615 t, tz = self._changectx.date()
618 t, tz = self._changectx.date()
616 try:
619 try:
617 return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
620 return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
618 except OSError, err:
621 except OSError, err:
619 if err.errno != errno.ENOENT: raise
622 if err.errno != errno.ENOENT: raise
620 return (t, tz)
623 return (t, tz)
621
624
622 def cmp(self, text): return self._repo.wread(self._path) == text
625 def cmp(self, text): return self._repo.wread(self._path) == text
@@ -1,67 +1,68
1 #!/bin/sh
1 #!/bin/sh
2
2
3 add()
3 add()
4 {
4 {
5 echo $2 >> $1
5 echo $2 >> $1
6 }
6 }
7
7
8 hg init t
8 hg init t
9 cd t
9 cd t
10
10
11 # set up a boring main branch
11 # set up a boring main branch
12 add a a
12 add a a
13 hg add a
13 hg add a
14 hg ci -m0
14 hg ci -m0
15
15
16 add a m1
16 add a m1
17 hg ci -m1
17 hg ci -m1
18
18
19 add a m2
19 add a m2
20 hg ci -m2
20 hg ci -m2
21
21
22 show()
22 show()
23 {
23 {
24 echo "- $2: $1"
24 echo "- $2: $1"
25 hg st -C $1
25 hg st -C $1
26 echo
26 echo
27 hg diff --git $1
27 hg diff --git $1
28 echo
28 echo
29 }
29 }
30
30
31 count=0
31 count=0
32 # make a new branch and get diff/status output
32 # make a new branch and get diff/status output
33 # $1 - first commit
33 # $1 - first commit
34 # $2 - second commit
34 # $2 - second commit
35 # $3 - working dir action
35 # $3 - working dir action
36 # $4 - test description
36 # $4 - test description
37 tb()
37 tb()
38 {
38 {
39 hg co -q -C 0
39 hg co -q -C 0
40
40
41 add a $count
41 add a $count
42 count=`expr $count + 1`
42 count=`expr $count + 1`
43 hg ci -m "t0"
43 hg ci -m "t0"
44 $1
44 $1
45 hg ci -m "t1"
45 hg ci -m "t1"
46 $2
46 $2
47 hg ci -m "t2"
47 hg ci -m "t2"
48 $3
48 $3
49
49
50 echo "** $4 **"
50 echo "** $4 **"
51 echo "** $1 / $2 / $3"
51 echo "** $1 / $2 / $3"
52 show "" "working to parent"
52 show "" "working to parent"
53 show "--rev 0" "working to root"
53 show "--rev 0" "working to root"
54 show "--rev 2" "working to branch"
54 show "--rev 2" "working to branch"
55 show "--rev 0 --rev ." "root to parent"
55 show "--rev 0 --rev ." "root to parent"
56 show "--rev . --rev 0" "parent to root"
56 show "--rev . --rev 0" "parent to root"
57 show "--rev 2 --rev ." "branch to parent"
57 show "--rev 2 --rev ." "branch to parent"
58 show "--rev . --rev 2" "parent to branch"
58 show "--rev . --rev 2" "parent to branch"
59 echo
59 echo
60 }
60 }
61
61
62 tb "add a a1" "add a a2" "hg mv a b" "rename in working dir"
62 tb "add a a1" "add a a2" "hg mv a b" "rename in working dir"
63 tb "add a a1" "add a a2" "hg cp a b" "copy in working dir"
63 tb "add a a1" "add a a2" "hg cp a b" "copy in working dir"
64 tb "hg mv a b" "add b b1" "add b w" "single rename"
64 tb "hg mv a b" "add b b1" "add b w" "single rename"
65 tb "hg cp a b" "add b b1" "add a w" "single copy"
65 tb "hg cp a b" "add b b1" "add a w" "single copy"
66 tb "hg mv a b" "hg mv b c" "hg mv c d" "rename chain"
66 tb "hg mv a b" "hg mv b c" "hg mv c d" "rename chain"
67 tb "hg cp a b" "hg cp b c" "hg cp c d" "copy chain"
67 tb "hg cp a b" "hg cp b c" "hg cp c d" "copy chain"
68 tb "add a a1" "hg mv a b" "hg mv b a" "circular rename"
@@ -1,795 +1,895
1 ** rename in working dir **
1 ** rename in working dir **
2 ** add a a1 / add a a2 / hg mv a b
2 ** add a a1 / add a a2 / hg mv a b
3 - working to parent:
3 - working to parent:
4 A b
4 A b
5 a
5 a
6 R a
6 R a
7
7
8 diff --git a/a b/b
8 diff --git a/a b/b
9 rename from a
9 rename from a
10 rename to b
10 rename to b
11
11
12 - working to root: --rev 0
12 - working to root: --rev 0
13 A b
13 A b
14 a
14 a
15 R a
15 R a
16
16
17 diff --git a/a b/b
17 diff --git a/a b/b
18 rename from a
18 rename from a
19 rename to b
19 rename to b
20 --- a/a
20 --- a/a
21 +++ b/b
21 +++ b/b
22 @@ -1,1 +1,4 @@
22 @@ -1,1 +1,4 @@
23 a
23 a
24 +0
24 +0
25 +a1
25 +a1
26 +a2
26 +a2
27
27
28 - working to branch: --rev 2
28 - working to branch: --rev 2
29 A b
29 A b
30 a
30 a
31 R a
31 R a
32
32
33 diff --git a/a b/b
33 diff --git a/a b/b
34 rename from a
34 rename from a
35 rename to b
35 rename to b
36 --- a/a
36 --- a/a
37 +++ b/b
37 +++ b/b
38 @@ -1,3 +1,4 @@
38 @@ -1,3 +1,4 @@
39 a
39 a
40 -m1
40 -m1
41 -m2
41 -m2
42 +0
42 +0
43 +a1
43 +a1
44 +a2
44 +a2
45
45
46 - root to parent: --rev 0 --rev .
46 - root to parent: --rev 0 --rev .
47 M a
47 M a
48
48
49 diff --git a/a b/a
49 diff --git a/a b/a
50 --- a/a
50 --- a/a
51 +++ b/a
51 +++ b/a
52 @@ -1,1 +1,4 @@
52 @@ -1,1 +1,4 @@
53 a
53 a
54 +0
54 +0
55 +a1
55 +a1
56 +a2
56 +a2
57
57
58 - parent to root: --rev . --rev 0
58 - parent to root: --rev . --rev 0
59 M a
59 M a
60
60
61 diff --git a/a b/a
61 diff --git a/a b/a
62 --- a/a
62 --- a/a
63 +++ b/a
63 +++ b/a
64 @@ -1,4 +1,1 @@
64 @@ -1,4 +1,1 @@
65 a
65 a
66 -0
66 -0
67 -a1
67 -a1
68 -a2
68 -a2
69
69
70 - branch to parent: --rev 2 --rev .
70 - branch to parent: --rev 2 --rev .
71 M a
71 M a
72
72
73 diff --git a/a b/a
73 diff --git a/a b/a
74 --- a/a
74 --- a/a
75 +++ b/a
75 +++ b/a
76 @@ -1,3 +1,4 @@
76 @@ -1,3 +1,4 @@
77 a
77 a
78 -m1
78 -m1
79 -m2
79 -m2
80 +0
80 +0
81 +a1
81 +a1
82 +a2
82 +a2
83
83
84 - parent to branch: --rev . --rev 2
84 - parent to branch: --rev . --rev 2
85 M a
85 M a
86
86
87 diff --git a/a b/a
87 diff --git a/a b/a
88 --- a/a
88 --- a/a
89 +++ b/a
89 +++ b/a
90 @@ -1,4 +1,3 @@
90 @@ -1,4 +1,3 @@
91 a
91 a
92 -0
92 -0
93 -a1
93 -a1
94 -a2
94 -a2
95 +m1
95 +m1
96 +m2
96 +m2
97
97
98
98
99 ** copy in working dir **
99 ** copy in working dir **
100 ** add a a1 / add a a2 / hg cp a b
100 ** add a a1 / add a a2 / hg cp a b
101 - working to parent:
101 - working to parent:
102 A b
102 A b
103 a
103 a
104
104
105 diff --git a/a b/b
105 diff --git a/a b/b
106 copy from a
106 copy from a
107 copy to b
107 copy to b
108
108
109 - working to root: --rev 0
109 - working to root: --rev 0
110 M a
110 M a
111 A b
111 A b
112 a
112 a
113
113
114 diff --git a/a b/a
114 diff --git a/a b/a
115 --- a/a
115 --- a/a
116 +++ b/a
116 +++ b/a
117 @@ -1,1 +1,4 @@
117 @@ -1,1 +1,4 @@
118 a
118 a
119 +1
119 +1
120 +a1
120 +a1
121 +a2
121 +a2
122 diff --git a/a b/b
122 diff --git a/a b/b
123 copy from a
123 copy from a
124 copy to b
124 copy to b
125 --- a/a
125 --- a/a
126 +++ b/b
126 +++ b/b
127 @@ -1,1 +1,4 @@
127 @@ -1,1 +1,4 @@
128 a
128 a
129 +1
129 +1
130 +a1
130 +a1
131 +a2
131 +a2
132
132
133 - working to branch: --rev 2
133 - working to branch: --rev 2
134 M a
134 M a
135 A b
135 A b
136 a
136 a
137
137
138 diff --git a/a b/a
138 diff --git a/a b/a
139 --- a/a
139 --- a/a
140 +++ b/a
140 +++ b/a
141 @@ -1,3 +1,4 @@
141 @@ -1,3 +1,4 @@
142 a
142 a
143 -m1
143 -m1
144 -m2
144 -m2
145 +1
145 +1
146 +a1
146 +a1
147 +a2
147 +a2
148 diff --git a/a b/b
148 diff --git a/a b/b
149 copy from a
149 copy from a
150 copy to b
150 copy to b
151 --- a/a
151 --- a/a
152 +++ b/b
152 +++ b/b
153 @@ -1,3 +1,4 @@
153 @@ -1,3 +1,4 @@
154 a
154 a
155 -m1
155 -m1
156 -m2
156 -m2
157 +1
157 +1
158 +a1
158 +a1
159 +a2
159 +a2
160
160
161 - root to parent: --rev 0 --rev .
161 - root to parent: --rev 0 --rev .
162 M a
162 M a
163
163
164 diff --git a/a b/a
164 diff --git a/a b/a
165 --- a/a
165 --- a/a
166 +++ b/a
166 +++ b/a
167 @@ -1,1 +1,4 @@
167 @@ -1,1 +1,4 @@
168 a
168 a
169 +1
169 +1
170 +a1
170 +a1
171 +a2
171 +a2
172
172
173 - parent to root: --rev . --rev 0
173 - parent to root: --rev . --rev 0
174 M a
174 M a
175
175
176 diff --git a/a b/a
176 diff --git a/a b/a
177 --- a/a
177 --- a/a
178 +++ b/a
178 +++ b/a
179 @@ -1,4 +1,1 @@
179 @@ -1,4 +1,1 @@
180 a
180 a
181 -1
181 -1
182 -a1
182 -a1
183 -a2
183 -a2
184
184
185 - branch to parent: --rev 2 --rev .
185 - branch to parent: --rev 2 --rev .
186 M a
186 M a
187
187
188 diff --git a/a b/a
188 diff --git a/a b/a
189 --- a/a
189 --- a/a
190 +++ b/a
190 +++ b/a
191 @@ -1,3 +1,4 @@
191 @@ -1,3 +1,4 @@
192 a
192 a
193 -m1
193 -m1
194 -m2
194 -m2
195 +1
195 +1
196 +a1
196 +a1
197 +a2
197 +a2
198
198
199 - parent to branch: --rev . --rev 2
199 - parent to branch: --rev . --rev 2
200 M a
200 M a
201
201
202 diff --git a/a b/a
202 diff --git a/a b/a
203 --- a/a
203 --- a/a
204 +++ b/a
204 +++ b/a
205 @@ -1,4 +1,3 @@
205 @@ -1,4 +1,3 @@
206 a
206 a
207 -1
207 -1
208 -a1
208 -a1
209 -a2
209 -a2
210 +m1
210 +m1
211 +m2
211 +m2
212
212
213
213
214 ** single rename **
214 ** single rename **
215 ** hg mv a b / add b b1 / add b w
215 ** hg mv a b / add b b1 / add b w
216 - working to parent:
216 - working to parent:
217 M b
217 M b
218
218
219 diff --git a/b b/b
219 diff --git a/b b/b
220 --- a/b
220 --- a/b
221 +++ b/b
221 +++ b/b
222 @@ -1,3 +1,4 @@
222 @@ -1,3 +1,4 @@
223 a
223 a
224 2
224 2
225 b1
225 b1
226 +w
226 +w
227
227
228 - working to root: --rev 0
228 - working to root: --rev 0
229 A b
229 A b
230 a
230 a
231 R a
231 R a
232
232
233 diff --git a/a b/b
233 diff --git a/a b/b
234 rename from a
234 rename from a
235 rename to b
235 rename to b
236 --- a/a
236 --- a/a
237 +++ b/b
237 +++ b/b
238 @@ -1,1 +1,4 @@
238 @@ -1,1 +1,4 @@
239 a
239 a
240 +2
240 +2
241 +b1
241 +b1
242 +w
242 +w
243
243
244 - working to branch: --rev 2
244 - working to branch: --rev 2
245 A b
245 A b
246 a
246 a
247 R a
247 R a
248
248
249 diff --git a/a b/b
249 diff --git a/a b/b
250 rename from a
250 rename from a
251 rename to b
251 rename to b
252 --- a/a
252 --- a/a
253 +++ b/b
253 +++ b/b
254 @@ -1,3 +1,4 @@
254 @@ -1,3 +1,4 @@
255 a
255 a
256 -m1
256 -m1
257 -m2
257 -m2
258 +2
258 +2
259 +b1
259 +b1
260 +w
260 +w
261
261
262 - root to parent: --rev 0 --rev .
262 - root to parent: --rev 0 --rev .
263 A b
263 A b
264 a
264 a
265 R a
265 R a
266
266
267 diff --git a/a b/b
267 diff --git a/a b/b
268 rename from a
268 rename from a
269 rename to b
269 rename to b
270 --- a/a
270 --- a/a
271 +++ b/b
271 +++ b/b
272 @@ -1,1 +1,3 @@
272 @@ -1,1 +1,3 @@
273 a
273 a
274 +2
274 +2
275 +b1
275 +b1
276
276
277 - parent to root: --rev . --rev 0
277 - parent to root: --rev . --rev 0
278 A a
278 A a
279 b
279 b
280 R b
280 R b
281
281
282 diff --git a/b b/a
282 diff --git a/b b/a
283 rename from b
283 rename from b
284 rename to a
284 rename to a
285 --- a/b
285 --- a/b
286 +++ b/a
286 +++ b/a
287 @@ -1,3 +1,1 @@
287 @@ -1,3 +1,1 @@
288 a
288 a
289 -2
289 -2
290 -b1
290 -b1
291
291
292 - branch to parent: --rev 2 --rev .
292 - branch to parent: --rev 2 --rev .
293 A b
293 A b
294 a
294 a
295 R a
295 R a
296
296
297 diff --git a/a b/b
297 diff --git a/a b/b
298 rename from a
298 rename from a
299 rename to b
299 rename to b
300 --- a/a
300 --- a/a
301 +++ b/b
301 +++ b/b
302 @@ -1,3 +1,3 @@
302 @@ -1,3 +1,3 @@
303 a
303 a
304 -m1
304 -m1
305 -m2
305 -m2
306 +2
306 +2
307 +b1
307 +b1
308
308
309 - parent to branch: --rev . --rev 2
309 - parent to branch: --rev . --rev 2
310 A a
310 A a
311 b
311 b
312 R b
312 R b
313
313
314 diff --git a/b b/a
314 diff --git a/b b/a
315 rename from b
315 rename from b
316 rename to a
316 rename to a
317 --- a/b
317 --- a/b
318 +++ b/a
318 +++ b/a
319 @@ -1,3 +1,3 @@
319 @@ -1,3 +1,3 @@
320 a
320 a
321 -2
321 -2
322 -b1
322 -b1
323 +m1
323 +m1
324 +m2
324 +m2
325
325
326
326
327 ** single copy **
327 ** single copy **
328 ** hg cp a b / add b b1 / add a w
328 ** hg cp a b / add b b1 / add a w
329 - working to parent:
329 - working to parent:
330 M a
330 M a
331
331
332 diff --git a/a b/a
332 diff --git a/a b/a
333 --- a/a
333 --- a/a
334 +++ b/a
334 +++ b/a
335 @@ -1,2 +1,3 @@
335 @@ -1,2 +1,3 @@
336 a
336 a
337 3
337 3
338 +w
338 +w
339
339
340 - working to root: --rev 0
340 - working to root: --rev 0
341 M a
341 M a
342 A b
342 A b
343 a
343 a
344
344
345 diff --git a/a b/a
345 diff --git a/a b/a
346 --- a/a
346 --- a/a
347 +++ b/a
347 +++ b/a
348 @@ -1,1 +1,3 @@
348 @@ -1,1 +1,3 @@
349 a
349 a
350 +3
350 +3
351 +w
351 +w
352 diff --git a/a b/b
352 diff --git a/a b/b
353 copy from a
353 copy from a
354 copy to b
354 copy to b
355 --- a/a
355 --- a/a
356 +++ b/b
356 +++ b/b
357 @@ -1,1 +1,3 @@
357 @@ -1,1 +1,3 @@
358 a
358 a
359 +3
359 +3
360 +b1
360 +b1
361
361
362 - working to branch: --rev 2
362 - working to branch: --rev 2
363 M a
363 M a
364 A b
364 A b
365 a
365 a
366
366
367 diff --git a/a b/a
367 diff --git a/a b/a
368 --- a/a
368 --- a/a
369 +++ b/a
369 +++ b/a
370 @@ -1,3 +1,3 @@
370 @@ -1,3 +1,3 @@
371 a
371 a
372 -m1
372 -m1
373 -m2
373 -m2
374 +3
374 +3
375 +w
375 +w
376 diff --git a/a b/b
376 diff --git a/a b/b
377 copy from a
377 copy from a
378 copy to b
378 copy to b
379 --- a/a
379 --- a/a
380 +++ b/b
380 +++ b/b
381 @@ -1,3 +1,3 @@
381 @@ -1,3 +1,3 @@
382 a
382 a
383 -m1
383 -m1
384 -m2
384 -m2
385 +3
385 +3
386 +b1
386 +b1
387
387
388 - root to parent: --rev 0 --rev .
388 - root to parent: --rev 0 --rev .
389 M a
389 M a
390 A b
390 A b
391 a
391 a
392
392
393 diff --git a/a b/a
393 diff --git a/a b/a
394 --- a/a
394 --- a/a
395 +++ b/a
395 +++ b/a
396 @@ -1,1 +1,2 @@
396 @@ -1,1 +1,2 @@
397 a
397 a
398 +3
398 +3
399 diff --git a/a b/b
399 diff --git a/a b/b
400 copy from a
400 copy from a
401 copy to b
401 copy to b
402 --- a/a
402 --- a/a
403 +++ b/b
403 +++ b/b
404 @@ -1,1 +1,3 @@
404 @@ -1,1 +1,3 @@
405 a
405 a
406 +3
406 +3
407 +b1
407 +b1
408
408
409 - parent to root: --rev . --rev 0
409 - parent to root: --rev . --rev 0
410 M a
410 M a
411 R b
411 R b
412
412
413 diff --git a/a b/a
413 diff --git a/a b/a
414 --- a/a
414 --- a/a
415 +++ b/a
415 +++ b/a
416 @@ -1,2 +1,1 @@
416 @@ -1,2 +1,1 @@
417 a
417 a
418 -3
418 -3
419 diff --git a/b b/b
419 diff --git a/b b/b
420 deleted file mode 100644
420 deleted file mode 100644
421 --- a/b
421 --- a/b
422 +++ /dev/null
422 +++ /dev/null
423 @@ -1,3 +0,0 @@
423 @@ -1,3 +0,0 @@
424 -a
424 -a
425 -3
425 -3
426 -b1
426 -b1
427
427
428 - branch to parent: --rev 2 --rev .
428 - branch to parent: --rev 2 --rev .
429 M a
429 M a
430 A b
430 A b
431 a
431 a
432
432
433 diff --git a/a b/a
433 diff --git a/a b/a
434 --- a/a
434 --- a/a
435 +++ b/a
435 +++ b/a
436 @@ -1,3 +1,2 @@
436 @@ -1,3 +1,2 @@
437 a
437 a
438 -m1
438 -m1
439 -m2
439 -m2
440 +3
440 +3
441 diff --git a/a b/b
441 diff --git a/a b/b
442 copy from a
442 copy from a
443 copy to b
443 copy to b
444 --- a/a
444 --- a/a
445 +++ b/b
445 +++ b/b
446 @@ -1,3 +1,3 @@
446 @@ -1,3 +1,3 @@
447 a
447 a
448 -m1
448 -m1
449 -m2
449 -m2
450 +3
450 +3
451 +b1
451 +b1
452
452
453 - parent to branch: --rev . --rev 2
453 - parent to branch: --rev . --rev 2
454 M a
454 M a
455 R b
455 R b
456
456
457 diff --git a/a b/a
457 diff --git a/a b/a
458 --- a/a
458 --- a/a
459 +++ b/a
459 +++ b/a
460 @@ -1,2 +1,3 @@
460 @@ -1,2 +1,3 @@
461 a
461 a
462 -3
462 -3
463 +m1
463 +m1
464 +m2
464 +m2
465 diff --git a/b b/b
465 diff --git a/b b/b
466 deleted file mode 100644
466 deleted file mode 100644
467 --- a/b
467 --- a/b
468 +++ /dev/null
468 +++ /dev/null
469 @@ -1,3 +0,0 @@
469 @@ -1,3 +0,0 @@
470 -a
470 -a
471 -3
471 -3
472 -b1
472 -b1
473
473
474
474
475 ** rename chain **
475 ** rename chain **
476 ** hg mv a b / hg mv b c / hg mv c d
476 ** hg mv a b / hg mv b c / hg mv c d
477 - working to parent:
477 - working to parent:
478 A d
478 A d
479 c
479 c
480 R c
480 R c
481
481
482 diff --git a/c b/d
482 diff --git a/c b/d
483 rename from c
483 rename from c
484 rename to d
484 rename to d
485
485
486 - working to root: --rev 0
486 - working to root: --rev 0
487 A d
487 A d
488 a
488 a
489 R a
489 R a
490
490
491 diff --git a/a b/d
491 diff --git a/a b/d
492 rename from a
492 rename from a
493 rename to d
493 rename to d
494 --- a/a
494 --- a/a
495 +++ b/d
495 +++ b/d
496 @@ -1,1 +1,2 @@
496 @@ -1,1 +1,2 @@
497 a
497 a
498 +4
498 +4
499
499
500 - working to branch: --rev 2
500 - working to branch: --rev 2
501 A d
501 A d
502 a
502 a
503 R a
503 R a
504
504
505 diff --git a/a b/d
505 diff --git a/a b/d
506 rename from a
506 rename from a
507 rename to d
507 rename to d
508 --- a/a
508 --- a/a
509 +++ b/d
509 +++ b/d
510 @@ -1,3 +1,2 @@
510 @@ -1,3 +1,2 @@
511 a
511 a
512 -m1
512 -m1
513 -m2
513 -m2
514 +4
514 +4
515
515
516 - root to parent: --rev 0 --rev .
516 - root to parent: --rev 0 --rev .
517 A c
517 A c
518 a
518 a
519 R a
519 R a
520
520
521 diff --git a/a b/c
521 diff --git a/a b/c
522 rename from a
522 rename from a
523 rename to c
523 rename to c
524 --- a/a
524 --- a/a
525 +++ b/c
525 +++ b/c
526 @@ -1,1 +1,2 @@
526 @@ -1,1 +1,2 @@
527 a
527 a
528 +4
528 +4
529
529
530 - parent to root: --rev . --rev 0
530 - parent to root: --rev . --rev 0
531 A a
531 A a
532 c
532 c
533 R c
533 R c
534
534
535 diff --git a/c b/a
535 diff --git a/c b/a
536 rename from c
536 rename from c
537 rename to a
537 rename to a
538 --- a/c
538 --- a/c
539 +++ b/a
539 +++ b/a
540 @@ -1,2 +1,1 @@
540 @@ -1,2 +1,1 @@
541 a
541 a
542 -4
542 -4
543
543
544 - branch to parent: --rev 2 --rev .
544 - branch to parent: --rev 2 --rev .
545 A c
545 A c
546 a
546 a
547 R a
547 R a
548
548
549 diff --git a/a b/c
549 diff --git a/a b/c
550 rename from a
550 rename from a
551 rename to c
551 rename to c
552 --- a/a
552 --- a/a
553 +++ b/c
553 +++ b/c
554 @@ -1,3 +1,2 @@
554 @@ -1,3 +1,2 @@
555 a
555 a
556 -m1
556 -m1
557 -m2
557 -m2
558 +4
558 +4
559
559
560 - parent to branch: --rev . --rev 2
560 - parent to branch: --rev . --rev 2
561 A a
561 A a
562 c
562 c
563 R c
563 R c
564
564
565 diff --git a/c b/a
565 diff --git a/c b/a
566 rename from c
566 rename from c
567 rename to a
567 rename to a
568 --- a/c
568 --- a/c
569 +++ b/a
569 +++ b/a
570 @@ -1,2 +1,3 @@
570 @@ -1,2 +1,3 @@
571 a
571 a
572 -4
572 -4
573 +m1
573 +m1
574 +m2
574 +m2
575
575
576
576
577 ** copy chain **
577 ** copy chain **
578 ** hg cp a b / hg cp b c / hg cp c d
578 ** hg cp a b / hg cp b c / hg cp c d
579 - working to parent:
579 - working to parent:
580 A d
580 A d
581 c
581 c
582
582
583 diff --git a/c b/d
583 diff --git a/c b/d
584 copy from c
584 copy from c
585 copy to d
585 copy to d
586
586
587 - working to root: --rev 0
587 - working to root: --rev 0
588 M a
588 M a
589 A b
589 A b
590 a
590 a
591 A c
591 A c
592 a
592 a
593 A d
593 A d
594 a
594 a
595
595
596 diff --git a/a b/a
596 diff --git a/a b/a
597 --- a/a
597 --- a/a
598 +++ b/a
598 +++ b/a
599 @@ -1,1 +1,2 @@
599 @@ -1,1 +1,2 @@
600 a
600 a
601 +5
601 +5
602 diff --git a/a b/b
602 diff --git a/a b/b
603 copy from a
603 copy from a
604 copy to b
604 copy to b
605 --- a/a
605 --- a/a
606 +++ b/b
606 +++ b/b
607 @@ -1,1 +1,2 @@
607 @@ -1,1 +1,2 @@
608 a
608 a
609 +5
609 +5
610 diff --git a/a b/c
610 diff --git a/a b/c
611 copy from a
611 copy from a
612 copy to c
612 copy to c
613 --- a/a
613 --- a/a
614 +++ b/c
614 +++ b/c
615 @@ -1,1 +1,2 @@
615 @@ -1,1 +1,2 @@
616 a
616 a
617 +5
617 +5
618 diff --git a/a b/d
618 diff --git a/a b/d
619 copy from a
619 copy from a
620 copy to d
620 copy to d
621 --- a/a
621 --- a/a
622 +++ b/d
622 +++ b/d
623 @@ -1,1 +1,2 @@
623 @@ -1,1 +1,2 @@
624 a
624 a
625 +5
625 +5
626
626
627 - working to branch: --rev 2
627 - working to branch: --rev 2
628 M a
628 M a
629 A b
629 A b
630 a
630 a
631 A c
631 A c
632 a
632 a
633 A d
633 A d
634 a
634 a
635
635
636 diff --git a/a b/a
636 diff --git a/a b/a
637 --- a/a
637 --- a/a
638 +++ b/a
638 +++ b/a
639 @@ -1,3 +1,2 @@
639 @@ -1,3 +1,2 @@
640 a
640 a
641 -m1
641 -m1
642 -m2
642 -m2
643 +5
643 +5
644 diff --git a/a b/b
644 diff --git a/a b/b
645 copy from a
645 copy from a
646 copy to b
646 copy to b
647 --- a/a
647 --- a/a
648 +++ b/b
648 +++ b/b
649 @@ -1,3 +1,2 @@
649 @@ -1,3 +1,2 @@
650 a
650 a
651 -m1
651 -m1
652 -m2
652 -m2
653 +5
653 +5
654 diff --git a/a b/c
654 diff --git a/a b/c
655 copy from a
655 copy from a
656 copy to c
656 copy to c
657 --- a/a
657 --- a/a
658 +++ b/c
658 +++ b/c
659 @@ -1,3 +1,2 @@
659 @@ -1,3 +1,2 @@
660 a
660 a
661 -m1
661 -m1
662 -m2
662 -m2
663 +5
663 +5
664 diff --git a/a b/d
664 diff --git a/a b/d
665 copy from a
665 copy from a
666 copy to d
666 copy to d
667 --- a/a
667 --- a/a
668 +++ b/d
668 +++ b/d
669 @@ -1,3 +1,2 @@
669 @@ -1,3 +1,2 @@
670 a
670 a
671 -m1
671 -m1
672 -m2
672 -m2
673 +5
673 +5
674
674
675 - root to parent: --rev 0 --rev .
675 - root to parent: --rev 0 --rev .
676 M a
676 M a
677 A b
677 A b
678 a
678 a
679 A c
679 A c
680 a
680 a
681
681
682 diff --git a/a b/a
682 diff --git a/a b/a
683 --- a/a
683 --- a/a
684 +++ b/a
684 +++ b/a
685 @@ -1,1 +1,2 @@
685 @@ -1,1 +1,2 @@
686 a
686 a
687 +5
687 +5
688 diff --git a/a b/b
688 diff --git a/a b/b
689 copy from a
689 copy from a
690 copy to b
690 copy to b
691 --- a/a
691 --- a/a
692 +++ b/b
692 +++ b/b
693 @@ -1,1 +1,2 @@
693 @@ -1,1 +1,2 @@
694 a
694 a
695 +5
695 +5
696 diff --git a/a b/c
696 diff --git a/a b/c
697 copy from a
697 copy from a
698 copy to c
698 copy to c
699 --- a/a
699 --- a/a
700 +++ b/c
700 +++ b/c
701 @@ -1,1 +1,2 @@
701 @@ -1,1 +1,2 @@
702 a
702 a
703 +5
703 +5
704
704
705 - parent to root: --rev . --rev 0
705 - parent to root: --rev . --rev 0
706 M a
706 M a
707 R b
707 R b
708 R c
708 R c
709
709
710 diff --git a/a b/a
710 diff --git a/a b/a
711 --- a/a
711 --- a/a
712 +++ b/a
712 +++ b/a
713 @@ -1,2 +1,1 @@
713 @@ -1,2 +1,1 @@
714 a
714 a
715 -5
715 -5
716 diff --git a/b b/b
716 diff --git a/b b/b
717 deleted file mode 100644
717 deleted file mode 100644
718 --- a/b
718 --- a/b
719 +++ /dev/null
719 +++ /dev/null
720 @@ -1,2 +0,0 @@
720 @@ -1,2 +0,0 @@
721 -a
721 -a
722 -5
722 -5
723 diff --git a/c b/c
723 diff --git a/c b/c
724 deleted file mode 100644
724 deleted file mode 100644
725 --- a/c
725 --- a/c
726 +++ /dev/null
726 +++ /dev/null
727 @@ -1,2 +0,0 @@
727 @@ -1,2 +0,0 @@
728 -a
728 -a
729 -5
729 -5
730
730
731 - branch to parent: --rev 2 --rev .
731 - branch to parent: --rev 2 --rev .
732 M a
732 M a
733 A b
733 A b
734 a
734 a
735 A c
735 A c
736 a
736 a
737
737
738 diff --git a/a b/a
738 diff --git a/a b/a
739 --- a/a
739 --- a/a
740 +++ b/a
740 +++ b/a
741 @@ -1,3 +1,2 @@
741 @@ -1,3 +1,2 @@
742 a
742 a
743 -m1
743 -m1
744 -m2
744 -m2
745 +5
745 +5
746 diff --git a/a b/b
746 diff --git a/a b/b
747 copy from a
747 copy from a
748 copy to b
748 copy to b
749 --- a/a
749 --- a/a
750 +++ b/b
750 +++ b/b
751 @@ -1,3 +1,2 @@
751 @@ -1,3 +1,2 @@
752 a
752 a
753 -m1
753 -m1
754 -m2
754 -m2
755 +5
755 +5
756 diff --git a/a b/c
756 diff --git a/a b/c
757 copy from a
757 copy from a
758 copy to c
758 copy to c
759 --- a/a
759 --- a/a
760 +++ b/c
760 +++ b/c
761 @@ -1,3 +1,2 @@
761 @@ -1,3 +1,2 @@
762 a
762 a
763 -m1
763 -m1
764 -m2
764 -m2
765 +5
765 +5
766
766
767 - parent to branch: --rev . --rev 2
767 - parent to branch: --rev . --rev 2
768 M a
768 M a
769 R b
769 R b
770 R c
770 R c
771
771
772 diff --git a/a b/a
772 diff --git a/a b/a
773 --- a/a
773 --- a/a
774 +++ b/a
774 +++ b/a
775 @@ -1,2 +1,3 @@
775 @@ -1,2 +1,3 @@
776 a
776 a
777 -5
777 -5
778 +m1
778 +m1
779 +m2
779 +m2
780 diff --git a/b b/b
780 diff --git a/b b/b
781 deleted file mode 100644
781 deleted file mode 100644
782 --- a/b
782 --- a/b
783 +++ /dev/null
783 +++ /dev/null
784 @@ -1,2 +0,0 @@
784 @@ -1,2 +0,0 @@
785 -a
785 -a
786 -5
786 -5
787 diff --git a/c b/c
787 diff --git a/c b/c
788 deleted file mode 100644
788 deleted file mode 100644
789 --- a/c
789 --- a/c
790 +++ /dev/null
790 +++ /dev/null
791 @@ -1,2 +0,0 @@
791 @@ -1,2 +0,0 @@
792 -a
792 -a
793 -5
793 -5
794
794
795
795
796 ** circular rename **
797 ** add a a1 / hg mv a b / hg mv b a
798 - working to parent:
799 A a
800 b
801 R b
802
803 diff --git a/b b/a
804 rename from b
805 rename to a
806
807 - working to root: --rev 0
808 M a
809
810 diff --git a/a b/a
811 --- a/a
812 +++ b/a
813 @@ -1,1 +1,3 @@
814 a
815 +6
816 +a1
817
818 - working to branch: --rev 2
819 M a
820
821 diff --git a/a b/a
822 --- a/a
823 +++ b/a
824 @@ -1,3 +1,3 @@
825 a
826 -m1
827 -m2
828 +6
829 +a1
830
831 - root to parent: --rev 0 --rev .
832 A b
833 a
834 R a
835
836 diff --git a/a b/b
837 rename from a
838 rename to b
839 --- a/a
840 +++ b/b
841 @@ -1,1 +1,3 @@
842 a
843 +6
844 +a1
845
846 - parent to root: --rev . --rev 0
847 A a
848 b
849 R b
850
851 diff --git a/b b/a
852 rename from b
853 rename to a
854 --- a/b
855 +++ b/a
856 @@ -1,3 +1,1 @@
857 a
858 -6
859 -a1
860
861 - branch to parent: --rev 2 --rev .
862 A b
863 a
864 R a
865
866 diff --git a/a b/b
867 rename from a
868 rename to b
869 --- a/a
870 +++ b/b
871 @@ -1,3 +1,3 @@
872 a
873 -m1
874 -m2
875 +6
876 +a1
877
878 - parent to branch: --rev . --rev 2
879 A a
880 b
881 R b
882
883 diff --git a/b b/a
884 rename from b
885 rename to a
886 --- a/b
887 +++ b/a
888 @@ -1,3 +1,3 @@
889 a
890 -6
891 -a1
892 +m1
893 +m2
894
895
General Comments 0
You need to be logged in to leave comments. Login now