subrepos: prompt on conflicts on update with dirty subrepos
Consider a repository with a single subrepository. The changesets in
the main repository reference the subrepository changesets like this:
m0 -> s0
m1 -> s1
m2 -> s2
Starting from a state (m1, s0), doing 'hg update m2' in the main
repository will yield a conflict: the subrepo is at revision s0 but
the target revision says it should be at revision s2.
Before this change, Mercurial would do (m1, s0) -> (m2, s2) and thus
ignore the conflict between the working copy and the target revision.
With this change, the user is prompted to resolve the conflict by
choosing which revision he wants. This is consistent with 'hg merge',
which also prompts the user when it detects conflicts in the merged
.hgsubstate files.
The prompt looks like this:
$ hg update tip
subrepository sources for my-subrepo differ
use (l)ocal source (
fc627a69481f) or (r)emote source (
12a213df6fa9)?
--- a/mercurial/subrepo.py Wed Feb 16 01:29:26 2011 +0100
+++ b/mercurial/subrepo.py Wed Feb 09 10:53:09 2011 +0100
@@ -163,6 +163,17 @@
# record merged .hgsubstate
writestate(repo, sm)
+def _updateprompt(ui, sub, dirty, local, remote):
+ if dirty:
+ msg = (_(' subrepository sources for %s differ\n'
+ 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
+ % (subrelpath(sub), local, remote))
+ else:
+ msg = (_(' subrepository sources for %s differ (in checked out version)\n'
+ 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
+ % (subrelpath(sub), local, remote))
+ return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0)
+
def reporelpath(repo):
"""return path to this (sub)repo as seen from outermost repo"""
parent = repo
@@ -442,14 +453,26 @@
cur = self._repo['.']
dst = self._repo[state[1]]
anc = dst.ancestor(cur)
- if anc == cur:
- self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
- hg.update(self._repo, state[1])
- elif anc == dst:
- self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
+
+ def mergefunc():
+ if anc == cur:
+ self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
+ hg.update(self._repo, state[1])
+ elif anc == dst:
+ self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
+ else:
+ self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
+ hg.merge(self._repo, state[1], remind=False)
+
+ wctx = self._repo[None]
+ if self.dirty():
+ if anc != dst:
+ if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
+ mergefunc()
+ else:
+ mergefunc()
else:
- self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
- hg.merge(self._repo, state[1], remind=False)
+ mergefunc()
def push(self, force):
# push subrepos depth-first for coherent ordering
@@ -608,10 +631,12 @@
self._ui.status(status)
def merge(self, state):
- old = int(self._state[1])
- new = int(state[1])
- if new > old:
- self.get(state)
+ old = self._state[1]
+ new = state[1]
+ if new != self._wcrev():
+ dirty = old == self._wcrev() or self._wcchanged()[0]
+ if _updateprompt(self._ui, self, dirty, self._wcrev(), new):
+ self.get(state, False)
def push(self, force):
# push is a no-op for SVN
@@ -850,10 +875,21 @@
source, revision, kind = state
self._fetch(source, revision)
base = self._gitcommand(['merge-base', revision, self._state[1]])
- if base == revision:
- self.get(state) # fast forward merge
- elif base != self._state[1]:
- self._gitcommand(['merge', '--no-commit', revision])
+ out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
+
+ def mergefunc():
+ if base == revision:
+ self.get(state) # fast forward merge
+ elif base != self._state[1]:
+ self._gitcommand(['merge', '--no-commit', revision])
+
+ if self.dirty():
+ if self._gitstate() != revision:
+ dirty = self._gitstate() == self._state[1] or code != 0
+ if _updateprompt(self._ui, self, dirty, self._state[1], revision):
+ mergefunc()
+ else:
+ mergefunc()
def push(self, force):
# if a branch in origin contains the revision, nothing to do
--- a/tests/test-subrepo-git.t Wed Feb 16 01:29:26 2011 +0100
+++ b/tests/test-subrepo-git.t Wed Feb 09 10:53:09 2011 +0100
@@ -329,3 +329,117 @@
f1
f2
g
+
+Sticky subrepositories, no changes
+ $ cd $TESTTMP/ta
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+ $ hg update 1 > /dev/null 2>&1
+ $ hg id -n
+ 1
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ cd s
+ $ git add f1
+ $ cd ..
+ $ hg id -n
+ 1
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+ $ hg update 4
+ subrepository sources for s differ
+ use (l)ocal source (da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7) or (r)emote source (aa84837ccfbdfedcdcdeeedc309d73e6eb069edc)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 4+
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+ $ hg update --clean tip > /dev/null 2>&1
+
+Sticky subrepository, revision updates
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+ $ cd s
+ $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ Previous HEAD position was 32a3438... fff
+ HEAD is now at aa84837... f
+ $ cd ..
+ $ hg update 1
+ subrepository sources for s differ (in checked out version)
+ use (l)ocal source (32a343883b74769118bb1d3b4b1fbf9156f4dddc) or (r)emote source (da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ cd s
+ $ git add f1
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+ $ hg id -n
+ 1+
+ $ hg update 7
+ subrepository sources for s differ
+ use (l)ocal source (32a343883b74769118bb1d3b4b1fbf9156f4dddc) or (r)emote source (32a343883b74769118bb1d3b4b1fbf9156f4dddc)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+
+Sticky repository, update --clean
+ $ hg update --clean tip
+ Previous HEAD position was aa84837... f
+ HEAD is now at 32a3438... fff
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ HEAD is now at 32a3438... fff
+ $ cd ..
+ $ hg update 1
+ Previous HEAD position was 32a3438... fff
+ HEAD is now at da5f5b1... g
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+
--- a/tests/test-subrepo-svn.t Wed Feb 16 01:29:26 2011 +0100
+++ b/tests/test-subrepo-svn.t Wed Feb 09 10:53:09 2011 +0100
@@ -296,3 +296,145 @@
? * f2 (glob)
Performing status on external item at 'externals'
+
+Sticky subrepositories, no changes
+ $ cd $TESTTMP/sub/t
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+ $ hg update 1
+ U $TESTTMP/sub/t/s/alpha
+
+ Fetching external item into '$TESTTMP/sub/t/s/externals'
+ Checked out external at revision 1.
+
+ Checked out revision 2.
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1
+ $ cd s
+ $ svnversion
+ 2
+ $ cd ..
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ cd s
+ $ svn add f1
+ A f1
+ $ cd ..
+ $ hg id -n
+ 1
+ $ cd s
+ $ svnversion
+ 2M
+ $ cd ..
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (2) or (r)emote source (3)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2+
+ $ cd s
+ $ svnversion
+ 2M
+ $ cd ..
+ $ hg update --clean tip
+ U $TESTTMP/sub/t/s/alpha
+
+ Fetching external item into '$TESTTMP/sub/t/s/externals'
+ Checked out external at revision 1.
+
+ Checked out revision 3.
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Sticky subrepository, revision updates
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+ $ cd s
+ $ svn update -r 1
+ U alpha
+ U .
+
+ Fetching external item into 'externals'
+ Updated external to revision 1.
+
+ Updated to revision 1.
+ $ cd ..
+ $ hg update 1
+ subrepository sources for s differ (in checked out version)
+ use (l)ocal source (1) or (r)emote source (2)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ svnversion
+ 1
+ $ cd ..
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ cd s
+ $ svn add f1
+ A f1
+ $ svnversion
+ 1M
+ $ cd ..
+ $ hg id -n
+ 1+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (1) or (r)emote source (3)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 1M
+ $ cd ..
+
+Sticky repository, update --clean
+ $ hg update --clean tip
+ U $TESTTMP/sub/t/s/alpha
+ U $TESTTMP/sub/t/s
+
+ Fetching external item into '$TESTTMP/sub/t/s/externals'
+ Checked out external at revision 1.
+
+ Checked out revision 3.
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ svn update -r 2
+ U alpha
+
+ Fetching external item into 'externals'
+ Updated external to revision 1.
+
+ Updated to revision 2.
+ $ cd ..
+ $ hg update 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ svnversion
+ 2
+ $ cd ..
--- a/tests/test-subrepo.t Wed Feb 16 01:29:26 2011 +0100
+++ b/tests/test-subrepo.t Wed Feb 09 10:53:09 2011 +0100
@@ -706,3 +706,125 @@
$ hg status -S
? s/b
? s/c
+
+Sticky subrepositories, no changes
+ $ cd $TESTTMP/sub/t
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+ $ hg update 11
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 365661e5936a
+ $ hg -R s id
+ fc627a69481f
+ $ hg -R t id
+ e95bcfa18a35
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ touch t/f1
+ $ hg add -S s/f1
+ $ hg add -S t/f1
+ $ hg id
+ 365661e5936a
+ $ hg -R s id
+ fc627a69481f+
+ $ hg -R t id
+ e95bcfa18a35+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
+ l
+ subrepository sources for t differ
+ use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8+ tip
+ $ hg -R s id
+ fc627a69481f+
+ $ hg -R t id
+ e95bcfa18a35+
+ $ hg update --clean tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Sticky subrepository, revision updates
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+ $ cd s
+ $ hg update -r -2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../t
+ $ hg update -r 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+ $ hg update 10
+ subrepository sources for t differ (in checked out version)
+ use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ e45c8b14af55+
+ $ hg -R s id
+ 1c833a7a9e3a
+ $ hg -R t id
+ 7af322bc1198
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ touch t/f1
+ $ hg add -S s/f1
+ $ hg add -S t/f1
+ $ hg id
+ e45c8b14af55+
+ $ hg -R s id
+ 1c833a7a9e3a+
+ $ hg -R t id
+ 7af322bc1198+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
+ l
+ subrepository sources for t differ
+ use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 1c833a7a9e3a+
+ $ hg -R t id
+ 7af322bc1198+
+
+Sticky repository, update --clean
+ $ hg update --clean tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ hg update fc627a69481f
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+ $ hg update 11
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 11+
+ $ hg -R s id
+ fc627a69481f
+ $ hg -R t id
+ e95bcfa18a35