diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1764,9 +1764,29 @@ class localrepository(object): unfi = self.unfiltered() def localphasemove(nodes, phase=phases.public): """move to in the local source repo""" - phases.advanceboundary(self, phase, nodes) + if locallock is not None: + phases.advanceboundary(self, phase, nodes) + else: + # repo is not locked, do not change any phases! + # Informs the user that phases should have been moved when + # applicable. + actualmoves = [n for n in nodes if phase < self[n].phase()] + phasestr = phases.phasenames[phase] + if actualmoves: + self.ui.status(_('cannot lock source repo, skipping local' + ' %s phase update\n') % phasestr) # get local lock as we might write phase data - locallock = self.lock() + locallock = None + try: + locallock = self.lock() + except IOError, err: + if err.errno != errno.EACCES: + raise + # source repo cannot be locked. + # We do not abort the push, but just disable the local phase + # synchronisation. + msg = 'cannot lock source repository: %s\n' % err + self.ui.debug(msg) try: self.checkpush(force, revs) lock = None @@ -1918,7 +1938,8 @@ class localrepository(object): if lock is not None: lock.release() finally: - locallock.release() + if locallock is not None: + locallock.release() self.ui.debug("checking for updated bookmarks\n") rb = remote.listkeys('bookmarks') diff --git a/tests/test-phases-exchange.t b/tests/test-phases-exchange.t --- a/tests/test-phases-exchange.t +++ b/tests/test-phases-exchange.t @@ -1062,5 +1062,43 @@ 2. cloning publishing repository | o 0 public a-A - 054250a37db4 + +Pushing From an unlockable repo +-------------------------------- +(issue3684) + +Unability to lock the source repo should not prevent the push. It will prevent +the retrieval of remote phase during push. For example, pushing to a publishing +server won't turn changeset public. + +1. Test that push is not prevented + + $ hg init Phi + $ cd Upsilon + $ chmod -R -w .hg + $ hg push ../Phi + pushing to ../Phi + searching for changes + adding changesets + adding manifests + adding file changes + added 14 changesets with 14 changes to 14 files (+3 heads) + $ chmod -R +w .hg + +2. Test that failed phases movement are reported + + $ hg phase --force --draft 3 + $ chmod -R -w .hg + $ hg push ../Phi + pushing to ../Phi + searching for changes + no changes found + cannot lock source repo, skipping local public phase update + [1] + $ chmod -R +w .hg + $ hgph Upsilon + + $ cd .. + $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS