Issue2067

Title invalid sha1 in .hgsubstate due to modified file in subrepo
Priority bug Status resolved
Superseder Nosy List ede, kuk, mg, mpm, tonfa
Assigned To Topics subrepositories diff

Created on 2010-03-01.14:04:08 by kuk, last changed 2010-07-15.10:13:05 by mg.

Files
File name Uploaded Type Edit Remove
test_hgsubstate_corruption kuk, 2010-03-01.14:04:07 text/plain
Messages
msg13104 (view) Author: mg Date: 2010-07-15.10:10:35
I just tried to run the tesT_hgsubstte_corruption script and did not see the
extra '+' mentioned. So it looks like this was fixed by Matt in f0ea93557133.

That changeset refers to Issue2217 so I'm marking this issue as superseeded
by Issue2217.
msg12194 (view) Author: kuk Date: 2010-03-31.20:25:03
# HG changeset patch
# User Klaus Koch <kuk42@gmx.net>
# Date 1269982722 -7200
# Branch stable
# Node ID 44919208a23d7e56681102f3399ecd2093018193
# Parent  1b45468d3debdfe66625814939a4bf925d9a4dc8
subrepo: fix dirty ids in .hgsubstate (issue2076); never matching condition

diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -67,13 +67,14 @@
         repo.ui.debug("  subrepo %s: %s %s\n" % (s, msg, r))
 
     for s, l in s1.items():
+        cleanl = l[:]
         if wctx != actx and wctx.sub(s).dirty():
-            l = (l[0], l[1] + "+")
+            l = (l[0], l[1] + "+", l[2])
         a = sa.get(s, nullstate)
         if s in s2:
             r = s2[s]
             if l == r or r == a: # no change or local is newer
-                sm[s] = l
+                sm[s] = cleanl
                 continue
             elif l == a: # other side changed
                 debug(s, "other changed, get", r)
@@ -95,7 +96,7 @@
             else:
                 debug(s, "both sides changed, merge with", r)
                 wctx.sub(s).merge(r)
-                sm[s] = l
+                sm[s] = cleanl
         elif l == a: # remote removed, local unchanged
             debug(s, "remote removed, remove")
             wctx.sub(s).remove()
@@ -111,8 +112,23 @@
         if s in s1:
             continue
         elif s not in sa:
