##// END OF EJS Templates
convert: fix syncing deletes from p2 merge commit...
Durham Goode -
r26078:5ca58734 default
parent child Browse files
Show More
@@ -1,616 +1,621 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 from mercurial import merge as mergemod
27
27
28 from common import NoRepo, commit, converter_source, converter_sink, mapfile
28 from common import NoRepo, commit, converter_source, converter_sink, mapfile
29
29
30 import re
30 import re
31 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
31 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
32
32
33 class mercurial_sink(converter_sink):
33 class mercurial_sink(converter_sink):
34 def __init__(self, ui, path):
34 def __init__(self, ui, path):
35 converter_sink.__init__(self, ui, path)
35 converter_sink.__init__(self, ui, path)
36 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
36 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
37 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
37 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
38 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
38 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
39 self.lastbranch = None
39 self.lastbranch = None
40 if os.path.isdir(path) and len(os.listdir(path)) > 0:
40 if os.path.isdir(path) and len(os.listdir(path)) > 0:
41 try:
41 try:
42 self.repo = hg.repository(self.ui, path)
42 self.repo = hg.repository(self.ui, path)
43 if not self.repo.local():
43 if not self.repo.local():
44 raise NoRepo(_('%s is not a local Mercurial repository')
44 raise NoRepo(_('%s is not a local Mercurial repository')
45 % path)
45 % path)
46 except error.RepoError as err:
46 except error.RepoError as err:
47 ui.traceback()
47 ui.traceback()
48 raise NoRepo(err.args[0])
48 raise NoRepo(err.args[0])
49 else:
49 else:
50 try:
50 try:
51 ui.status(_('initializing destination %s repository\n') % path)
51 ui.status(_('initializing destination %s repository\n') % path)
52 self.repo = hg.repository(self.ui, path, create=True)
52 self.repo = hg.repository(self.ui, path, create=True)
53 if not self.repo.local():
53 if not self.repo.local():
54 raise NoRepo(_('%s is not a local Mercurial repository')
54 raise NoRepo(_('%s is not a local Mercurial repository')
55 % path)
55 % path)
56 self.created.append(path)
56 self.created.append(path)
57 except error.RepoError:
57 except error.RepoError:
58 ui.traceback()
58 ui.traceback()
59 raise NoRepo(_("could not create hg repository %s as sink")
59 raise NoRepo(_("could not create hg repository %s as sink")
60 % path)
60 % path)
61 self.lock = None
61 self.lock = None
62 self.wlock = None
62 self.wlock = None
63 self.filemapmode = False
63 self.filemapmode = False
64 self.subrevmaps = {}
64 self.subrevmaps = {}
65
65
66 def before(self):
66 def before(self):
67 self.ui.debug('run hg sink pre-conversion action\n')
67 self.ui.debug('run hg sink pre-conversion action\n')
68 self.wlock = self.repo.wlock()
68 self.wlock = self.repo.wlock()
69 self.lock = self.repo.lock()
69 self.lock = self.repo.lock()
70
70
71 def after(self):
71 def after(self):
72 self.ui.debug('run hg sink post-conversion action\n')
72 self.ui.debug('run hg sink post-conversion action\n')
73 if self.lock:
73 if self.lock:
74 self.lock.release()
74 self.lock.release()
75 if self.wlock:
75 if self.wlock:
76 self.wlock.release()
76 self.wlock.release()
77
77
78 def revmapfile(self):
78 def revmapfile(self):
79 return self.repo.join("shamap")
79 return self.repo.join("shamap")
80
80
81 def authorfile(self):
81 def authorfile(self):
82 return self.repo.join("authormap")
82 return self.repo.join("authormap")
83
83
84 def setbranch(self, branch, pbranches):
84 def setbranch(self, branch, pbranches):
85 if not self.clonebranches:
85 if not self.clonebranches:
86 return
86 return
87
87
88 setbranch = (branch != self.lastbranch)
88 setbranch = (branch != self.lastbranch)
89 self.lastbranch = branch
89 self.lastbranch = branch
90 if not branch:
90 if not branch:
91 branch = 'default'
91 branch = 'default'
92 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]
93 if pbranches:
93 if pbranches:
94 pbranch = pbranches[0][1]
94 pbranch = pbranches[0][1]
95 else:
95 else:
96 pbranch = 'default'
96 pbranch = 'default'
97
97
98 branchpath = os.path.join(self.path, branch)
98 branchpath = os.path.join(self.path, branch)
99 if setbranch:
99 if setbranch:
100 self.after()
100 self.after()
101 try:
101 try:
102 self.repo = hg.repository(self.ui, branchpath)
102 self.repo = hg.repository(self.ui, branchpath)
103 except Exception:
103 except Exception:
104 self.repo = hg.repository(self.ui, branchpath, create=True)
104 self.repo = hg.repository(self.ui, branchpath, create=True)
105 self.before()
105 self.before()
106
106
107 # pbranches may bring revisions from other branches (merge parents)
107 # pbranches may bring revisions from other branches (merge parents)
108 # Make sure we have them, or pull them.
108 # Make sure we have them, or pull them.
109 missings = {}
109 missings = {}
110 for b in pbranches:
110 for b in pbranches:
111 try:
111 try:
112 self.repo.lookup(b[0])
112 self.repo.lookup(b[0])
113 except Exception:
113 except Exception:
114 missings.setdefault(b[1], []).append(b[0])
114 missings.setdefault(b[1], []).append(b[0])
115
115
116 if missings:
116 if missings:
117 self.after()
117 self.after()
118 for pbranch, heads in sorted(missings.iteritems()):
118 for pbranch, heads in sorted(missings.iteritems()):
119 pbranchpath = os.path.join(self.path, pbranch)
119 pbranchpath = os.path.join(self.path, pbranch)
120 prepo = hg.peer(self.ui, {}, pbranchpath)
120 prepo = hg.peer(self.ui, {}, pbranchpath)
121 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
121 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
122 exchange.pull(self.repo, prepo,
122 exchange.pull(self.repo, prepo,
123 [prepo.lookup(h) for h in heads])
123 [prepo.lookup(h) for h in heads])
124 self.before()
124 self.before()
125
125
126 def _rewritetags(self, source, revmap, data):
126 def _rewritetags(self, source, revmap, data):
127 fp = cStringIO.StringIO()
127 fp = cStringIO.StringIO()
128 for line in data.splitlines():
128 for line in data.splitlines():
129 s = line.split(' ', 1)
129 s = line.split(' ', 1)
130 if len(s) != 2:
130 if len(s) != 2:
131 continue
131 continue
132 revid = revmap.get(source.lookuprev(s[0]))
132 revid = revmap.get(source.lookuprev(s[0]))
133 if not revid:
133 if not revid:
134 if s[0] == hex(nullid):
134 if s[0] == hex(nullid):
135 revid = s[0]
135 revid = s[0]
136 else:
136 else:
137 continue
137 continue
138 fp.write('%s %s\n' % (revid, s[1]))
138 fp.write('%s %s\n' % (revid, s[1]))
139 return fp.getvalue()
139 return fp.getvalue()
140
140
141 def _rewritesubstate(self, source, data):
141 def _rewritesubstate(self, source, data):
142 fp = cStringIO.StringIO()
142 fp = cStringIO.StringIO()
143 for line in data.splitlines():
143 for line in data.splitlines():
144 s = line.split(' ', 1)
144 s = line.split(' ', 1)
145 if len(s) != 2:
145 if len(s) != 2:
146 continue
146 continue
147
147
148 revid = s[0]
148 revid = s[0]
149 subpath = s[1]
149 subpath = s[1]
150 if revid != hex(nullid):
150 if revid != hex(nullid):
151 revmap = self.subrevmaps.get(subpath)
151 revmap = self.subrevmaps.get(subpath)
152 if revmap is None:
152 if revmap is None:
153 revmap = mapfile(self.ui,
153 revmap = mapfile(self.ui,
154 self.repo.wjoin(subpath, '.hg/shamap'))
154 self.repo.wjoin(subpath, '.hg/shamap'))
155 self.subrevmaps[subpath] = revmap
155 self.subrevmaps[subpath] = revmap
156
156
157 # 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
158 # need to be converted, in which case they can be cloned
158 # need to be converted, in which case they can be cloned
159 # into place instead of converted. Therefore, only warn
159 # into place instead of converted. Therefore, only warn
160 # once.
160 # once.
161 msg = _('no ".hgsubstate" updates will be made for "%s"\n')
161 msg = _('no ".hgsubstate" updates will be made for "%s"\n')
162 if len(revmap) == 0:
162 if len(revmap) == 0:
163 sub = self.repo.wvfs.reljoin(subpath, '.hg')
163 sub = self.repo.wvfs.reljoin(subpath, '.hg')
164
164
165 if self.repo.wvfs.exists(sub):
165 if self.repo.wvfs.exists(sub):
166 self.ui.warn(msg % subpath)
166 self.ui.warn(msg % subpath)
167
167
168 newid = revmap.get(revid)
168 newid = revmap.get(revid)
169 if not newid:
169 if not newid:
170 if len(revmap) > 0:
170 if len(revmap) > 0:
171 self.ui.warn(_("%s is missing from %s/.hg/shamap\n") %
171 self.ui.warn(_("%s is missing from %s/.hg/shamap\n") %
172 (revid, subpath))
172 (revid, subpath))
173 else:
173 else:
174 revid = newid
174 revid = newid
175
175
176 fp.write('%s %s\n' % (revid, subpath))
176 fp.write('%s %s\n' % (revid, subpath))
177
177
178 return fp.getvalue()
178 return fp.getvalue()
179
179
180 def _calculatemergedfiles(self, source, p1ctx, p2ctx):
180 def _calculatemergedfiles(self, source, p1ctx, p2ctx):
181 """Calculates the files from p2 that we need to pull in when merging p1
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.
182 and p2, given that the merge is coming from the given source.
183
183
184 This prevents us from losing files that only exist in the target p2 and
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
185 that don't come from the source repo (like if you're merging multiple
186 repositories together).
186 repositories together).
187 """
187 """
188 anc = [p1ctx.ancestor(p2ctx)]
188 anc = [p1ctx.ancestor(p2ctx)]
189 # Calculate what files are coming from p2
189 # Calculate what files are coming from p2
190 actions, diverge, rename = mergemod.calculateupdates(
190 actions, diverge, rename = mergemod.calculateupdates(
191 self.repo, p1ctx, p2ctx, anc,
191 self.repo, p1ctx, p2ctx, anc,
192 True, # branchmerge
192 True, # branchmerge
193 True, # force
193 True, # force
194 False, # partial
194 False, # partial
195 False, # acceptremote
195 False, # acceptremote
196 False, # followcopies
196 False, # followcopies
197 )
197 )
198
198
199 for file, (action, info, msg) in actions.iteritems():
199 for file, (action, info, msg) in actions.iteritems():
200 if source.targetfilebelongstosource(file):
200 if source.targetfilebelongstosource(file):
201 # If the file belongs to the source repo, ignore the p2
201 # If the file belongs to the source repo, ignore the p2
202 # since it will be covered by the existing fileset.
202 # since it will be covered by the existing fileset.
203 continue
203 continue
204
204
205 # If the file requires actual merging, abort. We don't have enough
205 # If the file requires actual merging, abort. We don't have enough
206 # context to resolve merges correctly.
206 # context to resolve merges correctly.
207 if action in ['m', 'dm', 'cd', 'dc']:
207 if action in ['m', 'dm', 'cd', 'dc']:
208 raise util.Abort(_("unable to convert merge commit "
208 raise util.Abort(_("unable to convert merge commit "
209 "since target parents do not merge cleanly (file "
209 "since target parents do not merge cleanly (file "
210 "%s, parents %s and %s)") % (file, p1ctx,
210 "%s, parents %s and %s)") % (file, p1ctx,
211 p2ctx))
211 p2ctx))
212 elif action == 'k':
212 elif action == 'k':
213 # 'keep' means nothing changed from p1
213 # 'keep' means nothing changed from p1
214 continue
214 continue
215 else:
215 else:
216 # Any other change means we want to take the p2 version
216 # Any other change means we want to take the p2 version
217 yield file
217 yield file
218
218
219 def putcommit(self, files, copies, parents, commit, source, revmap, full,
219 def putcommit(self, files, copies, parents, commit, source, revmap, full,
220 cleanp2):
220 cleanp2):
221 files = dict(files)
221 files = dict(files)
222
222
223 def getfilectx(repo, memctx, f):
223 def getfilectx(repo, memctx, f):
224 if p2ctx and f in p2files and f not in copies:
224 if p2ctx and f in p2files and f not in copies:
225 self.ui.debug('reusing %s from p2\n' % f)
225 self.ui.debug('reusing %s from p2\n' % f)
226 return p2ctx[f]
226 try:
227 return p2ctx[f]
228 except error.ManifestLookupError:
229 # If the file doesn't exist in p2, then we're syncing a
230 # delete, so just return None.
231 return None
227 try:
232 try:
228 v = files[f]
233 v = files[f]
229 except KeyError:
234 except KeyError:
230 return None
235 return None
231 data, mode = source.getfile(f, v)
236 data, mode = source.getfile(f, v)
232 if data is None:
237 if data is None:
233 return None
238 return None
234 if f == '.hgtags':
239 if f == '.hgtags':
235 data = self._rewritetags(source, revmap, data)
240 data = self._rewritetags(source, revmap, data)
236 if f == '.hgsubstate':
241 if f == '.hgsubstate':
237 data = self._rewritesubstate(source, data)
242 data = self._rewritesubstate(source, data)
238 return context.memfilectx(self.repo, f, data, 'l' in mode,
243 return context.memfilectx(self.repo, f, data, 'l' in mode,
239 'x' in mode, copies.get(f))
244 'x' in mode, copies.get(f))
240
245
241 pl = []
246 pl = []
242 for p in parents:
247 for p in parents:
243 if p not in pl:
248 if p not in pl:
244 pl.append(p)
249 pl.append(p)
245 parents = pl
250 parents = pl
246 nparents = len(parents)
251 nparents = len(parents)
247 if self.filemapmode and nparents == 1:
252 if self.filemapmode and nparents == 1:
248 m1node = self.repo.changelog.read(bin(parents[0]))[0]
253 m1node = self.repo.changelog.read(bin(parents[0]))[0]
249 parent = parents[0]
254 parent = parents[0]
250
255
251 if len(parents) < 2:
256 if len(parents) < 2:
252 parents.append(nullid)
257 parents.append(nullid)
253 if len(parents) < 2:
258 if len(parents) < 2:
254 parents.append(nullid)
259 parents.append(nullid)
255 p2 = parents.pop(0)
260 p2 = parents.pop(0)
256
261
257 text = commit.desc
262 text = commit.desc
258
263
259 sha1s = re.findall(sha1re, text)
264 sha1s = re.findall(sha1re, text)
260 for sha1 in sha1s:
265 for sha1 in sha1s:
261 oldrev = source.lookuprev(sha1)
266 oldrev = source.lookuprev(sha1)
262 newrev = revmap.get(oldrev)
267 newrev = revmap.get(oldrev)
263 if newrev is not None:
268 if newrev is not None:
264 text = text.replace(sha1, newrev[:len(sha1)])
269 text = text.replace(sha1, newrev[:len(sha1)])
265
270
266 extra = commit.extra.copy()
271 extra = commit.extra.copy()
267
272
268 sourcename = self.repo.ui.config('convert', 'hg.sourcename')
273 sourcename = self.repo.ui.config('convert', 'hg.sourcename')
269 if sourcename:
274 if sourcename:
270 extra['convert_source'] = sourcename
275 extra['convert_source'] = sourcename
271
276
272 for label in ('source', 'transplant_source', 'rebase_source',
277 for label in ('source', 'transplant_source', 'rebase_source',
273 'intermediate-source'):
278 'intermediate-source'):
274 node = extra.get(label)
279 node = extra.get(label)
275
280
276 if node is None:
281 if node is None:
277 continue
282 continue
278
283
279 # Only transplant stores its reference in binary
284 # Only transplant stores its reference in binary
280 if label == 'transplant_source':
285 if label == 'transplant_source':
281 node = hex(node)
286 node = hex(node)
282
287
283 newrev = revmap.get(node)
288 newrev = revmap.get(node)
284 if newrev is not None:
289 if newrev is not None:
285 if label == 'transplant_source':
290 if label == 'transplant_source':
286 newrev = bin(newrev)
291 newrev = bin(newrev)
287
292
288 extra[label] = newrev
293 extra[label] = newrev
289
294
290 if self.branchnames and commit.branch:
295 if self.branchnames and commit.branch:
291 extra['branch'] = commit.branch
296 extra['branch'] = commit.branch
292 if commit.rev and commit.saverev:
297 if commit.rev and commit.saverev:
293 extra['convert_revision'] = commit.rev
298 extra['convert_revision'] = commit.rev
294
299
295 while parents:
300 while parents:
296 p1 = p2
301 p1 = p2
297 p2 = parents.pop(0)
302 p2 = parents.pop(0)
298 p1ctx = self.repo[p1]
303 p1ctx = self.repo[p1]
299 p2ctx = None
304 p2ctx = None
300 if p2 != nullid:
305 if p2 != nullid:
301 p2ctx = self.repo[p2]
306 p2ctx = self.repo[p2]
302 fileset = set(files)
307 fileset = set(files)
303 if full:
308 if full:
304 fileset.update(self.repo[p1])
309 fileset.update(self.repo[p1])
305 fileset.update(self.repo[p2])
310 fileset.update(self.repo[p2])
306
311
307 if p2ctx:
312 if p2ctx:
308 p2files = set(cleanp2)
313 p2files = set(cleanp2)
309 for file in self._calculatemergedfiles(source, p1ctx, p2ctx):
314 for file in self._calculatemergedfiles(source, p1ctx, p2ctx):
310 p2files.add(file)
315 p2files.add(file)
311 fileset.add(file)
316 fileset.add(file)
312
317
313 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
318 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
314 getfilectx, commit.author, commit.date, extra)
319 getfilectx, commit.author, commit.date, extra)
315
320
316 # We won't know if the conversion changes the node until after the
321 # We won't know if the conversion changes the node until after the
317 # commit, so copy the source's phase for now.
322 # commit, so copy the source's phase for now.
318 self.repo.ui.setconfig('phases', 'new-commit',
323 self.repo.ui.setconfig('phases', 'new-commit',
319 phases.phasenames[commit.phase], 'convert')
324 phases.phasenames[commit.phase], 'convert')
320
325
321 tr = self.repo.transaction("convert")
326 tr = self.repo.transaction("convert")
322
327
323 try:
328 try:
324 node = hex(self.repo.commitctx(ctx))
329 node = hex(self.repo.commitctx(ctx))
325
330
326 # If the node value has changed, but the phase is lower than
331 # If the node value has changed, but the phase is lower than
327 # draft, set it back to draft since it hasn't been exposed
332 # draft, set it back to draft since it hasn't been exposed
328 # anywhere.
333 # anywhere.
329 if commit.rev != node:
334 if commit.rev != node:
330 ctx = self.repo[node]
335 ctx = self.repo[node]
331 if ctx.phase() < phases.draft:
336 if ctx.phase() < phases.draft:
332 phases.retractboundary(self.repo, tr, phases.draft,
337 phases.retractboundary(self.repo, tr, phases.draft,
333 [ctx.node()])
338 [ctx.node()])
334 tr.close()
339 tr.close()
335 finally:
340 finally:
336 tr.release()
341 tr.release()
337
342
338 text = "(octopus merge fixup)\n"
343 text = "(octopus merge fixup)\n"
339 p2 = node
344 p2 = node
340
345
341 if self.filemapmode and nparents == 1:
346 if self.filemapmode and nparents == 1:
342 man = self.repo.manifest
347 man = self.repo.manifest
343 mnode = self.repo.changelog.read(bin(p2))[0]
348 mnode = self.repo.changelog.read(bin(p2))[0]
344 closed = 'close' in commit.extra
349 closed = 'close' in commit.extra
345 if not closed and not man.cmp(m1node, man.revision(mnode)):
350 if not closed and not man.cmp(m1node, man.revision(mnode)):
346 self.ui.status(_("filtering out empty revision\n"))
351 self.ui.status(_("filtering out empty revision\n"))
347 self.repo.rollback(force=True)
352 self.repo.rollback(force=True)
348 return parent
353 return parent
349 return p2
354 return p2
350
355
351 def puttags(self, tags):
356 def puttags(self, tags):
352 try:
357 try:
353 parentctx = self.repo[self.tagsbranch]
358 parentctx = self.repo[self.tagsbranch]
354 tagparent = parentctx.node()
359 tagparent = parentctx.node()
355 except error.RepoError:
360 except error.RepoError:
356 parentctx = None
361 parentctx = None
357 tagparent = nullid
362 tagparent = nullid
358
363
359 oldlines = set()
364 oldlines = set()
360 for branch, heads in self.repo.branchmap().iteritems():
365 for branch, heads in self.repo.branchmap().iteritems():
361 for h in heads:
366 for h in heads:
362 if '.hgtags' in self.repo[h]:
367 if '.hgtags' in self.repo[h]:
363 oldlines.update(
368 oldlines.update(
364 set(self.repo[h]['.hgtags'].data().splitlines(True)))
369 set(self.repo[h]['.hgtags'].data().splitlines(True)))
365 oldlines = sorted(list(oldlines))
370 oldlines = sorted(list(oldlines))
366
371
367 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
372 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
368 if newlines == oldlines:
373 if newlines == oldlines:
369 return None, None
374 return None, None
370
375
371 # if the old and new tags match, then there is nothing to update
376 # if the old and new tags match, then there is nothing to update
372 oldtags = set()
377 oldtags = set()
373 newtags = set()
378 newtags = set()
374 for line in oldlines:
379 for line in oldlines:
375 s = line.strip().split(' ', 1)
380 s = line.strip().split(' ', 1)
376 if len(s) != 2:
381 if len(s) != 2:
377 continue
382 continue
378 oldtags.add(s[1])
383 oldtags.add(s[1])
379 for line in newlines:
384 for line in newlines:
380 s = line.strip().split(' ', 1)
385 s = line.strip().split(' ', 1)
381 if len(s) != 2:
386 if len(s) != 2:
382 continue
387 continue
383 if s[1] not in oldtags:
388 if s[1] not in oldtags:
384 newtags.add(s[1].strip())
389 newtags.add(s[1].strip())
385
390
386 if not newtags:
391 if not newtags:
387 return None, None
392 return None, None
388
393
389 data = "".join(newlines)
394 data = "".join(newlines)
390 def getfilectx(repo, memctx, f):
395 def getfilectx(repo, memctx, f):
391 return context.memfilectx(repo, f, data, False, False, None)
396 return context.memfilectx(repo, f, data, False, False, None)
392
397
393 self.ui.status(_("updating tags\n"))
398 self.ui.status(_("updating tags\n"))
394 date = "%s 0" % int(time.mktime(time.gmtime()))
399 date = "%s 0" % int(time.mktime(time.gmtime()))
395 extra = {'branch': self.tagsbranch}
400 extra = {'branch': self.tagsbranch}
396 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
401 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
397 [".hgtags"], getfilectx, "convert-repo", date,
402 [".hgtags"], getfilectx, "convert-repo", date,
398 extra)
403 extra)
399 node = self.repo.commitctx(ctx)
404 node = self.repo.commitctx(ctx)
400 return hex(node), hex(tagparent)
405 return hex(node), hex(tagparent)
401
406
402 def setfilemapmode(self, active):
407 def setfilemapmode(self, active):
403 self.filemapmode = active
408 self.filemapmode = active
404
409
405 def putbookmarks(self, updatedbookmark):
410 def putbookmarks(self, updatedbookmark):
406 if not len(updatedbookmark):
411 if not len(updatedbookmark):
407 return
412 return
408
413
409 self.ui.status(_("updating bookmarks\n"))
414 self.ui.status(_("updating bookmarks\n"))
410 destmarks = self.repo._bookmarks
415 destmarks = self.repo._bookmarks
411 for bookmark in updatedbookmark:
416 for bookmark in updatedbookmark:
412 destmarks[bookmark] = bin(updatedbookmark[bookmark])
417 destmarks[bookmark] = bin(updatedbookmark[bookmark])
413 destmarks.write()
418 destmarks.write()
414
419
415 def hascommitfrommap(self, rev):
420 def hascommitfrommap(self, rev):
416 # the exact semantics of clonebranches is unclear so we can't say no
421 # the exact semantics of clonebranches is unclear so we can't say no
417 return rev in self.repo or self.clonebranches
422 return rev in self.repo or self.clonebranches
418
423
419 def hascommitforsplicemap(self, rev):
424 def hascommitforsplicemap(self, rev):
420 if rev not in self.repo and self.clonebranches:
425 if rev not in self.repo and self.clonebranches:
421 raise util.Abort(_('revision %s not found in destination '
426 raise util.Abort(_('revision %s not found in destination '
422 'repository (lookups with clonebranches=true '
427 'repository (lookups with clonebranches=true '
423 'are not implemented)') % rev)
428 'are not implemented)') % rev)
424 return rev in self.repo
429 return rev in self.repo
425
430
426 class mercurial_source(converter_source):
431 class mercurial_source(converter_source):
427 def __init__(self, ui, path, revs=None):
432 def __init__(self, ui, path, revs=None):
428 converter_source.__init__(self, ui, path, revs)
433 converter_source.__init__(self, ui, path, revs)
429 if revs and len(revs) > 1:
434 if revs and len(revs) > 1:
430 raise util.Abort(_("mercurial source does not support specifying "
435 raise util.Abort(_("mercurial source does not support specifying "
431 "multiple revisions"))
436 "multiple revisions"))
432 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
437 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
433 self.ignored = set()
438 self.ignored = set()
434 self.saverev = ui.configbool('convert', 'hg.saverev', False)
439 self.saverev = ui.configbool('convert', 'hg.saverev', False)
435 try:
440 try:
436 self.repo = hg.repository(self.ui, path)
441 self.repo = hg.repository(self.ui, path)
437 # try to provoke an exception if this isn't really a hg
442 # try to provoke an exception if this isn't really a hg
438 # repo, but some other bogus compatible-looking url
443 # repo, but some other bogus compatible-looking url
439 if not self.repo.local():
444 if not self.repo.local():
440 raise error.RepoError
445 raise error.RepoError
441 except error.RepoError:
446 except error.RepoError:
442 ui.traceback()
447 ui.traceback()
443 raise NoRepo(_("%s is not a local Mercurial repository") % path)
448 raise NoRepo(_("%s is not a local Mercurial repository") % path)
444 self.lastrev = None
449 self.lastrev = None
445 self.lastctx = None
450 self.lastctx = None
446 self._changescache = None, None
451 self._changescache = None, None
447 self.convertfp = None
452 self.convertfp = None
448 # Restrict converted revisions to startrev descendants
453 # Restrict converted revisions to startrev descendants
449 startnode = ui.config('convert', 'hg.startrev')
454 startnode = ui.config('convert', 'hg.startrev')
450 hgrevs = ui.config('convert', 'hg.revs')
455 hgrevs = ui.config('convert', 'hg.revs')
451 if hgrevs is None:
456 if hgrevs is None:
452 if startnode is not None:
457 if startnode is not None:
453 try:
458 try:
454 startnode = self.repo.lookup(startnode)
459 startnode = self.repo.lookup(startnode)
455 except error.RepoError:
460 except error.RepoError:
456 raise util.Abort(_('%s is not a valid start revision')
461 raise util.Abort(_('%s is not a valid start revision')
457 % startnode)
462 % startnode)
458 startrev = self.repo.changelog.rev(startnode)
463 startrev = self.repo.changelog.rev(startnode)
459 children = {startnode: 1}
464 children = {startnode: 1}
460 for r in self.repo.changelog.descendants([startrev]):
465 for r in self.repo.changelog.descendants([startrev]):
461 children[self.repo.changelog.node(r)] = 1
466 children[self.repo.changelog.node(r)] = 1
462 self.keep = children.__contains__
467 self.keep = children.__contains__
463 else:
468 else:
464 self.keep = util.always
469 self.keep = util.always
465 if revs:
470 if revs:
466 self._heads = [self.repo[revs[0]].node()]
471 self._heads = [self.repo[revs[0]].node()]
467 else:
472 else:
468 self._heads = self.repo.heads()
473 self._heads = self.repo.heads()
469 else:
474 else:
470 if revs or startnode is not None:
475 if revs or startnode is not None:
471 raise util.Abort(_('hg.revs cannot be combined with '
476 raise util.Abort(_('hg.revs cannot be combined with '
472 'hg.startrev or --rev'))
477 'hg.startrev or --rev'))
473 nodes = set()
478 nodes = set()
474 parents = set()
479 parents = set()
475 for r in scmutil.revrange(self.repo, [hgrevs]):
480 for r in scmutil.revrange(self.repo, [hgrevs]):
476 ctx = self.repo[r]
481 ctx = self.repo[r]
477 nodes.add(ctx.node())
482 nodes.add(ctx.node())
478 parents.update(p.node() for p in ctx.parents())
483 parents.update(p.node() for p in ctx.parents())
479 self.keep = nodes.__contains__
484 self.keep = nodes.__contains__
480 self._heads = nodes - parents
485 self._heads = nodes - parents
481
486
482 def changectx(self, rev):
487 def changectx(self, rev):
483 if self.lastrev != rev:
488 if self.lastrev != rev:
484 self.lastctx = self.repo[rev]
489 self.lastctx = self.repo[rev]
485 self.lastrev = rev
490 self.lastrev = rev
486 return self.lastctx
491 return self.lastctx
487
492
488 def parents(self, ctx):
493 def parents(self, ctx):
489 return [p for p in ctx.parents() if p and self.keep(p.node())]
494 return [p for p in ctx.parents() if p and self.keep(p.node())]
490
495
491 def getheads(self):
496 def getheads(self):
492 return [hex(h) for h in self._heads if self.keep(h)]
497 return [hex(h) for h in self._heads if self.keep(h)]
493
498
494 def getfile(self, name, rev):
499 def getfile(self, name, rev):
495 try:
500 try:
496 fctx = self.changectx(rev)[name]
501 fctx = self.changectx(rev)[name]
497 return fctx.data(), fctx.flags()
502 return fctx.data(), fctx.flags()
498 except error.LookupError:
503 except error.LookupError:
499 return None, None
504 return None, None
500
505
501 def getchanges(self, rev, full):
506 def getchanges(self, rev, full):
502 ctx = self.changectx(rev)
507 ctx = self.changectx(rev)
503 parents = self.parents(ctx)
508 parents = self.parents(ctx)
504 if full or not parents:
509 if full or not parents:
505 files = copyfiles = ctx.manifest()
510 files = copyfiles = ctx.manifest()
506 if parents:
511 if parents:
507 if self._changescache[0] == rev:
512 if self._changescache[0] == rev:
508 m, a, r = self._changescache[1]
513 m, a, r = self._changescache[1]
509 else:
514 else:
510 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
515 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
511 if not full:
516 if not full:
512 files = m + a + r
517 files = m + a + r
513 copyfiles = m + a
518 copyfiles = m + a
514 # getcopies() is also run for roots and before filtering so missing
519 # getcopies() is also run for roots and before filtering so missing
515 # revlogs are detected early
520 # revlogs are detected early
516 copies = self.getcopies(ctx, parents, copyfiles)
521 copies = self.getcopies(ctx, parents, copyfiles)
517 cleanp2 = set()
522 cleanp2 = set()
518 if len(parents) == 2:
523 if len(parents) == 2:
519 cleanp2.update(self.repo.status(parents[1].node(), ctx.node(),
524 cleanp2.update(self.repo.status(parents[1].node(), ctx.node(),
520 clean=True).clean)
525 clean=True).clean)
521 changes = [(f, rev) for f in files if f not in self.ignored]
526 changes = [(f, rev) for f in files if f not in self.ignored]
522 changes.sort()
527 changes.sort()
523 return changes, copies, cleanp2
528 return changes, copies, cleanp2
524
529
525 def getcopies(self, ctx, parents, files):
530 def getcopies(self, ctx, parents, files):
526 copies = {}
531 copies = {}
527 for name in files:
532 for name in files:
528 if name in self.ignored:
533 if name in self.ignored:
529 continue
534 continue
530 try:
535 try:
531 copysource, _copynode = ctx.filectx(name).renamed()
536 copysource, _copynode = ctx.filectx(name).renamed()
532 if copysource in self.ignored:
537 if copysource in self.ignored:
533 continue
538 continue
534 # Ignore copy sources not in parent revisions
539 # Ignore copy sources not in parent revisions
535 found = False
540 found = False
536 for p in parents:
541 for p in parents:
537 if copysource in p:
542 if copysource in p:
538 found = True
543 found = True
539 break
544 break
540 if not found:
545 if not found:
541 continue
546 continue
542 copies[name] = copysource
547 copies[name] = copysource
543 except TypeError:
548 except TypeError:
544 pass
549 pass
545 except error.LookupError as e:
550 except error.LookupError as e:
546 if not self.ignoreerrors:
551 if not self.ignoreerrors:
547 raise
552 raise
548 self.ignored.add(name)
553 self.ignored.add(name)
549 self.ui.warn(_('ignoring: %s\n') % e)
554 self.ui.warn(_('ignoring: %s\n') % e)
550 return copies
555 return copies
551
556
552 def getcommit(self, rev):
557 def getcommit(self, rev):
553 ctx = self.changectx(rev)
558 ctx = self.changectx(rev)
554 parents = [p.hex() for p in self.parents(ctx)]
559 parents = [p.hex() for p in self.parents(ctx)]
555 crev = rev
560 crev = rev
556
561
557 return commit(author=ctx.user(),
562 return commit(author=ctx.user(),
558 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
563 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
559 desc=ctx.description(), rev=crev, parents=parents,
564 desc=ctx.description(), rev=crev, parents=parents,
560 branch=ctx.branch(), extra=ctx.extra(),
565 branch=ctx.branch(), extra=ctx.extra(),
561 sortkey=ctx.rev(), saverev=self.saverev,
566 sortkey=ctx.rev(), saverev=self.saverev,
562 phase=ctx.phase())
567 phase=ctx.phase())
563
568
564 def gettags(self):
569 def gettags(self):
565 # This will get written to .hgtags, filter non global tags out.
570 # This will get written to .hgtags, filter non global tags out.
566 tags = [t for t in self.repo.tagslist()
571 tags = [t for t in self.repo.tagslist()
567 if self.repo.tagtype(t[0]) == 'global']
572 if self.repo.tagtype(t[0]) == 'global']
568 return dict([(name, hex(node)) for name, node in tags
573 return dict([(name, hex(node)) for name, node in tags
569 if self.keep(node)])
574 if self.keep(node)])
570
575
571 def getchangedfiles(self, rev, i):
576 def getchangedfiles(self, rev, i):
572 ctx = self.changectx(rev)
577 ctx = self.changectx(rev)
573 parents = self.parents(ctx)
578 parents = self.parents(ctx)
574 if not parents and i is None:
579 if not parents and i is None:
575 i = 0
580 i = 0
576 changes = [], ctx.manifest().keys(), []
581 changes = [], ctx.manifest().keys(), []
577 else:
582 else:
578 i = i or 0
583 i = i or 0
579 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
584 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
580 changes = [[f for f in l if f not in self.ignored] for l in changes]
585 changes = [[f for f in l if f not in self.ignored] for l in changes]
581
586
582 if i == 0:
587 if i == 0:
583 self._changescache = (rev, changes)
588 self._changescache = (rev, changes)
584
589
585 return changes[0] + changes[1] + changes[2]
590 return changes[0] + changes[1] + changes[2]
586
591
587 def converted(self, rev, destrev):
592 def converted(self, rev, destrev):
588 if self.convertfp is None:
593 if self.convertfp is None:
589 self.convertfp = open(self.repo.join('shamap'), 'a')
594 self.convertfp = open(self.repo.join('shamap'), 'a')
590 self.convertfp.write('%s %s\n' % (destrev, rev))
595 self.convertfp.write('%s %s\n' % (destrev, rev))
591 self.convertfp.flush()
596 self.convertfp.flush()
592
597
593 def before(self):
598 def before(self):
594 self.ui.debug('run hg source pre-conversion action\n')
599 self.ui.debug('run hg source pre-conversion action\n')
595
600
596 def after(self):
601 def after(self):
597 self.ui.debug('run hg source post-conversion action\n')
602 self.ui.debug('run hg source post-conversion action\n')
598
603
599 def hasnativeorder(self):
604 def hasnativeorder(self):
600 return True
605 return True
601
606
602 def hasnativeclose(self):
607 def hasnativeclose(self):
603 return True
608 return True
604
609
605 def lookuprev(self, rev):
610 def lookuprev(self, rev):
606 try:
611 try:
607 return hex(self.repo.lookup(rev))
612 return hex(self.repo.lookup(rev))
608 except (error.RepoError, error.LookupError):
613 except (error.RepoError, error.LookupError):
609 return None
614 return None
610
615
611 def getbookmarks(self):
616 def getbookmarks(self):
612 return bookmarks.listbookmarks(self.repo)
617 return bookmarks.listbookmarks(self.repo)
613
618
614 def checkrevformat(self, revstr, mapname='splicemap'):
619 def checkrevformat(self, revstr, mapname='splicemap'):
615 """ Mercurial, revision string is a 40 byte hex """
620 """ Mercurial, revision string is a 40 byte hex """
616 self.checkhexformat(revstr, mapname)
621 self.checkhexformat(revstr, mapname)
@@ -1,731 +1,743 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 ..
674 $ cd ..
675
675
676 test converting merges into a repo that contains other files
676 test converting merges into a repo that contains other files
677
677
678 $ hg init merge-test1
678 $ hg init merge-test1
679 $ cd merge-test1
679 $ cd merge-test1
680 $ touch a && hg commit -Aqm a
680 $ touch a && hg commit -Aqm 'add a'
681 $ hg up -q null
681 $ echo a > a && hg commit -Aqm 'edit a'
682 $ touch b && hg commit -Aqm b
682 $ hg up -q 0
683 $ hg merge -q 0 && hg commit -qm merge
683 $ touch b && hg commit -Aqm 'add b'
684 $ hg merge -q 1 && hg commit -qm 'merge a & b'
685
684 $ cd ..
686 $ cd ..
685 $ hg init merge-test2
687 $ hg init merge-test2
686 $ cd merge-test2
688 $ cd merge-test2
687 $ mkdir converted
689 $ mkdir converted
688 $ touch converted/a && hg commit -Aqm 'a'
690 $ touch converted/a toberemoved && hg commit -Aqm 'add converted/a & toberemoved'
689 $ touch x && hg commit -Aqm 'x'
691 $ touch x && rm toberemoved && hg commit -Aqm 'add x & remove tobremoved'
690 $ cd ..
692 $ cd ..
691 $ hg log -G -T '{node}' -R merge-test1
693 $ hg log -G -T '{shortest(node)} {desc}' -R merge-test1
692 @ ea7c1a7ae9588677a715ce4f204cd89c28d5471f
694 @ 1191 merge a & b
693 |\
695 |\
694 | o d7486e00c6f1b633dcadc0582f78006d805c7a0f
696 | o 9077 add b
695 |
697 | |
696 o 3903775176ed42b1458a6281db4a0ccf4d9f287a
698 o | d19f edit a
699 |/
700 o ac82 add a
697
701
698 $ hg log -G -T '{node}' -R merge-test2
702 $ hg log -G -T '{shortest(node)} {desc}' -R merge-test2
699 @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
703 @ 150e add x & remove tobremoved
700 |
704 |
701 o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
705 o bbac add converted/a & toberemoved
702
706
703 - Build a shamap where the target converted/a is in on top of an unrelated
707 - 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
708 - change to 'x'. This simulates using convert to merge several repositories
705 - together.
709 - together.
706 $ cat >> merge-test2/.hg/shamap <<EOF
710 $ cat >> merge-test2/.hg/shamap <<EOF
707 > 3903775176ed42b1458a6281db4a0ccf4d9f287a 34f1aa7da42559bae87920880b522d47b3ddbc0d
711 > $(hg -R merge-test1 log -r 0 -T '{node}') $(hg -R merge-test2 log -r 0 -T '{node}')
712 > $(hg -R merge-test1 log -r 1 -T '{node}') $(hg -R merge-test2 log -r 1 -T '{node}')
708 > EOF
713 > EOF
709 $ cat >> merge-test-filemap <<EOF
714 $ cat >> merge-test-filemap <<EOF
710 > rename . converted/
715 > rename . converted/
711 > EOF
716 > EOF
712 $ hg convert --filemap merge-test-filemap merge-test1 merge-test2 --traceback
717 $ hg convert --filemap merge-test-filemap merge-test1 merge-test2 --traceback
713 scanning source...
718 scanning source...
714 sorting...
719 sorting...
715 converting...
720 converting...
716 1 b
721 1 add b
717 0 merge
722 0 merge a & b
718 $ hg -R merge-test2 manifest -r tip
723 $ hg -R merge-test2 manifest -r tip
719 converted/a
724 converted/a
720 converted/b
725 converted/b
721 x
726 x
722 $ hg -R merge-test2 log -G -T '{node}\n{files % "{file}\n"}'
727 $ hg -R merge-test2 log -G -T '{shortest(node)} {desc}\n{files % "- {file}\n"}\n'
723 o 4b5e2f0218d3442a0c14892b18685bf9c8059c4a
728 o 6eaa merge a & b
724 |\
729 |\ - converted/a
725 | o 214325dd2e4cff981dcf00cb120cd39e1ea36dcc
730 | | - toberemoved
726 | converted/b
731 | |
727 @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
732 | o 2995 add b
728 | x
733 | | - converted/b
729 o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
734 | |
730 converted/a
735 @ | 150e add x & remove tobremoved
736 |/ - toberemoved
737 | - x
738 |
739 o bbac add converted/a & toberemoved
740 - converted/a
741 - toberemoved
742
731
743
General Comments 0
You need to be logged in to leave comments. Login now