##// END OF EJS Templates
convert: keep branch switching merges with ancestors (issue3340)...
Patrick Mezard -
r17103:5146de7b default
parent child Browse files
Show More
@@ -1,382 +1,392
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
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 mparents = []
299 mparents = []
299 wp = None
300 knownparents = set()
301 branch = self.commits[rev].branch
302 hasbranchparent = False
300 for i, p1 in enumerate(parents):
303 for i, p1 in enumerate(parents):
301 mp1 = self.parentmap[p1]
304 mp1 = self.parentmap[p1]
302 if mp1 == SKIPREV or mp1 in mparents:
305 if mp1 == SKIPREV or mp1 in knownparents:
303 continue
306 continue
304 for p2 in parents:
307 isancestor = util.any(p2 for p2 in parents
305 if p1 == p2 or mp1 == self.parentmap[p2]:
308 if p1 != p2 and mp1 != self.parentmap[p2]
306 continue
309 and mp1 in self.wantedancestors[p2])
307 if mp1 in self.wantedancestors[p2]:
310 if not isancestor and not hasbranchparent and len(parents) > 1:
308 break
311 # This could be expensive, avoid unnecessary calls.
309 else:
312 if self._cachedcommit(p1).branch == branch:
310 mparents.append(mp1)
313 hasbranchparent = True
311 wp = i
314 mparents.append((p1, mp1, i, isancestor))
312
315 knownparents.add(mp1)
313 if wp is None and parents:
316 # Discard parents ancestors of other parents if there is a
317 # non-ancestor one on the same branch than current revision.
318 if hasbranchparent:
319 mparents = [p for p in mparents if not p[3]]
320 wp = None
321 if mparents:
322 wp = max(p[2] for p in mparents)
323 mparents = [p[1] for p in mparents]
324 elif parents:
314 wp = 0
325 wp = 0
315
326
316 self.origparents[rev] = parents
327 self.origparents[rev] = parents
317
328
318 closed = False
329 closed = False
319 if 'close' in self.commits[rev].extra:
330 if 'close' in self.commits[rev].extra:
320 # A branch closing revision is only useful if one of its
331 # A branch closing revision is only useful if one of its
321 # parents belong to the branch being closed
332 # parents belong to the branch being closed
322 branch = self.commits[rev].branch
323 pbranches = [self._cachedcommit(p).branch for p in mparents]
333 pbranches = [self._cachedcommit(p).branch for p in mparents]
324 if branch in pbranches:
334 if branch in pbranches:
325 closed = True
335 closed = True
326
336
327 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):
328 # We don't want this revision.
338 # We don't want this revision.
329 # Update our state and tell the convert process to map this
339 # Update our state and tell the convert process to map this
330 # revision to the same revision its parent as mapped to.
340 # revision to the same revision its parent as mapped to.
331 p = None
341 p = None
332 if parents:
342 if parents:
333 p = parents[wp]
343 p = parents[wp]
334 self.mark_not_wanted(rev, p)
344 self.mark_not_wanted(rev, p)
335 self.convertedorder.append((rev, False, p))
345 self.convertedorder.append((rev, False, p))
336 self._discard(*parents)
346 self._discard(*parents)
337 return self.parentmap[rev]
347 return self.parentmap[rev]
338
348
339 # We want this revision.
349 # We want this revision.
340 # Rewrite the parents of the commit object
350 # Rewrite the parents of the commit object
341 self.commits[rev].parents = mparents
351 self.commits[rev].parents = mparents
342 self.mark_wanted(rev, parents)
352 self.mark_wanted(rev, parents)
343 self.convertedorder.append((rev, True, None))
353 self.convertedorder.append((rev, True, None))
344 self._discard(*parents)
354 self._discard(*parents)
345
355
346 # Get the real changes and do the filtering/mapping. To be
356 # Get the real changes and do the filtering/mapping. To be
347 # 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
348 # original filename in the rev part of the return value.
358 # original filename in the rev part of the return value.
349 changes, copies = self.base.getchanges(rev)
359 changes, copies = self.base.getchanges(rev)
350 newnames = {}
360 newnames = {}
351 files = []
361 files = []
352 for f, r in changes:
362 for f, r in changes:
353 newf = self.filemapper(f)
363 newf = self.filemapper(f)
354 if newf:
364 if newf:
355 files.append((newf, (f, r)))
365 files.append((newf, (f, r)))
356 newnames[f] = newf
366 newnames[f] = newf
357
367
358 ncopies = {}
368 ncopies = {}
359 for c in copies:
369 for c in copies:
360 newc = self.filemapper(c)
370 newc = self.filemapper(c)
361 if newc:
371 if newc:
362 newsource = self.filemapper(copies[c])
372 newsource = self.filemapper(copies[c])
363 if newsource:
373 if newsource:
364 ncopies[newc] = newsource
374 ncopies[newc] = newsource
365
375
366 return files, ncopies
376 return files, ncopies
367
377
368 def getfile(self, name, rev):
378 def getfile(self, name, rev):
369 realname, realrev = rev
379 realname, realrev = rev
370 return self.base.getfile(realname, realrev)
380 return self.base.getfile(realname, realrev)
371
381
372 def gettags(self):
382 def gettags(self):
373 return self.base.gettags()
383 return self.base.gettags()
374
384
375 def hasnativeorder(self):
385 def hasnativeorder(self):
376 return self.base.hasnativeorder()
386 return self.base.hasnativeorder()
377
387
378 def lookuprev(self, rev):
388 def lookuprev(self, rev):
379 return self.base.lookuprev(rev)
389 return self.base.lookuprev(rev)
380
390
381 def getbookmarks(self):
391 def getbookmarks(self):
382 return self.base.getbookmarks()
392 return self.base.getbookmarks()
@@ -1,377 +1,563
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
379 test merge parents/empty merges pruning
380
381 $ glog()
382 > {
383 > hg glog --template '{rev}:{node|short}@{branch} "{desc}" files: {files}\n' "$@"
384 > }
385
386 test anonymous branch pruning
387
388 $ hg init anonymousbranch
389 $ cd anonymousbranch
390 $ echo a > a
391 $ echo b > b
392 $ hg ci -Am add
393 adding a
394 adding b
395 $ echo a >> a
396 $ hg ci -m changea
397 $ hg up 0
398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 $ echo b >> b
400 $ hg ci -m changeb
401 created new head
402 $ hg up 1
403 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
404 $ hg merge
405 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 (branch merge, don't forget to commit)
407 $ hg ci -m merge
408 $ cd ..
409
410 $ cat > filemap <<EOF
411 > include a
412 > EOF
413 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg
414 initializing destination anonymousbranch-hg repository
415 scanning source...
416 sorting...
417 converting...
418 3 add
419 2 changea
420 1 changeb
421 0 merge
422 $ glog -R anonymousbranch
423 @ 3:c71d5201a498@default "merge" files:
424 |\
425 | o 2:607eb44b17f9@default "changeb" files: b
426 | |
427 o | 1:1f60ea617824@default "changea" files: a
428 |/
429 o 0:0146e6129113@default "add" files: a b
430
431 $ glog -R anonymousbranch-hg
432 o 1:cda818e7219b@default "changea" files: a
433 |
434 o 0:c334dc3be0da@default "add" files: a
435
436 $ cat anonymousbranch-hg/.hg/shamap
437 0146e6129113dba9ac90207cfdf2d7ed35257ae5 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
438 1f60ea61782421edf8d051ff4fcb61b330f26a4a cda818e7219b5f7f3fb9f49780054ed6a1905ec3
439 607eb44b17f9348cd5cbd26e16af87ba77b0b037 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
440 c71d5201a498b2658d105a6bf69d7a0df2649aea cda818e7219b5f7f3fb9f49780054ed6a1905ec3
441
442 $ cat > filemap <<EOF
443 > include b
444 > EOF
445 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg2
446 initializing destination anonymousbranch-hg2 repository
447 scanning source...
448 sorting...
449 converting...
450 3 add
451 2 changea
452 1 changeb
453 0 merge
454 $ glog -R anonymousbranch
455 @ 3:c71d5201a498@default "merge" files:
456 |\
457 | o 2:607eb44b17f9@default "changeb" files: b
458 | |
459 o | 1:1f60ea617824@default "changea" files: a
460 |/
461 o 0:0146e6129113@default "add" files: a b
462
463 $ glog -R anonymousbranch-hg2
464 o 1:62dd350b0df6@default "changeb" files: b
465 |
466 o 0:4b9ced861657@default "add" files: b
467
468 $ cat anonymousbranch-hg2/.hg/shamap
469 0146e6129113dba9ac90207cfdf2d7ed35257ae5 4b9ced86165703791653059a1db6ed864630a523
470 1f60ea61782421edf8d051ff4fcb61b330f26a4a 4b9ced86165703791653059a1db6ed864630a523
471 607eb44b17f9348cd5cbd26e16af87ba77b0b037 62dd350b0df695f7d2c82a02e0499b16fd790f22
472 c71d5201a498b2658d105a6bf69d7a0df2649aea 62dd350b0df695f7d2c82a02e0499b16fd790f22
473
474 test named branch pruning
475
476 $ hg init namedbranch
477 $ cd namedbranch
478 $ echo a > a
479 $ echo b > b
480 $ hg ci -Am add
481 adding a
482 adding b
483 $ echo a >> a
484 $ hg ci -m changea
485 $ hg up 0
486 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
487 $ hg branch foo
488 marked working directory as branch foo
489 (branches are permanent and global, did you want a bookmark?)
490 $ echo b >> b
491 $ hg ci -m changeb
492 $ hg up default
493 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
494 $ hg merge foo
495 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
496 (branch merge, don't forget to commit)
497 $ hg ci -m merge
498 $ cd ..
499
500 $ cat > filemap <<EOF
501 > include a
502 > EOF
503 $ hg convert --filemap filemap namedbranch namedbranch-hg
504 initializing destination namedbranch-hg repository
505 scanning source...
506 sorting...
507 converting...
508 3 add
509 2 changea
510 1 changeb
511 0 merge
512 $ glog -R namedbranch
513 @ 3:73899bcbe45c@default "merge" files:
514 |\
515 | o 2:8097982d19fc@foo "changeb" files: b
516 | |
517 o | 1:1f60ea617824@default "changea" files: a
518 |/
519 o 0:0146e6129113@default "add" files: a b
520
521 $ glog -R namedbranch-hg
522 o 1:cda818e7219b@default "changea" files: a
523 |
524 o 0:c334dc3be0da@default "add" files: a
525
526
527 $ cd namedbranch
528 $ hg --config extensions.mq= strip tip
529 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
531 $ hg up foo
532 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
533 $ hg merge default
534 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
535 (branch merge, don't forget to commit)
536 $ hg ci -m merge
537 $ cd ..
538
539 $ hg convert --filemap filemap namedbranch namedbranch-hg2
540 initializing destination namedbranch-hg2 repository
541 scanning source...
542 sorting...
543 converting...
544 3 add
545 2 changea
546 1 changeb
547 0 merge
548 $ glog -R namedbranch
549 @ 3:e1959de76e1b@foo "merge" files:
550 |\
551 | o 2:8097982d19fc@foo "changeb" files: b
552 | |
553 o | 1:1f60ea617824@default "changea" files: a
554 |/
555 o 0:0146e6129113@default "add" files: a b
556
557 $ glog -R namedbranch-hg2
558 o 2:dcf314454667@foo "merge" files:
559 |\
560 | o 1:cda818e7219b@default "changea" files: a
561 |/
562 o 0:c334dc3be0da@default "add" files: a
563
General Comments 0
You need to be logged in to leave comments. Login now