##// END OF EJS Templates
destutil: choose non-closed branch head at first (BC)...
FUJIWARA Katsunori -
r28385:3f9e25a4 default
parent child Browse files
Show More
@@ -1,378 +1,422
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from .i18n import _
10 from .i18n import _
11 from . import (
11 from . import (
12 bookmarks,
12 bookmarks,
13 error,
13 error,
14 obsolete,
14 obsolete,
15 )
15 )
16
16
17 def _destupdatevalidate(repo, rev, clean, check):
17 def _destupdatevalidate(repo, rev, clean, check):
18 """validate that the destination comply to various rules
18 """validate that the destination comply to various rules
19
19
20 This exists as its own function to help wrapping from extensions."""
20 This exists as its own function to help wrapping from extensions."""
21 wc = repo[None]
21 wc = repo[None]
22 p1 = wc.p1()
22 p1 = wc.p1()
23 if not clean:
23 if not clean:
24 # Check that the update is linear.
24 # Check that the update is linear.
25 #
25 #
26 # Mercurial do not allow update-merge for non linear pattern
26 # Mercurial do not allow update-merge for non linear pattern
27 # (that would be technically possible but was considered too confusing
27 # (that would be technically possible but was considered too confusing
28 # for user a long time ago)
28 # for user a long time ago)
29 #
29 #
30 # See mercurial.merge.update for details
30 # See mercurial.merge.update for details
31 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
31 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
32 dirty = wc.dirty(missing=True)
32 dirty = wc.dirty(missing=True)
33 foreground = obsolete.foreground(repo, [p1.node()])
33 foreground = obsolete.foreground(repo, [p1.node()])
34 if not repo[rev].node() in foreground:
34 if not repo[rev].node() in foreground:
35 if dirty:
35 if dirty:
36 msg = _("uncommitted changes")
36 msg = _("uncommitted changes")
37 hint = _("commit and merge, or update --clean to"
37 hint = _("commit and merge, or update --clean to"
38 " discard changes")
38 " discard changes")
39 raise error.UpdateAbort(msg, hint=hint)
39 raise error.UpdateAbort(msg, hint=hint)
40 elif not check: # destination is not a descendant.
40 elif not check: # destination is not a descendant.
41 msg = _("not a linear update")
41 msg = _("not a linear update")
42 hint = _("merge or update --check to force update")
42 hint = _("merge or update --check to force update")
43 raise error.UpdateAbort(msg, hint=hint)
43 raise error.UpdateAbort(msg, hint=hint)
44
44
45 def _destupdateobs(repo, clean, check):
45 def _destupdateobs(repo, clean, check):
46 """decide of an update destination from obsolescence markers"""
46 """decide of an update destination from obsolescence markers"""
47 node = None
47 node = None
48 wc = repo[None]
48 wc = repo[None]
49 p1 = wc.p1()
49 p1 = wc.p1()
50 movemark = None
50 movemark = None
51
51
52 if p1.obsolete() and not p1.children():
52 if p1.obsolete() and not p1.children():
53 # allow updating to successors
53 # allow updating to successors
54 successors = obsolete.successorssets(repo, p1.node())
54 successors = obsolete.successorssets(repo, p1.node())
55
55
56 # behavior of certain cases is as follows,
56 # behavior of certain cases is as follows,
57 #
57 #
58 # divergent changesets: update to highest rev, similar to what
58 # divergent changesets: update to highest rev, similar to what
59 # is currently done when there are more than one head
59 # is currently done when there are more than one head
60 # (i.e. 'tip')
60 # (i.e. 'tip')
61 #
61 #
62 # replaced changesets: same as divergent except we know there
62 # replaced changesets: same as divergent except we know there
63 # is no conflict
63 # is no conflict
64 #
64 #
65 # pruned changeset: no update is done; though, we could
65 # pruned changeset: no update is done; though, we could
66 # consider updating to the first non-obsolete parent,
66 # consider updating to the first non-obsolete parent,
67 # similar to what is current done for 'hg prune'
67 # similar to what is current done for 'hg prune'
68
68
69 if successors:
69 if successors:
70 # flatten the list here handles both divergent (len > 1)
70 # flatten the list here handles both divergent (len > 1)
71 # and the usual case (len = 1)
71 # and the usual case (len = 1)
72 successors = [n for sub in successors for n in sub]
72 successors = [n for sub in successors for n in sub]
73
73
74 # get the max revision for the given successors set,
74 # get the max revision for the given successors set,
75 # i.e. the 'tip' of a set
75 # i.e. the 'tip' of a set
76 node = repo.revs('max(%ln)', successors).first()
76 node = repo.revs('max(%ln)', successors).first()
77 if bookmarks.isactivewdirparent(repo):
77 if bookmarks.isactivewdirparent(repo):
78 movemark = repo['.'].node()
78 movemark = repo['.'].node()
79 return node, movemark, None
79 return node, movemark, None
80
80
81 def _destupdatebook(repo, clean, check):
81 def _destupdatebook(repo, clean, check):
82 """decide on an update destination from active bookmark"""
82 """decide on an update destination from active bookmark"""
83 # we also move the active bookmark, if any
83 # we also move the active bookmark, if any
84 activemark = None
84 activemark = None
85 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
85 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
86 if node is not None:
86 if node is not None:
87 activemark = node
87 activemark = node
88 return node, movemark, activemark
88 return node, movemark, activemark
89
89
90 def _destupdatebranch(repo, clean, check):
90 def _destupdatebranch(repo, clean, check):
91 """decide on an update destination from current branch"""
91 """decide on an update destination from current branch
92
93 This ignores closed branch heads.
94 """
92 wc = repo[None]
95 wc = repo[None]
93 movemark = node = None
96 movemark = node = None
94 currentbranch = wc.branch()
97 currentbranch = wc.branch()
95 if currentbranch in repo.branchmap():
98 if currentbranch in repo.branchmap():
96 heads = repo.branchheads(currentbranch, closed=True)
99 heads = repo.branchheads(currentbranch)
97 if heads:
100 if heads:
98 node = repo.revs('max(.::(%ln))', heads).first()
101 node = repo.revs('max(.::(%ln))', heads).first()
99 if bookmarks.isactivewdirparent(repo):
102 if bookmarks.isactivewdirparent(repo):
100 movemark = repo['.'].node()
103 movemark = repo['.'].node()
101 else:
104 else:
102 if currentbranch == 'default': # no default branch!
105 if currentbranch == 'default': # no default branch!
103 node = repo.lookup('tip') # update to tip
106 # update to the tipmost non-closed branch head
107 node = repo.revs('max(head() and not closed())').first()
104 else:
108 else:
105 raise error.Abort(_("branch %s not found") % currentbranch)
109 raise error.Abort(_("branch %s not found") % currentbranch)
106 return node, movemark, None
110 return node, movemark, None
107
111
112 def _destupdatebranchfallback(repo, clean, check):
113 """decide on an update destination from closed heads in current branch"""
114 wc = repo[None]
115 currentbranch = wc.branch()
116 movemark = None
117 if currentbranch in repo.branchmap():
118 # here, all descendant branch heads are closed
119 heads = repo.branchheads(currentbranch, closed=True)
120 assert heads, "any branch has at least one head"
121 node = repo.revs('max(.::(%ln))', heads).first()
122 assert node is not None, ("any revision has at least "
123 "one descendant branch head")
124 if bookmarks.isactivewdirparent(repo):
125 movemark = repo['.'].node()
126 else:
127 # here, no "default" branch, and all branches are closed
128 node = repo.lookup('tip')
129 assert node is not None, "'tip' exists even in empty repository"
130 return node, movemark, None
131
108 # order in which each step should be evalutated
132 # order in which each step should be evalutated
109 # steps are run until one finds a destination
133 # steps are run until one finds a destination
110 destupdatesteps = ['evolution', 'bookmark', 'branch']
134 destupdatesteps = ['evolution', 'bookmark', 'branch', 'branchfallback']
111 # mapping to ease extension overriding steps.
135 # mapping to ease extension overriding steps.
112 destupdatestepmap = {'evolution': _destupdateobs,
136 destupdatestepmap = {'evolution': _destupdateobs,
113 'bookmark': _destupdatebook,
137 'bookmark': _destupdatebook,
114 'branch': _destupdatebranch,
138 'branch': _destupdatebranch,
139 'branchfallback': _destupdatebranchfallback,
115 }
140 }
116
141
117 def destupdate(repo, clean=False, check=False):
142 def destupdate(repo, clean=False, check=False):
118 """destination for bare update operation
143 """destination for bare update operation
119
144
120 return (rev, movemark, activemark)
145 return (rev, movemark, activemark)
121
146
122 - rev: the revision to update to,
147 - rev: the revision to update to,
123 - movemark: node to move the active bookmark from
148 - movemark: node to move the active bookmark from
124 (cf bookmark.calculate update),
149 (cf bookmark.calculate update),
125 - activemark: a bookmark to activate at the end of the update.
150 - activemark: a bookmark to activate at the end of the update.
126 """
151 """
127 node = movemark = activemark = None
152 node = movemark = activemark = None
128
153
129 for step in destupdatesteps:
154 for step in destupdatesteps:
130 node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
155 node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
131 if node is not None:
156 if node is not None:
132 break
157 break
133 rev = repo[node].rev()
158 rev = repo[node].rev()
134
159
135 _destupdatevalidate(repo, rev, clean, check)
160 _destupdatevalidate(repo, rev, clean, check)
136
161
137 return rev, movemark, activemark
162 return rev, movemark, activemark
138
163
139 msgdestmerge = {
164 msgdestmerge = {
140 # too many matching divergent bookmark
165 # too many matching divergent bookmark
141 'toomanybookmarks':
166 'toomanybookmarks':
142 {'merge':
167 {'merge':
143 (_("multiple matching bookmarks to merge -"
168 (_("multiple matching bookmarks to merge -"
144 " please merge with an explicit rev or bookmark"),
169 " please merge with an explicit rev or bookmark"),
145 _("run 'hg heads' to see all heads")),
170 _("run 'hg heads' to see all heads")),
146 'rebase':
171 'rebase':
147 (_("multiple matching bookmarks to rebase -"
172 (_("multiple matching bookmarks to rebase -"
148 " please rebase to an explicit rev or bookmark"),
173 " please rebase to an explicit rev or bookmark"),
149 _("run 'hg heads' to see all heads")),
174 _("run 'hg heads' to see all heads")),
150 },
175 },
151 # no other matching divergent bookmark
176 # no other matching divergent bookmark
152 'nootherbookmarks':
177 'nootherbookmarks':
153 {'merge':
178 {'merge':
154 (_("no matching bookmark to merge - "
179 (_("no matching bookmark to merge - "
155 "please merge with an explicit rev or bookmark"),
180 "please merge with an explicit rev or bookmark"),
156 _("run 'hg heads' to see all heads")),
181 _("run 'hg heads' to see all heads")),
157 'rebase':
182 'rebase':
158 (_("no matching bookmark to rebase - "
183 (_("no matching bookmark to rebase - "
159 "please rebase to an explicit rev or bookmark"),
184 "please rebase to an explicit rev or bookmark"),
160 _("run 'hg heads' to see all heads")),
185 _("run 'hg heads' to see all heads")),
161 },
186 },
162 # branch have too many unbookmarked heads, no obvious destination
187 # branch have too many unbookmarked heads, no obvious destination
163 'toomanyheads':
188 'toomanyheads':
164 {'merge':
189 {'merge':
165 (_("branch '%s' has %d heads - please merge with an explicit rev"),
190 (_("branch '%s' has %d heads - please merge with an explicit rev"),
166 _("run 'hg heads .' to see heads")),
191 _("run 'hg heads .' to see heads")),
167 'rebase':
192 'rebase':
168 (_("branch '%s' has %d heads - please rebase to an explicit rev"),
193 (_("branch '%s' has %d heads - please rebase to an explicit rev"),
169 _("run 'hg heads .' to see heads")),
194 _("run 'hg heads .' to see heads")),
170 },
195 },
171 # branch have no other unbookmarked heads
196 # branch have no other unbookmarked heads
172 'bookmarkedheads':
197 'bookmarkedheads':
173 {'merge':
198 {'merge':
174 (_("heads are bookmarked - please merge with an explicit rev"),
199 (_("heads are bookmarked - please merge with an explicit rev"),
175 _("run 'hg heads' to see all heads")),
200 _("run 'hg heads' to see all heads")),
176 'rebase':
201 'rebase':
177 (_("heads are bookmarked - please rebase to an explicit rev"),
202 (_("heads are bookmarked - please rebase to an explicit rev"),
178 _("run 'hg heads' to see all heads")),
203 _("run 'hg heads' to see all heads")),
179 },
204 },
180 # branch have just a single heads, but there is other branches
205 # branch have just a single heads, but there is other branches
181 'nootherbranchheads':
206 'nootherbranchheads':
182 {'merge':
207 {'merge':
183 (_("branch '%s' has one head - please merge with an explicit rev"),
208 (_("branch '%s' has one head - please merge with an explicit rev"),
184 _("run 'hg heads' to see all heads")),
209 _("run 'hg heads' to see all heads")),
185 'rebase':
210 'rebase':
186 (_("branch '%s' has one head - please rebase to an explicit rev"),
211 (_("branch '%s' has one head - please rebase to an explicit rev"),
187 _("run 'hg heads' to see all heads")),
212 _("run 'hg heads' to see all heads")),
188 },
213 },
189 # repository have a single head
214 # repository have a single head
190 'nootherheads':
215 'nootherheads':
191 {'merge':
216 {'merge':
192 (_('nothing to merge'),
217 (_('nothing to merge'),
193 None),
218 None),
194 'rebase':
219 'rebase':
195 (_('nothing to rebase'),
220 (_('nothing to rebase'),
196 None),
221 None),
197 },
222 },
198 # repository have a single head and we are not on it
223 # repository have a single head and we are not on it
199 'nootherheadsbehind':
224 'nootherheadsbehind':
200 {'merge':
225 {'merge':
201 (_('nothing to merge'),
226 (_('nothing to merge'),
202 _("use 'hg update' instead")),
227 _("use 'hg update' instead")),
203 'rebase':
228 'rebase':
204 (_('nothing to rebase'),
229 (_('nothing to rebase'),
205 _("use 'hg update' instead")),
230 _("use 'hg update' instead")),
206 },
231 },
207 # We are not on a head
232 # We are not on a head
208 'notatheads':
233 'notatheads':
209 {'merge':
234 {'merge':
210 (_('working directory not at a head revision'),
235 (_('working directory not at a head revision'),
211 _("use 'hg update' or merge with an explicit revision")),
236 _("use 'hg update' or merge with an explicit revision")),
212 'rebase':
237 'rebase':
213 (_('working directory not at a head revision'),
238 (_('working directory not at a head revision'),
214 _("use 'hg update' or rebase to an explicit revision"))
239 _("use 'hg update' or rebase to an explicit revision"))
215 },
240 },
216 'emptysourceset':
241 'emptysourceset':
217 {'merge':
242 {'merge':
218 (_('source set is empty'),
243 (_('source set is empty'),
219 None),
244 None),
220 'rebase':
245 'rebase':
221 (_('source set is empty'),
246 (_('source set is empty'),
222 None),
247 None),
223 },
248 },
224 'multiplebranchessourceset':
249 'multiplebranchessourceset':
225 {'merge':
250 {'merge':
226 (_('source set is rooted in multiple branches'),
251 (_('source set is rooted in multiple branches'),
227 None),
252 None),
228 'rebase':
253 'rebase':
229 (_('rebaseset is rooted in multiple named branches'),
254 (_('rebaseset is rooted in multiple named branches'),
230 _('specify an explicit destination with --dest')),
255 _('specify an explicit destination with --dest')),
231 },
256 },
232 }
257 }
233
258
234 def _destmergebook(repo, action='merge', sourceset=None):
259 def _destmergebook(repo, action='merge', sourceset=None):
235 """find merge destination in the active bookmark case"""
260 """find merge destination in the active bookmark case"""
236 node = None
261 node = None
237 bmheads = repo.bookmarkheads(repo._activebookmark)
262 bmheads = repo.bookmarkheads(repo._activebookmark)
238 curhead = repo[repo._activebookmark].node()
263 curhead = repo[repo._activebookmark].node()
239 if len(bmheads) == 2:
264 if len(bmheads) == 2:
240 if curhead == bmheads[0]:
265 if curhead == bmheads[0]:
241 node = bmheads[1]
266 node = bmheads[1]
242 else:
267 else:
243 node = bmheads[0]
268 node = bmheads[0]
244 elif len(bmheads) > 2:
269 elif len(bmheads) > 2:
245 msg, hint = msgdestmerge['toomanybookmarks'][action]
270 msg, hint = msgdestmerge['toomanybookmarks'][action]
246 raise error.ManyMergeDestAbort(msg, hint=hint)
271 raise error.ManyMergeDestAbort(msg, hint=hint)
247 elif len(bmheads) <= 1:
272 elif len(bmheads) <= 1:
248 msg, hint = msgdestmerge['nootherbookmarks'][action]
273 msg, hint = msgdestmerge['nootherbookmarks'][action]
249 raise error.NoMergeDestAbort(msg, hint=hint)
274 raise error.NoMergeDestAbort(msg, hint=hint)
250 assert node is not None
275 assert node is not None
251 return node
276 return node
252
277
253 def _destmergebranch(repo, action='merge', sourceset=None, onheadcheck=True):
278 def _destmergebranch(repo, action='merge', sourceset=None, onheadcheck=True):
254 """find merge destination based on branch heads"""
279 """find merge destination based on branch heads"""
255 node = None
280 node = None
256
281
257 if sourceset is None:
282 if sourceset is None:
258 sourceset = [repo[repo.dirstate.p1()].rev()]
283 sourceset = [repo[repo.dirstate.p1()].rev()]
259 branch = repo.dirstate.branch()
284 branch = repo.dirstate.branch()
260 elif not sourceset:
285 elif not sourceset:
261 msg, hint = msgdestmerge['emptysourceset'][action]
286 msg, hint = msgdestmerge['emptysourceset'][action]
262 raise error.NoMergeDestAbort(msg, hint=hint)
287 raise error.NoMergeDestAbort(msg, hint=hint)
263 else:
288 else:
264 branch = None
289 branch = None
265 for ctx in repo.set('roots(%ld::%ld)', sourceset, sourceset):
290 for ctx in repo.set('roots(%ld::%ld)', sourceset, sourceset):
266 if branch is not None and ctx.branch() != branch:
291 if branch is not None and ctx.branch() != branch:
267 msg, hint = msgdestmerge['multiplebranchessourceset'][action]
292 msg, hint = msgdestmerge['multiplebranchessourceset'][action]
268 raise error.ManyMergeDestAbort(msg, hint=hint)
293 raise error.ManyMergeDestAbort(msg, hint=hint)
269 branch = ctx.branch()
294 branch = ctx.branch()
270
295
271 bheads = repo.branchheads(branch)
296 bheads = repo.branchheads(branch)
272 onhead = repo.revs('%ld and %ln', sourceset, bheads)
297 onhead = repo.revs('%ld and %ln', sourceset, bheads)
273 if onheadcheck and not onhead:
298 if onheadcheck and not onhead:
274 # Case A: working copy if not on a head. (merge only)
299 # Case A: working copy if not on a head. (merge only)
275 #
300 #
276 # This is probably a user mistake We bailout pointing at 'hg update'
301 # This is probably a user mistake We bailout pointing at 'hg update'
277 if len(repo.heads()) <= 1:
302 if len(repo.heads()) <= 1:
278 msg, hint = msgdestmerge['nootherheadsbehind'][action]
303 msg, hint = msgdestmerge['nootherheadsbehind'][action]
279 else:
304 else:
280 msg, hint = msgdestmerge['notatheads'][action]
305 msg, hint = msgdestmerge['notatheads'][action]
281 raise error.Abort(msg, hint=hint)
306 raise error.Abort(msg, hint=hint)
282 # remove heads descendants of source from the set
307 # remove heads descendants of source from the set
283 bheads = list(repo.revs('%ln - (%ld::)', bheads, sourceset))
308 bheads = list(repo.revs('%ln - (%ld::)', bheads, sourceset))
284 # filters out bookmarked heads
309 # filters out bookmarked heads
285 nbhs = list(repo.revs('%ld - bookmark()', bheads))
310 nbhs = list(repo.revs('%ld - bookmark()', bheads))
286 if len(nbhs) > 1:
311 if len(nbhs) > 1:
287 # Case B: There is more than 1 other anonymous heads
312 # Case B: There is more than 1 other anonymous heads
288 #
313 #
289 # This means that there will be more than 1 candidate. This is
314 # This means that there will be more than 1 candidate. This is
290 # ambiguous. We abort asking the user to pick as explicit destination
315 # ambiguous. We abort asking the user to pick as explicit destination
291 # instead.
316 # instead.
292 msg, hint = msgdestmerge['toomanyheads'][action]
317 msg, hint = msgdestmerge['toomanyheads'][action]
293 msg %= (branch, len(bheads) + 1)
318 msg %= (branch, len(bheads) + 1)
294 raise error.ManyMergeDestAbort(msg, hint=hint)
319 raise error.ManyMergeDestAbort(msg, hint=hint)
295 elif not nbhs:
320 elif not nbhs:
296 # Case B: There is no other anonymous heads
321 # Case B: There is no other anonymous heads
297 #
322 #
298 # This means that there is no natural candidate to merge with.
323 # This means that there is no natural candidate to merge with.
299 # We abort, with various messages for various cases.
324 # We abort, with various messages for various cases.
300 if bheads:
325 if bheads:
301 msg, hint = msgdestmerge['bookmarkedheads'][action]
326 msg, hint = msgdestmerge['bookmarkedheads'][action]
302 elif len(repo.heads()) > 1:
327 elif len(repo.heads()) > 1:
303 msg, hint = msgdestmerge['nootherbranchheads'][action]
328 msg, hint = msgdestmerge['nootherbranchheads'][action]
304 msg %= branch
329 msg %= branch
305 elif not onhead:
330 elif not onhead:
306 # if 'onheadcheck == False' (rebase case),
331 # if 'onheadcheck == False' (rebase case),
307 # this was not caught in Case A.
332 # this was not caught in Case A.
308 msg, hint = msgdestmerge['nootherheadsbehind'][action]
333 msg, hint = msgdestmerge['nootherheadsbehind'][action]
309 else:
334 else:
310 msg, hint = msgdestmerge['nootherheads'][action]
335 msg, hint = msgdestmerge['nootherheads'][action]
311 raise error.NoMergeDestAbort(msg, hint=hint)
336 raise error.NoMergeDestAbort(msg, hint=hint)
312 else:
337 else:
313 node = nbhs[0]
338 node = nbhs[0]
314 assert node is not None
339 assert node is not None
315 return node
340 return node
316
341
317 def destmerge(repo, action='merge', sourceset=None, onheadcheck=True):
342 def destmerge(repo, action='merge', sourceset=None, onheadcheck=True):
318 """return the default destination for a merge
343 """return the default destination for a merge
319
344
320 (or raise exception about why it can't pick one)
345 (or raise exception about why it can't pick one)
321
346
322 :action: the action being performed, controls emitted error message
347 :action: the action being performed, controls emitted error message
323 """
348 """
324 if repo._activebookmark:
349 if repo._activebookmark:
325 node = _destmergebook(repo, action=action, sourceset=sourceset)
350 node = _destmergebook(repo, action=action, sourceset=sourceset)
326 else:
351 else:
327 node = _destmergebranch(repo, action=action, sourceset=sourceset,
352 node = _destmergebranch(repo, action=action, sourceset=sourceset,
328 onheadcheck=onheadcheck)
353 onheadcheck=onheadcheck)
329 return repo[node].rev()
354 return repo[node].rev()
330
355
331 histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
356 histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
332
357
333 def desthistedit(ui, repo):
358 def desthistedit(ui, repo):
334 """Default base revision to edit for `hg histedit`."""
359 """Default base revision to edit for `hg histedit`."""
335 # Avoid cycle: scmutil -> revset -> destutil
360 # Avoid cycle: scmutil -> revset -> destutil
336 from . import scmutil
361 from . import scmutil
337
362
338 default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
363 default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
339 if default:
364 if default:
340 revs = scmutil.revrange(repo, [default])
365 revs = scmutil.revrange(repo, [default])
341 if revs:
366 if revs:
342 # The revset supplied by the user may not be in ascending order nor
367 # The revset supplied by the user may not be in ascending order nor
343 # take the first revision. So do this manually.
368 # take the first revision. So do this manually.
344 revs.sort()
369 revs.sort()
345 return revs.first()
370 return revs.first()
346
371
347 return None
372 return None
348
373
349 def _statusotherbook(ui, repo):
374 def _statusotherbook(ui, repo):
350 bmheads = repo.bookmarkheads(repo._activebookmark)
375 bmheads = repo.bookmarkheads(repo._activebookmark)
351 curhead = repo[repo._activebookmark].node()
376 curhead = repo[repo._activebookmark].node()
352 if repo.revs('%n and parents()', curhead):
377 if repo.revs('%n and parents()', curhead):
353 # we are on the active bookmark
378 # we are on the active bookmark
354 bmheads = [b for b in bmheads if curhead != b]
379 bmheads = [b for b in bmheads if curhead != b]
355 if bmheads:
380 if bmheads:
356 msg = _('%i other divergent bookmarks for "%s"\n')
381 msg = _('%i other divergent bookmarks for "%s"\n')
357 ui.status(msg % (len(bmheads), repo._activebookmark))
382 ui.status(msg % (len(bmheads), repo._activebookmark))
358
383
359 def _statusotherbranchheads(ui, repo):
384 def _statusotherbranchheads(ui, repo):
360 currentbranch = repo.dirstate.branch()
385 currentbranch = repo.dirstate.branch()
361 allheads = repo.branchheads(currentbranch, closed=True)
386 allheads = repo.branchheads(currentbranch, closed=True)
362 heads = repo.branchheads(currentbranch)
387 heads = repo.branchheads(currentbranch)
363 if repo.revs('%ln and parents()', allheads):
388 if repo.revs('%ln and parents()', allheads):
364 # we are on a head, even though it might be closed
389 # we are on a head, even though it might be closed
390 #
391 # on closed otherheads
392 # ========= ==========
393 # o 0 all heads for current branch are closed
394 # N only descendant branch heads are closed
395 # x 0 there is only one non-closed branch head
396 # N there are some non-closed branch heads
397 # ========= ==========
365 otherheads = repo.revs('%ln - parents()', heads)
398 otherheads = repo.revs('%ln - parents()', heads)
399 if repo['.'].closesbranch():
400 ui.status(_('updated to a closed branch head, '
401 'because all descendant heads are closed.\n'
402 'beware of re-opening closed head '
403 'by subsequent commit here.\n'))
366 if otherheads:
404 if otherheads:
367 ui.status(_('%i other heads for branch "%s"\n') %
405 ui.status(_('%i other heads for branch "%s"\n') %
368 (len(otherheads), currentbranch))
406 (len(otherheads), currentbranch))
407 else:
408 ui.status(_('all heads for branch "%s" are closed.\n') %
409 currentbranch)
410 elif otherheads:
411 ui.status(_('%i other heads for branch "%s"\n') %
412 (len(otherheads), currentbranch))
369
413
370 def statusotherdests(ui, repo):
414 def statusotherdests(ui, repo):
371 """Print message about other head"""
415 """Print message about other head"""
372 # XXX we should probably include a hint:
416 # XXX we should probably include a hint:
373 # - about what to do
417 # - about what to do
374 # - how to see such heads
418 # - how to see such heads
375 if repo._activebookmark:
419 if repo._activebookmark:
376 _statusotherbook(ui, repo)
420 _statusotherbook(ui, repo)
377 else:
421 else:
378 _statusotherbranchheads(ui, repo)
422 _statusotherbranchheads(ui, repo)
@@ -1,204 +1,223
1 $ hg init
1 $ hg init
2
2
3 no bookmarks
3 no bookmarks
4
4
5 $ hg bookmarks
5 $ hg bookmarks
6 no bookmarks set
6 no bookmarks set
7
7
8 set bookmark X
8 set bookmark X
9
9
10 $ hg bookmark X
10 $ hg bookmark X
11
11
12 list bookmarks
12 list bookmarks
13
13
14 $ hg bookmark
14 $ hg bookmark
15 * X -1:000000000000
15 * X -1:000000000000
16
16
17 list bookmarks with color
17 list bookmarks with color
18
18
19 $ hg --config extensions.color= --config color.mode=ansi \
19 $ hg --config extensions.color= --config color.mode=ansi \
20 > bookmark --color=always
20 > bookmark --color=always
21 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
21 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
22
22
23 update to bookmark X
23 update to bookmark X
24
24
25 $ hg update X
25 $ hg update X
26 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
26 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 (activating bookmark X)
27 (activating bookmark X)
28
28
29 list bookmarks
29 list bookmarks
30
30
31 $ hg bookmarks
31 $ hg bookmarks
32 * X -1:000000000000
32 * X -1:000000000000
33
33
34 rename
34 rename
35
35
36 $ hg bookmark -m X Z
36 $ hg bookmark -m X Z
37
37
38 list bookmarks
38 list bookmarks
39
39
40 $ cat .hg/bookmarks.current
40 $ cat .hg/bookmarks.current
41 Z (no-eol)
41 Z (no-eol)
42 $ cat .hg/bookmarks
42 $ cat .hg/bookmarks
43 0000000000000000000000000000000000000000 Z
43 0000000000000000000000000000000000000000 Z
44 $ hg bookmarks
44 $ hg bookmarks
45 * Z -1:000000000000
45 * Z -1:000000000000
46
46
47 new bookmarks X and Y, first one made active
47 new bookmarks X and Y, first one made active
48
48
49 $ hg bookmark Y X
49 $ hg bookmark Y X
50
50
51 list bookmarks
51 list bookmarks
52
52
53 $ hg bookmark
53 $ hg bookmark
54 X -1:000000000000
54 X -1:000000000000
55 * Y -1:000000000000
55 * Y -1:000000000000
56 Z -1:000000000000
56 Z -1:000000000000
57
57
58 $ hg bookmark -d X
58 $ hg bookmark -d X
59
59
60 commit
60 commit
61
61
62 $ echo 'b' > b
62 $ echo 'b' > b
63 $ hg add b
63 $ hg add b
64 $ hg commit -m'test'
64 $ hg commit -m'test'
65
65
66 list bookmarks
66 list bookmarks
67
67
68 $ hg bookmark
68 $ hg bookmark
69 * Y 0:719295282060
69 * Y 0:719295282060
70 Z -1:000000000000
70 Z -1:000000000000
71
71
72 Verify that switching to Z updates the active bookmark:
72 Verify that switching to Z updates the active bookmark:
73 $ hg update Z
73 $ hg update Z
74 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
74 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
75 (activating bookmark Z)
75 (activating bookmark Z)
76 $ hg bookmark
76 $ hg bookmark
77 Y 0:719295282060
77 Y 0:719295282060
78 * Z -1:000000000000
78 * Z -1:000000000000
79
79
80 Switch back to Y for the remaining tests in this file:
80 Switch back to Y for the remaining tests in this file:
81 $ hg update Y
81 $ hg update Y
82 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 (activating bookmark Y)
83 (activating bookmark Y)
84
84
85 delete bookmarks
85 delete bookmarks
86
86
87 $ hg bookmark -d Y
87 $ hg bookmark -d Y
88 $ hg bookmark -d Z
88 $ hg bookmark -d Z
89
89
90 list bookmarks
90 list bookmarks
91
91
92 $ hg bookmark
92 $ hg bookmark
93 no bookmarks set
93 no bookmarks set
94
94
95 update to tip
95 update to tip
96
96
97 $ hg update tip
97 $ hg update tip
98 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
99
99
100 set bookmark Y using -r . but make sure that the active
100 set bookmark Y using -r . but make sure that the active
101 bookmark is not activated
101 bookmark is not activated
102
102
103 $ hg bookmark -r . Y
103 $ hg bookmark -r . Y
104
104
105 list bookmarks, Y should not be active
105 list bookmarks, Y should not be active
106
106
107 $ hg bookmark
107 $ hg bookmark
108 Y 0:719295282060
108 Y 0:719295282060
109
109
110 now, activate Y
110 now, activate Y
111
111
112 $ hg up -q Y
112 $ hg up -q Y
113
113
114 set bookmark Z using -i
114 set bookmark Z using -i
115
115
116 $ hg bookmark -r . -i Z
116 $ hg bookmark -r . -i Z
117 $ hg bookmarks
117 $ hg bookmarks
118 * Y 0:719295282060
118 * Y 0:719295282060
119 Z 0:719295282060
119 Z 0:719295282060
120
120
121 deactivate active bookmark using -i
121 deactivate active bookmark using -i
122
122
123 $ hg bookmark -i Y
123 $ hg bookmark -i Y
124 $ hg bookmarks
124 $ hg bookmarks
125 Y 0:719295282060
125 Y 0:719295282060
126 Z 0:719295282060
126 Z 0:719295282060
127
127
128 $ hg up -q Y
128 $ hg up -q Y
129 $ hg bookmark -i
129 $ hg bookmark -i
130 $ hg bookmarks
130 $ hg bookmarks
131 Y 0:719295282060
131 Y 0:719295282060
132 Z 0:719295282060
132 Z 0:719295282060
133 $ hg bookmark -i
133 $ hg bookmark -i
134 no active bookmark
134 no active bookmark
135 $ hg up -q Y
135 $ hg up -q Y
136 $ hg bookmarks
136 $ hg bookmarks
137 * Y 0:719295282060
137 * Y 0:719295282060
138 Z 0:719295282060
138 Z 0:719295282060
139
139
140 deactivate active bookmark while renaming
140 deactivate active bookmark while renaming
141
141
142 $ hg bookmark -i -m Y X
142 $ hg bookmark -i -m Y X
143 $ hg bookmarks
143 $ hg bookmarks
144 X 0:719295282060
144 X 0:719295282060
145 Z 0:719295282060
145 Z 0:719295282060
146
146
147 bare update moves the active bookmark forward and clear the divergent bookmarks
147 bare update moves the active bookmark forward and clear the divergent bookmarks
148
148
149 $ echo a > a
149 $ echo a > a
150 $ hg ci -Am1
150 $ hg ci -Am1
151 adding a
151 adding a
152 $ echo b >> a
152 $ echo b >> a
153 $ hg ci -Am2
153 $ hg ci -Am2
154 $ hg bookmark X@1 -r 1
154 $ hg bookmark X@1 -r 1
155 $ hg bookmark X@2 -r 2
155 $ hg bookmark X@2 -r 2
156 $ hg update X
156 $ hg update X
157 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
157 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
158 (activating bookmark X)
158 (activating bookmark X)
159 $ hg bookmarks
159 $ hg bookmarks
160 * X 0:719295282060
160 * X 0:719295282060
161 X@1 1:cc586d725fbe
161 X@1 1:cc586d725fbe
162 X@2 2:49e1c4e84c58
162 X@2 2:49e1c4e84c58
163 Z 0:719295282060
163 Z 0:719295282060
164 $ hg update
164 $ hg update
165 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
165 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
166 updating bookmark X
166 updating bookmark X
167 $ hg bookmarks
167 $ hg bookmarks
168 * X 2:49e1c4e84c58
168 * X 2:49e1c4e84c58
169 Z 0:719295282060
169 Z 0:719295282060
170
170
171 test deleting .hg/bookmarks.current when explicitly updating
171 test deleting .hg/bookmarks.current when explicitly updating
172 to a revision
172 to a revision
173
173
174 $ echo a >> b
174 $ echo a >> b
175 $ hg ci -m.
175 $ hg ci -m.
176 $ hg up -q X
176 $ hg up -q X
177 $ test -f .hg/bookmarks.current
177 $ test -f .hg/bookmarks.current
178
178
179 try to update to it again to make sure we don't
179 try to update to it again to make sure we don't
180 set and then unset it
180 set and then unset it
181
181
182 $ hg up -q X
182 $ hg up -q X
183 $ test -f .hg/bookmarks.current
183 $ test -f .hg/bookmarks.current
184
184
185 $ hg up -q 1
185 $ hg up -q 1
186 $ test -f .hg/bookmarks.current
186 $ test -f .hg/bookmarks.current
187 [1]
187 [1]
188
188
189 when a bookmark is active, hg up -r . is
189 when a bookmark is active, hg up -r . is
190 analogous to hg book -i <active bookmark>
190 analogous to hg book -i <active bookmark>
191
191
192 $ hg up -q X
192 $ hg up -q X
193 $ hg up -q .
193 $ hg up -q .
194 $ test -f .hg/bookmarks.current
194 $ test -f .hg/bookmarks.current
195 [1]
195 [1]
196
196
197 issue 4552 -- simulate a pull moving the active bookmark
197 issue 4552 -- simulate a pull moving the active bookmark
198
198
199 $ hg up -q X
199 $ hg up -q X
200 $ printf "Z" > .hg/bookmarks.current
200 $ printf "Z" > .hg/bookmarks.current
201 $ hg log -T '{activebookmark}\n' -r Z
201 $ hg log -T '{activebookmark}\n' -r Z
202 Z
202 Z
203 $ hg log -T '{bookmarks % "{active}\n"}' -r Z
203 $ hg log -T '{bookmarks % "{active}\n"}' -r Z
204 Z
204 Z
205
206 test that updating to closed branch head also advances active bookmark
207
208 $ hg commit --close-branch -m "closed"
209 $ hg update -q ".^1"
210 $ hg bookmark Y
211 $ hg bookmarks
212 X 3:4d6bd4bfb1ae
213 * Y 3:4d6bd4bfb1ae
214 Z 0:719295282060
215 $ hg update
216 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 updating bookmark Y
218 $ hg bookmarks
219 X 3:4d6bd4bfb1ae
220 * Y 4:8fa964221e8e
221 Z 0:719295282060
222 $ hg parents -q
223 4:8fa964221e8e
@@ -1,303 +1,386
1 # Construct the following history tree:
1 # Construct the following history tree:
2 #
2 #
3 # @ 5:e1bb631146ca b1
3 # @ 5:e1bb631146ca b1
4 # |
4 # |
5 # o 4:a4fdb3b883c4 0:b608b9236435 b1
5 # o 4:a4fdb3b883c4 0:b608b9236435 b1
6 # |
6 # |
7 # | o 3:4b57d2520816 1:44592833ba9f
7 # | o 3:4b57d2520816 1:44592833ba9f
8 # | |
8 # | |
9 # | | o 2:063f31070f65
9 # | | o 2:063f31070f65
10 # | |/
10 # | |/
11 # | o 1:44592833ba9f
11 # | o 1:44592833ba9f
12 # |/
12 # |/
13 # o 0:b608b9236435
13 # o 0:b608b9236435
14
14
15 $ mkdir b1
15 $ mkdir b1
16 $ cd b1
16 $ cd b1
17 $ hg init
17 $ hg init
18 $ echo foo > foo
18 $ echo foo > foo
19 $ echo zero > a
19 $ echo zero > a
20 $ hg init sub
20 $ hg init sub
21 $ echo suba > sub/suba
21 $ echo suba > sub/suba
22 $ hg --cwd sub ci -Am addsuba
22 $ hg --cwd sub ci -Am addsuba
23 adding suba
23 adding suba
24 $ echo 'sub = sub' > .hgsub
24 $ echo 'sub = sub' > .hgsub
25 $ hg ci -qAm0
25 $ hg ci -qAm0
26 $ echo one > a ; hg ci -m1
26 $ echo one > a ; hg ci -m1
27 $ echo two > a ; hg ci -m2
27 $ echo two > a ; hg ci -m2
28 $ hg up -q 1
28 $ hg up -q 1
29 $ echo three > a ; hg ci -qm3
29 $ echo three > a ; hg ci -qm3
30 $ hg up -q 0
30 $ hg up -q 0
31 $ hg branch -q b1
31 $ hg branch -q b1
32 $ echo four > a ; hg ci -qm4
32 $ echo four > a ; hg ci -qm4
33 $ echo five > a ; hg ci -qm5
33 $ echo five > a ; hg ci -qm5
34
34
35 Initial repo state:
35 Initial repo state:
36
36
37 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
37 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
38 @ 5:ff252e8273df b1
38 @ 5:ff252e8273df b1
39 |
39 |
40 o 4:d047485b3896 0:60829823a42a b1
40 o 4:d047485b3896 0:60829823a42a b1
41 |
41 |
42 | o 3:6efa171f091b 1:0786582aa4b1
42 | o 3:6efa171f091b 1:0786582aa4b1
43 | |
43 | |
44 | | o 2:bd10386d478c
44 | | o 2:bd10386d478c
45 | |/
45 | |/
46 | o 1:0786582aa4b1
46 | o 1:0786582aa4b1
47 |/
47 |/
48 o 0:60829823a42a
48 o 0:60829823a42a
49
49
50
50
51 Make sure update doesn't assume b1 is a repository if invoked from outside:
51 Make sure update doesn't assume b1 is a repository if invoked from outside:
52
52
53 $ cd ..
53 $ cd ..
54 $ hg update b1
54 $ hg update b1
55 abort: no repository found in '$TESTTMP' (.hg not found)!
55 abort: no repository found in '$TESTTMP' (.hg not found)!
56 [255]
56 [255]
57 $ cd b1
57 $ cd b1
58
58
59 Test helper functions:
59 Test helper functions:
60
60
61 $ revtest () {
61 $ revtest () {
62 > msg=$1
62 > msg=$1
63 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
63 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
64 > startrev=$3
64 > startrev=$3
65 > targetrev=$4
65 > targetrev=$4
66 > opt=$5
66 > opt=$5
67 > hg up -qC $startrev
67 > hg up -qC $startrev
68 > test $dirtyflag = dirty && echo dirty > foo
68 > test $dirtyflag = dirty && echo dirty > foo
69 > test $dirtyflag = dirtysub && echo dirty > sub/suba
69 > test $dirtyflag = dirtysub && echo dirty > sub/suba
70 > hg up $opt $targetrev
70 > hg up $opt $targetrev
71 > hg parent --template 'parent={rev}\n'
71 > hg parent --template 'parent={rev}\n'
72 > hg stat -S
72 > hg stat -S
73 > }
73 > }
74
74
75 $ norevtest () {
75 $ norevtest () {
76 > msg=$1
76 > msg=$1
77 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
77 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
78 > startrev=$3
78 > startrev=$3
79 > opt=$4
79 > opt=$4
80 > hg up -qC $startrev
80 > hg up -qC $startrev
81 > test $dirtyflag = dirty && echo dirty > foo
81 > test $dirtyflag = dirty && echo dirty > foo
82 > test $dirtyflag = dirtysub && echo dirty > sub/suba
82 > test $dirtyflag = dirtysub && echo dirty > sub/suba
83 > hg up $opt
83 > hg up $opt
84 > hg parent --template 'parent={rev}\n'
84 > hg parent --template 'parent={rev}\n'
85 > hg stat -S
85 > hg stat -S
86 > }
86 > }
87
87
88 Test cases are documented in a table in the update function of merge.py.
88 Test cases are documented in a table in the update function of merge.py.
89 Cases are run as shown in that table, row by row.
89 Cases are run as shown in that table, row by row.
90
90
91 $ norevtest 'none clean linear' clean 4
91 $ norevtest 'none clean linear' clean 4
92 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 parent=5
93 parent=5
94
94
95 $ norevtest 'none clean same' clean 2
95 $ norevtest 'none clean same' clean 2
96 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 1 other heads for branch "default"
97 1 other heads for branch "default"
98 parent=2
98 parent=2
99
99
100
100
101 $ revtest 'none clean linear' clean 1 2
101 $ revtest 'none clean linear' clean 1 2
102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 parent=2
103 parent=2
104
104
105 $ revtest 'none clean same' clean 2 3
105 $ revtest 'none clean same' clean 2 3
106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 parent=3
107 parent=3
108
108
109 $ revtest 'none clean cross' clean 3 4
109 $ revtest 'none clean cross' clean 3 4
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 parent=4
111 parent=4
112
112
113
113
114 $ revtest 'none dirty linear' dirty 1 2
114 $ revtest 'none dirty linear' dirty 1 2
115 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
115 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 parent=2
116 parent=2
117 M foo
117 M foo
118
118
119 $ revtest 'none dirtysub linear' dirtysub 1 2
119 $ revtest 'none dirtysub linear' dirtysub 1 2
120 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 parent=2
121 parent=2
122 M sub/suba
122 M sub/suba
123
123
124 $ revtest 'none dirty same' dirty 2 3
124 $ revtest 'none dirty same' dirty 2 3
125 abort: uncommitted changes
125 abort: uncommitted changes
126 (commit or update --clean to discard changes)
126 (commit or update --clean to discard changes)
127 parent=2
127 parent=2
128 M foo
128 M foo
129
129
130 $ revtest 'none dirtysub same' dirtysub 2 3
130 $ revtest 'none dirtysub same' dirtysub 2 3
131 abort: uncommitted changes
131 abort: uncommitted changes
132 (commit or update --clean to discard changes)
132 (commit or update --clean to discard changes)
133 parent=2
133 parent=2
134 M sub/suba
134 M sub/suba
135
135
136 $ revtest 'none dirty cross' dirty 3 4
136 $ revtest 'none dirty cross' dirty 3 4
137 abort: uncommitted changes
137 abort: uncommitted changes
138 (commit or update --clean to discard changes)
138 (commit or update --clean to discard changes)
139 parent=3
139 parent=3
140 M foo
140 M foo
141
141
142 $ norevtest 'none dirty cross' dirty 2
142 $ norevtest 'none dirty cross' dirty 2
143 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
144 1 other heads for branch "default"
144 1 other heads for branch "default"
145 parent=2
145 parent=2
146 M foo
146 M foo
147
147
148 $ revtest 'none dirtysub cross' dirtysub 3 4
148 $ revtest 'none dirtysub cross' dirtysub 3 4
149 abort: uncommitted changes
149 abort: uncommitted changes
150 (commit or update --clean to discard changes)
150 (commit or update --clean to discard changes)
151 parent=3
151 parent=3
152 M sub/suba
152 M sub/suba
153
153
154 $ revtest '-C dirty linear' dirty 1 2 -C
154 $ revtest '-C dirty linear' dirty 1 2 -C
155 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 parent=2
156 parent=2
157
157
158 $ revtest '-c dirty linear' dirty 1 2 -c
158 $ revtest '-c dirty linear' dirty 1 2 -c
159 abort: uncommitted changes
159 abort: uncommitted changes
160 parent=1
160 parent=1
161 M foo
161 M foo
162
162
163 $ revtest '-c dirtysub linear' dirtysub 1 2 -c
163 $ revtest '-c dirtysub linear' dirtysub 1 2 -c
164 abort: uncommitted changes in subrepository 'sub'
164 abort: uncommitted changes in subrepository 'sub'
165 parent=1
165 parent=1
166 M sub/suba
166 M sub/suba
167
167
168 $ norevtest '-c clean same' clean 2 -c
168 $ norevtest '-c clean same' clean 2 -c
169 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 1 other heads for branch "default"
170 1 other heads for branch "default"
171 parent=2
171 parent=2
172
172
173 $ revtest '-cC dirty linear' dirty 1 2 -cC
173 $ revtest '-cC dirty linear' dirty 1 2 -cC
174 abort: cannot specify both -c/--check and -C/--clean
174 abort: cannot specify both -c/--check and -C/--clean
175 parent=1
175 parent=1
176 M foo
176 M foo
177
177
178 $ cd ..
178 $ cd ..
179
179
180 Test updating with closed head
180 Test updating with closed head
181 ---------------------------------------------------------------------
181 ---------------------------------------------------------------------
182
182
183 $ hg clone -U -q b1 closed-heads
183 $ hg clone -U -q b1 closed-heads
184 $ cd closed-heads
184 $ cd closed-heads
185
185
186 Test updating if at least one non-closed branch head exists
186 Test updating if at least one non-closed branch head exists
187
187
188 if on the closed branch head:
188 if on the closed branch head:
189 - updating is no-op
189 - update to "."
190 - "updated to a closed branch head ...." message is displayed
190 - "N other heads for ...." message is displayed
191 - "N other heads for ...." message is displayed
191
192
192 $ hg update -q -C 3
193 $ hg update -q -C 3
193 $ hg commit --close-branch -m 6
194 $ hg commit --close-branch -m 6
194 $ norevtest "on closed branch head" clean 6
195 $ norevtest "on closed branch head" clean 6
195 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
196 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
197 updated to a closed branch head, because all descendant heads are closed.
198 beware of re-opening closed head by subsequent commit here.
199 1 other heads for branch "default"
200 parent=6
201
202 if descendant non-closed branch head exists, and it is only one branch head:
203 - update to it, even if its revision is less than closed one
204 - "N other heads for ...." message isn't displayed
205
206 $ norevtest "non-closed 2 should be chosen" clean 1
207 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 parent=2
209
210 if all descendant branch heads are closed, but there is another branch head:
211 - update to the tipmost descendant head
212 - "updated to a closed branch head ...." message is displayed
213 - "N other heads for ...." message is displayed
214
215 $ norevtest "all descendant branch heads are closed" clean 3
216 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 updated to a closed branch head, because all descendant heads are closed.
218 beware of re-opening closed head by subsequent commit here.
196 1 other heads for branch "default"
219 1 other heads for branch "default"
197 parent=6
220 parent=6
198
221
199 Test updating if all branch heads are closed
222 Test updating if all branch heads are closed
200
223
201 if on the closed branch head:
224 if on the closed branch head:
202 - updating is no-op
225 - update to "."
203 - "N other heads for ...." message isn't displayed
226 - "updated to a closed branch head ...." message is displayed
227 - "all heads of branch ...." message is displayed
204
228
205 $ hg update -q -C 2
229 $ hg update -q -C 2
206 $ hg commit --close-branch -m 7
230 $ hg commit --close-branch -m 7
207 $ norevtest "all heads of branch default are closed" clean 6
231 $ norevtest "all heads of branch default are closed" clean 6
208 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 updated to a closed branch head, because all descendant heads are closed.
234 beware of re-opening closed head by subsequent commit here.
235 all heads for branch "default" are closed.
209 parent=6
236 parent=6
210
237
238 if not on the closed branch head:
239 - update to the tipmost descendant (closed) head
240 - "updated to a closed branch head ...." message is displayed
241 - "all heads of branch ...." message is displayed
242
243 $ norevtest "all heads of branch default are closed" clean 1
244 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 updated to a closed branch head, because all descendant heads are closed.
246 beware of re-opening closed head by subsequent commit here.
247 all heads for branch "default" are closed.
248 parent=7
249
250 $ cd ..
251
252 Test updating if "default" branch doesn't exist and no revision is
253 checked out (= "default" is used as current branch)
254
255 $ hg init no-default-branch
256 $ cd no-default-branch
257
258 $ hg branch foobar
259 marked working directory as branch foobar
260 (branches are permanent and global, did you want a bookmark?)
261 $ echo a > a
262 $ hg commit -m "#0" -A
263 adding a
264 $ echo 1 >> a
265 $ hg commit -m "#1"
266 $ hg update -q 0
267 $ echo 3 >> a
268 $ hg commit -m "#2"
269 created new head
270 $ hg commit --close-branch -m "#3"
271
272 if there is at least one non-closed branch head:
273 - update to the tipmost branch head
274
275 $ norevtest "non-closed 1 should be chosen" clean null
276 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
277 parent=1
278
279 if all branch heads are closed
280 - update to "tip"
281 - "updated to a closed branch head ...." message is displayed
282 - "all heads for branch "XXXX" are closed" message is displayed
283
284 $ hg update -q -C 1
285 $ hg commit --close-branch -m "#4"
286
287 $ norevtest "all branches are closed" clean null
288 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
289 updated to a closed branch head, because all descendant heads are closed.
290 beware of re-opening closed head by subsequent commit here.
291 all heads for branch "foobar" are closed.
292 parent=4
293
211 $ cd ../b1
294 $ cd ../b1
212
295
213 Test obsolescence behavior
296 Test obsolescence behavior
214 ---------------------------------------------------------------------
297 ---------------------------------------------------------------------
215
298
216 successors should be taken in account when checking head destination
299 successors should be taken in account when checking head destination
217
300
218 $ cat << EOF >> $HGRCPATH
301 $ cat << EOF >> $HGRCPATH
219 > [ui]
302 > [ui]
220 > logtemplate={rev}:{node|short} {desc|firstline}
303 > logtemplate={rev}:{node|short} {desc|firstline}
221 > [experimental]
304 > [experimental]
222 > evolution=createmarkers
305 > evolution=createmarkers
223 > EOF
306 > EOF
224
307
225 Test no-argument update to a successor of an obsoleted changeset
308 Test no-argument update to a successor of an obsoleted changeset
226
309
227 $ hg log -G
310 $ hg log -G
228 o 5:ff252e8273df 5
311 o 5:ff252e8273df 5
229 |
312 |
230 o 4:d047485b3896 4
313 o 4:d047485b3896 4
231 |
314 |
232 | o 3:6efa171f091b 3
315 | o 3:6efa171f091b 3
233 | |
316 | |
234 | | o 2:bd10386d478c 2
317 | | o 2:bd10386d478c 2
235 | |/
318 | |/
236 | @ 1:0786582aa4b1 1
319 | @ 1:0786582aa4b1 1
237 |/
320 |/
238 o 0:60829823a42a 0
321 o 0:60829823a42a 0
239
322
240 $ hg book bm -r 3
323 $ hg book bm -r 3
241 $ hg status
324 $ hg status
242 M foo
325 M foo
243
326
244 We add simple obsolescence marker between 3 and 4 (indirect successors)
327 We add simple obsolescence marker between 3 and 4 (indirect successors)
245
328
246 $ hg id --debug -i -r 3
329 $ hg id --debug -i -r 3
247 6efa171f091b00a3c35edc15d48c52a498929953
330 6efa171f091b00a3c35edc15d48c52a498929953
248 $ hg id --debug -i -r 4
331 $ hg id --debug -i -r 4
249 d047485b3896813b2a624e86201983520f003206
332 d047485b3896813b2a624e86201983520f003206
250 $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
333 $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
251 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206
334 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206
252
335
253 Test that 5 is detected as a valid destination from 3 and also accepts moving
336 Test that 5 is detected as a valid destination from 3 and also accepts moving
254 the bookmark (issue4015)
337 the bookmark (issue4015)
255
338
256 $ hg up --quiet --hidden 3
339 $ hg up --quiet --hidden 3
257 $ hg up 5
340 $ hg up 5
258 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
341 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
259 $ hg book bm
342 $ hg book bm
260 moving bookmark 'bm' forward from 6efa171f091b
343 moving bookmark 'bm' forward from 6efa171f091b
261 $ hg bookmarks
344 $ hg bookmarks
262 * bm 5:ff252e8273df
345 * bm 5:ff252e8273df
263
346
264 Test that 4 is detected as the no-argument destination from 3 and also moves
347 Test that 4 is detected as the no-argument destination from 3 and also moves
265 the bookmark with it
348 the bookmark with it
266 $ hg up --quiet 0 # we should be able to update to 3 directly
349 $ hg up --quiet 0 # we should be able to update to 3 directly
267 $ hg up --quiet --hidden 3 # but not implemented yet.
350 $ hg up --quiet --hidden 3 # but not implemented yet.
268 $ hg book -f bm
351 $ hg book -f bm
269 $ hg up
352 $ hg up
270 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
271 updating bookmark bm
354 updating bookmark bm
272 $ hg book
355 $ hg book
273 * bm 4:d047485b3896
356 * bm 4:d047485b3896
274
357
275 Test that 5 is detected as a valid destination from 1
358 Test that 5 is detected as a valid destination from 1
276 $ hg up --quiet 0 # we should be able to update to 3 directly
359 $ hg up --quiet 0 # we should be able to update to 3 directly
277 $ hg up --quiet --hidden 3 # but not implemented yet.
360 $ hg up --quiet --hidden 3 # but not implemented yet.
278 $ hg up 5
361 $ hg up 5
279 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
362 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
280
363
281 Test that 5 is not detected as a valid destination from 2
364 Test that 5 is not detected as a valid destination from 2
282 $ hg up --quiet 0
365 $ hg up --quiet 0
283 $ hg up --quiet 2
366 $ hg up --quiet 2
284 $ hg up 5
367 $ hg up 5
285 abort: uncommitted changes
368 abort: uncommitted changes
286 (commit or update --clean to discard changes)
369 (commit or update --clean to discard changes)
287 [255]
370 [255]
288
371
289 Test that we don't crash when updating from a pruned changeset (i.e. has no
372 Test that we don't crash when updating from a pruned changeset (i.e. has no
290 successors). Behavior should probably be that we update to the first
373 successors). Behavior should probably be that we update to the first
291 non-obsolete parent but that will be decided later.
374 non-obsolete parent but that will be decided later.
292 $ hg id --debug -r 2
375 $ hg id --debug -r 2
293 bd10386d478cd5a9faf2e604114c8e6da62d3889
376 bd10386d478cd5a9faf2e604114c8e6da62d3889
294 $ hg up --quiet 0
377 $ hg up --quiet 0
295 $ hg up --quiet 2
378 $ hg up --quiet 2
296 $ hg debugobsolete bd10386d478cd5a9faf2e604114c8e6da62d3889
379 $ hg debugobsolete bd10386d478cd5a9faf2e604114c8e6da62d3889
297 $ hg up
380 $ hg up
298 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
299
382
300 Test experimental revset support
383 Test experimental revset support
301
384
302 $ hg log -r '_destupdate()'
385 $ hg log -r '_destupdate()'
303 2:bd10386d478c 2 (no-eol)
386 2:bd10386d478c 2 (no-eol)
General Comments 0
You need to be logged in to leave comments. Login now