##// END OF EJS Templates
convert: mercurial source: convert global tags only - not local tags...
Mads Kiilerich -
r21498:6b8daeea default
parent child Browse files
Show More
@@ -1,446 +1,448
1 1 # hg.py - hg backend for convert extension
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 # Notes for hg->hg conversion:
9 9 #
10 10 # * Old versions of Mercurial didn't trim the whitespace from the ends
11 11 # of commit messages, but new versions do. Changesets created by
12 12 # those older versions, then converted, may thus have different
13 13 # hashes for changesets that are otherwise identical.
14 14 #
15 15 # * Using "--config convert.hg.saverev=true" will make the source
16 16 # identifier to be stored in the converted revision. This will cause
17 17 # the converted revision to have a different identity than the
18 18 # source.
19 19
20 20
21 21 import os, time, cStringIO
22 22 from mercurial.i18n import _
23 23 from mercurial.node import bin, hex, nullid
24 24 from mercurial import hg, util, context, bookmarks, error, scmutil
25 25
26 26 from common import NoRepo, commit, converter_source, converter_sink
27 27
28 28 import re
29 29 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
30 30
31 31 class mercurial_sink(converter_sink):
32 32 def __init__(self, ui, path):
33 33 converter_sink.__init__(self, ui, path)
34 34 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
35 35 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
36 36 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
37 37 self.lastbranch = None
38 38 if os.path.isdir(path) and len(os.listdir(path)) > 0:
39 39 try:
40 40 self.repo = hg.repository(self.ui, path)
41 41 if not self.repo.local():
42 42 raise NoRepo(_('%s is not a local Mercurial repository')
43 43 % path)
44 44 except error.RepoError, err:
45 45 ui.traceback()
46 46 raise NoRepo(err.args[0])
47 47 else:
48 48 try:
49 49 ui.status(_('initializing destination %s repository\n') % path)
50 50 self.repo = hg.repository(self.ui, path, create=True)
51 51 if not self.repo.local():
52 52 raise NoRepo(_('%s is not a local Mercurial repository')
53 53 % path)
54 54 self.created.append(path)
55 55 except error.RepoError:
56 56 ui.traceback()
57 57 raise NoRepo(_("could not create hg repository %s as sink")
58 58 % path)
59 59 self.lock = None
60 60 self.wlock = None
61 61 self.filemapmode = False
62 62
63 63 def before(self):
64 64 self.ui.debug('run hg sink pre-conversion action\n')
65 65 self.wlock = self.repo.wlock()
66 66 self.lock = self.repo.lock()
67 67
68 68 def after(self):
69 69 self.ui.debug('run hg sink post-conversion action\n')
70 70 if self.lock:
71 71 self.lock.release()
72 72 if self.wlock:
73 73 self.wlock.release()
74 74
75 75 def revmapfile(self):
76 76 return self.repo.join("shamap")
77 77
78 78 def authorfile(self):
79 79 return self.repo.join("authormap")
80 80
81 81 def setbranch(self, branch, pbranches):
82 82 if not self.clonebranches:
83 83 return
84 84
85 85 setbranch = (branch != self.lastbranch)
86 86 self.lastbranch = branch
87 87 if not branch:
88 88 branch = 'default'
89 89 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
90 90 pbranch = pbranches and pbranches[0][1] or 'default'
91 91
92 92 branchpath = os.path.join(self.path, branch)
93 93 if setbranch:
94 94 self.after()
95 95 try:
96 96 self.repo = hg.repository(self.ui, branchpath)
97 97 except Exception:
98 98 self.repo = hg.repository(self.ui, branchpath, create=True)
99 99 self.before()
100 100
101 101 # pbranches may bring revisions from other branches (merge parents)
102 102 # Make sure we have them, or pull them.
103 103 missings = {}
104 104 for b in pbranches:
105 105 try:
106 106 self.repo.lookup(b[0])
107 107 except Exception:
108 108 missings.setdefault(b[1], []).append(b[0])
109 109
110 110 if missings:
111 111 self.after()
112 112 for pbranch, heads in sorted(missings.iteritems()):
113 113 pbranchpath = os.path.join(self.path, pbranch)
114 114 prepo = hg.peer(self.ui, {}, pbranchpath)
115 115 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
116 116 self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
117 117 self.before()
118 118
119 119 def _rewritetags(self, source, revmap, data):
120 120 fp = cStringIO.StringIO()
121 121 for line in data.splitlines():
122 122 s = line.split(' ', 1)
123 123 if len(s) != 2:
124 124 continue
125 125 revid = revmap.get(source.lookuprev(s[0]))
126 126 if not revid:
127 127 continue
128 128 fp.write('%s %s\n' % (revid, s[1]))
129 129 return fp.getvalue()
130 130
131 131 def putcommit(self, files, copies, parents, commit, source, revmap):
132 132
133 133 files = dict(files)
134 134 def getfilectx(repo, memctx, f):
135 135 v = files[f]
136 136 data, mode = source.getfile(f, v)
137 137 if f == '.hgtags':
138 138 data = self._rewritetags(source, revmap, data)
139 139 return context.memfilectx(f, data, 'l' in mode, 'x' in mode,
140 140 copies.get(f))
141 141
142 142 pl = []
143 143 for p in parents:
144 144 if p not in pl:
145 145 pl.append(p)
146 146 parents = pl
147 147 nparents = len(parents)
148 148 if self.filemapmode and nparents == 1:
149 149 m1node = self.repo.changelog.read(bin(parents[0]))[0]
150 150 parent = parents[0]
151 151
152 152 if len(parents) < 2:
153 153 parents.append(nullid)
154 154 if len(parents) < 2:
155 155 parents.append(nullid)
156 156 p2 = parents.pop(0)
157 157
158 158 text = commit.desc
159 159
160 160 sha1s = re.findall(sha1re, text)
161 161 for sha1 in sha1s:
162 162 oldrev = source.lookuprev(sha1)
163 163 newrev = revmap.get(oldrev)
164 164 if newrev is not None:
165 165 text = text.replace(sha1, newrev[:len(sha1)])
166 166
167 167 extra = commit.extra.copy()
168 168 if self.branchnames and commit.branch:
169 169 extra['branch'] = commit.branch
170 170 if commit.rev:
171 171 extra['convert_revision'] = commit.rev
172 172
173 173 while parents:
174 174 p1 = p2
175 175 p2 = parents.pop(0)
176 176 ctx = context.memctx(self.repo, (p1, p2), text, files.keys(),
177 177 getfilectx, commit.author, commit.date, extra)
178 178 self.repo.commitctx(ctx)
179 179 text = "(octopus merge fixup)\n"
180 180 p2 = hex(self.repo.changelog.tip())
181 181
182 182 if self.filemapmode and nparents == 1:
183 183 man = self.repo.manifest
184 184 mnode = self.repo.changelog.read(bin(p2))[0]
185 185 closed = 'close' in commit.extra
186 186 if not closed and not man.cmp(m1node, man.revision(mnode)):
187 187 self.ui.status(_("filtering out empty revision\n"))
188 188 self.repo.rollback(force=True)
189 189 return parent
190 190 return p2
191 191
192 192 def puttags(self, tags):
193 193 try:
194 194 parentctx = self.repo[self.tagsbranch]
195 195 tagparent = parentctx.node()
196 196 except error.RepoError:
197 197 parentctx = None
198 198 tagparent = nullid
199 199
200 200 oldlines = set()
201 201 for branch, heads in self.repo.branchmap().iteritems():
202 202 for h in heads:
203 203 if '.hgtags' in self.repo[h]:
204 204 oldlines.update(
205 205 set(self.repo[h]['.hgtags'].data().splitlines(True)))
206 206 oldlines = sorted(list(oldlines))
207 207
208 208 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
209 209 if newlines == oldlines:
210 210 return None, None
211 211
212 212 # if the old and new tags match, then there is nothing to update
213 213 oldtags = set()
214 214 newtags = set()
215 215 for line in oldlines:
216 216 s = line.strip().split(' ', 1)
217 217 if len(s) != 2:
218 218 continue
219 219 oldtags.add(s[1])
220 220 for line in newlines:
221 221 s = line.strip().split(' ', 1)
222 222 if len(s) != 2:
223 223 continue
224 224 if s[1] not in oldtags:
225 225 newtags.add(s[1].strip())
226 226
227 227 if not newtags:
228 228 return None, None
229 229
230 230 data = "".join(newlines)
231 231 def getfilectx(repo, memctx, f):
232 232 return context.memfilectx(f, data, False, False, None)
233 233
234 234 self.ui.status(_("updating tags\n"))
235 235 date = "%s 0" % int(time.mktime(time.gmtime()))
236 236 extra = {'branch': self.tagsbranch}
237 237 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
238 238 [".hgtags"], getfilectx, "convert-repo", date,
239 239 extra)
240 240 self.repo.commitctx(ctx)
241 241 return hex(self.repo.changelog.tip()), hex(tagparent)
242 242
243 243 def setfilemapmode(self, active):
244 244 self.filemapmode = active
245 245
246 246 def putbookmarks(self, updatedbookmark):
247 247 if not len(updatedbookmark):
248 248 return
249 249
250 250 self.ui.status(_("updating bookmarks\n"))
251 251 destmarks = self.repo._bookmarks
252 252 for bookmark in updatedbookmark:
253 253 destmarks[bookmark] = bin(updatedbookmark[bookmark])
254 254 destmarks.write()
255 255
256 256 def hascommit(self, rev):
257 257 if rev not in self.repo and self.clonebranches:
258 258 raise util.Abort(_('revision %s not found in destination '
259 259 'repository (lookups with clonebranches=true '
260 260 'are not implemented)') % rev)
261 261 return rev in self.repo
262 262
263 263 class mercurial_source(converter_source):
264 264 def __init__(self, ui, path, rev=None):
265 265 converter_source.__init__(self, ui, path, rev)
266 266 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
267 267 self.ignored = set()
268 268 self.saverev = ui.configbool('convert', 'hg.saverev', False)
269 269 try:
270 270 self.repo = hg.repository(self.ui, path)
271 271 # try to provoke an exception if this isn't really a hg
272 272 # repo, but some other bogus compatible-looking url
273 273 if not self.repo.local():
274 274 raise error.RepoError
275 275 except error.RepoError:
276 276 ui.traceback()
277 277 raise NoRepo(_("%s is not a local Mercurial repository") % path)
278 278 self.lastrev = None
279 279 self.lastctx = None
280 280 self._changescache = None
281 281 self.convertfp = None
282 282 # Restrict converted revisions to startrev descendants
283 283 startnode = ui.config('convert', 'hg.startrev')
284 284 hgrevs = ui.config('convert', 'hg.revs')
285 285 if hgrevs is None:
286 286 if startnode is not None:
287 287 try:
288 288 startnode = self.repo.lookup(startnode)
289 289 except error.RepoError:
290 290 raise util.Abort(_('%s is not a valid start revision')
291 291 % startnode)
292 292 startrev = self.repo.changelog.rev(startnode)
293 293 children = {startnode: 1}
294 294 for r in self.repo.changelog.descendants([startrev]):
295 295 children[self.repo.changelog.node(r)] = 1
296 296 self.keep = children.__contains__
297 297 else:
298 298 self.keep = util.always
299 299 if rev:
300 300 self._heads = [self.repo[rev].node()]
301 301 else:
302 302 self._heads = self.repo.heads()
303 303 else:
304 304 if rev or startnode is not None:
305 305 raise util.Abort(_('hg.revs cannot be combined with '
306 306 'hg.startrev or --rev'))
307 307 nodes = set()
308 308 parents = set()
309 309 for r in scmutil.revrange(self.repo, [hgrevs]):
310 310 ctx = self.repo[r]
311 311 nodes.add(ctx.node())
312 312 parents.update(p.node() for p in ctx.parents())
313 313 self.keep = nodes.__contains__
314 314 self._heads = nodes - parents
315 315
316 316 def changectx(self, rev):
317 317 if self.lastrev != rev:
318 318 self.lastctx = self.repo[rev]
319 319 self.lastrev = rev
320 320 return self.lastctx
321 321
322 322 def parents(self, ctx):
323 323 return [p for p in ctx.parents() if p and self.keep(p.node())]
324 324
325 325 def getheads(self):
326 326 return [hex(h) for h in self._heads if self.keep(h)]
327 327
328 328 def getfile(self, name, rev):
329 329 try:
330 330 fctx = self.changectx(rev)[name]
331 331 return fctx.data(), fctx.flags()
332 332 except error.LookupError, err:
333 333 raise IOError(err)
334 334
335 335 def getchanges(self, rev):
336 336 ctx = self.changectx(rev)
337 337 parents = self.parents(ctx)
338 338 if not parents:
339 339 files = sorted(ctx.manifest())
340 340 # getcopies() is not needed for roots, but it is a simple way to
341 341 # detect missing revlogs and abort on errors or populate
342 342 # self.ignored
343 343 self.getcopies(ctx, parents, files)
344 344 return [(f, rev) for f in files if f not in self.ignored], {}
345 345 if self._changescache and self._changescache[0] == rev:
346 346 m, a, r = self._changescache[1]
347 347 else:
348 348 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
349 349 # getcopies() detects missing revlogs early, run it before
350 350 # filtering the changes.
351 351 copies = self.getcopies(ctx, parents, m + a)
352 352 changes = [(name, rev) for name in m + a + r
353 353 if name not in self.ignored]
354 354 return sorted(changes), copies
355 355
356 356 def getcopies(self, ctx, parents, files):
357 357 copies = {}
358 358 for name in files:
359 359 if name in self.ignored:
360 360 continue
361 361 try:
362 362 copysource, _copynode = ctx.filectx(name).renamed()
363 363 if copysource in self.ignored:
364 364 continue
365 365 # Ignore copy sources not in parent revisions
366 366 found = False
367 367 for p in parents:
368 368 if copysource in p:
369 369 found = True
370 370 break
371 371 if not found:
372 372 continue
373 373 copies[name] = copysource
374 374 except TypeError:
375 375 pass
376 376 except error.LookupError, e:
377 377 if not self.ignoreerrors:
378 378 raise
379 379 self.ignored.add(name)
380 380 self.ui.warn(_('ignoring: %s\n') % e)
381 381 return copies
382 382
383 383 def getcommit(self, rev):
384 384 ctx = self.changectx(rev)
385 385 parents = [p.hex() for p in self.parents(ctx)]
386 386 if self.saverev:
387 387 crev = rev
388 388 else:
389 389 crev = None
390 390 return commit(author=ctx.user(),
391 391 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
392 392 desc=ctx.description(), rev=crev, parents=parents,
393 393 branch=ctx.branch(), extra=ctx.extra(),
394 394 sortkey=ctx.rev())
395 395
396 396 def gettags(self):
397 tags = [t for t in self.repo.tagslist() if t[0] != 'tip']
397 # This will get written to .hgtags, filter non global tags out.
398 tags = [t for t in self.repo.tagslist()
399 if self.repo.tagtype(t[0]) == 'global']
398 400 return dict([(name, hex(node)) for name, node in tags
399 401 if self.keep(node)])
400 402
401 403 def getchangedfiles(self, rev, i):
402 404 ctx = self.changectx(rev)
403 405 parents = self.parents(ctx)
404 406 if not parents and i is None:
405 407 i = 0
406 408 changes = [], ctx.manifest().keys(), []
407 409 else:
408 410 i = i or 0
409 411 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
410 412 changes = [[f for f in l if f not in self.ignored] for l in changes]
411 413
412 414 if i == 0:
413 415 self._changescache = (rev, changes)
414 416
415 417 return changes[0] + changes[1] + changes[2]
416 418
417 419 def converted(self, rev, destrev):
418 420 if self.convertfp is None:
419 421 self.convertfp = open(self.repo.join('shamap'), 'a')
420 422 self.convertfp.write('%s %s\n' % (destrev, rev))
421 423 self.convertfp.flush()
422 424
423 425 def before(self):
424 426 self.ui.debug('run hg source pre-conversion action\n')
425 427
426 428 def after(self):
427 429 self.ui.debug('run hg source post-conversion action\n')
428 430
429 431 def hasnativeorder(self):
430 432 return True
431 433
432 434 def hasnativeclose(self):
433 435 return True
434 436
435 437 def lookuprev(self, rev):
436 438 try:
437 439 return hex(self.repo.lookup(rev))
438 440 except error.RepoError:
439 441 return None
440 442
441 443 def getbookmarks(self):
442 444 return bookmarks.listbookmarks(self.repo)
443 445
444 446 def checkrevformat(self, revstr, mapname='splicemap'):
445 447 """ Mercurial, revision string is a 40 byte hex """
446 448 self.checkhexformat(revstr, mapname)
@@ -1,392 +1,394
1 1
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [extensions]
4 4 > convert=
5 5 > [convert]
6 6 > hg.saverev=False
7 7 > EOF
8 8 $ hg init orig
9 9 $ cd orig
10 10 $ echo foo > foo
11 11 $ echo bar > bar
12 12 $ hg ci -qAm 'add foo and bar'
13 13 $ hg rm foo
14 14 $ hg ci -m 'remove foo'
15 15 $ mkdir foo
16 16 $ echo file > foo/file
17 17 $ hg ci -qAm 'add foo/file'
18 18 $ hg tag some-tag
19 $ hg tag -l local-tag
19 20 $ hg log
20 21 changeset: 3:593cbf6fb2b4
22 tag: local-tag
21 23 tag: tip
22 24 user: test
23 25 date: Thu Jan 01 00:00:00 1970 +0000
24 26 summary: Added tag some-tag for changeset ad681a868e44
25 27
26 28 changeset: 2:ad681a868e44
27 29 tag: some-tag
28 30 user: test
29 31 date: Thu Jan 01 00:00:00 1970 +0000
30 32 summary: add foo/file
31 33
32 34 changeset: 1:cbba8ecc03b7
33 35 user: test
34 36 date: Thu Jan 01 00:00:00 1970 +0000
35 37 summary: remove foo
36 38
37 39 changeset: 0:327daa9251fa
38 40 user: test
39 41 date: Thu Jan 01 00:00:00 1970 +0000
40 42 summary: add foo and bar
41 43
42 44 $ cd ..
43 45 $ hg convert orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
44 46 initializing destination new repository
45 47 scanning source...
46 48 sorting...
47 49 converting...
48 50 3 add foo and bar
49 51 2 remove foo
50 52 1 add foo/file
51 53 0 Added tag some-tag for changeset ad681a868e44
52 54 $ cd new
53 55 $ hg out ../orig
54 56 comparing with ../orig
55 57 searching for changes
56 58 no changes found
57 59 [1]
58 60
59 61 dirstate should be empty:
60 62
61 63 $ hg debugstate
62 64 $ hg parents -q
63 65 $ hg up -C
64 66 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 67 $ hg copy bar baz
66 68
67 69 put something in the dirstate:
68 70
69 71 $ hg debugstate > debugstate
70 72 $ grep baz debugstate
71 73 a 0 -1 unset baz
72 74 copy: bar -> baz
73 75
74 76 add a new revision in the original repo
75 77
76 78 $ cd ../orig
77 79 $ echo baz > baz
78 80 $ hg ci -qAm 'add baz'
79 81 $ cd ..
80 82 $ hg convert orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
81 83 scanning source...
82 84 sorting...
83 85 converting...
84 86 0 add baz
85 87 $ cd new
86 88 $ hg out ../orig
87 89 comparing with ../orig
88 90 searching for changes
89 91 no changes found
90 92 [1]
91 93
92 94 dirstate should be the same (no output below):
93 95
94 96 $ hg debugstate > new-debugstate
95 97 $ diff debugstate new-debugstate
96 98
97 99 no copies
98 100
99 101 $ hg up -C
100 102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 103 $ hg debugrename baz
102 104 baz not renamed
103 105 $ cd ..
104 106
105 107 test tag rewriting
106 108
107 109 $ cat > filemap <<EOF
108 110 > exclude foo
109 111 > EOF
110 112 $ hg convert --filemap filemap orig new-filemap 2>&1 | grep -v 'subversion python bindings could not be loaded'
111 113 initializing destination new-filemap repository
112 114 scanning source...
113 115 sorting...
114 116 converting...
115 117 4 add foo and bar
116 118 3 remove foo
117 119 2 add foo/file
118 120 1 Added tag some-tag for changeset ad681a868e44
119 121 0 add baz
120 122 $ cd new-filemap
121 123 $ hg tags
122 124 tip 2:3c74706b1ff8
123 125 some-tag 0:ba8636729451
124 126 $ cd ..
125 127
126 128
127 129 Test cases for hg-hg roundtrip
128 130
129 131 Helper
130 132
131 133 $ glog()
132 134 > {
133 135 > hg log -G --template '{rev} {node|short} "{desc}" files: {files}\n' $*
134 136 > }
135 137
136 138 Create a tricky source repo
137 139
138 140 $ hg init source
139 141 $ cd source
140 142
141 143 $ echo 0 > 0
142 144 $ hg ci -Aqm '0: add 0'
143 145 $ echo a > a
144 146 $ mkdir dir
145 147 $ echo b > dir/b
146 148 $ hg ci -qAm '1: add a and dir/b'
147 149 $ echo c > dir/c
148 150 $ hg ci -qAm '2: add dir/c'
149 151 $ hg copy a e
150 152 $ echo b >> b
151 153 $ hg ci -qAm '3: copy a to e, change b'
152 154 $ hg up -qr -3
153 155 $ echo a >> a
154 156 $ hg ci -qAm '4: change a'
155 157 $ hg merge
156 158 merging a and e to e
157 159 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
158 160 (branch merge, don't forget to commit)
159 161 $ hg copy b dir/d
160 162 $ hg ci -qAm '5: merge 2 and 3, copy b to dir/d'
161 163 $ echo a >> a
162 164 $ hg ci -qAm '6: change a'
163 165
164 166 $ hg mani
165 167 0
166 168 a
167 169 b
168 170 dir/b
169 171 dir/c
170 172 dir/d
171 173 e
172 174 $ glog
173 175 @ 6 0613c8e59a3d "6: change a" files: a
174 176 |
175 177 o 5 717e9b37cdb7 "5: merge 2 and 3, copy b to dir/d" files: dir/d e
176 178 |\
177 179 | o 4 86a55cb968d5 "4: change a" files: a
178 180 | |
179 181 o | 3 0e6e235919dd "3: copy a to e, change b" files: b e
180 182 | |
181 183 o | 2 0394b0d5e4f7 "2: add dir/c" files: dir/c
182 184 |/
183 185 o 1 333546584845 "1: add a and dir/b" files: a dir/b
184 186 |
185 187 o 0 d1a24e2ebd23 "0: add 0" files: 0
186 188
187 189 $ cd ..
188 190
189 191 Convert excluding rev 0 and dir/ (and thus rev2):
190 192
191 193 $ cat << EOF > filemap
192 194 > exclude dir
193 195 > EOF
194 196
195 197 $ hg convert --filemap filemap source dest --config convert.hg.revs=1::
196 198 initializing destination dest repository
197 199 scanning source...
198 200 sorting...
199 201 converting...
200 202 5 1: add a and dir/b
201 203 4 2: add dir/c
202 204 3 3: copy a to e, change b
203 205 2 4: change a
204 206 1 5: merge 2 and 3, copy b to dir/d
205 207 0 6: change a
206 208
207 209 Verify that conversion skipped rev 2:
208 210
209 211 $ glog -R dest
210 212 o 4 78814e84a217 "6: change a" files: a
211 213 |
212 214 o 3 f7cff662c5e5 "5: merge 2 and 3, copy b to dir/d" files: e
213 215 |\
214 216 | o 2 ab40a95b0072 "4: change a" files: a
215 217 | |
216 218 o | 1 bd51f17597bf "3: copy a to e, change b" files: b e
217 219 |/
218 220 o 0 a4a1dae0fe35 "1: add a and dir/b" files: 0 a
219 221
220 222
221 223 Verify mapping correct in both directions:
222 224
223 225 $ cat source/.hg/shamap
224 226 a4a1dae0fe3514cefd9b8541b7abbc8f44f946d5 333546584845f70c4cfecb992341aaef0e708166
225 227 bd51f17597bf32268e68a560b206898c3960cda2 0e6e235919dd8e9285ba8eb5adf703af9ad99378
226 228 ab40a95b00725307e79c2fd271000aa8af9759f4 86a55cb968d51770cba2a1630d6cc637b574580a
227 229 f7cff662c5e581e6f3f1a85ffdd2bcb35825f6ba 717e9b37cdb7eb9917ca8e30aa3f986e6d5b177d
228 230 78814e84a217894517c2de392b903ed05e6871a4 0613c8e59a3ddb9789072ef52f1ed13496489bb4
229 231 $ cat dest/.hg/shamap
230 232 333546584845f70c4cfecb992341aaef0e708166 a4a1dae0fe3514cefd9b8541b7abbc8f44f946d5
231 233 0394b0d5e4f761ced559fd0bbdc6afc16cb3f7d1 a4a1dae0fe3514cefd9b8541b7abbc8f44f946d5
232 234 0e6e235919dd8e9285ba8eb5adf703af9ad99378 bd51f17597bf32268e68a560b206898c3960cda2
233 235 86a55cb968d51770cba2a1630d6cc637b574580a ab40a95b00725307e79c2fd271000aa8af9759f4
234 236 717e9b37cdb7eb9917ca8e30aa3f986e6d5b177d f7cff662c5e581e6f3f1a85ffdd2bcb35825f6ba
235 237 0613c8e59a3ddb9789072ef52f1ed13496489bb4 78814e84a217894517c2de392b903ed05e6871a4
236 238
237 239 Verify meta data converted correctly:
238 240
239 241 $ hg -R dest log -r 1 --debug -p --git
240 242 changeset: 1:bd51f17597bf32268e68a560b206898c3960cda2
241 243 phase: draft
242 244 parent: 0:a4a1dae0fe3514cefd9b8541b7abbc8f44f946d5
243 245 parent: -1:0000000000000000000000000000000000000000
244 246 manifest: 1:040c72ed9b101773c24ac314776bfc846943781f
245 247 user: test
246 248 date: Thu Jan 01 00:00:00 1970 +0000
247 249 files+: b e
248 250 extra: branch=default
249 251 description:
250 252 3: copy a to e, change b
251 253
252 254
253 255 diff --git a/b b/b
254 256 new file mode 100644
255 257 --- /dev/null
256 258 +++ b/b
257 259 @@ -0,0 +1,1 @@
258 260 +b
259 261 diff --git a/a b/e
260 262 copy from a
261 263 copy to e
262 264
263 265 Verify files included and excluded correctly:
264 266
265 267 $ hg -R dest manifest -r tip
266 268 0
267 269 a
268 270 b
269 271 e
270 272
271 273
272 274 Make changes in dest and convert back:
273 275
274 276 $ hg -R dest up -q
275 277 $ echo dest > dest/dest
276 278 $ hg -R dest ci -Aqm 'change in dest'
277 279 $ hg -R dest tip
278 280 changeset: 5:a2e0e3cc6d1d
279 281 tag: tip
280 282 user: test
281 283 date: Thu Jan 01 00:00:00 1970 +0000
282 284 summary: change in dest
283 285
284 286
285 287 (converting merges back after using a filemap will probably cause chaos so we
286 288 exclude merges.)
287 289
288 290 $ hg convert dest source --config convert.hg.revs='!merge()'
289 291 scanning source...
290 292 sorting...
291 293 converting...
292 294 0 change in dest
293 295
294 296 Verify the conversion back:
295 297
296 298 $ hg -R source log --debug -r tip
297 299 changeset: 7:e6d364a69ff1248b2099e603b0c145504cade6f0
298 300 tag: tip
299 301 phase: draft
300 302 parent: 6:0613c8e59a3ddb9789072ef52f1ed13496489bb4
301 303 parent: -1:0000000000000000000000000000000000000000
302 304 manifest: 7:aa3e9542f3b76d4f1f1b2e9c7ce9dbb48b6a95ec
303 305 user: test
304 306 date: Thu Jan 01 00:00:00 1970 +0000
305 307 files+: dest
306 308 extra: branch=default
307 309 description:
308 310 change in dest
309 311
310 312
311 313 Files that had been excluded are still present:
312 314
313 315 $ hg -R source manifest -r tip
314 316 0
315 317 a
316 318 b
317 319 dest
318 320 dir/b
319 321 dir/c
320 322 dir/d
321 323 e
322 324
323 325 More source changes
324 326
325 327 $ cd source
326 328 $ echo 1 >> a
327 329 $ hg ci -m '8: source first branch'
328 330 created new head
329 331 $ hg up -qr -2
330 332 $ echo 2 >> a
331 333 $ hg ci -m '9: source second branch'
332 334 $ hg merge -q --tool internal:local
333 335 $ hg ci -m '10: source merge'
334 336 $ echo >> a
335 337 $ hg ci -m '11: source change'
336 338
337 339 $ hg mani
338 340 0
339 341 a
340 342 b
341 343 dest
342 344 dir/b
343 345 dir/c
344 346 dir/d
345 347 e
346 348
347 349 $ glog -r 6:
348 350 @ 11 0c8927d1f7f4 "11: source change" files: a
349 351 |
350 352 o 10 9ccb7ee8d261 "10: source merge" files: a
351 353 |\
352 354 | o 9 f131b1518dba "9: source second branch" files: a
353 355 | |
354 356 o | 8 669cf0e74b50 "8: source first branch" files: a
355 357 | |
356 358 | o 7 e6d364a69ff1 "change in dest" files: dest
357 359 |/
358 360 o 6 0613c8e59a3d "6: change a" files: a
359 361 |
360 362 $ cd ..
361 363
362 364 $ hg convert --filemap filemap source dest --config convert.hg.revs=3:
363 365 scanning source...
364 366 sorting...
365 367 converting...
366 368 3 8: source first branch
367 369 2 9: source second branch
368 370 1 10: source merge
369 371 0 11: source change
370 372
371 373 $ glog -R dest
372 374 o 9 8432d597b263 "11: source change" files: a
373 375 |
374 376 o 8 632ffacdcd6f "10: source merge" files: a
375 377 |\
376 378 | o 7 049cfee90ee6 "9: source second branch" files: a
377 379 | |
378 380 o | 6 9b6845e036e5 "8: source first branch" files: a
379 381 | |
380 382 | @ 5 a2e0e3cc6d1d "change in dest" files: dest
381 383 |/
382 384 o 4 78814e84a217 "6: change a" files: a
383 385 |
384 386 o 3 f7cff662c5e5 "5: merge 2 and 3, copy b to dir/d" files: e
385 387 |\
386 388 | o 2 ab40a95b0072 "4: change a" files: a
387 389 | |
388 390 o | 1 bd51f17597bf "3: copy a to e, change b" files: b e
389 391 |/
390 392 o 0 a4a1dae0fe35 "1: add a and dir/b" files: 0 a
391 393
392 394 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now