##// END OF EJS Templates
convert: fix convert dropping p2 contents during filemap merge...
Durham Goode -
r26037:a75d2453 default
parent child Browse files
Show More
@@ -1,568 +1,616 b''
1 # hg.py - hg backend for convert extension
1 # hg.py - hg backend for convert extension
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # Notes for hg->hg conversion:
8 # Notes for hg->hg conversion:
9 #
9 #
10 # * Old versions of Mercurial didn't trim the whitespace from the ends
10 # * Old versions of Mercurial didn't trim the whitespace from the ends
11 # of commit messages, but new versions do. Changesets created by
11 # of commit messages, but new versions do. Changesets created by
12 # those older versions, then converted, may thus have different
12 # those older versions, then converted, may thus have different
13 # hashes for changesets that are otherwise identical.
13 # hashes for changesets that are otherwise identical.
14 #
14 #
15 # * Using "--config convert.hg.saverev=true" will make the source
15 # * Using "--config convert.hg.saverev=true" will make the source
16 # identifier to be stored in the converted revision. This will cause
16 # identifier to be stored in the converted revision. This will cause
17 # the converted revision to have a different identity than the
17 # the converted revision to have a different identity than the
18 # source.
18 # source.
19
19
20
20
21 import os, time, cStringIO
21 import os, time, cStringIO
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23 from mercurial.node import bin, hex, nullid
23 from mercurial.node import bin, hex, nullid
24 from mercurial import hg, util, context, bookmarks, error, scmutil, exchange
24 from mercurial import hg, util, context, bookmarks, error, scmutil, exchange
25 from mercurial import phases
25 from mercurial import phases
26 from mercurial import merge as mergemod
26
27
27 from common import NoRepo, commit, converter_source, converter_sink, mapfile
28 from common import NoRepo, commit, converter_source, converter_sink, mapfile
28
29
29 import re
30 import re
30 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
31 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
31
32
32 class mercurial_sink(converter_sink):
33 class mercurial_sink(converter_sink):
33 def __init__(self, ui, path):
34 def __init__(self, ui, path):
34 converter_sink.__init__(self, ui, path)
35 converter_sink.__init__(self, ui, path)
35 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
36 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
36 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
37 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
37 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
38 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
38 self.lastbranch = None
39 self.lastbranch = None
39 if os.path.isdir(path) and len(os.listdir(path)) > 0:
40 if os.path.isdir(path) and len(os.listdir(path)) > 0:
40 try:
41 try:
41 self.repo = hg.repository(self.ui, path)
42 self.repo = hg.repository(self.ui, path)
42 if not self.repo.local():
43 if not self.repo.local():
43 raise NoRepo(_('%s is not a local Mercurial repository')
44 raise NoRepo(_('%s is not a local Mercurial repository')
44 % path)
45 % path)
45 except error.RepoError as err:
46 except error.RepoError as err:
46 ui.traceback()
47 ui.traceback()
47 raise NoRepo(err.args[0])
48 raise NoRepo(err.args[0])
48 else:
49 else:
49 try:
50 try:
50 ui.status(_('initializing destination %s repository\n') % path)
51 ui.status(_('initializing destination %s repository\n') % path)
51 self.repo = hg.repository(self.ui, path, create=True)
52 self.repo = hg.repository(self.ui, path, create=True)
52 if not self.repo.local():
53 if not self.repo.local():
53 raise NoRepo(_('%s is not a local Mercurial repository')
54 raise NoRepo(_('%s is not a local Mercurial repository')
54 % path)
55 % path)
55 self.created.append(path)
56 self.created.append(path)
56 except error.RepoError:
57 except error.RepoError:
57 ui.traceback()
58 ui.traceback()
58 raise NoRepo(_("could not create hg repository %s as sink")
59 raise NoRepo(_("could not create hg repository %s as sink")
59 % path)
60 % path)
60 self.lock = None
61 self.lock = None
61 self.wlock = None
62 self.wlock = None
62 self.filemapmode = False
63 self.filemapmode = False
63 self.subrevmaps = {}
64 self.subrevmaps = {}
64
65
65 def before(self):
66 def before(self):
66 self.ui.debug('run hg sink pre-conversion action\n')
67 self.ui.debug('run hg sink pre-conversion action\n')
67 self.wlock = self.repo.wlock()
68 self.wlock = self.repo.wlock()
68 self.lock = self.repo.lock()
69 self.lock = self.repo.lock()
69
70
70 def after(self):
71 def after(self):
71 self.ui.debug('run hg sink post-conversion action\n')
72 self.ui.debug('run hg sink post-conversion action\n')
72 if self.lock:
73 if self.lock:
73 self.lock.release()
74 self.lock.release()
74 if self.wlock:
75 if self.wlock:
75 self.wlock.release()
76 self.wlock.release()
76
77
77 def revmapfile(self):
78 def revmapfile(self):
78 return self.repo.join("shamap")
79 return self.repo.join("shamap")
79
80
80 def authorfile(self):
81 def authorfile(self):
81 return self.repo.join("authormap")
82 return self.repo.join("authormap")
82
83
83 def setbranch(self, branch, pbranches):
84 def setbranch(self, branch, pbranches):
84 if not self.clonebranches:
85 if not self.clonebranches:
85 return
86 return
86
87
87 setbranch = (branch != self.lastbranch)
88 setbranch = (branch != self.lastbranch)
88 self.lastbranch = branch
89 self.lastbranch = branch
89 if not branch:
90 if not branch:
90 branch = 'default'
91 branch = 'default'
91 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
92 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
92 if pbranches:
93 if pbranches:
93 pbranch = pbranches[0][1]
94 pbranch = pbranches[0][1]
94 else:
95 else:
95 pbranch = 'default'
96 pbranch = 'default'
96
97
97 branchpath = os.path.join(self.path, branch)
98 branchpath = os.path.join(self.path, branch)
98 if setbranch:
99 if setbranch:
99 self.after()
100 self.after()
100 try:
101 try:
101 self.repo = hg.repository(self.ui, branchpath)
102 self.repo = hg.repository(self.ui, branchpath)
102 except Exception:
103 except Exception:
103 self.repo = hg.repository(self.ui, branchpath, create=True)
104 self.repo = hg.repository(self.ui, branchpath, create=True)
104 self.before()
105 self.before()
105
106
106 # pbranches may bring revisions from other branches (merge parents)
107 # pbranches may bring revisions from other branches (merge parents)
107 # Make sure we have them, or pull them.
108 # Make sure we have them, or pull them.
108 missings = {}
109 missings = {}
109 for b in pbranches:
110 for b in pbranches:
110 try:
111 try:
111 self.repo.lookup(b[0])
112 self.repo.lookup(b[0])
112 except Exception:
113 except Exception:
113 missings.setdefault(b[1], []).append(b[0])
114 missings.setdefault(b[1], []).append(b[0])
114
115
115 if missings:
116 if missings:
116 self.after()
117 self.after()
117 for pbranch, heads in sorted(missings.iteritems()):
118 for pbranch, heads in sorted(missings.iteritems()):
118 pbranchpath = os.path.join(self.path, pbranch)
119 pbranchpath = os.path.join(self.path, pbranch)
119 prepo = hg.peer(self.ui, {}, pbranchpath)
120 prepo = hg.peer(self.ui, {}, pbranchpath)
120 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
121 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
121 exchange.pull(self.repo, prepo,
122 exchange.pull(self.repo, prepo,
122 [prepo.lookup(h) for h in heads])
123 [prepo.lookup(h) for h in heads])
123 self.before()
124 self.before()
124
125
125 def _rewritetags(self, source, revmap, data):
126 def _rewritetags(self, source, revmap, data):
126 fp = cStringIO.StringIO()
127 fp = cStringIO.StringIO()
127 for line in data.splitlines():
128 for line in data.splitlines():
128 s = line.split(' ', 1)
129 s = line.split(' ', 1)
129 if len(s) != 2:
130 if len(s) != 2:
130 continue
131 continue
131 revid = revmap.get(source.lookuprev(s[0]))
132 revid = revmap.get(source.lookuprev(s[0]))
132 if not revid:
133 if not revid:
133 if s[0] == hex(nullid):
134 if s[0] == hex(nullid):
134 revid = s[0]
135 revid = s[0]
135 else:
136 else:
136 continue
137 continue
137 fp.write('%s %s\n' % (revid, s[1]))
138 fp.write('%s %s\n' % (revid, s[1]))
138 return fp.getvalue()
139 return fp.getvalue()
139
140
140 def _rewritesubstate(self, source, data):
141 def _rewritesubstate(self, source, data):
141 fp = cStringIO.StringIO()
142 fp = cStringIO.StringIO()
142 for line in data.splitlines():
143 for line in data.splitlines():
143 s = line.split(' ', 1)
144 s = line.split(' ', 1)
144 if len(s) != 2:
145 if len(s) != 2:
145 continue
146 continue
146
147
147 revid = s[0]
148 revid = s[0]
148 subpath = s[1]
149 subpath = s[1]
149 if revid != hex(nullid):
150 if revid != hex(nullid):
150 revmap = self.subrevmaps.get(subpath)
151 revmap = self.subrevmaps.get(subpath)
151 if revmap is None:
152 if revmap is None:
152 revmap = mapfile(self.ui,
153 revmap = mapfile(self.ui,
153 self.repo.wjoin(subpath, '.hg/shamap'))
154 self.repo.wjoin(subpath, '.hg/shamap'))
154 self.subrevmaps[subpath] = revmap
155 self.subrevmaps[subpath] = revmap
155
156
156 # It is reasonable that one or more of the subrepos don't
157 # It is reasonable that one or more of the subrepos don't
157 # need to be converted, in which case they can be cloned
158 # need to be converted, in which case they can be cloned
158 # into place instead of converted. Therefore, only warn
159 # into place instead of converted. Therefore, only warn
159 # once.
160 # once.
160 msg = _('no ".hgsubstate" updates will be made for "%s"\n')
161 msg = _('no ".hgsubstate" updates will be made for "%s"\n')
161 if len(revmap) == 0:
162 if len(revmap) == 0:
162 sub = self.repo.wvfs.reljoin(subpath, '.hg')
163 sub = self.repo.wvfs.reljoin(subpath, '.hg')
163
164
164 if self.repo.wvfs.exists(sub):
165 if self.repo.wvfs.exists(sub):
165 self.ui.warn(msg % subpath)
166 self.ui.warn(msg % subpath)
166
167
167 newid = revmap.get(revid)
168 newid = revmap.get(revid)
168 if not newid:
169 if not newid:
169 if len(revmap) > 0:
170 if len(revmap) > 0:
170 self.ui.warn(_("%s is missing from %s/.hg/shamap\n") %
171 self.ui.warn(_("%s is missing from %s/.hg/shamap\n") %
171 (revid, subpath))
172 (revid, subpath))
172 else:
173 else:
173 revid = newid
174 revid = newid
174
175
175 fp.write('%s %s\n' % (revid, subpath))
176 fp.write('%s %s\n' % (revid, subpath))
176
177
177 return fp.getvalue()
178 return fp.getvalue()
178
179
180 def _calculatemergedfiles(self, source, p1ctx, p2ctx):
181 """Calculates the files from p2 that we need to pull in when merging p1
182 and p2, given that the merge is coming from the given source.
183
184 This prevents us from losing files that only exist in the target p2 and
185 that don't come from the source repo (like if you're merging multiple
186 repositories together).
187 """
188 anc = [p1ctx.ancestor(p2ctx)]
189 # Calculate what files are coming from p2
190 actions, diverge, rename = mergemod.calculateupdates(
191 self.repo, p1ctx, p2ctx, anc,
192 True, # branchmerge
193 True, # force
194 False, # partial
195 False, # acceptremote
196 False, # followcopies
197 )
198
199 for file, (action, info, msg) in actions.iteritems():
200 if source.targetfilebelongstosource(file):
201 # If the file belongs to the source repo, ignore the p2
202 # since it will be covered by the existing fileset.
203 continue
204
205 # If the file requires actual merging, abort. We don't have enough
206 # context to resolve merges correctly.
207 if action in ['m', 'dm', 'cd', 'dc']:
208 raise util.Abort(_("unable to convert merge commit "
209 "since target parents do not merge cleanly (file "
210 "%s, parents %s and %s)") % (file, p1ctx,
211 p2ctx))
212 elif action == 'k':
213 # 'keep' means nothing changed from p1
214 continue
215 else:
216 # Any other change means we want to take the p2 version
217 yield file
218
179 def putcommit(self, files, copies, parents, commit, source, revmap, full,
219 def putcommit(self, files, copies, parents, commit, source, revmap, full,
180 cleanp2):
220 cleanp2):
181 files = dict(files)
221 files = dict(files)
182
222
183 def getfilectx(repo, memctx, f):
223 def getfilectx(repo, memctx, f):
184 if p2ctx and f in cleanp2 and f not in copies:
224 if p2ctx and f in p2files and f not in copies:
185 self.ui.debug('reusing %s from p2\n' % f)
225 self.ui.debug('reusing %s from p2\n' % f)
186 return p2ctx[f]
226 return p2ctx[f]
187 try:
227 try:
188 v = files[f]
228 v = files[f]
189 except KeyError:
229 except KeyError:
190 return None
230 return None
191 data, mode = source.getfile(f, v)
231 data, mode = source.getfile(f, v)
192 if data is None:
232 if data is None:
193 return None
233 return None
194 if f == '.hgtags':
234 if f == '.hgtags':
195 data = self._rewritetags(source, revmap, data)
235 data = self._rewritetags(source, revmap, data)
196 if f == '.hgsubstate':
236 if f == '.hgsubstate':
197 data = self._rewritesubstate(source, data)
237 data = self._rewritesubstate(source, data)
198 return context.memfilectx(self.repo, f, data, 'l' in mode,
238 return context.memfilectx(self.repo, f, data, 'l' in mode,
199 'x' in mode, copies.get(f))
239 'x' in mode, copies.get(f))
200
240
201 pl = []
241 pl = []
202 for p in parents:
242 for p in parents:
203 if p not in pl:
243 if p not in pl:
204 pl.append(p)
244 pl.append(p)
205 parents = pl
245 parents = pl
206 nparents = len(parents)
246 nparents = len(parents)
207 if self.filemapmode and nparents == 1:
247 if self.filemapmode and nparents == 1:
208 m1node = self.repo.changelog.read(bin(parents[0]))[0]
248 m1node = self.repo.changelog.read(bin(parents[0]))[0]
209 parent = parents[0]
249 parent = parents[0]
210
250
211 if len(parents) < 2:
251 if len(parents) < 2:
212 parents.append(nullid)
252 parents.append(nullid)
213 if len(parents) < 2:
253 if len(parents) < 2:
214 parents.append(nullid)
254 parents.append(nullid)
215 p2 = parents.pop(0)
255 p2 = parents.pop(0)
216
256
217 text = commit.desc
257 text = commit.desc
218
258
219 sha1s = re.findall(sha1re, text)
259 sha1s = re.findall(sha1re, text)
220 for sha1 in sha1s:
260 for sha1 in sha1s:
221 oldrev = source.lookuprev(sha1)
261 oldrev = source.lookuprev(sha1)
222 newrev = revmap.get(oldrev)
262 newrev = revmap.get(oldrev)
223 if newrev is not None:
263 if newrev is not None:
224 text = text.replace(sha1, newrev[:len(sha1)])
264 text = text.replace(sha1, newrev[:len(sha1)])
225
265
226 extra = commit.extra.copy()
266 extra = commit.extra.copy()
227
267
228 sourcename = self.repo.ui.config('convert', 'hg.sourcename')
268 sourcename = self.repo.ui.config('convert', 'hg.sourcename')
229 if sourcename:
269 if sourcename:
230 extra['convert_source'] = sourcename
270 extra['convert_source'] = sourcename
231
271
232 for label in ('source', 'transplant_source', 'rebase_source',
272 for label in ('source', 'transplant_source', 'rebase_source',
233 'intermediate-source'):
273 'intermediate-source'):
234 node = extra.get(label)
274 node = extra.get(label)
235
275
236 if node is None:
276 if node is None:
237 continue
277 continue
238
278
239 # Only transplant stores its reference in binary
279 # Only transplant stores its reference in binary
240 if label == 'transplant_source':
280 if label == 'transplant_source':
241 node = hex(node)
281 node = hex(node)
242
282
243 newrev = revmap.get(node)
283 newrev = revmap.get(node)
244 if newrev is not None:
284 if newrev is not None:
245 if label == 'transplant_source':
285 if label == 'transplant_source':
246 newrev = bin(newrev)
286 newrev = bin(newrev)
247
287
248 extra[label] = newrev
288 extra[label] = newrev
249
289
250 if self.branchnames and commit.branch:
290 if self.branchnames and commit.branch:
251 extra['branch'] = commit.branch
291 extra['branch'] = commit.branch
252 if commit.rev and commit.saverev:
292 if commit.rev and commit.saverev:
253 extra['convert_revision'] = commit.rev
293 extra['convert_revision'] = commit.rev
254
294
255 while parents:
295 while parents:
256 p1 = p2
296 p1 = p2
257 p2 = parents.pop(0)
297 p2 = parents.pop(0)
298 p1ctx = self.repo[p1]
258 p2ctx = None
299 p2ctx = None
259 if p2 != nullid:
300 if p2 != nullid:
260 p2ctx = self.repo[p2]
301 p2ctx = self.repo[p2]
261 fileset = set(files)
302 fileset = set(files)
262 if full:
303 if full:
263 fileset.update(self.repo[p1])
304 fileset.update(self.repo[p1])
264 fileset.update(self.repo[p2])
305 fileset.update(self.repo[p2])
306
307 if p2ctx:
308 p2files = set(cleanp2)
309 for file in self._calculatemergedfiles(source, p1ctx, p2ctx):
310 p2files.add(file)
311 fileset.add(file)
312
265 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
313 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
266 getfilectx, commit.author, commit.date, extra)
314 getfilectx, commit.author, commit.date, extra)
267
315
268 # We won't know if the conversion changes the node until after the
316 # We won't know if the conversion changes the node until after the
269 # commit, so copy the source's phase for now.
317 # commit, so copy the source's phase for now.
270 self.repo.ui.setconfig('phases', 'new-commit',
318 self.repo.ui.setconfig('phases', 'new-commit',
271 phases.phasenames[commit.phase], 'convert')
319 phases.phasenames[commit.phase], 'convert')
272
320
273 tr = self.repo.transaction("convert")
321 tr = self.repo.transaction("convert")
274
322
275 try:
323 try:
276 node = hex(self.repo.commitctx(ctx))
324 node = hex(self.repo.commitctx(ctx))
277
325
278 # If the node value has changed, but the phase is lower than
326 # If the node value has changed, but the phase is lower than
279 # draft, set it back to draft since it hasn't been exposed
327 # draft, set it back to draft since it hasn't been exposed
280 # anywhere.
328 # anywhere.
281 if commit.rev != node:
329 if commit.rev != node:
282 ctx = self.repo[node]
330 ctx = self.repo[node]
283 if ctx.phase() < phases.draft:
331 if ctx.phase() < phases.draft:
284 phases.retractboundary(self.repo, tr, phases.draft,
332 phases.retractboundary(self.repo, tr, phases.draft,
285 [ctx.node()])
333 [ctx.node()])
286 tr.close()
334 tr.close()
287 finally:
335 finally:
288 tr.release()
336 tr.release()
289
337
290 text = "(octopus merge fixup)\n"
338 text = "(octopus merge fixup)\n"
291 p2 = node
339 p2 = node
292
340
293 if self.filemapmode and nparents == 1:
341 if self.filemapmode and nparents == 1:
294 man = self.repo.manifest
342 man = self.repo.manifest
295 mnode = self.repo.changelog.read(bin(p2))[0]
343 mnode = self.repo.changelog.read(bin(p2))[0]
296 closed = 'close' in commit.extra
344 closed = 'close' in commit.extra
297 if not closed and not man.cmp(m1node, man.revision(mnode)):
345 if not closed and not man.cmp(m1node, man.revision(mnode)):
298 self.ui.status(_("filtering out empty revision\n"))
346 self.ui.status(_("filtering out empty revision\n"))
299 self.repo.rollback(force=True)
347 self.repo.rollback(force=True)
300 return parent
348 return parent
301 return p2
349 return p2
302
350
303 def puttags(self, tags):
351 def puttags(self, tags):
304 try:
352 try:
305 parentctx = self.repo[self.tagsbranch]
353 parentctx = self.repo[self.tagsbranch]
306 tagparent = parentctx.node()
354 tagparent = parentctx.node()
307 except error.RepoError:
355 except error.RepoError:
308 parentctx = None
356 parentctx = None
309 tagparent = nullid
357 tagparent = nullid
310
358
311 oldlines = set()
359 oldlines = set()
312 for branch, heads in self.repo.branchmap().iteritems():
360 for branch, heads in self.repo.branchmap().iteritems():
313 for h in heads:
361 for h in heads:
314 if '.hgtags' in self.repo[h]:
362 if '.hgtags' in self.repo[h]:
315 oldlines.update(
363 oldlines.update(
316 set(self.repo[h]['.hgtags'].data().splitlines(True)))
364 set(self.repo[h]['.hgtags'].data().splitlines(True)))
317 oldlines = sorted(list(oldlines))
365 oldlines = sorted(list(oldlines))
318
366
319 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
367 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
320 if newlines == oldlines:
368 if newlines == oldlines:
321 return None, None
369 return None, None
322
370
323 # if the old and new tags match, then there is nothing to update
371 # if the old and new tags match, then there is nothing to update
324 oldtags = set()
372 oldtags = set()
325 newtags = set()
373 newtags = set()
326 for line in oldlines:
374 for line in oldlines:
327 s = line.strip().split(' ', 1)
375 s = line.strip().split(' ', 1)
328 if len(s) != 2:
376 if len(s) != 2:
329 continue
377 continue
330 oldtags.add(s[1])
378 oldtags.add(s[1])
331 for line in newlines:
379 for line in newlines:
332 s = line.strip().split(' ', 1)
380 s = line.strip().split(' ', 1)
333 if len(s) != 2:
381 if len(s) != 2:
334 continue
382 continue
335 if s[1] not in oldtags:
383 if s[1] not in oldtags:
336 newtags.add(s[1].strip())
384 newtags.add(s[1].strip())
337
385
338 if not newtags:
386 if not newtags:
339 return None, None
387 return None, None
340
388
341 data = "".join(newlines)
389 data = "".join(newlines)
342 def getfilectx(repo, memctx, f):
390 def getfilectx(repo, memctx, f):
343 return context.memfilectx(repo, f, data, False, False, None)
391 return context.memfilectx(repo, f, data, False, False, None)
344
392
345 self.ui.status(_("updating tags\n"))
393 self.ui.status(_("updating tags\n"))
346 date = "%s 0" % int(time.mktime(time.gmtime()))
394 date = "%s 0" % int(time.mktime(time.gmtime()))
347 extra = {'branch': self.tagsbranch}
395 extra = {'branch': self.tagsbranch}
348 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
396 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
349 [".hgtags"], getfilectx, "convert-repo", date,
397 [".hgtags"], getfilectx, "convert-repo", date,
350 extra)
398 extra)
351 node = self.repo.commitctx(ctx)
399 node = self.repo.commitctx(ctx)
352 return hex(node), hex(tagparent)
400 return hex(node), hex(tagparent)
353
401
354 def setfilemapmode(self, active):
402 def setfilemapmode(self, active):
355 self.filemapmode = active
403 self.filemapmode = active
356
404
357 def putbookmarks(self, updatedbookmark):
405 def putbookmarks(self, updatedbookmark):
358 if not len(updatedbookmark):
406 if not len(updatedbookmark):
359 return
407 return
360
408
361 self.ui.status(_("updating bookmarks\n"))
409 self.ui.status(_("updating bookmarks\n"))
362 destmarks = self.repo._bookmarks
410 destmarks = self.repo._bookmarks
363 for bookmark in updatedbookmark:
411 for bookmark in updatedbookmark:
364 destmarks[bookmark] = bin(updatedbookmark[bookmark])
412 destmarks[bookmark] = bin(updatedbookmark[bookmark])
365 destmarks.write()
413 destmarks.write()
366
414
367 def hascommitfrommap(self, rev):
415 def hascommitfrommap(self, rev):
368 # the exact semantics of clonebranches is unclear so we can't say no
416 # the exact semantics of clonebranches is unclear so we can't say no
369 return rev in self.repo or self.clonebranches
417 return rev in self.repo or self.clonebranches
370
418
371 def hascommitforsplicemap(self, rev):
419 def hascommitforsplicemap(self, rev):
372 if rev not in self.repo and self.clonebranches:
420 if rev not in self.repo and self.clonebranches:
373 raise util.Abort(_('revision %s not found in destination '
421 raise util.Abort(_('revision %s not found in destination '
374 'repository (lookups with clonebranches=true '
422 'repository (lookups with clonebranches=true '
375 'are not implemented)') % rev)
423 'are not implemented)') % rev)
376 return rev in self.repo
424 return rev in self.repo
377
425
378 class mercurial_source(converter_source):
426 class mercurial_source(converter_source):
379 def __init__(self, ui, path, revs=None):
427 def __init__(self, ui, path, revs=None):
380 converter_source.__init__(self, ui, path, revs)
428 converter_source.__init__(self, ui, path, revs)
381 if revs and len(revs) > 1:
429 if revs and len(revs) > 1:
382 raise util.Abort(_("mercurial source does not support specifying "
430 raise util.Abort(_("mercurial source does not support specifying "
383 "multiple revisions"))
431 "multiple revisions"))
384 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
432 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
385 self.ignored = set()
433 self.ignored = set()
386 self.saverev = ui.configbool('convert', 'hg.saverev', False)
434 self.saverev = ui.configbool('convert', 'hg.saverev', False)
387 try:
435 try:
388 self.repo = hg.repository(self.ui, path)
436 self.repo = hg.repository(self.ui, path)
389 # try to provoke an exception if this isn't really a hg
437 # try to provoke an exception if this isn't really a hg
390 # repo, but some other bogus compatible-looking url
438 # repo, but some other bogus compatible-looking url
391 if not self.repo.local():
439 if not self.repo.local():
392 raise error.RepoError
440 raise error.RepoError
393 except error.RepoError:
441 except error.RepoError:
394 ui.traceback()
442 ui.traceback()
395 raise NoRepo(_("%s is not a local Mercurial repository") % path)
443 raise NoRepo(_("%s is not a local Mercurial repository") % path)
396 self.lastrev = None
444 self.lastrev = None
397 self.lastctx = None
445 self.lastctx = None
398 self._changescache = None, None
446 self._changescache = None, None
399 self.convertfp = None
447 self.convertfp = None
400 # Restrict converted revisions to startrev descendants
448 # Restrict converted revisions to startrev descendants
401 startnode = ui.config('convert', 'hg.startrev')
449 startnode = ui.config('convert', 'hg.startrev')
402 hgrevs = ui.config('convert', 'hg.revs')
450 hgrevs = ui.config('convert', 'hg.revs')
403 if hgrevs is None:
451 if hgrevs is None:
404 if startnode is not None:
452 if startnode is not None:
405 try:
453 try:
406 startnode = self.repo.lookup(startnode)
454 startnode = self.repo.lookup(startnode)
407 except error.RepoError:
455 except error.RepoError:
408 raise util.Abort(_('%s is not a valid start revision')
456 raise util.Abort(_('%s is not a valid start revision')
409 % startnode)
457 % startnode)
410 startrev = self.repo.changelog.rev(startnode)
458 startrev = self.repo.changelog.rev(startnode)
411 children = {startnode: 1}
459 children = {startnode: 1}
412 for r in self.repo.changelog.descendants([startrev]):
460 for r in self.repo.changelog.descendants([startrev]):
413 children[self.repo.changelog.node(r)] = 1
461 children[self.repo.changelog.node(r)] = 1
414 self.keep = children.__contains__
462 self.keep = children.__contains__
415 else:
463 else:
416 self.keep = util.always
464 self.keep = util.always
417 if revs:
465 if revs:
418 self._heads = [self.repo[revs[0]].node()]
466 self._heads = [self.repo[revs[0]].node()]
419 else:
467 else:
420 self._heads = self.repo.heads()
468 self._heads = self.repo.heads()
421 else:
469 else:
422 if revs or startnode is not None:
470 if revs or startnode is not None:
423 raise util.Abort(_('hg.revs cannot be combined with '
471 raise util.Abort(_('hg.revs cannot be combined with '
424 'hg.startrev or --rev'))
472 'hg.startrev or --rev'))
425 nodes = set()
473 nodes = set()
426 parents = set()
474 parents = set()
427 for r in scmutil.revrange(self.repo, [hgrevs]):
475 for r in scmutil.revrange(self.repo, [hgrevs]):
428 ctx = self.repo[r]
476 ctx = self.repo[r]
429 nodes.add(ctx.node())
477 nodes.add(ctx.node())
430 parents.update(p.node() for p in ctx.parents())
478 parents.update(p.node() for p in ctx.parents())
431 self.keep = nodes.__contains__
479 self.keep = nodes.__contains__
432 self._heads = nodes - parents
480 self._heads = nodes - parents
433
481
434 def changectx(self, rev):
482 def changectx(self, rev):
435 if self.lastrev != rev:
483 if self.lastrev != rev:
436 self.lastctx = self.repo[rev]
484 self.lastctx = self.repo[rev]
437 self.lastrev = rev
485 self.lastrev = rev
438 return self.lastctx
486 return self.lastctx
439
487
440 def parents(self, ctx):
488 def parents(self, ctx):
441 return [p for p in ctx.parents() if p and self.keep(p.node())]
489 return [p for p in ctx.parents() if p and self.keep(p.node())]
442
490
443 def getheads(self):
491 def getheads(self):
444 return [hex(h) for h in self._heads if self.keep(h)]
492 return [hex(h) for h in self._heads if self.keep(h)]
445
493
446 def getfile(self, name, rev):
494 def getfile(self, name, rev):
447 try:
495 try:
448 fctx = self.changectx(rev)[name]
496 fctx = self.changectx(rev)[name]
449 return fctx.data(), fctx.flags()
497 return fctx.data(), fctx.flags()
450 except error.LookupError:
498 except error.LookupError:
451 return None, None
499 return None, None
452
500
453 def getchanges(self, rev, full):
501 def getchanges(self, rev, full):
454 ctx = self.changectx(rev)
502 ctx = self.changectx(rev)
455 parents = self.parents(ctx)
503 parents = self.parents(ctx)
456 if full or not parents:
504 if full or not parents:
457 files = copyfiles = ctx.manifest()
505 files = copyfiles = ctx.manifest()
458 if parents:
506 if parents:
459 if self._changescache[0] == rev:
507 if self._changescache[0] == rev:
460 m, a, r = self._changescache[1]
508 m, a, r = self._changescache[1]
461 else:
509 else:
462 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
510 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
463 if not full:
511 if not full:
464 files = m + a + r
512 files = m + a + r
465 copyfiles = m + a
513 copyfiles = m + a
466 # getcopies() is also run for roots and before filtering so missing
514 # getcopies() is also run for roots and before filtering so missing
467 # revlogs are detected early
515 # revlogs are detected early
468 copies = self.getcopies(ctx, parents, copyfiles)
516 copies = self.getcopies(ctx, parents, copyfiles)
469 cleanp2 = set()
517 cleanp2 = set()
470 if len(parents) == 2:
518 if len(parents) == 2:
471 cleanp2.update(self.repo.status(parents[1].node(), ctx.node(),
519 cleanp2.update(self.repo.status(parents[1].node(), ctx.node(),
472 clean=True).clean)
520 clean=True).clean)
473 changes = [(f, rev) for f in files if f not in self.ignored]
521 changes = [(f, rev) for f in files if f not in self.ignored]
474 changes.sort()
522 changes.sort()
475 return changes, copies, cleanp2
523 return changes, copies, cleanp2
476
524
477 def getcopies(self, ctx, parents, files):
525 def getcopies(self, ctx, parents, files):
478 copies = {}
526 copies = {}
479 for name in files:
527 for name in files:
480 if name in self.ignored:
528 if name in self.ignored:
481 continue
529 continue
482 try:
530 try:
483 copysource, _copynode = ctx.filectx(name).renamed()
531 copysource, _copynode = ctx.filectx(name).renamed()
484 if copysource in self.ignored:
532 if copysource in self.ignored:
485 continue
533 continue
486 # Ignore copy sources not in parent revisions
534 # Ignore copy sources not in parent revisions
487 found = False
535 found = False
488 for p in parents:
536 for p in parents:
489 if copysource in p:
537 if copysource in p:
490 found = True
538 found = True
491 break
539 break
492 if not found:
540 if not found:
493 continue
541 continue
494 copies[name] = copysource
542 copies[name] = copysource
495 except TypeError:
543 except TypeError:
496 pass
544 pass
497 except error.LookupError as e:
545 except error.LookupError as e:
498 if not self.ignoreerrors:
546 if not self.ignoreerrors:
499 raise
547 raise
500 self.ignored.add(name)
548 self.ignored.add(name)
501 self.ui.warn(_('ignoring: %s\n') % e)
549 self.ui.warn(_('ignoring: %s\n') % e)
502 return copies
550 return copies
503
551
504 def getcommit(self, rev):
552 def getcommit(self, rev):
505 ctx = self.changectx(rev)
553 ctx = self.changectx(rev)
506 parents = [p.hex() for p in self.parents(ctx)]
554 parents = [p.hex() for p in self.parents(ctx)]
507 crev = rev
555 crev = rev
508
556
509 return commit(author=ctx.user(),
557 return commit(author=ctx.user(),
510 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
558 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
511 desc=ctx.description(), rev=crev, parents=parents,
559 desc=ctx.description(), rev=crev, parents=parents,
512 branch=ctx.branch(), extra=ctx.extra(),
560 branch=ctx.branch(), extra=ctx.extra(),
513 sortkey=ctx.rev(), saverev=self.saverev,
561 sortkey=ctx.rev(), saverev=self.saverev,
514 phase=ctx.phase())
562 phase=ctx.phase())
515
563
516 def gettags(self):
564 def gettags(self):
517 # This will get written to .hgtags, filter non global tags out.
565 # This will get written to .hgtags, filter non global tags out.
518 tags = [t for t in self.repo.tagslist()
566 tags = [t for t in self.repo.tagslist()
519 if self.repo.tagtype(t[0]) == 'global']
567 if self.repo.tagtype(t[0]) == 'global']
520 return dict([(name, hex(node)) for name, node in tags
568 return dict([(name, hex(node)) for name, node in tags
521 if self.keep(node)])
569 if self.keep(node)])
522
570
523 def getchangedfiles(self, rev, i):
571 def getchangedfiles(self, rev, i):
524 ctx = self.changectx(rev)
572 ctx = self.changectx(rev)
525 parents = self.parents(ctx)
573 parents = self.parents(ctx)
526 if not parents and i is None:
574 if not parents and i is None:
527 i = 0
575 i = 0
528 changes = [], ctx.manifest().keys(), []
576 changes = [], ctx.manifest().keys(), []
529 else:
577 else:
530 i = i or 0
578 i = i or 0
531 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
579 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
532 changes = [[f for f in l if f not in self.ignored] for l in changes]
580 changes = [[f for f in l if f not in self.ignored] for l in changes]
533
581
534 if i == 0:
582 if i == 0:
535 self._changescache = (rev, changes)
583 self._changescache = (rev, changes)
536
584
537 return changes[0] + changes[1] + changes[2]
585 return changes[0] + changes[1] + changes[2]
538
586
539 def converted(self, rev, destrev):
587 def converted(self, rev, destrev):
540 if self.convertfp is None:
588 if self.convertfp is None:
541 self.convertfp = open(self.repo.join('shamap'), 'a')
589 self.convertfp = open(self.repo.join('shamap'), 'a')
542 self.convertfp.write('%s %s\n' % (destrev, rev))
590 self.convertfp.write('%s %s\n' % (destrev, rev))
543 self.convertfp.flush()
591 self.convertfp.flush()
544
592
545 def before(self):
593 def before(self):
546 self.ui.debug('run hg source pre-conversion action\n')
594 self.ui.debug('run hg source pre-conversion action\n')
547
595
548 def after(self):
596 def after(self):
549 self.ui.debug('run hg source post-conversion action\n')
597 self.ui.debug('run hg source post-conversion action\n')
550
598
551 def hasnativeorder(self):
599 def hasnativeorder(self):
552 return True
600 return True
553
601
554 def hasnativeclose(self):
602 def hasnativeclose(self):
555 return True
603 return True
556
604
557 def lookuprev(self, rev):
605 def lookuprev(self, rev):
558 try:
606 try:
559 return hex(self.repo.lookup(rev))
607 return hex(self.repo.lookup(rev))
560 except (error.RepoError, error.LookupError):
608 except (error.RepoError, error.LookupError):
561 return None
609 return None
562
610
563 def getbookmarks(self):
611 def getbookmarks(self):
564 return bookmarks.listbookmarks(self.repo)
612 return bookmarks.listbookmarks(self.repo)
565
613
566 def checkrevformat(self, revstr, mapname='splicemap'):
614 def checkrevformat(self, revstr, mapname='splicemap'):
567 """ Mercurial, revision string is a 40 byte hex """
615 """ Mercurial, revision string is a 40 byte hex """
568 self.checkhexformat(revstr, mapname)
616 self.checkhexformat(revstr, mapname)
@@ -1,673 +1,731 b''
1
1
2 $ HGMERGE=true; export HGMERGE
2 $ HGMERGE=true; export HGMERGE
3 $ echo '[extensions]' >> $HGRCPATH
3 $ echo '[extensions]' >> $HGRCPATH
4 $ echo 'convert =' >> $HGRCPATH
4 $ echo 'convert =' >> $HGRCPATH
5 $ glog()
5 $ glog()
6 > {
6 > {
7 > hg log -G --template '{rev} "{desc}" files: {files}\n' "$@"
7 > hg log -G --template '{rev} "{desc}" files: {files}\n' "$@"
8 > }
8 > }
9 $ hg init source
9 $ hg init source
10 $ cd source
10 $ cd source
11 $ echo foo > foo
11 $ echo foo > foo
12 $ echo baz > baz
12 $ echo baz > baz
13 $ mkdir -p dir/subdir
13 $ mkdir -p dir/subdir
14 $ echo dir/file >> dir/file
14 $ echo dir/file >> dir/file
15 $ echo dir/file2 >> dir/file2
15 $ echo dir/file2 >> dir/file2
16 $ echo dir/file3 >> dir/file3 # to be corrupted in rev 0
16 $ echo dir/file3 >> dir/file3 # to be corrupted in rev 0
17 $ echo dir/subdir/file3 >> dir/subdir/file3
17 $ echo dir/subdir/file3 >> dir/subdir/file3
18 $ echo dir/subdir/file4 >> dir/subdir/file4
18 $ echo dir/subdir/file4 >> dir/subdir/file4
19 $ hg ci -d '0 0' -qAm '0: add foo baz dir/'
19 $ hg ci -d '0 0' -qAm '0: add foo baz dir/'
20 $ echo bar > bar
20 $ echo bar > bar
21 $ echo quux > quux
21 $ echo quux > quux
22 $ echo dir/file4 >> dir/file4 # to be corrupted in rev 1
22 $ echo dir/file4 >> dir/file4 # to be corrupted in rev 1
23 $ hg copy foo copied
23 $ hg copy foo copied
24 $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied'
24 $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied'
25 $ echo >> foo
25 $ echo >> foo
26 $ hg ci -d '2 0' -m '2: change foo'
26 $ hg ci -d '2 0' -m '2: change foo'
27 $ hg up -qC 1
27 $ hg up -qC 1
28 $ echo >> bar
28 $ echo >> bar
29 $ echo >> quux
29 $ echo >> quux
30 $ hg ci -d '3 0' -m '3: change bar quux'
30 $ hg ci -d '3 0' -m '3: change bar quux'
31 created new head
31 created new head
32 $ hg up -qC 2
32 $ hg up -qC 2
33 $ hg merge -qr 3
33 $ hg merge -qr 3
34 $ echo >> bar
34 $ echo >> bar
35 $ echo >> baz
35 $ echo >> baz
36 $ hg ci -d '4 0' -m '4: first merge; change bar baz'
36 $ hg ci -d '4 0' -m '4: first merge; change bar baz'
37 $ echo >> bar
37 $ echo >> bar
38 $ echo 1 >> baz
38 $ echo 1 >> baz
39 $ echo >> quux
39 $ echo >> quux
40 $ hg ci -d '5 0' -m '5: change bar baz quux'
40 $ hg ci -d '5 0' -m '5: change bar baz quux'
41 $ hg up -qC 4
41 $ hg up -qC 4
42 $ echo >> foo
42 $ echo >> foo
43 $ echo 2 >> baz
43 $ echo 2 >> baz
44 $ hg ci -d '6 0' -m '6: change foo baz'
44 $ hg ci -d '6 0' -m '6: change foo baz'
45 created new head
45 created new head
46 $ hg up -qC 5
46 $ hg up -qC 5
47 $ hg merge -qr 6
47 $ hg merge -qr 6
48 $ echo >> bar
48 $ echo >> bar
49 $ hg ci -d '7 0' -m '7: second merge; change bar'
49 $ hg ci -d '7 0' -m '7: second merge; change bar'
50 $ echo >> foo
50 $ echo >> foo
51 $ hg ci -m '8: change foo'
51 $ hg ci -m '8: change foo'
52 $ glog
52 $ glog
53 @ 8 "8: change foo" files: foo
53 @ 8 "8: change foo" files: foo
54 |
54 |
55 o 7 "7: second merge; change bar" files: bar baz
55 o 7 "7: second merge; change bar" files: bar baz
56 |\
56 |\
57 | o 6 "6: change foo baz" files: baz foo
57 | o 6 "6: change foo baz" files: baz foo
58 | |
58 | |
59 o | 5 "5: change bar baz quux" files: bar baz quux
59 o | 5 "5: change bar baz quux" files: bar baz quux
60 |/
60 |/
61 o 4 "4: first merge; change bar baz" files: bar baz
61 o 4 "4: first merge; change bar baz" files: bar baz
62 |\
62 |\
63 | o 3 "3: change bar quux" files: bar quux
63 | o 3 "3: change bar quux" files: bar quux
64 | |
64 | |
65 o | 2 "2: change foo" files: foo
65 o | 2 "2: change foo" files: foo
66 |/
66 |/
67 o 1 "1: add bar quux; copy foo to copied" files: bar copied dir/file4 quux
67 o 1 "1: add bar quux; copy foo to copied" files: bar copied dir/file4 quux
68 |
68 |
69 o 0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/file3 dir/subdir/file3 dir/subdir/file4 foo
69 o 0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/file3 dir/subdir/file3 dir/subdir/file4 foo
70
70
71
71
72 final file versions in this repo:
72 final file versions in this repo:
73
73
74 $ hg manifest --debug
74 $ hg manifest --debug
75 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
75 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
76 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
76 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
77 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
77 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
78 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir/file
78 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir/file
79 75e6d3f8328f5f6ace6bf10b98df793416a09dca 644 dir/file2
79 75e6d3f8328f5f6ace6bf10b98df793416a09dca 644 dir/file2
80 e96dce0bc6a217656a3a410e5e6bec2c4f42bf7c 644 dir/file3
80 e96dce0bc6a217656a3a410e5e6bec2c4f42bf7c 644 dir/file3
81 6edd55f559cdce67132b12ca09e09cee08b60442 644 dir/file4
81 6edd55f559cdce67132b12ca09e09cee08b60442 644 dir/file4
82 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir/subdir/file3
82 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir/subdir/file3
83 57a1c1511590f3de52874adfa04effe8a77d64af 644 dir/subdir/file4
83 57a1c1511590f3de52874adfa04effe8a77d64af 644 dir/subdir/file4
84 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
84 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
85 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
85 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
86 $ hg debugrename copied
86 $ hg debugrename copied
87 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
87 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
88
88
89 $ cd ..
89 $ cd ..
90
90
91
91
92 Test interaction with startrev and verify that changing it is handled properly:
92 Test interaction with startrev and verify that changing it is handled properly:
93
93
94 $ > empty
94 $ > empty
95 $ hg convert --filemap empty source movingstart --config convert.hg.startrev=3 -r4
95 $ hg convert --filemap empty source movingstart --config convert.hg.startrev=3 -r4
96 initializing destination movingstart repository
96 initializing destination movingstart repository
97 scanning source...
97 scanning source...
98 sorting...
98 sorting...
99 converting...
99 converting...
100 1 3: change bar quux
100 1 3: change bar quux
101 0 4: first merge; change bar baz
101 0 4: first merge; change bar baz
102 $ hg convert --filemap empty source movingstart
102 $ hg convert --filemap empty source movingstart
103 scanning source...
103 scanning source...
104 sorting...
104 sorting...
105 converting...
105 converting...
106 3 5: change bar baz quux
106 3 5: change bar baz quux
107 2 6: change foo baz
107 2 6: change foo baz
108 1 7: second merge; change bar
108 1 7: second merge; change bar
109 warning: af455ce4166b3c9c88e6309c2b9332171dcea595 parent 61e22ca76c3b3e93df20338c4e02ce286898e825 is missing
109 warning: af455ce4166b3c9c88e6309c2b9332171dcea595 parent 61e22ca76c3b3e93df20338c4e02ce286898e825 is missing
110 warning: cf908b3eeedc301c9272ebae931da966d5b326c7 parent 59e1ab45c888289513b7354484dac8a88217beab is missing
110 warning: cf908b3eeedc301c9272ebae931da966d5b326c7 parent 59e1ab45c888289513b7354484dac8a88217beab is missing
111 0 8: change foo
111 0 8: change foo
112
112
113
113
114 splitrepo tests
114 splitrepo tests
115
115
116 $ splitrepo()
116 $ splitrepo()
117 > {
117 > {
118 > msg="$1"
118 > msg="$1"
119 > files="$2"
119 > files="$2"
120 > opts=$3
120 > opts=$3
121 > echo "% $files: $msg"
121 > echo "% $files: $msg"
122 > prefix=`echo "$files" | sed -e 's/ /-/g'`
122 > prefix=`echo "$files" | sed -e 's/ /-/g'`
123 > fmap="$prefix.fmap"
123 > fmap="$prefix.fmap"
124 > repo="$prefix.repo"
124 > repo="$prefix.repo"
125 > for i in $files; do
125 > for i in $files; do
126 > echo "include $i" >> "$fmap"
126 > echo "include $i" >> "$fmap"
127 > done
127 > done
128 > hg -q convert $opts --filemap "$fmap" --datesort source "$repo"
128 > hg -q convert $opts --filemap "$fmap" --datesort source "$repo"
129 > hg up -q -R "$repo"
129 > hg up -q -R "$repo"
130 > glog -R "$repo"
130 > glog -R "$repo"
131 > hg -R "$repo" manifest --debug
131 > hg -R "$repo" manifest --debug
132 > }
132 > }
133 $ splitrepo 'skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd' foo
133 $ splitrepo 'skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd' foo
134 % foo: skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd
134 % foo: skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd
135 @ 3 "8: change foo" files: foo
135 @ 3 "8: change foo" files: foo
136 |
136 |
137 o 2 "6: change foo baz" files: foo
137 o 2 "6: change foo baz" files: foo
138 |
138 |
139 o 1 "2: change foo" files: foo
139 o 1 "2: change foo" files: foo
140 |
140 |
141 o 0 "0: add foo baz dir/" files: foo
141 o 0 "0: add foo baz dir/" files: foo
142
142
143 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
143 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
144 $ splitrepo 'merges are not merges anymore' bar
144 $ splitrepo 'merges are not merges anymore' bar
145 % bar: merges are not merges anymore
145 % bar: merges are not merges anymore
146 @ 4 "7: second merge; change bar" files: bar
146 @ 4 "7: second merge; change bar" files: bar
147 |
147 |
148 o 3 "5: change bar baz quux" files: bar
148 o 3 "5: change bar baz quux" files: bar
149 |
149 |
150 o 2 "4: first merge; change bar baz" files: bar
150 o 2 "4: first merge; change bar baz" files: bar
151 |
151 |
152 o 1 "3: change bar quux" files: bar
152 o 1 "3: change bar quux" files: bar
153 |
153 |
154 o 0 "1: add bar quux; copy foo to copied" files: bar
154 o 0 "1: add bar quux; copy foo to copied" files: bar
155
155
156 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
156 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
157 $ splitrepo '1st merge is not a merge anymore; 2nd still is' baz
157 $ splitrepo '1st merge is not a merge anymore; 2nd still is' baz
158 % baz: 1st merge is not a merge anymore; 2nd still is
158 % baz: 1st merge is not a merge anymore; 2nd still is
159 @ 4 "7: second merge; change bar" files: baz
159 @ 4 "7: second merge; change bar" files: baz
160 |\
160 |\
161 | o 3 "6: change foo baz" files: baz
161 | o 3 "6: change foo baz" files: baz
162 | |
162 | |
163 o | 2 "5: change bar baz quux" files: baz
163 o | 2 "5: change bar baz quux" files: baz
164 |/
164 |/
165 o 1 "4: first merge; change bar baz" files: baz
165 o 1 "4: first merge; change bar baz" files: baz
166 |
166 |
167 o 0 "0: add foo baz dir/" files: baz
167 o 0 "0: add foo baz dir/" files: baz
168
168
169 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
169 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
170 $ splitrepo 'we add additional merges when they are interesting' 'foo quux'
170 $ splitrepo 'we add additional merges when they are interesting' 'foo quux'
171 % foo quux: we add additional merges when they are interesting
171 % foo quux: we add additional merges when they are interesting
172 @ 8 "8: change foo" files: foo
172 @ 8 "8: change foo" files: foo
173 |
173 |
174 o 7 "7: second merge; change bar" files:
174 o 7 "7: second merge; change bar" files:
175 |\
175 |\
176 | o 6 "6: change foo baz" files: foo
176 | o 6 "6: change foo baz" files: foo
177 | |
177 | |
178 o | 5 "5: change bar baz quux" files: quux
178 o | 5 "5: change bar baz quux" files: quux
179 |/
179 |/
180 o 4 "4: first merge; change bar baz" files:
180 o 4 "4: first merge; change bar baz" files:
181 |\
181 |\
182 | o 3 "3: change bar quux" files: quux
182 | o 3 "3: change bar quux" files: quux
183 | |
183 | |
184 o | 2 "2: change foo" files: foo
184 o | 2 "2: change foo" files: foo
185 |/
185 |/
186 o 1 "1: add bar quux; copy foo to copied" files: quux
186 o 1 "1: add bar quux; copy foo to copied" files: quux
187 |
187 |
188 o 0 "0: add foo baz dir/" files: foo
188 o 0 "0: add foo baz dir/" files: foo
189
189
190 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
190 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
191 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
191 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
192 $ splitrepo 'partial conversion' 'bar quux' '-r 3'
192 $ splitrepo 'partial conversion' 'bar quux' '-r 3'
193 % bar quux: partial conversion
193 % bar quux: partial conversion
194 @ 1 "3: change bar quux" files: bar quux
194 @ 1 "3: change bar quux" files: bar quux
195 |
195 |
196 o 0 "1: add bar quux; copy foo to copied" files: bar quux
196 o 0 "1: add bar quux; copy foo to copied" files: bar quux
197
197
198 b79105bedc55102f394e90a789c9c380117c1b4a 644 bar
198 b79105bedc55102f394e90a789c9c380117c1b4a 644 bar
199 db0421cc6b685a458c8d86c7d5c004f94429ea23 644 quux
199 db0421cc6b685a458c8d86c7d5c004f94429ea23 644 quux
200 $ splitrepo 'complete the partial conversion' 'bar quux'
200 $ splitrepo 'complete the partial conversion' 'bar quux'
201 % bar quux: complete the partial conversion
201 % bar quux: complete the partial conversion
202 @ 4 "7: second merge; change bar" files: bar
202 @ 4 "7: second merge; change bar" files: bar
203 |
203 |
204 o 3 "5: change bar baz quux" files: bar quux
204 o 3 "5: change bar baz quux" files: bar quux
205 |
205 |
206 o 2 "4: first merge; change bar baz" files: bar
206 o 2 "4: first merge; change bar baz" files: bar
207 |
207 |
208 o 1 "3: change bar quux" files: bar quux
208 o 1 "3: change bar quux" files: bar quux
209 |
209 |
210 o 0 "1: add bar quux; copy foo to copied" files: bar quux
210 o 0 "1: add bar quux; copy foo to copied" files: bar quux
211
211
212 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
212 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
213 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
213 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
214 $ rm -r foo.repo
214 $ rm -r foo.repo
215 $ splitrepo 'partial conversion' 'foo' '-r 3'
215 $ splitrepo 'partial conversion' 'foo' '-r 3'
216 % foo: partial conversion
216 % foo: partial conversion
217 @ 0 "0: add foo baz dir/" files: foo
217 @ 0 "0: add foo baz dir/" files: foo
218
218
219 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
219 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
220 $ splitrepo 'complete the partial conversion' 'foo'
220 $ splitrepo 'complete the partial conversion' 'foo'
221 % foo: complete the partial conversion
221 % foo: complete the partial conversion
222 @ 3 "8: change foo" files: foo
222 @ 3 "8: change foo" files: foo
223 |
223 |
224 o 2 "6: change foo baz" files: foo
224 o 2 "6: change foo baz" files: foo
225 |
225 |
226 o 1 "2: change foo" files: foo
226 o 1 "2: change foo" files: foo
227 |
227 |
228 o 0 "0: add foo baz dir/" files: foo
228 o 0 "0: add foo baz dir/" files: foo
229
229
230 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
230 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
231 $ splitrepo 'copied file; source not included in new repo' copied
231 $ splitrepo 'copied file; source not included in new repo' copied
232 % copied: copied file; source not included in new repo
232 % copied: copied file; source not included in new repo
233 @ 0 "1: add bar quux; copy foo to copied" files: copied
233 @ 0 "1: add bar quux; copy foo to copied" files: copied
234
234
235 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 copied
235 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 copied
236 $ hg --cwd copied.repo debugrename copied
236 $ hg --cwd copied.repo debugrename copied
237 copied not renamed
237 copied not renamed
238 $ splitrepo 'copied file; source included in new repo' 'foo copied'
238 $ splitrepo 'copied file; source included in new repo' 'foo copied'
239 % foo copied: copied file; source included in new repo
239 % foo copied: copied file; source included in new repo
240 @ 4 "8: change foo" files: foo
240 @ 4 "8: change foo" files: foo
241 |
241 |
242 o 3 "6: change foo baz" files: foo
242 o 3 "6: change foo baz" files: foo
243 |
243 |
244 o 2 "2: change foo" files: foo
244 o 2 "2: change foo" files: foo
245 |
245 |
246 o 1 "1: add bar quux; copy foo to copied" files: copied
246 o 1 "1: add bar quux; copy foo to copied" files: copied
247 |
247 |
248 o 0 "0: add foo baz dir/" files: foo
248 o 0 "0: add foo baz dir/" files: foo
249
249
250 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
250 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
251 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
251 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
252 $ hg --cwd foo-copied.repo debugrename copied
252 $ hg --cwd foo-copied.repo debugrename copied
253 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
253 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
254
254
255 verify the top level 'include .' if there is no other includes:
255 verify the top level 'include .' if there is no other includes:
256
256
257 $ echo "exclude something" > default.fmap
257 $ echo "exclude something" > default.fmap
258 $ hg convert -q --filemap default.fmap -r1 source dummydest2
258 $ hg convert -q --filemap default.fmap -r1 source dummydest2
259 $ hg -R dummydest2 log --template '{rev} {node|short} {desc|firstline}\n'
259 $ hg -R dummydest2 log --template '{rev} {node|short} {desc|firstline}\n'
260 1 61e22ca76c3b 1: add bar quux; copy foo to copied
260 1 61e22ca76c3b 1: add bar quux; copy foo to copied
261 0 c085cf2ee7fe 0: add foo baz dir/
261 0 c085cf2ee7fe 0: add foo baz dir/
262
262
263 $ echo "include somethingelse" >> default.fmap
263 $ echo "include somethingelse" >> default.fmap
264 $ hg convert -q --filemap default.fmap -r1 source dummydest3
264 $ hg convert -q --filemap default.fmap -r1 source dummydest3
265 $ hg -R dummydest3 log --template '{rev} {node|short} {desc|firstline}\n'
265 $ hg -R dummydest3 log --template '{rev} {node|short} {desc|firstline}\n'
266
266
267 $ echo "include ." >> default.fmap
267 $ echo "include ." >> default.fmap
268 $ hg convert -q --filemap default.fmap -r1 source dummydest4
268 $ hg convert -q --filemap default.fmap -r1 source dummydest4
269 $ hg -R dummydest4 log --template '{rev} {node|short} {desc|firstline}\n'
269 $ hg -R dummydest4 log --template '{rev} {node|short} {desc|firstline}\n'
270 1 61e22ca76c3b 1: add bar quux; copy foo to copied
270 1 61e22ca76c3b 1: add bar quux; copy foo to copied
271 0 c085cf2ee7fe 0: add foo baz dir/
271 0 c085cf2ee7fe 0: add foo baz dir/
272
272
273 ensure that the filemap contains duplicated slashes (issue3612)
273 ensure that the filemap contains duplicated slashes (issue3612)
274
274
275 $ cat > renames.fmap <<EOF
275 $ cat > renames.fmap <<EOF
276 > include dir
276 > include dir
277 > exclude dir/file2
277 > exclude dir/file2
278 > rename dir dir2//dir3
278 > rename dir dir2//dir3
279 > include foo
279 > include foo
280 > include copied
280 > include copied
281 > rename foo foo2/
281 > rename foo foo2/
282 > rename copied ./copied2
282 > rename copied ./copied2
283 > exclude dir/subdir
283 > exclude dir/subdir
284 > include dir/subdir/file3
284 > include dir/subdir/file3
285 > EOF
285 > EOF
286 $ rm source/.hg/store/data/dir/file3.i
286 $ rm source/.hg/store/data/dir/file3.i
287 $ rm source/.hg/store/data/dir/file4.i
287 $ rm source/.hg/store/data/dir/file4.i
288 $ hg -q convert --filemap renames.fmap --datesort source dummydest
288 $ hg -q convert --filemap renames.fmap --datesort source dummydest
289 abort: data/dir/file3.i@e96dce0bc6a2: no match found!
289 abort: data/dir/file3.i@e96dce0bc6a2: no match found!
290 [255]
290 [255]
291 $ hg -q convert --filemap renames.fmap --datesort --config convert.hg.ignoreerrors=1 source renames.repo
291 $ hg -q convert --filemap renames.fmap --datesort --config convert.hg.ignoreerrors=1 source renames.repo
292 ignoring: data/dir/file3.i@e96dce0bc6a2: no match found
292 ignoring: data/dir/file3.i@e96dce0bc6a2: no match found
293 ignoring: data/dir/file4.i@6edd55f559cd: no match found
293 ignoring: data/dir/file4.i@6edd55f559cd: no match found
294 $ hg up -q -R renames.repo
294 $ hg up -q -R renames.repo
295 $ glog -R renames.repo
295 $ glog -R renames.repo
296 @ 4 "8: change foo" files: foo2
296 @ 4 "8: change foo" files: foo2
297 |
297 |
298 o 3 "6: change foo baz" files: foo2
298 o 3 "6: change foo baz" files: foo2
299 |
299 |
300 o 2 "2: change foo" files: foo2
300 o 2 "2: change foo" files: foo2
301 |
301 |
302 o 1 "1: add bar quux; copy foo to copied" files: copied2
302 o 1 "1: add bar quux; copy foo to copied" files: copied2
303 |
303 |
304 o 0 "0: add foo baz dir/" files: dir2/dir3/file dir2/dir3/subdir/file3 foo2
304 o 0 "0: add foo baz dir/" files: dir2/dir3/file dir2/dir3/subdir/file3 foo2
305
305
306 $ hg -R renames.repo verify
306 $ hg -R renames.repo verify
307 checking changesets
307 checking changesets
308 checking manifests
308 checking manifests
309 crosschecking files in changesets and manifests
309 crosschecking files in changesets and manifests
310 checking files
310 checking files
311 4 files, 5 changesets, 7 total revisions
311 4 files, 5 changesets, 7 total revisions
312
312
313 $ hg -R renames.repo manifest --debug
313 $ hg -R renames.repo manifest --debug
314 d43feacba7a4f1f2080dde4a4b985bd8a0236d46 644 copied2
314 d43feacba7a4f1f2080dde4a4b985bd8a0236d46 644 copied2
315 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir2/dir3/file
315 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir2/dir3/file
316 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir2/dir3/subdir/file3
316 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir2/dir3/subdir/file3
317 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo2
317 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo2
318 $ hg --cwd renames.repo debugrename copied2
318 $ hg --cwd renames.repo debugrename copied2
319 copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd
319 copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd
320
320
321 copied:
321 copied:
322
322
323 $ hg --cwd source cat copied
323 $ hg --cwd source cat copied
324 foo
324 foo
325
325
326 copied2:
326 copied2:
327
327
328 $ hg --cwd renames.repo cat copied2
328 $ hg --cwd renames.repo cat copied2
329 foo
329 foo
330
330
331 filemap errors
331 filemap errors
332
332
333 $ cat > errors.fmap <<EOF
333 $ cat > errors.fmap <<EOF
334 > include dir/ # beware that comments changes error line numbers!
334 > include dir/ # beware that comments changes error line numbers!
335 > exclude /dir
335 > exclude /dir
336 > rename dir//dir /dir//dir/ "out of sync"
336 > rename dir//dir /dir//dir/ "out of sync"
337 > include
337 > include
338 > EOF
338 > EOF
339 $ hg -q convert --filemap errors.fmap source errors.repo
339 $ hg -q convert --filemap errors.fmap source errors.repo
340 errors.fmap:3: superfluous / in include '/dir'
340 errors.fmap:3: superfluous / in include '/dir'
341 errors.fmap:3: superfluous / in rename '/dir'
341 errors.fmap:3: superfluous / in rename '/dir'
342 errors.fmap:4: unknown directive 'out of sync'
342 errors.fmap:4: unknown directive 'out of sync'
343 errors.fmap:5: path to exclude is missing
343 errors.fmap:5: path to exclude is missing
344 abort: errors in filemap
344 abort: errors in filemap
345 [255]
345 [255]
346
346
347 test branch closing revision pruning if branch is pruned
347 test branch closing revision pruning if branch is pruned
348
348
349 $ hg init branchpruning
349 $ hg init branchpruning
350 $ cd branchpruning
350 $ cd branchpruning
351 $ hg branch foo
351 $ hg branch foo
352 marked working directory as branch foo
352 marked working directory as branch foo
353 (branches are permanent and global, did you want a bookmark?)
353 (branches are permanent and global, did you want a bookmark?)
354 $ echo a > a
354 $ echo a > a
355 $ hg ci -Am adda
355 $ hg ci -Am adda
356 adding a
356 adding a
357 $ hg ci --close-branch -m closefoo
357 $ hg ci --close-branch -m closefoo
358 $ hg up 0
358 $ hg up 0
359 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
360 $ hg branch empty
360 $ hg branch empty
361 marked working directory as branch empty
361 marked working directory as branch empty
362 (branches are permanent and global, did you want a bookmark?)
362 (branches are permanent and global, did you want a bookmark?)
363 $ hg ci -m emptybranch
363 $ hg ci -m emptybranch
364 $ hg ci --close-branch -m closeempty
364 $ hg ci --close-branch -m closeempty
365 $ hg up 0
365 $ hg up 0
366 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 $ hg branch default
367 $ hg branch default
368 marked working directory as branch default
368 marked working directory as branch default
369 (branches are permanent and global, did you want a bookmark?)
369 (branches are permanent and global, did you want a bookmark?)
370 $ echo b > b
370 $ echo b > b
371 $ hg ci -Am addb
371 $ hg ci -Am addb
372 adding b
372 adding b
373 $ hg ci --close-branch -m closedefault
373 $ hg ci --close-branch -m closedefault
374 $ cat > filemap <<EOF
374 $ cat > filemap <<EOF
375 > include b
375 > include b
376 > EOF
376 > EOF
377 $ cd ..
377 $ cd ..
378 $ hg convert branchpruning branchpruning-hg1
378 $ hg convert branchpruning branchpruning-hg1
379 initializing destination branchpruning-hg1 repository
379 initializing destination branchpruning-hg1 repository
380 scanning source...
380 scanning source...
381 sorting...
381 sorting...
382 converting...
382 converting...
383 5 adda
383 5 adda
384 4 closefoo
384 4 closefoo
385 3 emptybranch
385 3 emptybranch
386 2 closeempty
386 2 closeempty
387 1 addb
387 1 addb
388 0 closedefault
388 0 closedefault
389 $ glog -R branchpruning-hg1
389 $ glog -R branchpruning-hg1
390 _ 5 "closedefault" files:
390 _ 5 "closedefault" files:
391 |
391 |
392 o 4 "addb" files: b
392 o 4 "addb" files: b
393 |
393 |
394 | _ 3 "closeempty" files:
394 | _ 3 "closeempty" files:
395 | |
395 | |
396 | o 2 "emptybranch" files:
396 | o 2 "emptybranch" files:
397 |/
397 |/
398 | _ 1 "closefoo" files:
398 | _ 1 "closefoo" files:
399 |/
399 |/
400 o 0 "adda" files: a
400 o 0 "adda" files: a
401
401
402
402
403 exercise incremental conversion at the same time
403 exercise incremental conversion at the same time
404
404
405 $ hg convert -r0 --filemap branchpruning/filemap branchpruning branchpruning-hg2
405 $ hg convert -r0 --filemap branchpruning/filemap branchpruning branchpruning-hg2
406 initializing destination branchpruning-hg2 repository
406 initializing destination branchpruning-hg2 repository
407 scanning source...
407 scanning source...
408 sorting...
408 sorting...
409 converting...
409 converting...
410 0 adda
410 0 adda
411 $ hg convert -r4 --filemap branchpruning/filemap branchpruning branchpruning-hg2
411 $ hg convert -r4 --filemap branchpruning/filemap branchpruning branchpruning-hg2
412 scanning source...
412 scanning source...
413 sorting...
413 sorting...
414 converting...
414 converting...
415 0 addb
415 0 addb
416 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2
416 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2
417 scanning source...
417 scanning source...
418 sorting...
418 sorting...
419 converting...
419 converting...
420 3 closefoo
420 3 closefoo
421 2 emptybranch
421 2 emptybranch
422 1 closeempty
422 1 closeempty
423 0 closedefault
423 0 closedefault
424 $ glog -R branchpruning-hg2
424 $ glog -R branchpruning-hg2
425 _ 1 "closedefault" files:
425 _ 1 "closedefault" files:
426 |
426 |
427 o 0 "addb" files: b
427 o 0 "addb" files: b
428
428
429
429
430 Test rebuilding of map with unknown revisions in shamap - it used to crash
430 Test rebuilding of map with unknown revisions in shamap - it used to crash
431
431
432 $ cd branchpruning
432 $ cd branchpruning
433 $ hg up -r 2
433 $ hg up -r 2
434 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
434 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
435 $ hg merge 4
435 $ hg merge 4
436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 (branch merge, don't forget to commit)
437 (branch merge, don't forget to commit)
438 $ hg ci -m 'merging something'
438 $ hg ci -m 'merging something'
439 $ cd ..
439 $ cd ..
440 $ echo "53792d18237d2b64971fa571936869156655338d 6d955580116e82c4b029bd30f321323bae71a7f0" >> branchpruning-hg2/.hg/shamap
440 $ echo "53792d18237d2b64971fa571936869156655338d 6d955580116e82c4b029bd30f321323bae71a7f0" >> branchpruning-hg2/.hg/shamap
441 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2 --debug --config progress.debug=true
441 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2 --debug --config progress.debug=true
442 run hg source pre-conversion action
442 run hg source pre-conversion action
443 run hg sink pre-conversion action
443 run hg sink pre-conversion action
444 scanning source...
444 scanning source...
445 scanning: 1 revisions
445 scanning: 1 revisions
446 sorting...
446 sorting...
447 converting...
447 converting...
448 0 merging something
448 0 merging something
449 source: 2503605b178fe50e8fbbb0e77b97939540aa8c87
449 source: 2503605b178fe50e8fbbb0e77b97939540aa8c87
450 converting: 0/1 revisions (0.00%)
450 converting: 0/1 revisions (0.00%)
451 unknown revmap source: 53792d18237d2b64971fa571936869156655338d
451 unknown revmap source: 53792d18237d2b64971fa571936869156655338d
452 run hg sink post-conversion action
452 run hg sink post-conversion action
453 run hg source post-conversion action
453 run hg source post-conversion action
454
454
455
455
456 filemap rename undoing revision rename
456 filemap rename undoing revision rename
457
457
458 $ hg init renameundo
458 $ hg init renameundo
459 $ cd renameundo
459 $ cd renameundo
460 $ echo 1 > a
460 $ echo 1 > a
461 $ echo 1 > c
461 $ echo 1 > c
462 $ hg ci -qAm add
462 $ hg ci -qAm add
463 $ hg mv -q a b/a
463 $ hg mv -q a b/a
464 $ hg mv -q c b/c
464 $ hg mv -q c b/c
465 $ hg ci -qm rename
465 $ hg ci -qm rename
466 $ echo 2 > b/a
466 $ echo 2 > b/a
467 $ echo 2 > b/c
467 $ echo 2 > b/c
468 $ hg ci -qm modify
468 $ hg ci -qm modify
469 $ cd ..
469 $ cd ..
470
470
471 $ echo "rename b ." > renameundo.fmap
471 $ echo "rename b ." > renameundo.fmap
472 $ hg convert --filemap renameundo.fmap renameundo renameundo2
472 $ hg convert --filemap renameundo.fmap renameundo renameundo2
473 initializing destination renameundo2 repository
473 initializing destination renameundo2 repository
474 scanning source...
474 scanning source...
475 sorting...
475 sorting...
476 converting...
476 converting...
477 2 add
477 2 add
478 1 rename
478 1 rename
479 filtering out empty revision
479 filtering out empty revision
480 repository tip rolled back to revision 0 (undo convert)
480 repository tip rolled back to revision 0 (undo convert)
481 0 modify
481 0 modify
482 $ glog -R renameundo2
482 $ glog -R renameundo2
483 o 1 "modify" files: a c
483 o 1 "modify" files: a c
484 |
484 |
485 o 0 "add" files: a c
485 o 0 "add" files: a c
486
486
487
487
488
488
489 test merge parents/empty merges pruning
489 test merge parents/empty merges pruning
490
490
491 $ glog()
491 $ glog()
492 > {
492 > {
493 > hg log -G --template '{rev}:{node|short}@{branch} "{desc}" files: {files}\n' "$@"
493 > hg log -G --template '{rev}:{node|short}@{branch} "{desc}" files: {files}\n' "$@"
494 > }
494 > }
495
495
496 test anonymous branch pruning
496 test anonymous branch pruning
497
497
498 $ hg init anonymousbranch
498 $ hg init anonymousbranch
499 $ cd anonymousbranch
499 $ cd anonymousbranch
500 $ echo a > a
500 $ echo a > a
501 $ echo b > b
501 $ echo b > b
502 $ hg ci -Am add
502 $ hg ci -Am add
503 adding a
503 adding a
504 adding b
504 adding b
505 $ echo a >> a
505 $ echo a >> a
506 $ hg ci -m changea
506 $ hg ci -m changea
507 $ hg up 0
507 $ hg up 0
508 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
508 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
509 $ echo b >> b
509 $ echo b >> b
510 $ hg ci -m changeb
510 $ hg ci -m changeb
511 created new head
511 created new head
512 $ hg up 1
512 $ hg up 1
513 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
513 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
514 $ hg merge
514 $ hg merge
515 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
515 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
516 (branch merge, don't forget to commit)
516 (branch merge, don't forget to commit)
517 $ hg ci -m merge
517 $ hg ci -m merge
518 $ cd ..
518 $ cd ..
519
519
520 $ cat > filemap <<EOF
520 $ cat > filemap <<EOF
521 > include a
521 > include a
522 > EOF
522 > EOF
523 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg
523 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg
524 initializing destination anonymousbranch-hg repository
524 initializing destination anonymousbranch-hg repository
525 scanning source...
525 scanning source...
526 sorting...
526 sorting...
527 converting...
527 converting...
528 3 add
528 3 add
529 2 changea
529 2 changea
530 1 changeb
530 1 changeb
531 0 merge
531 0 merge
532 $ glog -R anonymousbranch
532 $ glog -R anonymousbranch
533 @ 3:c71d5201a498@default "merge" files:
533 @ 3:c71d5201a498@default "merge" files:
534 |\
534 |\
535 | o 2:607eb44b17f9@default "changeb" files: b
535 | o 2:607eb44b17f9@default "changeb" files: b
536 | |
536 | |
537 o | 1:1f60ea617824@default "changea" files: a
537 o | 1:1f60ea617824@default "changea" files: a
538 |/
538 |/
539 o 0:0146e6129113@default "add" files: a b
539 o 0:0146e6129113@default "add" files: a b
540
540
541 $ glog -R anonymousbranch-hg
541 $ glog -R anonymousbranch-hg
542 o 1:cda818e7219b@default "changea" files: a
542 o 1:cda818e7219b@default "changea" files: a
543 |
543 |
544 o 0:c334dc3be0da@default "add" files: a
544 o 0:c334dc3be0da@default "add" files: a
545
545
546 $ cat anonymousbranch-hg/.hg/shamap
546 $ cat anonymousbranch-hg/.hg/shamap
547 0146e6129113dba9ac90207cfdf2d7ed35257ae5 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
547 0146e6129113dba9ac90207cfdf2d7ed35257ae5 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
548 1f60ea61782421edf8d051ff4fcb61b330f26a4a cda818e7219b5f7f3fb9f49780054ed6a1905ec3
548 1f60ea61782421edf8d051ff4fcb61b330f26a4a cda818e7219b5f7f3fb9f49780054ed6a1905ec3
549 607eb44b17f9348cd5cbd26e16af87ba77b0b037 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
549 607eb44b17f9348cd5cbd26e16af87ba77b0b037 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
550 c71d5201a498b2658d105a6bf69d7a0df2649aea cda818e7219b5f7f3fb9f49780054ed6a1905ec3
550 c71d5201a498b2658d105a6bf69d7a0df2649aea cda818e7219b5f7f3fb9f49780054ed6a1905ec3
551
551
552 $ cat > filemap <<EOF
552 $ cat > filemap <<EOF
553 > include b
553 > include b
554 > EOF
554 > EOF
555 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg2
555 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg2
556 initializing destination anonymousbranch-hg2 repository
556 initializing destination anonymousbranch-hg2 repository
557 scanning source...
557 scanning source...
558 sorting...
558 sorting...
559 converting...
559 converting...
560 3 add
560 3 add
561 2 changea
561 2 changea
562 1 changeb
562 1 changeb
563 0 merge
563 0 merge
564 $ glog -R anonymousbranch
564 $ glog -R anonymousbranch
565 @ 3:c71d5201a498@default "merge" files:
565 @ 3:c71d5201a498@default "merge" files:
566 |\
566 |\
567 | o 2:607eb44b17f9@default "changeb" files: b
567 | o 2:607eb44b17f9@default "changeb" files: b
568 | |
568 | |
569 o | 1:1f60ea617824@default "changea" files: a
569 o | 1:1f60ea617824@default "changea" files: a
570 |/
570 |/
571 o 0:0146e6129113@default "add" files: a b
571 o 0:0146e6129113@default "add" files: a b
572
572
573 $ glog -R anonymousbranch-hg2
573 $ glog -R anonymousbranch-hg2
574 o 1:62dd350b0df6@default "changeb" files: b
574 o 1:62dd350b0df6@default "changeb" files: b
575 |
575 |
576 o 0:4b9ced861657@default "add" files: b
576 o 0:4b9ced861657@default "add" files: b
577
577
578 $ cat anonymousbranch-hg2/.hg/shamap
578 $ cat anonymousbranch-hg2/.hg/shamap
579 0146e6129113dba9ac90207cfdf2d7ed35257ae5 4b9ced86165703791653059a1db6ed864630a523
579 0146e6129113dba9ac90207cfdf2d7ed35257ae5 4b9ced86165703791653059a1db6ed864630a523
580 1f60ea61782421edf8d051ff4fcb61b330f26a4a 4b9ced86165703791653059a1db6ed864630a523
580 1f60ea61782421edf8d051ff4fcb61b330f26a4a 4b9ced86165703791653059a1db6ed864630a523
581 607eb44b17f9348cd5cbd26e16af87ba77b0b037 62dd350b0df695f7d2c82a02e0499b16fd790f22
581 607eb44b17f9348cd5cbd26e16af87ba77b0b037 62dd350b0df695f7d2c82a02e0499b16fd790f22
582 c71d5201a498b2658d105a6bf69d7a0df2649aea 62dd350b0df695f7d2c82a02e0499b16fd790f22
582 c71d5201a498b2658d105a6bf69d7a0df2649aea 62dd350b0df695f7d2c82a02e0499b16fd790f22
583
583
584 test named branch pruning
584 test named branch pruning
585
585
586 $ hg init namedbranch
586 $ hg init namedbranch
587 $ cd namedbranch
587 $ cd namedbranch
588 $ echo a > a
588 $ echo a > a
589 $ echo b > b
589 $ echo b > b
590 $ hg ci -Am add
590 $ hg ci -Am add
591 adding a
591 adding a
592 adding b
592 adding b
593 $ echo a >> a
593 $ echo a >> a
594 $ hg ci -m changea
594 $ hg ci -m changea
595 $ hg up 0
595 $ hg up 0
596 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
596 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
597 $ hg branch foo
597 $ hg branch foo
598 marked working directory as branch foo
598 marked working directory as branch foo
599 (branches are permanent and global, did you want a bookmark?)
599 (branches are permanent and global, did you want a bookmark?)
600 $ echo b >> b
600 $ echo b >> b
601 $ hg ci -m changeb
601 $ hg ci -m changeb
602 $ hg up default
602 $ hg up default
603 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
603 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
604 $ hg merge foo
604 $ hg merge foo
605 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
605 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
606 (branch merge, don't forget to commit)
606 (branch merge, don't forget to commit)
607 $ hg ci -m merge
607 $ hg ci -m merge
608 $ cd ..
608 $ cd ..
609
609
610 $ cat > filemap <<EOF
610 $ cat > filemap <<EOF
611 > include a
611 > include a
612 > EOF
612 > EOF
613 $ hg convert --filemap filemap namedbranch namedbranch-hg
613 $ hg convert --filemap filemap namedbranch namedbranch-hg
614 initializing destination namedbranch-hg repository
614 initializing destination namedbranch-hg repository
615 scanning source...
615 scanning source...
616 sorting...
616 sorting...
617 converting...
617 converting...
618 3 add
618 3 add
619 2 changea
619 2 changea
620 1 changeb
620 1 changeb
621 0 merge
621 0 merge
622 $ glog -R namedbranch
622 $ glog -R namedbranch
623 @ 3:73899bcbe45c@default "merge" files:
623 @ 3:73899bcbe45c@default "merge" files:
624 |\
624 |\
625 | o 2:8097982d19fc@foo "changeb" files: b
625 | o 2:8097982d19fc@foo "changeb" files: b
626 | |
626 | |
627 o | 1:1f60ea617824@default "changea" files: a
627 o | 1:1f60ea617824@default "changea" files: a
628 |/
628 |/
629 o 0:0146e6129113@default "add" files: a b
629 o 0:0146e6129113@default "add" files: a b
630
630
631 $ glog -R namedbranch-hg
631 $ glog -R namedbranch-hg
632 o 1:cda818e7219b@default "changea" files: a
632 o 1:cda818e7219b@default "changea" files: a
633 |
633 |
634 o 0:c334dc3be0da@default "add" files: a
634 o 0:c334dc3be0da@default "add" files: a
635
635
636
636
637 $ cd namedbranch
637 $ cd namedbranch
638 $ hg --config extensions.mq= strip tip
638 $ hg --config extensions.mq= strip tip
639 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
639 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
640 saved backup bundle to $TESTTMP/namedbranch/.hg/strip-backup/73899bcbe45c-92adf160-backup.hg (glob)
640 saved backup bundle to $TESTTMP/namedbranch/.hg/strip-backup/73899bcbe45c-92adf160-backup.hg (glob)
641 $ hg up foo
641 $ hg up foo
642 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
642 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
643 $ hg merge default
643 $ hg merge default
644 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
644 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 (branch merge, don't forget to commit)
645 (branch merge, don't forget to commit)
646 $ hg ci -m merge
646 $ hg ci -m merge
647 $ cd ..
647 $ cd ..
648
648
649 $ hg convert --filemap filemap namedbranch namedbranch-hg2
649 $ hg convert --filemap filemap namedbranch namedbranch-hg2
650 initializing destination namedbranch-hg2 repository
650 initializing destination namedbranch-hg2 repository
651 scanning source...
651 scanning source...
652 sorting...
652 sorting...
653 converting...
653 converting...
654 3 add
654 3 add
655 2 changea
655 2 changea
656 1 changeb
656 1 changeb
657 0 merge
657 0 merge
658 $ glog -R namedbranch
658 $ glog -R namedbranch
659 @ 3:e1959de76e1b@foo "merge" files:
659 @ 3:e1959de76e1b@foo "merge" files:
660 |\
660 |\
661 | o 2:8097982d19fc@foo "changeb" files: b
661 | o 2:8097982d19fc@foo "changeb" files: b
662 | |
662 | |
663 o | 1:1f60ea617824@default "changea" files: a
663 o | 1:1f60ea617824@default "changea" files: a
664 |/
664 |/
665 o 0:0146e6129113@default "add" files: a b
665 o 0:0146e6129113@default "add" files: a b
666
666
667 $ glog -R namedbranch-hg2
667 $ glog -R namedbranch-hg2
668 o 2:dcf314454667@foo "merge" files:
668 o 2:dcf314454667@foo "merge" files:
669 |\
669 |\
670 | o 1:cda818e7219b@default "changea" files: a
670 | o 1:cda818e7219b@default "changea" files: a
671 |/
671 |/
672 o 0:c334dc3be0da@default "add" files: a
672 o 0:c334dc3be0da@default "add" files: a
673
673
674 $ cd ..
675
676 test converting merges into a repo that contains other files
677
678 $ hg init merge-test1
679 $ cd merge-test1
680 $ touch a && hg commit -Aqm a
681 $ hg up -q null
682 $ touch b && hg commit -Aqm b
683 $ hg merge -q 0 && hg commit -qm merge
684 $ cd ..
685 $ hg init merge-test2
686 $ cd merge-test2
687 $ mkdir converted
688 $ touch converted/a && hg commit -Aqm 'a'
689 $ touch x && hg commit -Aqm 'x'
690 $ cd ..
691 $ hg log -G -T '{node}' -R merge-test1
692 @ ea7c1a7ae9588677a715ce4f204cd89c28d5471f
693 |\
694 | o d7486e00c6f1b633dcadc0582f78006d805c7a0f
695 |
696 o 3903775176ed42b1458a6281db4a0ccf4d9f287a
697
698 $ hg log -G -T '{node}' -R merge-test2
699 @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
700 |
701 o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
702
703 - Build a shamap where the target converted/a is in on top of an unrelated
704 - change to 'x'. This simulates using convert to merge several repositories
705 - together.
706 $ cat >> merge-test2/.hg/shamap <<EOF
707 > 3903775176ed42b1458a6281db4a0ccf4d9f287a 34f1aa7da42559bae87920880b522d47b3ddbc0d
708 > EOF
709 $ cat >> merge-test-filemap <<EOF
710 > rename . converted/
711 > EOF
712 $ hg convert --filemap merge-test-filemap merge-test1 merge-test2 --traceback
713 scanning source...
714 sorting...
715 converting...
716 1 b
717 0 merge
718 $ hg -R merge-test2 manifest -r tip
719 converted/a
720 converted/b
721 x
722 $ hg -R merge-test2 log -G -T '{node}\n{files % "{file}\n"}'
723 o 4b5e2f0218d3442a0c14892b18685bf9c8059c4a
724 |\
725 | o 214325dd2e4cff981dcf00cb120cd39e1ea36dcc
726 | converted/b
727 @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
728 | x
729 o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
730 converted/a
731
General Comments 0
You need to be logged in to leave comments. Login now