# HG changeset patch # User Maxim Dounin # Date 2007-12-29 14:11:48 # Node ID 180a3eee4b756498ec1e6e548a61eb6d77635ea7 # Parent 124577de40a759097bd0c5fae61af46dd35b11bc Fix copies reporting in log and convert. If copy logged in file revision, we report copy for changeset only if file revisions linkrev points back to the changeset in question or both changeset parents contain different file revisions. This fixes extra copies reported when executable bit was changed for previously copied file. diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -881,7 +881,8 @@ def debugrename(ui, repo, file1, *pats, ctx = repo.changectx(opts.get('rev', 'tip')) for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, ctx.node()): - m = ctx.filectx(abs).renamed() + fctx = ctx.filectx(abs) + m = fctx.filelog().renamed(fctx.filenode()) if m: ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1]))) else: @@ -1701,8 +1702,7 @@ def log(ui, repo, *pats, **opts): endrev = repo.changelog.count() rcache = {} ncache = {} - dcache = [] - def getrenamed(fn, rev, man): + def getrenamed(fn, rev): '''looks up all renames for a file (up to endrev) the first time the file is given. It indexes on the changerev and only parses the manifest if linkrev != changerev. @@ -1722,13 +1722,14 @@ def log(ui, repo, *pats, **opts): break if rev in rcache[fn]: return rcache[fn][rev] - mr = repo.manifest.rev(man) - if repo.manifest.parentrevs(mr) != (mr - 1, nullrev): - return ncache[fn].get(repo.manifest.find(man, fn)[0]) - if not dcache or dcache[0] != man: - dcache[:] = [man, repo.manifest.readdelta(man)] - if fn in dcache[1]: - return ncache[fn].get(dcache[1][fn]) + + # If linkrev != rev (i.e. rev not found in rcache) fallback to + # filectx logic. + + try: + return repo.changectx(rev).filectx(fn).renamed() + except revlog.LookupError: + pass return None df = False @@ -1765,9 +1766,8 @@ def log(ui, repo, *pats, **opts): copies = [] if opts.get('copies') and rev: - mf = get(rev)[0] for fn in get(rev)[3]: - rename = getrenamed(fn, rev, mf) + rename = getrenamed(fn, rev) if rename: copies.append((fn, rename[0])) displayer.show(rev, changenode, copies=copies) diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -235,6 +235,7 @@ class filectx(object): return self._changectx.rev() return self._filelog.linkrev(self._filenode) + def linkrev(self): return self._filelog.linkrev(self._filenode) def node(self): return self._changectx.node() def user(self): return self._changectx.user() def date(self): return self._changectx.date() @@ -245,12 +246,36 @@ class filectx(object): def changectx(self): return self._changectx def data(self): return self._filelog.read(self._filenode) - def renamed(self): return self._filelog.renamed(self._filenode) def path(self): return self._path def size(self): return self._filelog.size(self._filerev) def cmp(self, text): return self._filelog.cmp(self._filenode, text) + def renamed(self): + """check if file was actually renamed in this changeset revision + + If rename logged in file revision, we report copy for changeset only + if file revisions linkrev points back to the changeset in question + or both changeset parents contain different file revisions. + """ + + renamed = self._filelog.renamed(self._filenode) + if not renamed: + return renamed + + if self.rev() == self.linkrev(): + return renamed + + name = self.path() + fnode = self._filenode + for p in self._changectx.parents(): + try: + if fnode == p.filenode(name): + return None + except revlog.LookupError: + pass + return renamed + def parents(self): p = self._path fl = self._filelog @@ -322,7 +347,7 @@ class filectx(object): return [getctx(p, n) for p, n in pl if n != nullrev] # use linkrev to find the first changeset where self appeared - if self.rev() != self._filelog.linkrev(self._filenode): + if self.rev() != self.linkrev(): base = self.filectx(self.filerev()) else: base = self diff --git a/tests/test-convert-hg-source b/tests/test-convert-hg-source --- a/tests/test-convert-hg-source +++ b/tests/test-convert-hg-source @@ -29,6 +29,9 @@ hg up -C 1 hg merge 2 hg ci -m 'merge remote copy' -d '4 0' +chmod +x baz +hg ci -m 'mark baz executable' -d '5 0' + cd .. hg convert --datesort orig new 2>&1 | grep -v 'subversion python bindings could not be loaded' cd new diff --git a/tests/test-convert-hg-source.out b/tests/test-convert-hg-source.out --- a/tests/test-convert-hg-source.out +++ b/tests/test-convert-hg-source.out @@ -9,11 +9,12 @@ initializing destination new repository scanning source... sorting... converting... -4 add foo bar -3 change foo -2 make bar and baz copies of foo -1 merge local copy -0 merge remote copy +5 add foo bar +4 change foo +3 make bar and baz copies of foo +2 merge local copy +1 merge remote copy +0 mark baz executable comparing with ../orig searching for changes no changes found diff --git a/tests/test-convert-svn-sink.out b/tests/test-convert-svn-sink.out --- a/tests/test-convert-svn-sink.out +++ b/tests/test-convert-svn-sink.out @@ -167,31 +167,29 @@ c d1 % executable 5:f205b3636d77 -svn: Path 'b' does not exist assuming destination a-hg initializing svn wc 'a-hg-wc' scanning source... sorting... converting... 0 make a file executable -abort: svn exited with status 1 -At revision 5. - 5 5 test . - M 5 4 test c - 5 1 test d1 - 5 1 test d1/d2 - 5 1 test d1/d2/b +At revision 6. + 6 6 test . + 6 6 test c + 6 1 test d1 + 6 1 test d1/d2 + 6 1 test d1/d2/b + revision="6"> test /b + action="M">/c -remove a file +make a file executable executable diff --git a/tests/test-log b/tests/test-log --- a/tests/test-log +++ b/tests/test-log @@ -41,6 +41,11 @@ echo foo > foo hg ci -Ame2 -d '6 0' hg log -vC --template '{rev} {file_copies%filecopy}\n' -r 5 +echo % log copies, execute bit set +chmod +x e +hg ci -me3 -d '7 0' +hg log -vC --template '{rev} {file_copies%filecopy}\n' -r 6 + echo '% log -p d' hg log -pv d diff --git a/tests/test-log.out b/tests/test-log.out --- a/tests/test-log.out +++ b/tests/test-log.out @@ -86,6 +86,8 @@ 0 1 files updated, 0 files merged, 1 files removed, 0 files unresolved adding foo 5 e (dir/b) +% log copies, execute bit set +6 % log -p d changeset: 3:16b60bf3f99a user: test