# HG changeset patch # User Alexis S. L. Carvalho # Date 1191550897 10800 # Node ID 8a2915f57dfcc2b778ae6276e2cdd5629c8fb132 # Parent 756a43a30e34719589e0ced937b53be5a464e810 convert: add a mode where mercurial_sink skips empty revisions. The getchanges function of some converter_source classes can return some false positives. I.e. they sometimes claim that a file "foo" was changed in some revision, even though its contents are still the same. convert_svn is particularly bad, but I think this can also happen with convert_cvs and, at least in theory, with mercurial_source. For regular conversions this is not really a problem - as long as getfile returns the right contents, we'll get a converted revision with the right contents. But when we use --filemap, this could lead to superfluous revisions being converted. Instead of fixing every converter_source, I decided to change mercurial_sink to work around this problem. When --filemap is used, we're interested only in revisions that touch some specific files. If a revision doesn't change any of these files, then we're not interested in it (at least for revisions with a single parent; merges are special). For mercurial_sink, we abuse this property and rollback a commit if the manifest text hasn't changed. This avoids duplicating the logic from localrepo.filecommit to detect unchanged files. diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py --- a/hgext/convert/__init__.py +++ b/hgext/convert/__init__.py @@ -382,6 +382,7 @@ def convert(ui, src, dest=None, revmapfi fmap = opts.get('filemap') if fmap: srcc = filemap.filemap_source(ui, srcc, fmap) + destc.setfilemapmode(True) if not revmapfile: try: diff --git a/hgext/convert/common.py b/hgext/convert/common.py --- a/hgext/convert/common.py +++ b/hgext/convert/common.py @@ -167,3 +167,13 @@ class converter_sink(object): pbranch: branch name of parent commit parents: destination revisions of parent""" pass + + def setfilemapmode(self, active): + """Tell the destination that we're using a filemap + + Some converter_sources (svn in particular) can claim that a file + was changed in a revision, even if there was no change. This method + tells the destination that we're using a filemap and that it should + filter empty revisions. + """ + pass diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py --- a/hgext/convert/hg.py +++ b/hgext/convert/hg.py @@ -28,6 +28,7 @@ class mercurial_sink(converter_sink): raise NoRepo("could not open hg repo %s as sink" % path) self.lock = None self.wlock = None + self.filemapmode = False def before(self): self.wlock = self.repo.wlock() @@ -96,6 +97,10 @@ class mercurial_sink(converter_sink): pl.append(p) seen[p] = 1 parents = pl + nparents = len(parents) + if self.filemapmode and nparents == 1: + m1node = self.repo.changelog.read(bin(parents[0]))[0] + parent = parents[0] if len(parents) < 2: parents.append("0" * 40) if len(parents) < 2: parents.append("0" * 40) @@ -117,6 +122,13 @@ class mercurial_sink(converter_sink): text = "(octopus merge fixup)\n" p2 = hg.hex(self.repo.changelog.tip()) + if self.filemapmode and nparents == 1: + man = self.repo.manifest + mnode = self.repo.changelog.read(bin(p2))[0] + if not man.cmp(m1node, man.revision(mnode)): + self.repo.rollback() + self.repo.dirstate.clear() + return parent return p2 def puttags(self, tags): @@ -153,6 +165,9 @@ class mercurial_sink(converter_sink): date, tagparent, nullid) return hex(self.repo.changelog.tip()) + def setfilemapmode(self, active): + self.filemapmode = active + class mercurial_source(converter_source): def __init__(self, ui, path, rev=None): converter_source.__init__(self, ui, path, rev)