diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -526,7 +526,7 @@ class svnsubrepo(abstractsubrepo): self._ctx = ctx self._ui = ctx._repo.ui - def _svncommand(self, commands, filename=''): + def _svncommand(self, commands, filename='', failok=False): cmd = ['svn'] extrakw = {} if not self._ui.interactive(): @@ -551,15 +551,16 @@ class svnsubrepo(abstractsubrepo): universal_newlines=True, env=env, **extrakw) stdout, stderr = p.communicate() stderr = stderr.strip() - if p.returncode: - raise util.Abort(stderr or 'exited with code %d' % p.returncode) - if stderr: - self._ui.warn(stderr + '\n') - return stdout + if not failok: + if p.returncode: + raise util.Abort(stderr or 'exited with code %d' % p.returncode) + if stderr: + self._ui.warn(stderr + '\n') + return stdout, stderr @propertycache def _svnversion(self): - output = self._svncommand(['--version'], filename=None) + output, err = self._svncommand(['--version'], filename=None) m = re.search(r'^svn,\s+version\s+(\d+)\.(\d+)', output) if not m: raise util.Abort(_('cannot retrieve svn tool version')) @@ -569,7 +570,7 @@ class svnsubrepo(abstractsubrepo): # Get the working directory revision as well as the last # commit revision so we can compare the subrepo state with # both. We used to store the working directory one. - output = self._svncommand(['info', '--xml']) + output, err = self._svncommand(['info', '--xml']) doc = xml.dom.minidom.parseString(output) entries = doc.getElementsByTagName('entry') lastrev, rev = '0', '0' @@ -588,7 +589,7 @@ class svnsubrepo(abstractsubrepo): if the working directory was changed, and extchanges is True if any of these changes concern an external entry. """ - output = self._svncommand(['status', '--xml']) + output, err = self._svncommand(['status', '--xml']) externals, changes = [], [] doc = xml.dom.minidom.parseString(output) for e in doc.getElementsByTagName('entry'): @@ -623,13 +624,13 @@ class svnsubrepo(abstractsubrepo): if extchanged: # Do not try to commit externals raise util.Abort(_('cannot commit svn externals')) - commitinfo = self._svncommand(['commit', '-m', text]) + commitinfo, err = self._svncommand(['commit', '-m', text]) self._ui.status(commitinfo) newrev = re.search('Committed revision ([0-9]+).', commitinfo) if not newrev: raise util.Abort(commitinfo.splitlines()[-1]) newrev = newrev.groups()[0] - self._ui.status(self._svncommand(['update', '-r', newrev])) + self._ui.status(self._svncommand(['update', '-r', newrev])[0]) return newrev def remove(self): @@ -663,9 +664,15 @@ class svnsubrepo(abstractsubrepo): if self._svnversion >= (1, 5): args.append('--force') args.extend([state[0], '--revision', state[1]]) - status = self._svncommand(args) + status, err = self._svncommand(args, failok=True) if not re.search('Checked out revision [0-9]+.', status): - raise util.Abort(status.splitlines()[-1]) + if ('is already a working copy for a different URL' in err + and (self._wcchanged() == (False, False))): + # obstructed but clean working copy, so just blow it away. + self.remove() + self.get(state, overwrite=False) + return + raise util.Abort((status or err).splitlines()[-1]) self._ui.status(status) def merge(self, state): 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 @@ -489,3 +489,33 @@ are unknown directories being replaced b $ if "$TESTDIR/hghave" -q svn15; then > hg up 2 >/dev/null 2>&1 || echo update failed > fi + +Modify one of the externals to point to a different path so we can +test having obstructions when switching branches on checkout: + $ hg checkout tip + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo "obstruct = [svn] $SVNREPO/externals" >> .hgsub + $ svn co -r5 --quiet "$SVNREPO"/externals obstruct + $ hg commit -m 'Start making obstructed wc' + committing subrepository obstruct + $ hg book other + $ hg co -r 'p1(tip)' + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo "obstruct = [svn] $SVNREPO/src" >> .hgsub + $ svn co -r5 --quiet "$SVNREPO"/src obstruct + $ hg commit -m 'Other branch which will be obstructed' + committing subrepository obstruct + created new head + +Switching back to the head where we have another path mapped to the +same subrepo should work if the subrepo is clean. + $ hg co other + A $TESTTMP/rebaserepo/obstruct/other + Checked out revision 1. + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + +This is surprising, but is also correct based on the current code: + $ echo "updating should (maybe) fail" > obstruct/other + $ hg co tip + abort: crosses branches (merge branches or use --clean to discard changes) + [255]