diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -163,6 +163,17 @@ def submerge(repo, wctx, mctx, actx, ove # 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 @@ class hgsubrepo(abstractsubrepo): 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 @@ class svnsubrepo(abstractsubrepo): 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 @@ class gitsubrepo(abstractsubrepo): 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 diff --git a/tests/test-subrepo-git.t b/tests/test-subrepo-git.t --- a/tests/test-subrepo-git.t +++ b/tests/test-subrepo-git.t @@ -329,3 +329,117 @@ Check hg update --clean 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 .. + diff --git a/tests/test-subrepo-svn.t b/tests/test-subrepo-svn.t --- a/tests/test-subrepo-svn.t +++ b/tests/test-subrepo-svn.t @@ -296,3 +296,145 @@ Check hg update --clean ? * 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 .. diff --git a/tests/test-subrepo.t b/tests/test-subrepo.t --- a/tests/test-subrepo.t +++ b/tests/test-subrepo.t @@ -706,3 +706,125 @@ Check hg update --clean $ 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