-            debug(s, "remote added, get", r)
-            mctx.sub(s).get(r)
+            # is the working dir dirty?
+            if r[2] == 'hg':
+                dirty = mctx.sub(s)._repo[None].dirty()
+            elif r[2] == 'svn':
+                try:
+                    dirty = mctx.sub(s)._wcchanged()[0]
+                except Exception:
+                    dirty = False
+            else:
+                raise util.Abort(
+                    _('do not know how to get working dir state of %s') % 
s)
+            if dirty:
+                debug(s, "remote added, merge modified local with", r)
+                mctx.sub(s).merge(r)
+            else:
+                debug(s, "remote added, get", r)
+                mctx.sub(s).get(r)
             sm[s] = r
         elif r != sa[s]:
             if repo.ui.promptchoice(
diff --git a/tests/test-subrepo b/tests/test-subrepo
--- a/tests/test-subrepo
+++ b/tests/test-subrepo
@@ -33,6 +33,18 @@
 
 echo % leave sub dirty
 echo c > s/a
+echo '% check .hgsubstate contains no id with +'
+hg up 2
+cat .hgsubstate
+hg debugsub
+hg up 3
+hg id s
+cat .hgsubstate
+hg up 0
+hg id s
+hg up 3
+hg id s
+cat .hgsubstate
 hg ci -m4
 hg tip -R s
 
diff --git a/tests/test-subrepo.out b/tests/test-subrepo.out
--- a/tests/test-subrepo.out
+++ b/tests/test-subrepo.out
@@ -9,6 +9,24 @@
 % bump sub rev
 committing subrepository s
 % leave sub dirty
+% check .hgsubstate contains no id with +
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
+path s
+ source   s
+ revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+fc627a69481f+ tip
+fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
+ local changed .hgsubstate which remote deleted
+use (c)hanged version or (d)elete? c
+0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+fc627a69481f+ tip
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+fc627a69481f+ tip
+fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
 committing subrepository s
 changeset:   3:1c833a7a9e3a
 tag:         tip
msg12193 (view) Author: kuk Date: 2010-03-31.20:09:49
Due to network problems the patch was not uploaded.
msg12192 (view) Author: kuk Date: 2010-03-31.20:00:40
The attached patch
1. prevents the corruption of .hgsubstate by dirty ids and thus allows to 
update a modified subrepo to another state
2. lets the first conditional, line 75 in mercurial/subrepo.py match
3. prevents the overwriting of a modified subrepo by the original state of 
the remote.

The latter is due to the first fix.  The submerge function checked whether 
the  subrepo was in the ancestor state, however, it did not check whether 
the working dir of the subrepo was dirty.  Hence, the subrepo was 
overwritten by mctx.sub(s).get(r) and all modified files were reset to their 
original content.  The patch checks for a dirty working dir and uses 
mctx.sub(s).merge(r), if the working dir is dirty.

My understanding is quite limited, but it seems that subrepo classes need a 
new method for checking the state of the working dir, only.  The current 
method dirty checks for working dir state and state vs. current stored 
state.
msg12189 (view) Author: kuk Date: 2010-03-29.23:16:56
This patch fixes both the corruption of .hgsubstate by dirty ids and an 
obvious bug in mercurial/subrepos.py line 75, first conditional.

It does not resolve the situation happening when we do in test-subrepo

hg up 0
hg debugsub
rm .hgsubstate
hg debugsub
hg up 3

right after

echo '% check .hgsubstate contains no id with +'
hg up 2
hg debugsub
hg up 3
hg debugsub

inserted by the patch.


# HG changeset patch
# User Klaus Koch <kuk42@gmx.net>
# Date 1269892800 -7200
# Branch stable
# Node ID 6ace3f862c67d3e36aaba9cd89b001867c4ef7e7
# Parent  716e76f89e3a3073c49ed0329779c210b9529e38
subrepo: prevent dirty ids in .hgsubstate (issue2076), and fix never 
matching condition

diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -67,13 +67,14 @@
         repo.ui.debug("  subrepo %s: %s %s\n" % (s, msg, r))
 
     for s, l in s1.items():
+        cleanl = l[:]
         if wctx != actx and wctx.sub(s).dirty():
-            l = (l[0], l[1] + "+")
+            l = (l[0], l[1] + "+", 'hg')
         a = sa.get(s, nullstate)
         if s in s2:
             r = s2[s]
-            if l == r or r == a: # no change or local is newer
-                sm[s] = l
+            if cleanl == r or r == a: # no change or local is newer
+                sm[s] = cleanl
                 continue
             elif l == a: # other side changed
                 debug(s, "other changed, get", r)
@@ -95,7 +96,7 @@
             else:
                 debug(s, "both sides changed, merge with", r)
                 wctx.sub(s).merge(r)
-                sm[s] = l
+                sm[s] = cleanl
         elif l == a: # remote removed, local unchanged
             debug(s, "remote removed, remove")
             wctx.sub(s).remove()
diff --git a/tests/test-subrepo b/tests/test-subrepo
--- a/tests/test-subrepo
+++ b/tests/test-subrepo
@@ -33,6 +33,11 @@
 
 echo % leave sub dirty
 echo c > s/a
+echo '% check .hgsubstate contains no id with +'
+hg up 2
+hg debugsub
+hg up 3
+hg debugsub
 hg ci -m4
 hg tip -R s
 
diff --git a/tests/test-subrepo.out b/tests/test-subrepo.out
--- a/tests/test-subrepo.out
+++ b/tests/test-subrepo.out
@@ -9,6 +9,15 @@
 % bump sub rev
 committing subrepository s
 % leave sub dirty
+% check .hgsubstate contains no id with +
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+path s
+ source   s
+ revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+path s
+ source   s
+ revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
 committing subrepository s
 changeset:   3:1c833a7a9e3a
 tag:         tip
msg11907 (view) Author: tonfa Date: 2010-03-01.18:47:18
I think nullid for an hg subrepo should act as if the repo didn't exist.
msg11901 (view) Author: kuk Date: 2010-03-01.14:04:07
A modified file in the subrepository causes 'hg update' to write the
subrepository's sha1 with a plus added at the end (just as the output of 'hg
id <subrepo>) and to miss to update the subrepo.  This happens when the
update is done to a revision before or after the working dir parent.

See the attached file for a demonstration.

A workaround is to revert the .hgsubstate file and update *again* to the
working dir parent.
History
Date User Action Args
2010-07-15 10:13:05mgsetstatus: chatting -> resolved
nosy: mpm, tonfa, mg, ede, kuk
2010-07-15 10:10:41mglinkissue2217 superseder
2010-07-15 10:10:35mgsetnosy: mpm, tonfa, mg, ede, kuk
messages: + msg13104
2010-07-15 10:00:18mgsetnosy: + mg
2010-03-31 20:25:04kuksetnosy: mpm, tonfa, ede, kuk
messages: + msg12194
2010-03-31 20:09:49kuksetnosy: mpm, tonfa, ede, kuk
messages: + msg12193
2010-03-31 20:00:41kuksetnosy: mpm, tonfa, ede, kuk
messages: + msg12192
2010-03-29 23:16:56kuksetnosy: mpm, tonfa, ede, kuk
messages: + msg12189
2010-03-05 20:15:51edesetnosy: + ede
2010-03-01 18:47:23tonfasetnosy: + mpm
2010-03-01 18:47:18tonfasetstatus: unread -> chatting
nosy: + tonfa
messages: + msg11907
2010-03-01 14:04:08kukcreate