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