##// END OF EJS Templates
merge with stable
Matt Mackall -
r17175:f76e2196 merge default
parent child Browse files
Show More
@@ -1,392 +1,393
1 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
1 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
2 # Copyright 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
2 # Copyright 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
3 #
3 #
4 # This software may be used and distributed according to the terms of the
4 # This software may be used and distributed according to the terms of the
5 # GNU General Public License version 2 or any later version.
5 # GNU General Public License version 2 or any later version.
6
6
7 import shlex
7 import shlex
8 from mercurial.i18n import _
8 from mercurial.i18n import _
9 from mercurial import util
9 from mercurial import util
10 from common import SKIPREV, converter_source
10 from common import SKIPREV, converter_source
11
11
12 def rpairs(name):
12 def rpairs(name):
13 e = len(name)
13 e = len(name)
14 while e != -1:
14 while e != -1:
15 yield name[:e], name[e + 1:]
15 yield name[:e], name[e + 1:]
16 e = name.rfind('/', 0, e)
16 e = name.rfind('/', 0, e)
17 yield '.', name
17 yield '.', name
18
18
19 class filemapper(object):
19 class filemapper(object):
20 '''Map and filter filenames when importing.
20 '''Map and filter filenames when importing.
21 A name can be mapped to itself, a new name, or None (omit from new
21 A name can be mapped to itself, a new name, or None (omit from new
22 repository).'''
22 repository).'''
23
23
24 def __init__(self, ui, path=None):
24 def __init__(self, ui, path=None):
25 self.ui = ui
25 self.ui = ui
26 self.include = {}
26 self.include = {}
27 self.exclude = {}
27 self.exclude = {}
28 self.rename = {}
28 self.rename = {}
29 if path:
29 if path:
30 if self.parse(path):
30 if self.parse(path):
31 raise util.Abort(_('errors in filemap'))
31 raise util.Abort(_('errors in filemap'))
32
32
33 def parse(self, path):
33 def parse(self, path):
34 errs = 0
34 errs = 0
35 def check(name, mapping, listname):
35 def check(name, mapping, listname):
36 if not name:
36 if not name:
37 self.ui.warn(_('%s:%d: path to %s is missing\n') %
37 self.ui.warn(_('%s:%d: path to %s is missing\n') %
38 (lex.infile, lex.lineno, listname))
38 (lex.infile, lex.lineno, listname))
39 return 1
39 return 1
40 if name in mapping:
40 if name in mapping:
41 self.ui.warn(_('%s:%d: %r already in %s list\n') %
41 self.ui.warn(_('%s:%d: %r already in %s list\n') %
42 (lex.infile, lex.lineno, name, listname))
42 (lex.infile, lex.lineno, name, listname))
43 return 1
43 return 1
44 if (name.startswith('/') or
44 if (name.startswith('/') or
45 name.endswith('/') or
45 name.endswith('/') or
46 '//' in name):
46 '//' in name):
47 self.ui.warn(_('%s:%d: superfluous / in %s %r\n') %
47 self.ui.warn(_('%s:%d: superfluous / in %s %r\n') %
48 (lex.infile, lex.lineno, listname, name))
48 (lex.infile, lex.lineno, listname, name))
49 return 1
49 return 1
50 return 0
50 return 0
51 lex = shlex.shlex(open(path), path, True)
51 lex = shlex.shlex(open(path), path, True)
52 lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?'
52 lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?'
53 cmd = lex.get_token()
53 cmd = lex.get_token()
54 while cmd:
54 while cmd:
55 if cmd == 'include':
55 if cmd == 'include':
56 name = lex.get_token()
56 name = lex.get_token()
57 errs += check(name, self.exclude, 'exclude')
57 errs += check(name, self.exclude, 'exclude')
58 self.include[name] = name
58 self.include[name] = name
59 elif cmd == 'exclude':
59 elif cmd == 'exclude':
60 name = lex.get_token()
60 name = lex.get_token()
61 errs += check(name, self.include, 'include')
61 errs += check(name, self.include, 'include')
62 errs += check(name, self.rename, 'rename')
62 errs += check(name, self.rename, 'rename')
63 self.exclude[name] = name
63 self.exclude[name] = name
64 elif cmd == 'rename':
64 elif cmd == 'rename':
65 src = lex.get_token()
65 src = lex.get_token()
66 dest = lex.get_token()
66 dest = lex.get_token()
67 errs += check(src, self.exclude, 'exclude')
67 errs += check(src, self.exclude, 'exclude')
68 self.rename[src] = dest
68 self.rename[src] = dest
69 elif cmd == 'source':
69 elif cmd == 'source':
70 errs += self.parse(lex.get_token())
70 errs += self.parse(lex.get_token())
71 else:
71 else:
72 self.ui.warn(_('%s:%d: unknown directive %r\n') %
72 self.ui.warn(_('%s:%d: unknown directive %r\n') %
73 (lex.infile, lex.lineno, cmd))
73 (lex.infile, lex.lineno, cmd))
74 errs += 1
74 errs += 1
75 cmd = lex.get_token()
75 cmd = lex.get_token()
76 return errs
76 return errs
77
77
78 def lookup(self, name, mapping):
78 def lookup(self, name, mapping):
79 for pre, suf in rpairs(name):
79 for pre, suf in rpairs(name):
80 try:
80 try:
81 return mapping[pre], pre, suf
81 return mapping[pre], pre, suf
82 except KeyError:
82 except KeyError:
83 pass
83 pass
84 return '', name, ''
84 return '', name, ''
85
85
86 def __call__(self, name):
86 def __call__(self, name):
87 if self.include:
87 if self.include:
88 inc = self.lookup(name, self.include)[0]
88 inc = self.lookup(name, self.include)[0]
89 else:
89 else:
90 inc = name
90 inc = name
91 if self.exclude:
91 if self.exclude:
92 exc = self.lookup(name, self.exclude)[0]
92 exc = self.lookup(name, self.exclude)[0]
93 else:
93 else:
94 exc = ''
94 exc = ''
95 if (not self.include and exc) or (len(inc) <= len(exc)):
95 if (not self.include and exc) or (len(inc) <= len(exc)):
96 return None
96 return None
97 newpre, pre, suf = self.lookup(name, self.rename)
97 newpre, pre, suf = self.lookup(name, self.rename)
98 if newpre:
98 if newpre:
99 if newpre == '.':
99 if newpre == '.':
100 return suf
100 return suf
101 if suf:
101 if suf:
102 if newpre.endswith('/'):
102 if newpre.endswith('/'):
103 return newpre + suf
103 return newpre + suf
104 return newpre + '/' + suf
104 return newpre + '/' + suf
105 return newpre
105 return newpre
106 return name
106 return name
107
107
108 def active(self):
108 def active(self):
109 return bool(self.include or self.exclude or self.rename)
109 return bool(self.include or self.exclude or self.rename)
110
110
111 # This class does two additional things compared to a regular source:
111 # This class does two additional things compared to a regular source:
112 #
112 #
113 # - Filter and rename files. This is mostly wrapped by the filemapper
113 # - Filter and rename files. This is mostly wrapped by the filemapper
114 # class above. We hide the original filename in the revision that is
114 # class above. We hide the original filename in the revision that is
115 # returned by getchanges to be able to find things later in getfile.
115 # returned by getchanges to be able to find things later in getfile.
116 #
116 #
117 # - Return only revisions that matter for the files we're interested in.
117 # - Return only revisions that matter for the files we're interested in.
118 # This involves rewriting the parents of the original revision to
118 # This involves rewriting the parents of the original revision to
119 # create a graph that is restricted to those revisions.
119 # create a graph that is restricted to those revisions.
120 #
120 #
121 # This set of revisions includes not only revisions that directly
121 # This set of revisions includes not only revisions that directly
122 # touch files we're interested in, but also merges that merge two
122 # touch files we're interested in, but also merges that merge two
123 # or more interesting revisions.
123 # or more interesting revisions.
124
124
125 class filemap_source(converter_source):
125 class filemap_source(converter_source):
126 def __init__(self, ui, baseconverter, filemap):
126 def __init__(self, ui, baseconverter, filemap):
127 super(filemap_source, self).__init__(ui)
127 super(filemap_source, self).__init__(ui)
128 self.base = baseconverter
128 self.base = baseconverter
129 self.filemapper = filemapper(ui, filemap)
129 self.filemapper = filemapper(ui, filemap)
130 self.commits = {}
130 self.commits = {}
131 # if a revision rev has parent p in the original revision graph, then
131 # if a revision rev has parent p in the original revision graph, then
132 # rev will have parent self.parentmap[p] in the restricted graph.
132 # rev will have parent self.parentmap[p] in the restricted graph.
133 self.parentmap = {}
133 self.parentmap = {}
134 # self.wantedancestors[rev] is the set of all ancestors of rev that
134 # self.wantedancestors[rev] is the set of all ancestors of rev that
135 # are in the restricted graph.
135 # are in the restricted graph.
136 self.wantedancestors = {}
136 self.wantedancestors = {}
137 self.convertedorder = None
137 self.convertedorder = None
138 self._rebuilt = False
138 self._rebuilt = False
139 self.origparents = {}
139 self.origparents = {}
140 self.children = {}
140 self.children = {}
141 self.seenchildren = {}
141 self.seenchildren = {}
142
142
143 def before(self):
143 def before(self):
144 self.base.before()
144 self.base.before()
145
145
146 def after(self):
146 def after(self):
147 self.base.after()
147 self.base.after()
148
148
149 def setrevmap(self, revmap):
149 def setrevmap(self, revmap):
150 # rebuild our state to make things restartable
150 # rebuild our state to make things restartable
151 #
151 #
152 # To avoid calling getcommit for every revision that has already
152 # To avoid calling getcommit for every revision that has already
153 # been converted, we rebuild only the parentmap, delaying the
153 # been converted, we rebuild only the parentmap, delaying the
154 # rebuild of wantedancestors until we need it (i.e. until a
154 # rebuild of wantedancestors until we need it (i.e. until a
155 # merge).
155 # merge).
156 #
156 #
157 # We assume the order argument lists the revisions in
157 # We assume the order argument lists the revisions in
158 # topological order, so that we can infer which revisions were
158 # topological order, so that we can infer which revisions were
159 # wanted by previous runs.
159 # wanted by previous runs.
160 self._rebuilt = not revmap
160 self._rebuilt = not revmap
161 seen = {SKIPREV: SKIPREV}
161 seen = {SKIPREV: SKIPREV}
162 dummyset = set()
162 dummyset = set()
163 converted = []
163 converted = []
164 for rev in revmap.order:
164 for rev in revmap.order:
165 mapped = revmap[rev]
165 mapped = revmap[rev]
166 wanted = mapped not in seen
166 wanted = mapped not in seen
167 if wanted:
167 if wanted:
168 seen[mapped] = rev
168 seen[mapped] = rev
169 self.parentmap[rev] = rev
169 self.parentmap[rev] = rev
170 else:
170 else:
171 self.parentmap[rev] = seen[mapped]
171 self.parentmap[rev] = seen[mapped]
172 self.wantedancestors[rev] = dummyset
172 self.wantedancestors[rev] = dummyset
173 arg = seen[mapped]
173 arg = seen[mapped]
174 if arg == SKIPREV:
174 if arg == SKIPREV:
175 arg = None
175 arg = None
176 converted.append((rev, wanted, arg))
176 converted.append((rev, wanted, arg))
177 self.convertedorder = converted
177 self.convertedorder = converted
178 return self.base.setrevmap(revmap)
178 return self.base.setrevmap(revmap)
179
179
180 def rebuild(self):
180 def rebuild(self):
181 if self._rebuilt:
181 if self._rebuilt:
182 return True
182 return True
183 self._rebuilt = True
183 self._rebuilt = True
184 self.parentmap.clear()
184 self.parentmap.clear()
185 self.wantedancestors.clear()
185 self.wantedancestors.clear()
186 self.seenchildren.clear()
186 self.seenchildren.clear()
187 for rev, wanted, arg in self.convertedorder:
187 for rev, wanted, arg in self.convertedorder:
188 if rev not in self.origparents:
188 if rev not in self.origparents:
189 self.origparents[rev] = self.getcommit(rev).parents
189 self.origparents[rev] = self.getcommit(rev).parents
190 if arg is not None:
190 if arg is not None:
191 self.children[arg] = self.children.get(arg, 0) + 1
191 self.children[arg] = self.children.get(arg, 0) + 1
192
192
193 for rev, wanted, arg in self.convertedorder:
193 for rev, wanted, arg in self.convertedorder:
194 parents = self.origparents[rev]
194 parents = self.origparents[rev]
195 if wanted:
195 if wanted:
196 self.mark_wanted(rev, parents)
196 self.mark_wanted(rev, parents)
197 else:
197 else:
198 self.mark_not_wanted(rev, arg)
198 self.mark_not_wanted(rev, arg)
199 self._discard(arg, *parents)
199 self._discard(arg, *parents)
200
200
201 return True
201 return True
202
202
203 def getheads(self):
203 def getheads(self):
204 return self.base.getheads()
204 return self.base.getheads()
205
205
206 def getcommit(self, rev):
206 def getcommit(self, rev):
207 # We want to save a reference to the commit objects to be able
207 # We want to save a reference to the commit objects to be able
208 # to rewrite their parents later on.
208 # to rewrite their parents later on.
209 c = self.commits[rev] = self.base.getcommit(rev)
209 c = self.commits[rev] = self.base.getcommit(rev)
210 for p in c.parents:
210 for p in c.parents:
211 self.children[p] = self.children.get(p, 0) + 1
211 self.children[p] = self.children.get(p, 0) + 1
212 return c
212 return c
213
213
214 def _cachedcommit(self, rev):
214 def _cachedcommit(self, rev):
215 if rev in self.commits:
215 if rev in self.commits:
216 return self.commits[rev]
216 return self.commits[rev]
217 return self.base.getcommit(rev)
217 return self.base.getcommit(rev)
218
218
219 def _discard(self, *revs):
219 def _discard(self, *revs):
220 for r in revs:
220 for r in revs:
221 if r is None:
221 if r is None:
222 continue
222 continue
223 self.seenchildren[r] = self.seenchildren.get(r, 0) + 1
223 self.seenchildren[r] = self.seenchildren.get(r, 0) + 1
224 if self.seenchildren[r] == self.children[r]:
224 if self.seenchildren[r] == self.children[r]:
225 del self.wantedancestors[r]
225 del self.wantedancestors[r]
226 del self.parentmap[r]
226 del self.parentmap[r]
227 del self.seenchildren[r]
227 del self.seenchildren[r]
228 if self._rebuilt:
228 if self._rebuilt:
229 del self.children[r]
229 del self.children[r]
230
230
231 def wanted(self, rev, i):
231 def wanted(self, rev, i):
232 # Return True if we're directly interested in rev.
232 # Return True if we're directly interested in rev.
233 #
233 #
234 # i is an index selecting one of the parents of rev (if rev
234 # i is an index selecting one of the parents of rev (if rev
235 # has no parents, i is None). getchangedfiles will give us
235 # has no parents, i is None). getchangedfiles will give us
236 # the list of files that are different in rev and in the parent
236 # the list of files that are different in rev and in the parent
237 # indicated by i. If we're interested in any of these files,
237 # indicated by i. If we're interested in any of these files,
238 # we're interested in rev.
238 # we're interested in rev.
239 try:
239 try:
240 files = self.base.getchangedfiles(rev, i)
240 files = self.base.getchangedfiles(rev, i)
241 except NotImplementedError:
241 except NotImplementedError:
242 raise util.Abort(_("source repository doesn't support --filemap"))
242 raise util.Abort(_("source repository doesn't support --filemap"))
243 for f in files:
243 for f in files:
244 if self.filemapper(f):
244 if self.filemapper(f):
245 return True
245 return True
246 return False
246 return False
247
247
248 def mark_not_wanted(self, rev, p):
248 def mark_not_wanted(self, rev, p):
249 # Mark rev as not interesting and update data structures.
249 # Mark rev as not interesting and update data structures.
250
250
251 if p is None:
251 if p is None:
252 # A root revision. Use SKIPREV to indicate that it doesn't
252 # A root revision. Use SKIPREV to indicate that it doesn't
253 # map to any revision in the restricted graph. Put SKIPREV
253 # map to any revision in the restricted graph. Put SKIPREV
254 # in the set of wanted ancestors to simplify code elsewhere
254 # in the set of wanted ancestors to simplify code elsewhere
255 self.parentmap[rev] = SKIPREV
255 self.parentmap[rev] = SKIPREV
256 self.wantedancestors[rev] = set((SKIPREV,))
256 self.wantedancestors[rev] = set((SKIPREV,))
257 return
257 return
258
258
259 # Reuse the data from our parent.
259 # Reuse the data from our parent.
260 self.parentmap[rev] = self.parentmap[p]
260 self.parentmap[rev] = self.parentmap[p]
261 self.wantedancestors[rev] = self.wantedancestors[p]
261 self.wantedancestors[rev] = self.wantedancestors[p]
262
262
263 def mark_wanted(self, rev, parents):
263 def mark_wanted(self, rev, parents):
264 # Mark rev ss wanted and update data structures.
264 # Mark rev ss wanted and update data structures.
265
265
266 # rev will be in the restricted graph, so children of rev in
266 # rev will be in the restricted graph, so children of rev in
267 # the original graph should still have rev as a parent in the
267 # the original graph should still have rev as a parent in the
268 # restricted graph.
268 # restricted graph.
269 self.parentmap[rev] = rev
269 self.parentmap[rev] = rev
270
270
271 # The set of wanted ancestors of rev is the union of the sets
271 # The set of wanted ancestors of rev is the union of the sets
272 # of wanted ancestors of its parents. Plus rev itself.
272 # of wanted ancestors of its parents. Plus rev itself.
273 wrev = set()
273 wrev = set()
274 for p in parents:
274 for p in parents:
275 wrev.update(self.wantedancestors[p])
275 wrev.update(self.wantedancestors[p])
276 wrev.add(rev)
276 wrev.add(rev)
277 self.wantedancestors[rev] = wrev
277 self.wantedancestors[rev] = wrev
278
278
279 def getchanges(self, rev):
279 def getchanges(self, rev):
280 parents = self.commits[rev].parents
280 parents = self.commits[rev].parents
281 if len(parents) > 1:
281 if len(parents) > 1:
282 self.rebuild()
282 self.rebuild()
283
283
284 # To decide whether we're interested in rev we:
284 # To decide whether we're interested in rev we:
285 #
285 #
286 # - calculate what parents rev will have if it turns out we're
286 # - calculate what parents rev will have if it turns out we're
287 # interested in it. If it's going to have more than 1 parent,
287 # interested in it. If it's going to have more than 1 parent,
288 # we're interested in it.
288 # we're interested in it.
289 #
289 #
290 # - otherwise, we'll compare it with the single parent we found.
290 # - otherwise, we'll compare it with the single parent we found.
291 # If any of the files we're interested in is different in the
291 # If any of the files we're interested in is different in the
292 # the two revisions, we're interested in rev.
292 # the two revisions, we're interested in rev.
293
293
294 # A parent p is interesting if its mapped version (self.parentmap[p]):
294 # A parent p is interesting if its mapped version (self.parentmap[p]):
295 # - is not SKIPREV
295 # - is not SKIPREV
296 # - is still not in the list of parents (we don't want duplicates)
296 # - is still not in the list of parents (we don't want duplicates)
297 # - is not an ancestor of the mapped versions of the other parents or
297 # - is not an ancestor of the mapped versions of the other parents or
298 # there is no parent in the same branch than the current revision.
298 # there is no parent in the same branch than the current revision.
299 mparents = []
299 mparents = []
300 knownparents = set()
300 knownparents = set()
301 branch = self.commits[rev].branch
301 branch = self.commits[rev].branch
302 hasbranchparent = False
302 hasbranchparent = False
303 for i, p1 in enumerate(parents):
303 for i, p1 in enumerate(parents):
304 mp1 = self.parentmap[p1]
304 mp1 = self.parentmap[p1]
305 if mp1 == SKIPREV or mp1 in knownparents:
305 if mp1 == SKIPREV or mp1 in knownparents:
306 continue
306 continue
307 isancestor = util.any(p2 for p2 in parents
307 isancestor = util.any(p2 for p2 in parents
308 if p1 != p2 and mp1 != self.parentmap[p2]
308 if p1 != p2 and mp1 != self.parentmap[p2]
309 and mp1 in self.wantedancestors[p2])
309 and mp1 in self.wantedancestors[p2])
310 if not isancestor and not hasbranchparent and len(parents) > 1:
310 if not isancestor and not hasbranchparent and len(parents) > 1:
311 # This could be expensive, avoid unnecessary calls.
311 # This could be expensive, avoid unnecessary calls.
312 if self._cachedcommit(p1).branch == branch:
312 if self._cachedcommit(p1).branch == branch:
313 hasbranchparent = True
313 hasbranchparent = True
314 mparents.append((p1, mp1, i, isancestor))
314 mparents.append((p1, mp1, i, isancestor))
315 knownparents.add(mp1)
315 knownparents.add(mp1)
316 # Discard parents ancestors of other parents if there is a
316 # Discard parents ancestors of other parents if there is a
317 # non-ancestor one on the same branch than current revision.
317 # non-ancestor one on the same branch than current revision.
318 if hasbranchparent:
318 if hasbranchparent:
319 mparents = [p for p in mparents if not p[3]]
319 mparents = [p for p in mparents if not p[3]]
320 wp = None
320 wp = None
321 if mparents:
321 if mparents:
322 wp = max(p[2] for p in mparents)
322 wp = max(p[2] for p in mparents)
323 mparents = [p[1] for p in mparents]
323 mparents = [p[1] for p in mparents]
324 elif parents:
324 elif parents:
325 wp = 0
325 wp = 0
326
326
327 self.origparents[rev] = parents
327 self.origparents[rev] = parents
328
328
329 closed = False
329 closed = False
330 if 'close' in self.commits[rev].extra:
330 if 'close' in self.commits[rev].extra:
331 # A branch closing revision is only useful if one of its
331 # A branch closing revision is only useful if one of its
332 # parents belong to the branch being closed
332 # parents belong to the branch being closed
333 pbranches = [self._cachedcommit(p).branch for p in mparents]
333 pbranches = [self._cachedcommit(p).branch for p in mparents]
334 if branch in pbranches:
334 if branch in pbranches:
335 closed = True
335 closed = True
336
336
337 if len(mparents) < 2 and not closed and not self.wanted(rev, wp):
337 if len(mparents) < 2 and not closed and not self.wanted(rev, wp):
338 # We don't want this revision.
338 # We don't want this revision.
339 # Update our state and tell the convert process to map this
339 # Update our state and tell the convert process to map this
340 # revision to the same revision its parent as mapped to.
340 # revision to the same revision its parent as mapped to.
341 p = None
341 p = None
342 if parents:
342 if parents:
343 p = parents[wp]
343 p = parents[wp]
344 self.mark_not_wanted(rev, p)
344 self.mark_not_wanted(rev, p)
345 self.convertedorder.append((rev, False, p))
345 self.convertedorder.append((rev, False, p))
346 self._discard(*parents)
346 self._discard(*parents)
347 return self.parentmap[rev]
347 return self.parentmap[rev]
348
348
349 # We want this revision.
349 # We want this revision.
350 # Rewrite the parents of the commit object
350 # Rewrite the parents of the commit object
351 self.commits[rev].parents = mparents
351 self.commits[rev].parents = mparents
352 self.mark_wanted(rev, parents)
352 self.mark_wanted(rev, parents)
353 self.convertedorder.append((rev, True, None))
353 self.convertedorder.append((rev, True, None))
354 self._discard(*parents)
354 self._discard(*parents)
355
355
356 # Get the real changes and do the filtering/mapping. To be
356 # Get the real changes and do the filtering/mapping. To be
357 # able to get the files later on in getfile, we hide the
357 # able to get the files later on in getfile, we hide the
358 # original filename in the rev part of the return value.
358 # original filename in the rev part of the return value.
359 changes, copies = self.base.getchanges(rev)
359 changes, copies = self.base.getchanges(rev)
360 newnames = {}
360 newnames = {}
361 files = []
361 files = {}
362 for f, r in changes:
362 for f, r in changes:
363 newf = self.filemapper(f)
363 newf = self.filemapper(f)
364 if newf:
364 if newf and (newf != f or newf not in files):
365 files.append((newf, (f, r)))
365 files[newf] = (f, r)
366 newnames[f] = newf
366 newnames[f] = newf
367 files = sorted(files.items())
367
368
368 ncopies = {}
369 ncopies = {}
369 for c in copies:
370 for c in copies:
370 newc = self.filemapper(c)
371 newc = self.filemapper(c)
371 if newc:
372 if newc:
372 newsource = self.filemapper(copies[c])
373 newsource = self.filemapper(copies[c])
373 if newsource:
374 if newsource:
374 ncopies[newc] = newsource
375 ncopies[newc] = newsource
375
376
376 return files, ncopies
377 return files, ncopies
377
378
378 def getfile(self, name, rev):
379 def getfile(self, name, rev):
379 realname, realrev = rev
380 realname, realrev = rev
380 return self.base.getfile(realname, realrev)
381 return self.base.getfile(realname, realrev)
381
382
382 def gettags(self):
383 def gettags(self):
383 return self.base.gettags()
384 return self.base.gettags()
384
385
385 def hasnativeorder(self):
386 def hasnativeorder(self):
386 return self.base.hasnativeorder()
387 return self.base.hasnativeorder()
387
388
388 def lookuprev(self, rev):
389 def lookuprev(self, rev):
389 return self.base.lookuprev(rev)
390 return self.base.lookuprev(rev)
390
391
391 def getbookmarks(self):
392 def getbookmarks(self):
392 return self.base.getbookmarks()
393 return self.base.getbookmarks()
@@ -1,563 +1,596
1
1
2 $ HGMERGE=true; export HGMERGE
2 $ HGMERGE=true; export HGMERGE
3 $ echo '[extensions]' >> $HGRCPATH
3 $ echo '[extensions]' >> $HGRCPATH
4 $ echo 'graphlog =' >> $HGRCPATH
4 $ echo 'graphlog =' >> $HGRCPATH
5 $ echo 'convert =' >> $HGRCPATH
5 $ echo 'convert =' >> $HGRCPATH
6 $ glog()
6 $ glog()
7 > {
7 > {
8 > hg glog --template '{rev} "{desc}" files: {files}\n' "$@"
8 > hg glog --template '{rev} "{desc}" files: {files}\n' "$@"
9 > }
9 > }
10 $ hg init source
10 $ hg init source
11 $ cd source
11 $ cd source
12 $ echo foo > foo
12 $ echo foo > foo
13 $ echo baz > baz
13 $ echo baz > baz
14 $ mkdir -p dir/subdir
14 $ mkdir -p dir/subdir
15 $ echo dir/file >> dir/file
15 $ echo dir/file >> dir/file
16 $ echo dir/file2 >> dir/file2
16 $ echo dir/file2 >> dir/file2
17 $ echo dir/file3 >> dir/file3 # to be corrupted in rev 0
17 $ echo dir/file3 >> dir/file3 # to be corrupted in rev 0
18 $ echo dir/subdir/file3 >> dir/subdir/file3
18 $ echo dir/subdir/file3 >> dir/subdir/file3
19 $ echo dir/subdir/file4 >> dir/subdir/file4
19 $ echo dir/subdir/file4 >> dir/subdir/file4
20 $ hg ci -d '0 0' -qAm '0: add foo baz dir/'
20 $ hg ci -d '0 0' -qAm '0: add foo baz dir/'
21 $ echo bar > bar
21 $ echo bar > bar
22 $ echo quux > quux
22 $ echo quux > quux
23 $ echo dir/file4 >> dir/file4 # to be corrupted in rev 1
23 $ echo dir/file4 >> dir/file4 # to be corrupted in rev 1
24 $ hg copy foo copied
24 $ hg copy foo copied
25 $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied'
25 $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied'
26 $ echo >> foo
26 $ echo >> foo
27 $ hg ci -d '2 0' -m '2: change foo'
27 $ hg ci -d '2 0' -m '2: change foo'
28 $ hg up -qC 1
28 $ hg up -qC 1
29 $ echo >> bar
29 $ echo >> bar
30 $ echo >> quux
30 $ echo >> quux
31 $ hg ci -d '3 0' -m '3: change bar quux'
31 $ hg ci -d '3 0' -m '3: change bar quux'
32 created new head
32 created new head
33 $ hg up -qC 2
33 $ hg up -qC 2
34 $ hg merge -qr 3
34 $ hg merge -qr 3
35 $ echo >> bar
35 $ echo >> bar
36 $ echo >> baz
36 $ echo >> baz
37 $ hg ci -d '4 0' -m '4: first merge; change bar baz'
37 $ hg ci -d '4 0' -m '4: first merge; change bar baz'
38 $ echo >> bar
38 $ echo >> bar
39 $ echo 1 >> baz
39 $ echo 1 >> baz
40 $ echo >> quux
40 $ echo >> quux
41 $ hg ci -d '5 0' -m '5: change bar baz quux'
41 $ hg ci -d '5 0' -m '5: change bar baz quux'
42 $ hg up -qC 4
42 $ hg up -qC 4
43 $ echo >> foo
43 $ echo >> foo
44 $ echo 2 >> baz
44 $ echo 2 >> baz
45 $ hg ci -d '6 0' -m '6: change foo baz'
45 $ hg ci -d '6 0' -m '6: change foo baz'
46 created new head
46 created new head
47 $ hg up -qC 5
47 $ hg up -qC 5
48 $ hg merge -qr 6
48 $ hg merge -qr 6
49 $ echo >> bar
49 $ echo >> bar
50 $ hg ci -d '7 0' -m '7: second merge; change bar'
50 $ hg ci -d '7 0' -m '7: second merge; change bar'
51 $ echo >> foo
51 $ echo >> foo
52 $ hg ci -m '8: change foo'
52 $ hg ci -m '8: change foo'
53 $ glog
53 $ glog
54 @ 8 "8: change foo" files: foo
54 @ 8 "8: change foo" files: foo
55 |
55 |
56 o 7 "7: second merge; change bar" files: bar baz
56 o 7 "7: second merge; change bar" files: bar baz
57 |\
57 |\
58 | o 6 "6: change foo baz" files: baz foo
58 | o 6 "6: change foo baz" files: baz foo
59 | |
59 | |
60 o | 5 "5: change bar baz quux" files: bar baz quux
60 o | 5 "5: change bar baz quux" files: bar baz quux
61 |/
61 |/
62 o 4 "4: first merge; change bar baz" files: bar baz
62 o 4 "4: first merge; change bar baz" files: bar baz
63 |\
63 |\
64 | o 3 "3: change bar quux" files: bar quux
64 | o 3 "3: change bar quux" files: bar quux
65 | |
65 | |
66 o | 2 "2: change foo" files: foo
66 o | 2 "2: change foo" files: foo
67 |/
67 |/
68 o 1 "1: add bar quux; copy foo to copied" files: bar copied dir/file4 quux
68 o 1 "1: add bar quux; copy foo to copied" files: bar copied dir/file4 quux
69 |
69 |
70 o 0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/file3 dir/subdir/file3 dir/subdir/file4 foo
70 o 0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/file3 dir/subdir/file3 dir/subdir/file4 foo
71
71
72
72
73 final file versions in this repo:
73 final file versions in this repo:
74
74
75 $ hg manifest --debug
75 $ hg manifest --debug
76 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
76 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
77 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
77 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
78 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
78 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
79 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir/file
79 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir/file
80 75e6d3f8328f5f6ace6bf10b98df793416a09dca 644 dir/file2
80 75e6d3f8328f5f6ace6bf10b98df793416a09dca 644 dir/file2
81 e96dce0bc6a217656a3a410e5e6bec2c4f42bf7c 644 dir/file3
81 e96dce0bc6a217656a3a410e5e6bec2c4f42bf7c 644 dir/file3
82 6edd55f559cdce67132b12ca09e09cee08b60442 644 dir/file4
82 6edd55f559cdce67132b12ca09e09cee08b60442 644 dir/file4
83 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir/subdir/file3
83 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir/subdir/file3
84 57a1c1511590f3de52874adfa04effe8a77d64af 644 dir/subdir/file4
84 57a1c1511590f3de52874adfa04effe8a77d64af 644 dir/subdir/file4
85 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
85 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
86 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
86 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
87 $ hg debugrename copied
87 $ hg debugrename copied
88 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
88 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
89
89
90 $ cd ..
90 $ cd ..
91 $ splitrepo()
91 $ splitrepo()
92 > {
92 > {
93 > msg="$1"
93 > msg="$1"
94 > files="$2"
94 > files="$2"
95 > opts=$3
95 > opts=$3
96 > echo "% $files: $msg"
96 > echo "% $files: $msg"
97 > prefix=`echo "$files" | sed -e 's/ /-/g'`
97 > prefix=`echo "$files" | sed -e 's/ /-/g'`
98 > fmap="$prefix.fmap"
98 > fmap="$prefix.fmap"
99 > repo="$prefix.repo"
99 > repo="$prefix.repo"
100 > for i in $files; do
100 > for i in $files; do
101 > echo "include $i" >> "$fmap"
101 > echo "include $i" >> "$fmap"
102 > done
102 > done
103 > hg -q convert $opts --filemap "$fmap" --datesort source "$repo"
103 > hg -q convert $opts --filemap "$fmap" --datesort source "$repo"
104 > hg up -q -R "$repo"
104 > hg up -q -R "$repo"
105 > glog -R "$repo"
105 > glog -R "$repo"
106 > hg -R "$repo" manifest --debug
106 > hg -R "$repo" manifest --debug
107 > }
107 > }
108 $ splitrepo 'skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd' foo
108 $ splitrepo 'skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd' foo
109 % foo: skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd
109 % foo: skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd
110 @ 3 "8: change foo" files: foo
110 @ 3 "8: change foo" files: foo
111 |
111 |
112 o 2 "6: change foo baz" files: foo
112 o 2 "6: change foo baz" files: foo
113 |
113 |
114 o 1 "2: change foo" files: foo
114 o 1 "2: change foo" files: foo
115 |
115 |
116 o 0 "0: add foo baz dir/" files: foo
116 o 0 "0: add foo baz dir/" files: foo
117
117
118 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
118 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
119 $ splitrepo 'merges are not merges anymore' bar
119 $ splitrepo 'merges are not merges anymore' bar
120 % bar: merges are not merges anymore
120 % bar: merges are not merges anymore
121 @ 4 "7: second merge; change bar" files: bar
121 @ 4 "7: second merge; change bar" files: bar
122 |
122 |
123 o 3 "5: change bar baz quux" files: bar
123 o 3 "5: change bar baz quux" files: bar
124 |
124 |
125 o 2 "4: first merge; change bar baz" files: bar
125 o 2 "4: first merge; change bar baz" files: bar
126 |
126 |
127 o 1 "3: change bar quux" files: bar
127 o 1 "3: change bar quux" files: bar
128 |
128 |
129 o 0 "1: add bar quux; copy foo to copied" files: bar
129 o 0 "1: add bar quux; copy foo to copied" files: bar
130
130
131 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
131 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
132 $ splitrepo '1st merge is not a merge anymore; 2nd still is' baz
132 $ splitrepo '1st merge is not a merge anymore; 2nd still is' baz
133 % baz: 1st merge is not a merge anymore; 2nd still is
133 % baz: 1st merge is not a merge anymore; 2nd still is
134 @ 4 "7: second merge; change bar" files: baz
134 @ 4 "7: second merge; change bar" files: baz
135 |\
135 |\
136 | o 3 "6: change foo baz" files: baz
136 | o 3 "6: change foo baz" files: baz
137 | |
137 | |
138 o | 2 "5: change bar baz quux" files: baz
138 o | 2 "5: change bar baz quux" files: baz
139 |/
139 |/
140 o 1 "4: first merge; change bar baz" files: baz
140 o 1 "4: first merge; change bar baz" files: baz
141 |
141 |
142 o 0 "0: add foo baz dir/" files: baz
142 o 0 "0: add foo baz dir/" files: baz
143
143
144 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
144 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
145 $ splitrepo 'we add additional merges when they are interesting' 'foo quux'
145 $ splitrepo 'we add additional merges when they are interesting' 'foo quux'
146 % foo quux: we add additional merges when they are interesting
146 % foo quux: we add additional merges when they are interesting
147 @ 8 "8: change foo" files: foo
147 @ 8 "8: change foo" files: foo
148 |
148 |
149 o 7 "7: second merge; change bar" files:
149 o 7 "7: second merge; change bar" files:
150 |\
150 |\
151 | o 6 "6: change foo baz" files: foo
151 | o 6 "6: change foo baz" files: foo
152 | |
152 | |
153 o | 5 "5: change bar baz quux" files: quux
153 o | 5 "5: change bar baz quux" files: quux
154 |/
154 |/
155 o 4 "4: first merge; change bar baz" files:
155 o 4 "4: first merge; change bar baz" files:
156 |\
156 |\
157 | o 3 "3: change bar quux" files: quux
157 | o 3 "3: change bar quux" files: quux
158 | |
158 | |
159 o | 2 "2: change foo" files: foo
159 o | 2 "2: change foo" files: foo
160 |/
160 |/
161 o 1 "1: add bar quux; copy foo to copied" files: quux
161 o 1 "1: add bar quux; copy foo to copied" files: quux
162 |
162 |
163 o 0 "0: add foo baz dir/" files: foo
163 o 0 "0: add foo baz dir/" files: foo
164
164
165 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
165 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
166 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
166 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
167 $ splitrepo 'partial conversion' 'bar quux' '-r 3'
167 $ splitrepo 'partial conversion' 'bar quux' '-r 3'
168 % bar quux: partial conversion
168 % bar quux: partial conversion
169 @ 1 "3: change bar quux" files: bar quux
169 @ 1 "3: change bar quux" files: bar quux
170 |
170 |
171 o 0 "1: add bar quux; copy foo to copied" files: bar quux
171 o 0 "1: add bar quux; copy foo to copied" files: bar quux
172
172
173 b79105bedc55102f394e90a789c9c380117c1b4a 644 bar
173 b79105bedc55102f394e90a789c9c380117c1b4a 644 bar
174 db0421cc6b685a458c8d86c7d5c004f94429ea23 644 quux
174 db0421cc6b685a458c8d86c7d5c004f94429ea23 644 quux
175 $ splitrepo 'complete the partial conversion' 'bar quux'
175 $ splitrepo 'complete the partial conversion' 'bar quux'
176 % bar quux: complete the partial conversion
176 % bar quux: complete the partial conversion
177 @ 4 "7: second merge; change bar" files: bar
177 @ 4 "7: second merge; change bar" files: bar
178 |
178 |
179 o 3 "5: change bar baz quux" files: bar quux
179 o 3 "5: change bar baz quux" files: bar quux
180 |
180 |
181 o 2 "4: first merge; change bar baz" files: bar
181 o 2 "4: first merge; change bar baz" files: bar
182 |
182 |
183 o 1 "3: change bar quux" files: bar quux
183 o 1 "3: change bar quux" files: bar quux
184 |
184 |
185 o 0 "1: add bar quux; copy foo to copied" files: bar quux
185 o 0 "1: add bar quux; copy foo to copied" files: bar quux
186
186
187 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
187 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
188 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
188 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
189 $ rm -r foo.repo
189 $ rm -r foo.repo
190 $ splitrepo 'partial conversion' 'foo' '-r 3'
190 $ splitrepo 'partial conversion' 'foo' '-r 3'
191 % foo: partial conversion
191 % foo: partial conversion
192 @ 0 "0: add foo baz dir/" files: foo
192 @ 0 "0: add foo baz dir/" files: foo
193
193
194 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
194 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
195 $ splitrepo 'complete the partial conversion' 'foo'
195 $ splitrepo 'complete the partial conversion' 'foo'
196 % foo: complete the partial conversion
196 % foo: complete the partial conversion
197 @ 3 "8: change foo" files: foo
197 @ 3 "8: change foo" files: foo
198 |
198 |
199 o 2 "6: change foo baz" files: foo
199 o 2 "6: change foo baz" files: foo
200 |
200 |
201 o 1 "2: change foo" files: foo
201 o 1 "2: change foo" files: foo
202 |
202 |
203 o 0 "0: add foo baz dir/" files: foo
203 o 0 "0: add foo baz dir/" files: foo
204
204
205 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
205 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
206 $ splitrepo 'copied file; source not included in new repo' copied
206 $ splitrepo 'copied file; source not included in new repo' copied
207 % copied: copied file; source not included in new repo
207 % copied: copied file; source not included in new repo
208 @ 0 "1: add bar quux; copy foo to copied" files: copied
208 @ 0 "1: add bar quux; copy foo to copied" files: copied
209
209
210 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 copied
210 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 copied
211 $ hg --cwd copied.repo debugrename copied
211 $ hg --cwd copied.repo debugrename copied
212 copied not renamed
212 copied not renamed
213 $ splitrepo 'copied file; source included in new repo' 'foo copied'
213 $ splitrepo 'copied file; source included in new repo' 'foo copied'
214 % foo copied: copied file; source included in new repo
214 % foo copied: copied file; source included in new repo
215 @ 4 "8: change foo" files: foo
215 @ 4 "8: change foo" files: foo
216 |
216 |
217 o 3 "6: change foo baz" files: foo
217 o 3 "6: change foo baz" files: foo
218 |
218 |
219 o 2 "2: change foo" files: foo
219 o 2 "2: change foo" files: foo
220 |
220 |
221 o 1 "1: add bar quux; copy foo to copied" files: copied
221 o 1 "1: add bar quux; copy foo to copied" files: copied
222 |
222 |
223 o 0 "0: add foo baz dir/" files: foo
223 o 0 "0: add foo baz dir/" files: foo
224
224
225 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
225 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
226 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
226 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
227 $ hg --cwd foo-copied.repo debugrename copied
227 $ hg --cwd foo-copied.repo debugrename copied
228 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
228 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
229 $ cat > renames.fmap <<EOF
229 $ cat > renames.fmap <<EOF
230 > include dir
230 > include dir
231 > exclude dir/file2
231 > exclude dir/file2
232 > rename dir dir2
232 > rename dir dir2
233 > include foo
233 > include foo
234 > include copied
234 > include copied
235 > rename foo foo2
235 > rename foo foo2
236 > rename copied copied2
236 > rename copied copied2
237 > exclude dir/subdir
237 > exclude dir/subdir
238 > include dir/subdir/file3
238 > include dir/subdir/file3
239 > EOF
239 > EOF
240 $ rm source/.hg/store/data/dir/file3.i
240 $ rm source/.hg/store/data/dir/file3.i
241 $ rm source/.hg/store/data/dir/file4.i
241 $ rm source/.hg/store/data/dir/file4.i
242 $ hg -q convert --filemap renames.fmap --datesort source dummydest
242 $ hg -q convert --filemap renames.fmap --datesort source dummydest
243 abort: data/dir/file3.i@e96dce0bc6a2: no match found!
243 abort: data/dir/file3.i@e96dce0bc6a2: no match found!
244 [255]
244 [255]
245 $ hg -q convert --filemap renames.fmap --datesort --config convert.hg.ignoreerrors=1 source renames.repo
245 $ hg -q convert --filemap renames.fmap --datesort --config convert.hg.ignoreerrors=1 source renames.repo
246 ignoring: data/dir/file3.i@e96dce0bc6a2: no match found
246 ignoring: data/dir/file3.i@e96dce0bc6a2: no match found
247 ignoring: data/dir/file4.i@6edd55f559cd: no match found
247 ignoring: data/dir/file4.i@6edd55f559cd: no match found
248 $ hg up -q -R renames.repo
248 $ hg up -q -R renames.repo
249 $ glog -R renames.repo
249 $ glog -R renames.repo
250 @ 4 "8: change foo" files: foo2
250 @ 4 "8: change foo" files: foo2
251 |
251 |
252 o 3 "6: change foo baz" files: foo2
252 o 3 "6: change foo baz" files: foo2
253 |
253 |
254 o 2 "2: change foo" files: foo2
254 o 2 "2: change foo" files: foo2
255 |
255 |
256 o 1 "1: add bar quux; copy foo to copied" files: copied2
256 o 1 "1: add bar quux; copy foo to copied" files: copied2
257 |
257 |
258 o 0 "0: add foo baz dir/" files: dir2/file dir2/subdir/file3 foo2
258 o 0 "0: add foo baz dir/" files: dir2/file dir2/subdir/file3 foo2
259
259
260 $ hg -R renames.repo manifest --debug
260 $ hg -R renames.repo manifest --debug
261 d43feacba7a4f1f2080dde4a4b985bd8a0236d46 644 copied2
261 d43feacba7a4f1f2080dde4a4b985bd8a0236d46 644 copied2
262 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir2/file
262 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir2/file
263 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir2/subdir/file3
263 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir2/subdir/file3
264 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo2
264 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo2
265 $ hg --cwd renames.repo debugrename copied2
265 $ hg --cwd renames.repo debugrename copied2
266 copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd
266 copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd
267
267
268 copied:
268 copied:
269
269
270 $ hg --cwd source cat copied
270 $ hg --cwd source cat copied
271 foo
271 foo
272
272
273 copied2:
273 copied2:
274
274
275 $ hg --cwd renames.repo cat copied2
275 $ hg --cwd renames.repo cat copied2
276 foo
276 foo
277
277
278 filemap errors
278 filemap errors
279
279
280 $ cat > errors.fmap <<EOF
280 $ cat > errors.fmap <<EOF
281 > include dir/ # beware that comments changes error line numbers!
281 > include dir/ # beware that comments changes error line numbers!
282 > exclude /dir
282 > exclude /dir
283 > rename dir//dir /dir//dir/ "out of sync"
283 > rename dir//dir /dir//dir/ "out of sync"
284 > include
284 > include
285 > EOF
285 > EOF
286 $ hg -q convert --filemap errors.fmap source errors.repo
286 $ hg -q convert --filemap errors.fmap source errors.repo
287 errors.fmap:1: superfluous / in exclude 'dir/'
287 errors.fmap:1: superfluous / in exclude 'dir/'
288 errors.fmap:3: superfluous / in include '/dir'
288 errors.fmap:3: superfluous / in include '/dir'
289 errors.fmap:3: superfluous / in rename '/dir'
289 errors.fmap:3: superfluous / in rename '/dir'
290 errors.fmap:3: superfluous / in exclude 'dir//dir'
290 errors.fmap:3: superfluous / in exclude 'dir//dir'
291 errors.fmap:4: unknown directive 'out of sync'
291 errors.fmap:4: unknown directive 'out of sync'
292 errors.fmap:5: path to exclude is missing
292 errors.fmap:5: path to exclude is missing
293 abort: errors in filemap
293 abort: errors in filemap
294 [255]
294 [255]
295
295
296 test branch closing revision pruning if branch is pruned
296 test branch closing revision pruning if branch is pruned
297
297
298 $ hg init branchpruning
298 $ hg init branchpruning
299 $ cd branchpruning
299 $ cd branchpruning
300 $ hg branch foo
300 $ hg branch foo
301 marked working directory as branch foo
301 marked working directory as branch foo
302 (branches are permanent and global, did you want a bookmark?)
302 (branches are permanent and global, did you want a bookmark?)
303 $ echo a > a
303 $ echo a > a
304 $ hg ci -Am adda
304 $ hg ci -Am adda
305 adding a
305 adding a
306 $ hg ci --close-branch -m closefoo
306 $ hg ci --close-branch -m closefoo
307 $ hg up 0
307 $ hg up 0
308 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
309 $ hg branch empty
309 $ hg branch empty
310 marked working directory as branch empty
310 marked working directory as branch empty
311 (branches are permanent and global, did you want a bookmark?)
311 (branches are permanent and global, did you want a bookmark?)
312 $ hg ci -m emptybranch
312 $ hg ci -m emptybranch
313 $ hg ci --close-branch -m closeempty
313 $ hg ci --close-branch -m closeempty
314 $ hg up 0
314 $ hg up 0
315 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 $ hg branch default
316 $ hg branch default
317 marked working directory as branch default
317 marked working directory as branch default
318 (branches are permanent and global, did you want a bookmark?)
318 (branches are permanent and global, did you want a bookmark?)
319 $ echo b > b
319 $ echo b > b
320 $ hg ci -Am addb
320 $ hg ci -Am addb
321 adding b
321 adding b
322 $ hg ci --close-branch -m closedefault
322 $ hg ci --close-branch -m closedefault
323 $ cat > filemap <<EOF
323 $ cat > filemap <<EOF
324 > include b
324 > include b
325 > EOF
325 > EOF
326 $ cd ..
326 $ cd ..
327 $ hg convert branchpruning branchpruning-hg1
327 $ hg convert branchpruning branchpruning-hg1
328 initializing destination branchpruning-hg1 repository
328 initializing destination branchpruning-hg1 repository
329 scanning source...
329 scanning source...
330 sorting...
330 sorting...
331 converting...
331 converting...
332 5 adda
332 5 adda
333 4 closefoo
333 4 closefoo
334 3 emptybranch
334 3 emptybranch
335 2 closeempty
335 2 closeempty
336 1 addb
336 1 addb
337 0 closedefault
337 0 closedefault
338 $ glog -R branchpruning-hg1
338 $ glog -R branchpruning-hg1
339 o 5 "closedefault" files:
339 o 5 "closedefault" files:
340 |
340 |
341 o 4 "addb" files: b
341 o 4 "addb" files: b
342 |
342 |
343 | o 3 "closeempty" files:
343 | o 3 "closeempty" files:
344 | |
344 | |
345 | o 2 "emptybranch" files:
345 | o 2 "emptybranch" files:
346 |/
346 |/
347 | o 1 "closefoo" files:
347 | o 1 "closefoo" files:
348 |/
348 |/
349 o 0 "adda" files: a
349 o 0 "adda" files: a
350
350
351
351
352 exercise incremental conversion at the same time
352 exercise incremental conversion at the same time
353
353
354 $ hg convert -r0 --filemap branchpruning/filemap branchpruning branchpruning-hg2
354 $ hg convert -r0 --filemap branchpruning/filemap branchpruning branchpruning-hg2
355 initializing destination branchpruning-hg2 repository
355 initializing destination branchpruning-hg2 repository
356 scanning source...
356 scanning source...
357 sorting...
357 sorting...
358 converting...
358 converting...
359 0 adda
359 0 adda
360 $ hg convert -r4 --filemap branchpruning/filemap branchpruning branchpruning-hg2
360 $ hg convert -r4 --filemap branchpruning/filemap branchpruning branchpruning-hg2
361 scanning source...
361 scanning source...
362 sorting...
362 sorting...
363 converting...
363 converting...
364 0 addb
364 0 addb
365 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2
365 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2
366 scanning source...
366 scanning source...
367 sorting...
367 sorting...
368 converting...
368 converting...
369 3 closefoo
369 3 closefoo
370 2 emptybranch
370 2 emptybranch
371 1 closeempty
371 1 closeempty
372 0 closedefault
372 0 closedefault
373 $ glog -R branchpruning-hg2
373 $ glog -R branchpruning-hg2
374 o 1 "closedefault" files:
374 o 1 "closedefault" files:
375 |
375 |
376 o 0 "addb" files: b
376 o 0 "addb" files: b
377
377
378
378
379 filemap rename undoing revision rename
380
381 $ hg init renameundo
382 $ cd renameundo
383 $ echo 1 > a
384 $ echo 1 > c
385 $ hg ci -qAm add
386 $ hg mv -q a b/a
387 $ hg mv -q c b/c
388 $ hg ci -qm rename
389 $ echo 2 > b/a
390 $ echo 2 > b/c
391 $ hg ci -qm modify
392 $ cd ..
393
394 $ echo "rename b ." > renameundo.fmap
395 $ hg convert --filemap renameundo.fmap renameundo renameundo2
396 initializing destination renameundo2 repository
397 scanning source...
398 sorting...
399 converting...
400 2 add
401 1 rename
402 filtering out empty revision
403 repository tip rolled back to revision 0 (undo commit)
404 0 modify
405 $ glog -R renameundo2
406 o 1 "modify" files: a c
407 |
408 o 0 "add" files: a c
409
410
411
379 test merge parents/empty merges pruning
412 test merge parents/empty merges pruning
380
413
381 $ glog()
414 $ glog()
382 > {
415 > {
383 > hg glog --template '{rev}:{node|short}@{branch} "{desc}" files: {files}\n' "$@"
416 > hg glog --template '{rev}:{node|short}@{branch} "{desc}" files: {files}\n' "$@"
384 > }
417 > }
385
418
386 test anonymous branch pruning
419 test anonymous branch pruning
387
420
388 $ hg init anonymousbranch
421 $ hg init anonymousbranch
389 $ cd anonymousbranch
422 $ cd anonymousbranch
390 $ echo a > a
423 $ echo a > a
391 $ echo b > b
424 $ echo b > b
392 $ hg ci -Am add
425 $ hg ci -Am add
393 adding a
426 adding a
394 adding b
427 adding b
395 $ echo a >> a
428 $ echo a >> a
396 $ hg ci -m changea
429 $ hg ci -m changea
397 $ hg up 0
430 $ hg up 0
398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
431 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 $ echo b >> b
432 $ echo b >> b
400 $ hg ci -m changeb
433 $ hg ci -m changeb
401 created new head
434 created new head
402 $ hg up 1
435 $ hg up 1
403 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
436 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
404 $ hg merge
437 $ hg merge
405 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
438 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 (branch merge, don't forget to commit)
439 (branch merge, don't forget to commit)
407 $ hg ci -m merge
440 $ hg ci -m merge
408 $ cd ..
441 $ cd ..
409
442
410 $ cat > filemap <<EOF
443 $ cat > filemap <<EOF
411 > include a
444 > include a
412 > EOF
445 > EOF
413 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg
446 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg
414 initializing destination anonymousbranch-hg repository
447 initializing destination anonymousbranch-hg repository
415 scanning source...
448 scanning source...
416 sorting...
449 sorting...
417 converting...
450 converting...
418 3 add
451 3 add
419 2 changea
452 2 changea
420 1 changeb
453 1 changeb
421 0 merge
454 0 merge
422 $ glog -R anonymousbranch
455 $ glog -R anonymousbranch
423 @ 3:c71d5201a498@default "merge" files:
456 @ 3:c71d5201a498@default "merge" files:
424 |\
457 |\
425 | o 2:607eb44b17f9@default "changeb" files: b
458 | o 2:607eb44b17f9@default "changeb" files: b
426 | |
459 | |
427 o | 1:1f60ea617824@default "changea" files: a
460 o | 1:1f60ea617824@default "changea" files: a
428 |/
461 |/
429 o 0:0146e6129113@default "add" files: a b
462 o 0:0146e6129113@default "add" files: a b
430
463
431 $ glog -R anonymousbranch-hg
464 $ glog -R anonymousbranch-hg
432 o 1:cda818e7219b@default "changea" files: a
465 o 1:cda818e7219b@default "changea" files: a
433 |
466 |
434 o 0:c334dc3be0da@default "add" files: a
467 o 0:c334dc3be0da@default "add" files: a
435
468
436 $ cat anonymousbranch-hg/.hg/shamap
469 $ cat anonymousbranch-hg/.hg/shamap
437 0146e6129113dba9ac90207cfdf2d7ed35257ae5 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
470 0146e6129113dba9ac90207cfdf2d7ed35257ae5 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
438 1f60ea61782421edf8d051ff4fcb61b330f26a4a cda818e7219b5f7f3fb9f49780054ed6a1905ec3
471 1f60ea61782421edf8d051ff4fcb61b330f26a4a cda818e7219b5f7f3fb9f49780054ed6a1905ec3
439 607eb44b17f9348cd5cbd26e16af87ba77b0b037 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
472 607eb44b17f9348cd5cbd26e16af87ba77b0b037 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
440 c71d5201a498b2658d105a6bf69d7a0df2649aea cda818e7219b5f7f3fb9f49780054ed6a1905ec3
473 c71d5201a498b2658d105a6bf69d7a0df2649aea cda818e7219b5f7f3fb9f49780054ed6a1905ec3
441
474
442 $ cat > filemap <<EOF
475 $ cat > filemap <<EOF
443 > include b
476 > include b
444 > EOF
477 > EOF
445 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg2
478 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg2
446 initializing destination anonymousbranch-hg2 repository
479 initializing destination anonymousbranch-hg2 repository
447 scanning source...
480 scanning source...
448 sorting...
481 sorting...
449 converting...
482 converting...
450 3 add
483 3 add
451 2 changea
484 2 changea
452 1 changeb
485 1 changeb
453 0 merge
486 0 merge
454 $ glog -R anonymousbranch
487 $ glog -R anonymousbranch
455 @ 3:c71d5201a498@default "merge" files:
488 @ 3:c71d5201a498@default "merge" files:
456 |\
489 |\
457 | o 2:607eb44b17f9@default "changeb" files: b
490 | o 2:607eb44b17f9@default "changeb" files: b
458 | |
491 | |
459 o | 1:1f60ea617824@default "changea" files: a
492 o | 1:1f60ea617824@default "changea" files: a
460 |/
493 |/
461 o 0:0146e6129113@default "add" files: a b
494 o 0:0146e6129113@default "add" files: a b
462
495
463 $ glog -R anonymousbranch-hg2
496 $ glog -R anonymousbranch-hg2
464 o 1:62dd350b0df6@default "changeb" files: b
497 o 1:62dd350b0df6@default "changeb" files: b
465 |
498 |
466 o 0:4b9ced861657@default "add" files: b
499 o 0:4b9ced861657@default "add" files: b
467
500
468 $ cat anonymousbranch-hg2/.hg/shamap
501 $ cat anonymousbranch-hg2/.hg/shamap
469 0146e6129113dba9ac90207cfdf2d7ed35257ae5 4b9ced86165703791653059a1db6ed864630a523
502 0146e6129113dba9ac90207cfdf2d7ed35257ae5 4b9ced86165703791653059a1db6ed864630a523
470 1f60ea61782421edf8d051ff4fcb61b330f26a4a 4b9ced86165703791653059a1db6ed864630a523
503 1f60ea61782421edf8d051ff4fcb61b330f26a4a 4b9ced86165703791653059a1db6ed864630a523
471 607eb44b17f9348cd5cbd26e16af87ba77b0b037 62dd350b0df695f7d2c82a02e0499b16fd790f22
504 607eb44b17f9348cd5cbd26e16af87ba77b0b037 62dd350b0df695f7d2c82a02e0499b16fd790f22
472 c71d5201a498b2658d105a6bf69d7a0df2649aea 62dd350b0df695f7d2c82a02e0499b16fd790f22
505 c71d5201a498b2658d105a6bf69d7a0df2649aea 62dd350b0df695f7d2c82a02e0499b16fd790f22
473
506
474 test named branch pruning
507 test named branch pruning
475
508
476 $ hg init namedbranch
509 $ hg init namedbranch
477 $ cd namedbranch
510 $ cd namedbranch
478 $ echo a > a
511 $ echo a > a
479 $ echo b > b
512 $ echo b > b
480 $ hg ci -Am add
513 $ hg ci -Am add
481 adding a
514 adding a
482 adding b
515 adding b
483 $ echo a >> a
516 $ echo a >> a
484 $ hg ci -m changea
517 $ hg ci -m changea
485 $ hg up 0
518 $ hg up 0
486 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
519 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
487 $ hg branch foo
520 $ hg branch foo
488 marked working directory as branch foo
521 marked working directory as branch foo
489 (branches are permanent and global, did you want a bookmark?)
522 (branches are permanent and global, did you want a bookmark?)
490 $ echo b >> b
523 $ echo b >> b
491 $ hg ci -m changeb
524 $ hg ci -m changeb
492 $ hg up default
525 $ hg up default
493 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
526 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
494 $ hg merge foo
527 $ hg merge foo
495 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
528 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
496 (branch merge, don't forget to commit)
529 (branch merge, don't forget to commit)
497 $ hg ci -m merge
530 $ hg ci -m merge
498 $ cd ..
531 $ cd ..
499
532
500 $ cat > filemap <<EOF
533 $ cat > filemap <<EOF
501 > include a
534 > include a
502 > EOF
535 > EOF
503 $ hg convert --filemap filemap namedbranch namedbranch-hg
536 $ hg convert --filemap filemap namedbranch namedbranch-hg
504 initializing destination namedbranch-hg repository
537 initializing destination namedbranch-hg repository
505 scanning source...
538 scanning source...
506 sorting...
539 sorting...
507 converting...
540 converting...
508 3 add
541 3 add
509 2 changea
542 2 changea
510 1 changeb
543 1 changeb
511 0 merge
544 0 merge
512 $ glog -R namedbranch
545 $ glog -R namedbranch
513 @ 3:73899bcbe45c@default "merge" files:
546 @ 3:73899bcbe45c@default "merge" files:
514 |\
547 |\
515 | o 2:8097982d19fc@foo "changeb" files: b
548 | o 2:8097982d19fc@foo "changeb" files: b
516 | |
549 | |
517 o | 1:1f60ea617824@default "changea" files: a
550 o | 1:1f60ea617824@default "changea" files: a
518 |/
551 |/
519 o 0:0146e6129113@default "add" files: a b
552 o 0:0146e6129113@default "add" files: a b
520
553
521 $ glog -R namedbranch-hg
554 $ glog -R namedbranch-hg
522 o 1:cda818e7219b@default "changea" files: a
555 o 1:cda818e7219b@default "changea" files: a
523 |
556 |
524 o 0:c334dc3be0da@default "add" files: a
557 o 0:c334dc3be0da@default "add" files: a
525
558
526
559
527 $ cd namedbranch
560 $ cd namedbranch
528 $ hg --config extensions.mq= strip tip
561 $ hg --config extensions.mq= strip tip
529 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
562 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 saved backup bundle to $TESTTMP/namedbranch/.hg/strip-backup/73899bcbe45c-backup.hg (glob)
563 saved backup bundle to $TESTTMP/namedbranch/.hg/strip-backup/73899bcbe45c-backup.hg (glob)
531 $ hg up foo
564 $ hg up foo
532 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
565 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
533 $ hg merge default
566 $ hg merge default
534 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
567 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
535 (branch merge, don't forget to commit)
568 (branch merge, don't forget to commit)
536 $ hg ci -m merge
569 $ hg ci -m merge
537 $ cd ..
570 $ cd ..
538
571
539 $ hg convert --filemap filemap namedbranch namedbranch-hg2
572 $ hg convert --filemap filemap namedbranch namedbranch-hg2
540 initializing destination namedbranch-hg2 repository
573 initializing destination namedbranch-hg2 repository
541 scanning source...
574 scanning source...
542 sorting...
575 sorting...
543 converting...
576 converting...
544 3 add
577 3 add
545 2 changea
578 2 changea
546 1 changeb
579 1 changeb
547 0 merge
580 0 merge
548 $ glog -R namedbranch
581 $ glog -R namedbranch
549 @ 3:e1959de76e1b@foo "merge" files:
582 @ 3:e1959de76e1b@foo "merge" files:
550 |\
583 |\
551 | o 2:8097982d19fc@foo "changeb" files: b
584 | o 2:8097982d19fc@foo "changeb" files: b
552 | |
585 | |
553 o | 1:1f60ea617824@default "changea" files: a
586 o | 1:1f60ea617824@default "changea" files: a
554 |/
587 |/
555 o 0:0146e6129113@default "add" files: a b
588 o 0:0146e6129113@default "add" files: a b
556
589
557 $ glog -R namedbranch-hg2
590 $ glog -R namedbranch-hg2
558 o 2:dcf314454667@foo "merge" files:
591 o 2:dcf314454667@foo "merge" files:
559 |\
592 |\
560 | o 1:cda818e7219b@default "changea" files: a
593 | o 1:cda818e7219b@default "changea" files: a
561 |/
594 |/
562 o 0:c334dc3be0da@default "add" files: a
595 o 0:c334dc3be0da@default "add" files: a
563
596
General Comments 0
You need to be logged in to leave comments. Login now