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.
--- a/mercurial/commands.py Sat Dec 29 16:57:43 2007 +0300
+++ b/mercurial/commands.py Sat Dec 29 17:11:48 2007 +0300
@@ -881,7 +881,8 @@
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 @@
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 @@
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 @@
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)
--- a/mercurial/context.py Sat Dec 29 16:57:43 2007 +0300
+++ b/mercurial/context.py Sat Dec 29 17:11:48 2007 +0300
@@ -235,6 +235,7 @@
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 @@
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 @@
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
--- a/tests/test-convert-hg-source Sat Dec 29 16:57:43 2007 +0300
+++ b/tests/test-convert-hg-source Sat Dec 29 17:11:48 2007 +0300
@@ -29,6 +29,9 @@
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
--- a/tests/test-convert-hg-source.out Sat Dec 29 16:57:43 2007 +0300
+++ b/tests/test-convert-hg-source.out Sat Dec 29 17:11:48 2007 +0300
@@ -9,11 +9,12 @@
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
--- a/tests/test-convert-svn-sink.out Sat Dec 29 16:57:43 2007 +0300
+++ b/tests/test-convert-svn-sink.out Sat Dec 29 17:11:48 2007 +0300
@@ -167,31 +167,29 @@
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
<?xml version="1.0"?>
<log>
<logentry
- revision="5">
+ revision="6">
<author>test</author>
<date/>
<paths>
<path
- action="D">/b</path>
+ action="M">/c</path>
</paths>
-<msg>remove a file</msg>
+<msg>make a file executable</msg>
</logentry>
</log>
executable
--- a/tests/test-log Sat Dec 29 16:57:43 2007 +0300
+++ b/tests/test-log Sat Dec 29 17:11:48 2007 +0300
@@ -41,6 +41,11 @@
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
--- a/tests/test-log.out Sat Dec 29 16:57:43 2007 +0300
+++ b/tests/test-log.out Sat Dec 29 17:11:48 2007 +0300
@@ -86,6 +86,8 @@
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