Package: mercurial
Version: 0.9.4-1
Severity: important
Tags: patch
With the latest mercurial version, I experience repository corruption
in the sense that multiple heads are erroneously being generated in a
repository after a normal commit, *without* doing any merging at all.
I first noticed this behaviour when trying to convert a darcs repository
to mercurial using tailor (Debian package 0.9.28-2). tailor works
by successively transferring the changes for each foreign revision to the
mercurial repository, doing a commit with mercurial for each revision.
With mercurial 0.9.3, this produced a valid mercurial repository. With
version 0.9.4, however, I receive a repository with ~10 different heads
(instead of a single one, "tip") in every 100 changesets committed.
At first, I thought that tailor was to blame for this. But then,
recently, I got the exact same faulty behaviour with two other
repositories which I use for managing /etc, so mercurial had to be
at fault.
Now, in the upstream repository, this seems to be fixed already. With
hg bisect, I tracked the fix down to the following changeset:
changeset: 4952:a11921d24ec4
user: Alexis S. L. Carvalho <[EMAIL PROTECTED]>
date: Thu Jul 19 19:43:25 2007 -0300
files: mercurial/dirstate.py
description:
add dirstate._dirtypl variable
Theoretically, it's possible to forget modified dirstate
parents by doing:
dirstate.invalidate()
dirstate.setparents(p1, p2)
dirstate._map
The final access to _map should call _read(), which will
unconditionally overwrite dirstate._pl.
This doesn't actually happen right now because invalidate
accidentally ends up rebuilding dirstate._map.
I have to admit that I am not familiar with the inner workings of
mercurial, but applying this changeset to pristine mercurial 0.9.4
resolved the issue. (This indicates that the situation described above
is definitely not merely theoretical at all.)
Could you have a further look into this, and maybe apply this changeset
in consequence? This bug seems pretty nasty and should probably be
fixed sooner rather than later.
Regards,
Peter
-- System Information:
Debian Release: lenny/sid
APT prefers unstable
APT policy: (500, 'unstable'), (500, 'stable'), (400, 'testing'), (1,
'experimental')
Architecture: amd64 (x86_64)
Kernel: Linux 2.6.22-maia
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
Versions of packages mercurial depends on:
ii libc6 2.6-5 GNU C Library: Shared libraries
ii python 2.4.4-6 An interactive high-level object-o
ii python-support 0.6.4 automated rebuilding support for p
ii python2.5 2.5.1-3 An interactive high-level object-o
Versions of packages mercurial recommends:
ii rcs 5.7-18 The GNU Revision Control System
ii tk8.4 [wish] 8.4.15-1 Tk toolkit for Tcl and X11, v8.4 -
ii tkdiff 1:4.1.3-1 graphical side by side "diff" util
-- no debconf information
changeset: 4952:a11921d24ec4
user: Alexis S. L. Carvalho <[EMAIL PROTECTED]>
date: Thu Jul 19 19:43:25 2007 -0300
summary: add dirstate._dirtypl variable
diff -r 667290b6c95e -r a11921d24ec4 mercurial/dirstate.py
--- a/mercurial/dirstate.py Thu Jul 19 19:43:25 2007 -0300
+++ b/mercurial/dirstate.py Thu Jul 19 19:43:25 2007 -0300
@@ -21,6 +21,7 @@ class dirstate(object):
self._opener = opener
self._root = root
self._dirty = 0
+ self._dirtypl = 0
self._ui = ui
def __getattr__(self, name):
@@ -114,6 +115,7 @@ class dirstate(object):
def setparents(self, p1, p2=nullid):
self.markdirty()
+ self._dirtypl = 1
self._pl = p1, p2
def setbranch(self, branch):
@@ -126,7 +128,8 @@ class dirstate(object):
def _read(self):
self._map = {}
self._copymap = {}
- self._pl = [nullid, nullid]
+ if not self._dirtypl:
+ self._pl = [nullid, nullid]
try:
st = self._opener("dirstate").read()
except IOError, err:
@@ -135,7 +138,8 @@ class dirstate(object):
if not st:
return
- self._pl = [st[:20], st[20: 40]]
+ if not self._dirtypl:
+ self._pl = [st[:20], st[20: 40]]
# deref fields so they will be local in loop
dmap = self._map
@@ -262,6 +266,7 @@ class dirstate(object):
st.write(cs.getvalue())
st.rename()
self._dirty = 0
+ self._dirtypl = 0
def filterfiles(self, files):
ret = {}