Show More
@@ -0,0 +1,40 b'' | |||||
|
1 | Testing that convert.hg.preserve-hash=true can be used to make hg | |||
|
2 | convert from hg repo to hg repo preserve hashes, even if the | |||
|
3 | computation of the files list in commits change slightly between hg | |||
|
4 | versions. | |||
|
5 | ||||
|
6 | $ cat <<'EOF' >> "$HGRCPATH" | |||
|
7 | > [extensions] | |||
|
8 | > convert = | |||
|
9 | > EOF | |||
|
10 | $ cat <<'EOF' > changefileslist.py | |||
|
11 | > from mercurial import (changelog, extensions) | |||
|
12 | > def wrap(orig, clog, manifest, files, *args, **kwargs): | |||
|
13 | > return orig(clog, manifest, ["a"], *args, **kwargs) | |||
|
14 | > def extsetup(ui): | |||
|
15 | > extensions.wrapfunction(changelog.changelog, 'add', wrap) | |||
|
16 | > EOF | |||
|
17 | ||||
|
18 | $ hg init repo | |||
|
19 | $ cd repo | |||
|
20 | $ echo a > a; hg commit -qAm a | |||
|
21 | $ echo b > a; hg commit -qAm b | |||
|
22 | $ hg up -qr 0; echo c > c; hg commit -qAm c | |||
|
23 | $ hg merge -qr 1 | |||
|
24 | $ hg commit -m_ --config extensions.x=../changefileslist.py | |||
|
25 | $ hg log -r . -T '{node|short} {files|json}\n' | |||
|
26 | c085bbe93d59 ["a"] | |||
|
27 | ||||
|
28 | Now that we have a commit with a files list that's not what the | |||
|
29 | current hg version would create, check that convert either fixes it or | |||
|
30 | keeps it depending on config: | |||
|
31 | ||||
|
32 | $ hg convert -q . ../convert | |||
|
33 | $ hg --cwd ../convert log -r tip -T '{node|short} {files|json}\n' | |||
|
34 | b7c4d4bbacd3 [] | |||
|
35 | $ rm -rf ../convert | |||
|
36 | ||||
|
37 | $ hg convert -q . ../convert --config convert.hg.preserve-hash=true | |||
|
38 | $ hg --cwd ../convert log -r tip -T '{node|short} {files|json}\n' | |||
|
39 | c085bbe93d59 ["a"] | |||
|
40 | $ rm -rf ../convert |
@@ -439,6 +439,11 b' def convert(ui, src, dest=None, revmapfi' | |||||
439 | :convert.hg.sourcename: records the given string as a 'convert_source' extra |
|
439 | :convert.hg.sourcename: records the given string as a 'convert_source' extra | |
440 | value on each commit made in the target repository. The default is None. |
|
440 | value on each commit made in the target repository. The default is None. | |
441 |
|
441 | |||
|
442 | :convert.hg.preserve-hash: only works with mercurial sources. Make convert | |||
|
443 | prevent performance improvement to the list of modified files in commits | |||
|
444 | when such an improvement would cause the hash of a commit to change. | |||
|
445 | The default is False. | |||
|
446 | ||||
442 | All Destinations |
|
447 | All Destinations | |
443 | ################ |
|
448 | ################ | |
444 |
|
449 |
@@ -114,7 +114,7 b" SKIPREV = 'SKIP'" | |||||
114 | class commit(object): |
|
114 | class commit(object): | |
115 | def __init__(self, author, date, desc, parents, branch=None, rev=None, |
|
115 | def __init__(self, author, date, desc, parents, branch=None, rev=None, | |
116 | extra=None, sortkey=None, saverev=True, phase=phases.draft, |
|
116 | extra=None, sortkey=None, saverev=True, phase=phases.draft, | |
117 | optparents=None): |
|
117 | optparents=None, ctx=None): | |
118 | self.author = author or 'unknown' |
|
118 | self.author = author or 'unknown' | |
119 | self.date = date or '0 0' |
|
119 | self.date = date or '0 0' | |
120 | self.desc = desc |
|
120 | self.desc = desc | |
@@ -126,6 +126,7 b' class commit(object):' | |||||
126 | self.sortkey = sortkey |
|
126 | self.sortkey = sortkey | |
127 | self.saverev = saverev |
|
127 | self.saverev = saverev | |
128 | self.phase = phase |
|
128 | self.phase = phase | |
|
129 | self.ctx = ctx # for hg to hg conversions | |||
129 |
|
130 | |||
130 | class converter_source(object): |
|
131 | class converter_source(object): | |
131 | """Conversion source interface""" |
|
132 | """Conversion source interface""" |
@@ -339,7 +339,11 b' class mercurial_sink(common.converter_si' | |||||
339 | phases.phasenames[commit.phase], 'convert') |
|
339 | phases.phasenames[commit.phase], 'convert') | |
340 |
|
340 | |||
341 | with self.repo.transaction("convert") as tr: |
|
341 | with self.repo.transaction("convert") as tr: | |
342 | node = nodemod.hex(self.repo.commitctx(ctx)) |
|
342 | if self.repo.ui.config('convert', 'hg.preserve-hash'): | |
|
343 | origctx = commit.ctx | |||
|
344 | else: | |||
|
345 | origctx = None | |||
|
346 | node = nodemod.hex(self.repo.commitctx(ctx, origctx=origctx)) | |||
343 |
|
347 | |||
344 | # If the node value has changed, but the phase is lower than |
|
348 | # If the node value has changed, but the phase is lower than | |
345 | # draft, set it back to draft since it hasn't been exposed |
|
349 | # draft, set it back to draft since it hasn't been exposed | |
@@ -591,7 +595,8 b' class mercurial_source(common.converter_' | |||||
591 | extra=ctx.extra(), |
|
595 | extra=ctx.extra(), | |
592 | sortkey=ctx.rev(), |
|
596 | sortkey=ctx.rev(), | |
593 | saverev=self.saverev, |
|
597 | saverev=self.saverev, | |
594 |
phase=ctx.phase() |
|
598 | phase=ctx.phase(), | |
|
599 | ctx=ctx) | |||
595 |
|
600 | |||
596 | def numcommits(self): |
|
601 | def numcommits(self): | |
597 | return len(self.repo) |
|
602 | return len(self.repo) |
@@ -400,7 +400,7 b' def reposetup(ui, repo):' | |||||
400 | if wlock is not None: |
|
400 | if wlock is not None: | |
401 | wlock.release() |
|
401 | wlock.release() | |
402 |
|
402 | |||
403 | def commitctx(self, ctx, error=False): |
|
403 | def commitctx(self, ctx, error=False, origctx=None): | |
404 | for f in sorted(ctx.added() + ctx.modified()): |
|
404 | for f in sorted(ctx.added() + ctx.modified()): | |
405 | if not self._eolmatch(f): |
|
405 | if not self._eolmatch(f): | |
406 | continue |
|
406 | continue | |
@@ -416,6 +416,6 b' def reposetup(ui, repo):' | |||||
416 | if inconsistenteol(data): |
|
416 | if inconsistenteol(data): | |
417 | raise errormod.Abort(_("inconsistent newline style " |
|
417 | raise errormod.Abort(_("inconsistent newline style " | |
418 | "in %s\n") % f) |
|
418 | "in %s\n") % f) | |
419 | return super(eolrepo, self).commitctx(ctx, error) |
|
419 | return super(eolrepo, self).commitctx(ctx, error, origctx) | |
420 | repo.__class__ = eolrepo |
|
420 | repo.__class__ = eolrepo | |
421 | repo._hgcleardirstate() |
|
421 | repo._hgcleardirstate() |
@@ -785,8 +785,8 b' def reposetup(ui, repo):' | |||||
785 | finally: |
|
785 | finally: | |
786 | del self.commitctx |
|
786 | del self.commitctx | |
787 |
|
787 | |||
788 | def kwcommitctx(self, ctx, error=False): |
|
788 | def kwcommitctx(self, ctx, error=False, origctx=None): | |
789 | n = super(kwrepo, self).commitctx(ctx, error) |
|
789 | n = super(kwrepo, self).commitctx(ctx, error, origctx) | |
790 | # no lock needed, only called from repo.commit() which already locks |
|
790 | # no lock needed, only called from repo.commit() which already locks | |
791 | if not kwt.postcommit: |
|
791 | if not kwt.postcommit: | |
792 | restrict = kwt.restrict |
|
792 | restrict = kwt.restrict |
@@ -227,9 +227,9 b' def _reposetup(ui, repo):' | |||||
227 |
|
227 | |||
228 | class lfsrepo(repo.__class__): |
|
228 | class lfsrepo(repo.__class__): | |
229 | @localrepo.unfilteredmethod |
|
229 | @localrepo.unfilteredmethod | |
230 | def commitctx(self, ctx, error=False): |
|
230 | def commitctx(self, ctx, error=False, origctx=None): | |
231 | repo.svfs.options['lfstrack'] = _trackedmatcher(self) |
|
231 | repo.svfs.options['lfstrack'] = _trackedmatcher(self) | |
232 | return super(lfsrepo, self).commitctx(ctx, error) |
|
232 | return super(lfsrepo, self).commitctx(ctx, error, origctx=origctx) | |
233 |
|
233 | |||
234 | repo.__class__ = lfsrepo |
|
234 | repo.__class__ = lfsrepo | |
235 |
|
235 |
@@ -161,7 +161,7 b' def wraprepo(repo):' | |||||
161 | **kwargs) |
|
161 | **kwargs) | |
162 |
|
162 | |||
163 | @localrepo.unfilteredmethod |
|
163 | @localrepo.unfilteredmethod | |
164 | def commitctx(self, ctx, error=False): |
|
164 | def commitctx(self, ctx, error=False, origctx=None): | |
165 | """Add a new revision to current repository. |
|
165 | """Add a new revision to current repository. | |
166 | Revision information is passed via the context argument. |
|
166 | Revision information is passed via the context argument. | |
167 | """ |
|
167 | """ | |
@@ -179,7 +179,8 b' def wraprepo(repo):' | |||||
179 | files.append((f, hex(fparent1))) |
|
179 | files.append((f, hex(fparent1))) | |
180 | self.fileservice.prefetch(files) |
|
180 | self.fileservice.prefetch(files) | |
181 | return super(shallowrepository, self).commitctx(ctx, |
|
181 | return super(shallowrepository, self).commitctx(ctx, | |
182 |
error=error |
|
182 | error=error, | |
|
183 | origctx=origctx) | |||
183 |
|
184 | |||
184 | def backgroundprefetch(self, revs, base=None, repack=False, pats=None, |
|
185 | def backgroundprefetch(self, revs, base=None, repack=False, pats=None, | |
185 | opts=None): |
|
186 | opts=None): |
@@ -291,6 +291,9 b" coreconfigitem('convert', 'hg.clonebranc" | |||||
291 | coreconfigitem('convert', 'hg.ignoreerrors', |
|
291 | coreconfigitem('convert', 'hg.ignoreerrors', | |
292 | default=False, |
|
292 | default=False, | |
293 | ) |
|
293 | ) | |
|
294 | coreconfigitem('convert', 'hg.preserve-hash', | |||
|
295 | default=False, | |||
|
296 | ) | |||
294 | coreconfigitem('convert', 'hg.revs', |
|
297 | coreconfigitem('convert', 'hg.revs', | |
295 | default=None, |
|
298 | default=None, | |
296 | ) |
|
299 | ) |
@@ -2578,7 +2578,7 b' class localrepository(object):' | |||||
2578 | return ret |
|
2578 | return ret | |
2579 |
|
2579 | |||
2580 | @unfilteredmethod |
|
2580 | @unfilteredmethod | |
2581 | def commitctx(self, ctx, error=False): |
|
2581 | def commitctx(self, ctx, error=False, origctx=None): | |
2582 | """Add a new revision to current repository. |
|
2582 | """Add a new revision to current repository. | |
2583 | Revision information is passed via the context argument. |
|
2583 | Revision information is passed via the context argument. | |
2584 |
|
2584 | |||
@@ -2586,6 +2586,12 b' class localrepository(object):' | |||||
2586 | modified/added/removed files. On merge, it may be wider than the |
|
2586 | modified/added/removed files. On merge, it may be wider than the | |
2587 | ctx.files() to be committed, since any file nodes derived directly |
|
2587 | ctx.files() to be committed, since any file nodes derived directly | |
2588 | from p1 or p2 are excluded from the committed ctx.files(). |
|
2588 | from p1 or p2 are excluded from the committed ctx.files(). | |
|
2589 | ||||
|
2590 | origctx is for convert to work around the problem that bug | |||
|
2591 | fixes to the files list in changesets change hashes. For | |||
|
2592 | convert to be the identity, it can pass an origctx and this | |||
|
2593 | function will use the same files list when it makes sense to | |||
|
2594 | do so. | |||
2589 | """ |
|
2595 | """ | |
2590 |
|
2596 | |||
2591 | p1, p2 = ctx.p1(), ctx.p2() |
|
2597 | p1, p2 = ctx.p1(), ctx.p2() | |
@@ -2701,6 +2707,9 b' class localrepository(object):' | |||||
2701 | filesadded = filesadded or None |
|
2707 | filesadded = filesadded or None | |
2702 | filesremoved = filesremoved or None |
|
2708 | filesremoved = filesremoved or None | |
2703 |
|
2709 | |||
|
2710 | if origctx and origctx.manifestnode() == mn: | |||
|
2711 | files = origctx.files() | |||
|
2712 | ||||
2704 | # update changelog |
|
2713 | # update changelog | |
2705 | self.ui.note(_("committing changelog\n")) |
|
2714 | self.ui.note(_("committing changelog\n")) | |
2706 | self.changelog.delayupdate(tr) |
|
2715 | self.changelog.delayupdate(tr) |
@@ -1656,7 +1656,7 b' class ilocalrepositorymain(interfaceutil' | |||||
1656 | editor=False, extra=None): |
|
1656 | editor=False, extra=None): | |
1657 | """Add a new revision to the repository.""" |
|
1657 | """Add a new revision to the repository.""" | |
1658 |
|
1658 | |||
1659 | def commitctx(ctx, error=False): |
|
1659 | def commitctx(ctx, error=False, origctx=None): | |
1660 | """Commit a commitctx instance to the repository.""" |
|
1660 | """Commit a commitctx instance to the repository.""" | |
1661 |
|
1661 | |||
1662 | def destroying(): |
|
1662 | def destroying(): |
@@ -917,13 +917,13 b' cases.' | |||||
917 | > raise error.Abort(b'fail after finalization') |
|
917 | > raise error.Abort(b'fail after finalization') | |
918 | > def reposetup(ui, repo): |
|
918 | > def reposetup(ui, repo): | |
919 | > class failrepo(repo.__class__): |
|
919 | > class failrepo(repo.__class__): | |
920 | > def commitctx(self, ctx, error=False): |
|
920 | > def commitctx(self, ctx, error=False, origctx=None): | |
921 | > if self.ui.configbool(b'failafterfinalize', b'fail'): |
|
921 | > if self.ui.configbool(b'failafterfinalize', b'fail'): | |
922 | > # 'sorted()' by ASCII code on category names causes |
|
922 | > # 'sorted()' by ASCII code on category names causes | |
923 | > # invoking 'fail' after finalization of changelog |
|
923 | > # invoking 'fail' after finalization of changelog | |
924 | > # using "'cl-%i' % id(self)" as category name |
|
924 | > # using "'cl-%i' % id(self)" as category name | |
925 | > self.currenttransaction().addfinalize(b'zzzzzzzz', fail) |
|
925 | > self.currenttransaction().addfinalize(b'zzzzzzzz', fail) | |
926 | > return super(failrepo, self).commitctx(ctx, error) |
|
926 | > return super(failrepo, self).commitctx(ctx, error, origctx) | |
927 | > repo.__class__ = failrepo |
|
927 | > repo.__class__ = failrepo | |
928 | > EOF |
|
928 | > EOF | |
929 |
|
929 |
@@ -373,6 +373,11 b'' | |||||
373 | records the given string as a 'convert_source' extra value |
|
373 | records the given string as a 'convert_source' extra value | |
374 | on each commit made in the target repository. The default is |
|
374 | on each commit made in the target repository. The default is | |
375 | None. |
|
375 | None. | |
|
376 | convert.hg.preserve-hash | |||
|
377 | only works with mercurial sources. Make convert prevent | |||
|
378 | performance improvement to the list of modified files in | |||
|
379 | commits when such an improvement would cause the hash of a | |||
|
380 | commit to change. The default is False. | |||
376 |
|
381 | |||
377 | All Destinations |
|
382 | All Destinations | |
378 | ################ |
|
383 | ################ |
General Comments 0
You need to be logged in to leave comments.
Login now