##// END OF EJS Templates
destupdate: extract logic based on bookmarks in its own function...
Pierre-Yves David -
r26724:7fc759c0 default
parent child Browse files
Show More
@@ -1,167 +1,173 b''
1 # destutil.py - Mercurial utility function for command destination
1 # destutil.py - Mercurial utility function for command destination
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com> and other
3 # Copyright Matt Mackall <mpm@selenic.com> and other
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from .i18n import _
8 from .i18n import _
9 from . import (
9 from . import (
10 bookmarks,
10 bookmarks,
11 error,
11 error,
12 obsolete,
12 obsolete,
13 )
13 )
14
14
15 def _destupdatevalidate(repo, rev, clean, check):
15 def _destupdatevalidate(repo, rev, clean, check):
16 """validate that the destination comply to various rules
16 """validate that the destination comply to various rules
17
17
18 This exists as its own function to help wrapping from extensions."""
18 This exists as its own function to help wrapping from extensions."""
19 wc = repo[None]
19 wc = repo[None]
20 p1 = wc.p1()
20 p1 = wc.p1()
21 if not clean:
21 if not clean:
22 # Check that the update is linear.
22 # Check that the update is linear.
23 #
23 #
24 # Mercurial do not allow update-merge for non linear pattern
24 # Mercurial do not allow update-merge for non linear pattern
25 # (that would be technically possible but was considered too confusing
25 # (that would be technically possible but was considered too confusing
26 # for user a long time ago)
26 # for user a long time ago)
27 #
27 #
28 # See mercurial.merge.update for details
28 # See mercurial.merge.update for details
29 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
29 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
30 dirty = wc.dirty(missing=True)
30 dirty = wc.dirty(missing=True)
31 foreground = obsolete.foreground(repo, [p1.node()])
31 foreground = obsolete.foreground(repo, [p1.node()])
32 if not repo[rev].node() in foreground:
32 if not repo[rev].node() in foreground:
33 if dirty:
33 if dirty:
34 msg = _("uncommitted changes")
34 msg = _("uncommitted changes")
35 hint = _("commit and merge, or update --clean to"
35 hint = _("commit and merge, or update --clean to"
36 " discard changes")
36 " discard changes")
37 raise error.UpdateAbort(msg, hint=hint)
37 raise error.UpdateAbort(msg, hint=hint)
38 elif not check: # destination is not a descendant.
38 elif not check: # destination is not a descendant.
39 msg = _("not a linear update")
39 msg = _("not a linear update")
40 hint = _("merge or update --check to force update")
40 hint = _("merge or update --check to force update")
41 raise error.UpdateAbort(msg, hint=hint)
41 raise error.UpdateAbort(msg, hint=hint)
42
42
43 def _destupdateobs(repo, clean, check):
43 def _destupdateobs(repo, clean, check):
44 """decide of an update destination from obsolescence markers"""
44 """decide of an update destination from obsolescence markers"""
45 node = None
45 node = None
46 wc = repo[None]
46 wc = repo[None]
47 p1 = wc.p1()
47 p1 = wc.p1()
48 movemark = None
48 movemark = None
49
49
50 if p1.obsolete() and not p1.children():
50 if p1.obsolete() and not p1.children():
51 # allow updating to successors
51 # allow updating to successors
52 successors = obsolete.successorssets(repo, p1.node())
52 successors = obsolete.successorssets(repo, p1.node())
53
53
54 # behavior of certain cases is as follows,
54 # behavior of certain cases is as follows,
55 #
55 #
56 # divergent changesets: update to highest rev, similar to what
56 # divergent changesets: update to highest rev, similar to what
57 # is currently done when there are more than one head
57 # is currently done when there are more than one head
58 # (i.e. 'tip')
58 # (i.e. 'tip')
59 #
59 #
60 # replaced changesets: same as divergent except we know there
60 # replaced changesets: same as divergent except we know there
61 # is no conflict
61 # is no conflict
62 #
62 #
63 # pruned changeset: no update is done; though, we could
63 # pruned changeset: no update is done; though, we could
64 # consider updating to the first non-obsolete parent,
64 # consider updating to the first non-obsolete parent,
65 # similar to what is current done for 'hg prune'
65 # similar to what is current done for 'hg prune'
66
66
67 if successors:
67 if successors:
68 # flatten the list here handles both divergent (len > 1)
68 # flatten the list here handles both divergent (len > 1)
69 # and the usual case (len = 1)
69 # and the usual case (len = 1)
70 successors = [n for sub in successors for n in sub]
70 successors = [n for sub in successors for n in sub]
71
71
72 # get the max revision for the given successors set,
72 # get the max revision for the given successors set,
73 # i.e. the 'tip' of a set
73 # i.e. the 'tip' of a set
74 node = repo.revs('max(%ln)', successors).first()
74 node = repo.revs('max(%ln)', successors).first()
75 if bookmarks.isactivewdirparent(repo):
75 if bookmarks.isactivewdirparent(repo):
76 movemark = repo['.'].node()
76 movemark = repo['.'].node()
77 return node, movemark, None
77 return node, movemark, None
78
78
79 def _destupdatebook(repo, clean, check):
80 """decide on an update destination from active bookmark"""
81 # we also move the active bookmark, if any
82 activemark = None
83 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
84 if node is not None:
85 activemark = node
86 return node, movemark, activemark
87
79 def destupdate(repo, clean=False, check=False):
88 def destupdate(repo, clean=False, check=False):
80 """destination for bare update operation
89 """destination for bare update operation
81
90
82 return (rev, movemark, activemark)
91 return (rev, movemark, activemark)
83
92
84 - rev: the revision to update to,
93 - rev: the revision to update to,
85 - movemark: node to move the active bookmark from
94 - movemark: node to move the active bookmark from
86 (cf bookmark.calculate update),
95 (cf bookmark.calculate update),
87 - activemark: a bookmark to activate at the end of the update.
96 - activemark: a bookmark to activate at the end of the update.
88 """
97 """
89 node = None
98 node = None
90 wc = repo[None]
99 wc = repo[None]
91 movemark = activemark = None
100 movemark = activemark = None
92
101
93 node, movemark, activemark = _destupdateobs(repo, clean, check)
102 node, movemark, activemark = _destupdateobs(repo, clean, check)
103 if node is None:
104 node, movemark, activemark = _destupdatebook(repo, clean, check)
94
105
95 if node is None:
106 if node is None:
96 # we also move the active bookmark, if any
97 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
98 if node is not None:
99 activemark = node
100
101 if node is None:
107 if node is None:
102 try:
108 try:
103 node = repo.branchtip(wc.branch())
109 node = repo.branchtip(wc.branch())
104 except error.RepoLookupError:
110 except error.RepoLookupError:
105 if wc.branch() == 'default': # no default branch!
111 if wc.branch() == 'default': # no default branch!
106 node = repo.lookup('tip') # update to tip
112 node = repo.lookup('tip') # update to tip
107 else:
113 else:
108 raise error.Abort(_("branch %s not found") % wc.branch())
114 raise error.Abort(_("branch %s not found") % wc.branch())
109 rev = repo[node].rev()
115 rev = repo[node].rev()
110
116
111 _destupdatevalidate(repo, rev, clean, check)
117 _destupdatevalidate(repo, rev, clean, check)
112
118
113 return rev, movemark, activemark
119 return rev, movemark, activemark
114
120
115 def destmerge(repo):
121 def destmerge(repo):
116 if repo._activebookmark:
122 if repo._activebookmark:
117 bmheads = repo.bookmarkheads(repo._activebookmark)
123 bmheads = repo.bookmarkheads(repo._activebookmark)
118 curhead = repo[repo._activebookmark].node()
124 curhead = repo[repo._activebookmark].node()
119 if len(bmheads) == 2:
125 if len(bmheads) == 2:
120 if curhead == bmheads[0]:
126 if curhead == bmheads[0]:
121 node = bmheads[1]
127 node = bmheads[1]
122 else:
128 else:
123 node = bmheads[0]
129 node = bmheads[0]
124 elif len(bmheads) > 2:
130 elif len(bmheads) > 2:
125 raise error.Abort(_("multiple matching bookmarks to merge - "
131 raise error.Abort(_("multiple matching bookmarks to merge - "
126 "please merge with an explicit rev or bookmark"),
132 "please merge with an explicit rev or bookmark"),
127 hint=_("run 'hg heads' to see all heads"))
133 hint=_("run 'hg heads' to see all heads"))
128 elif len(bmheads) <= 1:
134 elif len(bmheads) <= 1:
129 raise error.Abort(_("no matching bookmark to merge - "
135 raise error.Abort(_("no matching bookmark to merge - "
130 "please merge with an explicit rev or bookmark"),
136 "please merge with an explicit rev or bookmark"),
131 hint=_("run 'hg heads' to see all heads"))
137 hint=_("run 'hg heads' to see all heads"))
132 else:
138 else:
133 branch = repo[None].branch()
139 branch = repo[None].branch()
134 bheads = repo.branchheads(branch)
140 bheads = repo.branchheads(branch)
135 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
141 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
136
142
137 if len(nbhs) > 2:
143 if len(nbhs) > 2:
138 raise error.Abort(_("branch '%s' has %d heads - "
144 raise error.Abort(_("branch '%s' has %d heads - "
139 "please merge with an explicit rev")
145 "please merge with an explicit rev")
140 % (branch, len(bheads)),
146 % (branch, len(bheads)),
141 hint=_("run 'hg heads .' to see heads"))
147 hint=_("run 'hg heads .' to see heads"))
142
148
143 parent = repo.dirstate.p1()
149 parent = repo.dirstate.p1()
144 if len(nbhs) <= 1:
150 if len(nbhs) <= 1:
145 if len(bheads) > 1:
151 if len(bheads) > 1:
146 raise error.Abort(_("heads are bookmarked - "
152 raise error.Abort(_("heads are bookmarked - "
147 "please merge with an explicit rev"),
153 "please merge with an explicit rev"),
148 hint=_("run 'hg heads' to see all heads"))
154 hint=_("run 'hg heads' to see all heads"))
149 if len(repo.heads()) > 1:
155 if len(repo.heads()) > 1:
150 raise error.Abort(_("branch '%s' has one head - "
156 raise error.Abort(_("branch '%s' has one head - "
151 "please merge with an explicit rev")
157 "please merge with an explicit rev")
152 % branch,
158 % branch,
153 hint=_("run 'hg heads' to see all heads"))
159 hint=_("run 'hg heads' to see all heads"))
154 msg, hint = _('nothing to merge'), None
160 msg, hint = _('nothing to merge'), None
155 if parent != repo.lookup(branch):
161 if parent != repo.lookup(branch):
156 hint = _("use 'hg update' instead")
162 hint = _("use 'hg update' instead")
157 raise error.Abort(msg, hint=hint)
163 raise error.Abort(msg, hint=hint)
158
164
159 if parent not in bheads:
165 if parent not in bheads:
160 raise error.Abort(_('working directory not at a head revision'),
166 raise error.Abort(_('working directory not at a head revision'),
161 hint=_("use 'hg update' or merge with an "
167 hint=_("use 'hg update' or merge with an "
162 "explicit revision"))
168 "explicit revision"))
163 if parent == nbhs[0]:
169 if parent == nbhs[0]:
164 node = nbhs[-1]
170 node = nbhs[-1]
165 else:
171 else:
166 node = nbhs[0]
172 node = nbhs[0]
167 return repo[node].rev()
173 return repo[node].rev()
General Comments 0
You need to be logged in to leave comments. Login now