Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/subrepo.py @ 13417:0748e18be470
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)?
author | Erik Zielke <ez@aragost.com> |
---|---|
date | Wed, 09 Feb 2011 10:53:09 +0100 |
parents | fa921dcd9993 |
children | 5ef29e0dd418 |
comparison
equal
deleted
inserted
replaced
13416:5431b3f3e52e | 13417:0748e18be470 |
---|---|
161 sm[s] = r | 161 sm[s] = r |
162 | 162 |
163 # record merged .hgsubstate | 163 # record merged .hgsubstate |
164 writestate(repo, sm) | 164 writestate(repo, sm) |
165 | 165 |
166 def _updateprompt(ui, sub, dirty, local, remote): | |
167 if dirty: | |
168 msg = (_(' subrepository sources for %s differ\n' | |
169 'use (l)ocal source (%s) or (r)emote source (%s)?\n') | |
170 % (subrelpath(sub), local, remote)) | |
171 else: | |
172 msg = (_(' subrepository sources for %s differ (in checked out version)\n' | |
173 'use (l)ocal source (%s) or (r)emote source (%s)?\n') | |
174 % (subrelpath(sub), local, remote)) | |
175 return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0) | |
176 | |
166 def reporelpath(repo): | 177 def reporelpath(repo): |
167 """return path to this (sub)repo as seen from outermost repo""" | 178 """return path to this (sub)repo as seen from outermost repo""" |
168 parent = repo | 179 parent = repo |
169 while hasattr(parent, '_subparent'): | 180 while hasattr(parent, '_subparent'): |
170 parent = parent._subparent | 181 parent = parent._subparent |
440 def merge(self, state): | 451 def merge(self, state): |
441 self._get(state) | 452 self._get(state) |
442 cur = self._repo['.'] | 453 cur = self._repo['.'] |
443 dst = self._repo[state[1]] | 454 dst = self._repo[state[1]] |
444 anc = dst.ancestor(cur) | 455 anc = dst.ancestor(cur) |
445 if anc == cur: | 456 |
446 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self)) | 457 def mergefunc(): |
447 hg.update(self._repo, state[1]) | 458 if anc == cur: |
448 elif anc == dst: | 459 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self)) |
449 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self)) | 460 hg.update(self._repo, state[1]) |
461 elif anc == dst: | |
462 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self)) | |
463 else: | |
464 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self)) | |
465 hg.merge(self._repo, state[1], remind=False) | |
466 | |
467 wctx = self._repo[None] | |
468 if self.dirty(): | |
469 if anc != dst: | |
470 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst): | |
471 mergefunc() | |
472 else: | |
473 mergefunc() | |
450 else: | 474 else: |
451 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self)) | 475 mergefunc() |
452 hg.merge(self._repo, state[1], remind=False) | |
453 | 476 |
454 def push(self, force): | 477 def push(self, force): |
455 # push subrepos depth-first for coherent ordering | 478 # push subrepos depth-first for coherent ordering |
456 c = self._repo[''] | 479 c = self._repo[''] |
457 subs = c.substate # only repos that are committed | 480 subs = c.substate # only repos that are committed |
606 if not re.search('Checked out revision [0-9]+.', status): | 629 if not re.search('Checked out revision [0-9]+.', status): |
607 raise util.Abort(status.splitlines()[-1]) | 630 raise util.Abort(status.splitlines()[-1]) |
608 self._ui.status(status) | 631 self._ui.status(status) |
609 | 632 |
610 def merge(self, state): | 633 def merge(self, state): |
611 old = int(self._state[1]) | 634 old = self._state[1] |
612 new = int(state[1]) | 635 new = state[1] |
613 if new > old: | 636 if new != self._wcrev(): |
614 self.get(state) | 637 dirty = old == self._wcrev() or self._wcchanged()[0] |
638 if _updateprompt(self._ui, self, dirty, self._wcrev(), new): | |
639 self.get(state, False) | |
615 | 640 |
616 def push(self, force): | 641 def push(self, force): |
617 # push is a no-op for SVN | 642 # push is a no-op for SVN |
618 return True | 643 return True |
619 | 644 |
848 | 873 |
849 def merge(self, state): | 874 def merge(self, state): |
850 source, revision, kind = state | 875 source, revision, kind = state |
851 self._fetch(source, revision) | 876 self._fetch(source, revision) |
852 base = self._gitcommand(['merge-base', revision, self._state[1]]) | 877 base = self._gitcommand(['merge-base', revision, self._state[1]]) |
853 if base == revision: | 878 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD']) |
854 self.get(state) # fast forward merge | 879 |
855 elif base != self._state[1]: | 880 def mergefunc(): |
856 self._gitcommand(['merge', '--no-commit', revision]) | 881 if base == revision: |
882 self.get(state) # fast forward merge | |
883 elif base != self._state[1]: | |
884 self._gitcommand(['merge', '--no-commit', revision]) | |
885 | |
886 if self.dirty(): | |
887 if self._gitstate() != revision: | |
888 dirty = self._gitstate() == self._state[1] or code != 0 | |
889 if _updateprompt(self._ui, self, dirty, self._state[1], revision): | |
890 mergefunc() | |
891 else: | |
892 mergefunc() | |
857 | 893 |
858 def push(self, force): | 894 def push(self, force): |
859 # if a branch in origin contains the revision, nothing to do | 895 # if a branch in origin contains the revision, nothing to do |
860 branch2rev, rev2branch = self._gitbranchmap() | 896 branch2rev, rev2branch = self._gitbranchmap() |
861 if self._state[1] in rev2branch: | 897 if self._state[1] in rev2branch: |