##// END OF EJS Templates
destutil: if wdp is obsolete, update to the closest non-obsolete ancestor...
av6 -
r49538:fbf7e383 default
parent child Browse files
Show More
@@ -1,493 +1,496 b''
1 1 # destutil.py - Mercurial utility function for command destination
2 2 #
3 3 # Copyright Olivia Mackall <olivia@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 __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from . import bookmarks, error, obsutil, scmutil, stack
12 12
13 13
14 14 def orphanpossibledestination(repo, rev):
15 15 """Return all changesets that may be a new parent for orphan `rev`.
16 16
17 17 This function works fine on non-orphan revisions, it's just silly
18 18 because there's no destination implied by obsolete markers, so
19 19 it'll return nothing.
20 20 """
21 21 tonode = repo.changelog.node
22 22 parents = repo.changelog.parentrevs
23 23 torev = repo.changelog.rev
24 24 dest = set()
25 25 tovisit = list(parents(rev))
26 26 while tovisit:
27 27 r = tovisit.pop()
28 28 succsets = obsutil.successorssets(repo, tonode(r))
29 29 if not succsets:
30 30 # if there are no successors for r, r was probably pruned
31 31 # and we should walk up to r's parents to try and find
32 32 # some successors.
33 33 tovisit.extend(parents(r))
34 34 else:
35 35 # We should probably pick only one destination from split
36 36 # (case where '1 < len(ss)'), This could be the currently
37 37 # tipmost, but the correct result is less clear when
38 38 # results of the split have been moved such that they
39 39 # reside on multiple branches.
40 40 for ss in succsets:
41 41 for n in ss:
42 42 dr = torev(n)
43 43 if dr != -1:
44 44 dest.add(dr)
45 45 return dest
46 46
47 47
48 48 def _destupdateobs(repo, clean):
49 49 """decide of an update destination from obsolescence markers"""
50 50 node = None
51 51 wc = repo[None]
52 52 p1 = wc.p1()
53 53 movemark = None
54 54
55 55 if p1.obsolete() and not p1.children():
56 56 # allow updating to successors
57 57 successors = obsutil.successorssets(repo, p1.node())
58 58
59 59 # behavior of certain cases is as follows,
60 60 #
61 61 # divergent changesets: update to highest rev, similar to what
62 62 # is currently done when there are more than one head
63 63 # (i.e. 'tip')
64 64 #
65 65 # replaced changesets: same as divergent except we know there
66 66 # is no conflict
67 67 #
68 # pruned changeset: no update is done; though, we could
69 # consider updating to the first non-obsolete parent,
70 # similar to what is current done for 'hg prune'
68 # pruned changeset: update to the closest non-obsolete ancestor,
69 # similar to what 'hg prune' currently does
71 70
72 71 if successors:
73 72 # flatten the list here handles both divergent (len > 1)
74 73 # and the usual case (len = 1)
75 74 successors = [n for sub in successors for n in sub]
76 75
77 76 # get the max revision for the given successors set,
78 77 # i.e. the 'tip' of a set
79 78 node = repo.revs(b'max(%ln)', successors).first()
80 if bookmarks.isactivewdirparent(repo):
81 movemark = repo[b'.'].node()
82 79 else:
83 # TODO: copy hg prune logic
84 node = repo[b'.'].node()
80 p1 = p1.p1()
81 while p1.obsolete():
82 p1 = p1.p1()
83 node = p1.node()
84
85 if node is not None and bookmarks.isactivewdirparent(repo):
86 movemark = repo[b'.'].node()
87
85 88 return node, movemark, None
86 89
87 90
88 91 def _destupdatebook(repo, clean):
89 92 """decide on an update destination from active bookmark"""
90 93 # we also move the active bookmark, if any
91 94 node = None
92 95 activemark, movemark = bookmarks.calculateupdate(repo.ui, repo)
93 96 if activemark is not None:
94 97 node = repo._bookmarks[activemark]
95 98 return node, movemark, activemark
96 99
97 100
98 101 def _destupdatebranch(repo, clean):
99 102 """decide on an update destination from current branch
100 103
101 104 This ignores closed branch heads.
102 105 """
103 106 wc = repo[None]
104 107 movemark = node = None
105 108 currentbranch = wc.branch()
106 109
107 110 if clean:
108 111 currentbranch = repo[b'.'].branch()
109 112
110 113 if currentbranch in repo.branchmap():
111 114 heads = repo.branchheads(currentbranch)
112 115 if heads:
113 116 node = repo.revs(b'max(.::(%ln))', heads).first()
114 117 if bookmarks.isactivewdirparent(repo):
115 118 movemark = repo[b'.'].node()
116 119 elif currentbranch == b'default' and not wc.p1():
117 120 # "null" parent belongs to "default" branch, but it doesn't exist, so
118 121 # update to the tipmost non-closed branch head
119 122 node = repo.revs(b'max(head() and not closed())').first()
120 123 else:
121 124 node = repo[b'.'].node()
122 125 return node, movemark, None
123 126
124 127
125 128 def _destupdatebranchfallback(repo, clean):
126 129 """decide on an update destination from closed heads in current branch"""
127 130 wc = repo[None]
128 131 currentbranch = wc.branch()
129 132 movemark = None
130 133 if currentbranch in repo.branchmap():
131 134 # here, all descendant branch heads are closed
132 135 heads = repo.branchheads(currentbranch, closed=True)
133 136 assert heads, b"any branch has at least one head"
134 137 node = repo.revs(b'max(.::(%ln))', heads).first()
135 138 assert (
136 139 node is not None
137 140 ), b"any revision has at least one descendant branch head"
138 141 if bookmarks.isactivewdirparent(repo):
139 142 movemark = repo[b'.'].node()
140 143 else:
141 144 # here, no "default" branch, and all branches are closed
142 145 node = repo.lookup(b'tip')
143 146 assert node is not None, b"'tip' exists even in empty repository"
144 147 return node, movemark, None
145 148
146 149
147 150 # order in which each step should be evaluated
148 151 # steps are run until one finds a destination
149 152 destupdatesteps = [b'evolution', b'bookmark', b'branch', b'branchfallback']
150 153 # mapping to ease extension overriding steps.
151 154 destupdatestepmap = {
152 155 b'evolution': _destupdateobs,
153 156 b'bookmark': _destupdatebook,
154 157 b'branch': _destupdatebranch,
155 158 b'branchfallback': _destupdatebranchfallback,
156 159 }
157 160
158 161
159 162 def destupdate(repo, clean=False):
160 163 """destination for bare update operation
161 164
162 165 return (rev, movemark, activemark)
163 166
164 167 - rev: the revision to update to,
165 168 - movemark: node to move the active bookmark from
166 169 (cf bookmark.calculate update),
167 170 - activemark: a bookmark to activate at the end of the update.
168 171 """
169 172 node = movemark = activemark = None
170 173
171 174 for step in destupdatesteps:
172 175 node, movemark, activemark = destupdatestepmap[step](repo, clean)
173 176 if node is not None:
174 177 break
175 178 rev = repo[node].rev()
176 179
177 180 return rev, movemark, activemark
178 181
179 182
180 183 msgdestmerge = {
181 184 # too many matching divergent bookmark
182 185 b'toomanybookmarks': {
183 186 b'merge': (
184 187 _(
185 188 b"multiple matching bookmarks to merge -"
186 189 b" please merge with an explicit rev or bookmark"
187 190 ),
188 191 _(b"run 'hg heads' to see all heads, specify rev with -r"),
189 192 ),
190 193 b'rebase': (
191 194 _(
192 195 b"multiple matching bookmarks to rebase -"
193 196 b" please rebase to an explicit rev or bookmark"
194 197 ),
195 198 _(b"run 'hg heads' to see all heads, specify destination with -d"),
196 199 ),
197 200 },
198 201 # no other matching divergent bookmark
199 202 b'nootherbookmarks': {
200 203 b'merge': (
201 204 _(
202 205 b"no matching bookmark to merge - "
203 206 b"please merge with an explicit rev or bookmark"
204 207 ),
205 208 _(b"run 'hg heads' to see all heads, specify rev with -r"),
206 209 ),
207 210 b'rebase': (
208 211 _(
209 212 b"no matching bookmark to rebase - "
210 213 b"please rebase to an explicit rev or bookmark"
211 214 ),
212 215 _(b"run 'hg heads' to see all heads, specify destination with -d"),
213 216 ),
214 217 },
215 218 # branch have too many unbookmarked heads, no obvious destination
216 219 b'toomanyheads': {
217 220 b'merge': (
218 221 _(b"branch '%s' has %d heads - please merge with an explicit rev"),
219 222 _(b"run 'hg heads .' to see heads, specify rev with -r"),
220 223 ),
221 224 b'rebase': (
222 225 _(b"branch '%s' has %d heads - please rebase to an explicit rev"),
223 226 _(b"run 'hg heads .' to see heads, specify destination with -d"),
224 227 ),
225 228 },
226 229 # branch have no other unbookmarked heads
227 230 b'bookmarkedheads': {
228 231 b'merge': (
229 232 _(b"heads are bookmarked - please merge with an explicit rev"),
230 233 _(b"run 'hg heads' to see all heads, specify rev with -r"),
231 234 ),
232 235 b'rebase': (
233 236 _(b"heads are bookmarked - please rebase to an explicit rev"),
234 237 _(b"run 'hg heads' to see all heads, specify destination with -d"),
235 238 ),
236 239 },
237 240 # branch have just a single heads, but there is other branches
238 241 b'nootherbranchheads': {
239 242 b'merge': (
240 243 _(b"branch '%s' has one head - please merge with an explicit rev"),
241 244 _(b"run 'hg heads' to see all heads, specify rev with -r"),
242 245 ),
243 246 b'rebase': (
244 247 _(b"branch '%s' has one head - please rebase to an explicit rev"),
245 248 _(b"run 'hg heads' to see all heads, specify destination with -d"),
246 249 ),
247 250 },
248 251 # repository have a single head
249 252 b'nootherheads': {
250 253 b'merge': (_(b'nothing to merge'), None),
251 254 b'rebase': (_(b'nothing to rebase'), None),
252 255 },
253 256 # repository have a single head and we are not on it
254 257 b'nootherheadsbehind': {
255 258 b'merge': (_(b'nothing to merge'), _(b"use 'hg update' instead")),
256 259 b'rebase': (_(b'nothing to rebase'), _(b"use 'hg update' instead")),
257 260 },
258 261 # We are not on a head
259 262 b'notatheads': {
260 263 b'merge': (
261 264 _(b'working directory not at a head revision'),
262 265 _(b"use 'hg update' or merge with an explicit revision"),
263 266 ),
264 267 b'rebase': (
265 268 _(b'working directory not at a head revision'),
266 269 _(b"use 'hg update' or rebase to an explicit revision"),
267 270 ),
268 271 },
269 272 b'emptysourceset': {
270 273 b'merge': (_(b'source set is empty'), None),
271 274 b'rebase': (_(b'source set is empty'), None),
272 275 },
273 276 b'multiplebranchessourceset': {
274 277 b'merge': (_(b'source set is rooted in multiple branches'), None),
275 278 b'rebase': (
276 279 _(b'rebaseset is rooted in multiple named branches'),
277 280 _(b'specify an explicit destination with --dest'),
278 281 ),
279 282 },
280 283 }
281 284
282 285
283 286 def _destmergebook(repo, action=b'merge', sourceset=None, destspace=None):
284 287 """find merge destination in the active bookmark case"""
285 288 node = None
286 289 bmheads = bookmarks.headsforactive(repo)
287 290 curhead = repo._bookmarks[repo._activebookmark]
288 291 if len(bmheads) == 2:
289 292 if curhead == bmheads[0]:
290 293 node = bmheads[1]
291 294 else:
292 295 node = bmheads[0]
293 296 elif len(bmheads) > 2:
294 297 msg, hint = msgdestmerge[b'toomanybookmarks'][action]
295 298 raise error.ManyMergeDestAbort(msg, hint=hint)
296 299 elif len(bmheads) <= 1:
297 300 msg, hint = msgdestmerge[b'nootherbookmarks'][action]
298 301 raise error.NoMergeDestAbort(msg, hint=hint)
299 302 assert node is not None
300 303 return node
301 304
302 305
303 306 def _destmergebranch(
304 307 repo, action=b'merge', sourceset=None, onheadcheck=True, destspace=None
305 308 ):
306 309 """find merge destination based on branch heads"""
307 310 node = None
308 311
309 312 if sourceset is None:
310 313 sourceset = [repo[repo.dirstate.p1()].rev()]
311 314 branch = repo.dirstate.branch()
312 315 elif not sourceset:
313 316 msg, hint = msgdestmerge[b'emptysourceset'][action]
314 317 raise error.NoMergeDestAbort(msg, hint=hint)
315 318 else:
316 319 branch = None
317 320 for ctx in repo.set(b'roots(%ld::%ld)', sourceset, sourceset):
318 321 if branch is not None and ctx.branch() != branch:
319 322 msg, hint = msgdestmerge[b'multiplebranchessourceset'][action]
320 323 raise error.ManyMergeDestAbort(msg, hint=hint)
321 324 branch = ctx.branch()
322 325
323 326 bheads = repo.branchheads(branch)
324 327 onhead = repo.revs(b'%ld and %ln', sourceset, bheads)
325 328 if onheadcheck and not onhead:
326 329 # Case A: working copy if not on a head. (merge only)
327 330 #
328 331 # This is probably a user mistake We bailout pointing at 'hg update'
329 332 if len(repo.heads()) <= 1:
330 333 msg, hint = msgdestmerge[b'nootherheadsbehind'][action]
331 334 else:
332 335 msg, hint = msgdestmerge[b'notatheads'][action]
333 336 raise error.Abort(msg, hint=hint)
334 337 # remove heads descendants of source from the set
335 338 bheads = list(repo.revs(b'%ln - (%ld::)', bheads, sourceset))
336 339 # filters out bookmarked heads
337 340 nbhs = list(repo.revs(b'%ld - bookmark()', bheads))
338 341
339 342 if destspace is not None:
340 343 # restrict search space
341 344 # used in the 'hg pull --rebase' case, see issue 5214.
342 345 nbhs = list(repo.revs(b'%ld and %ld', destspace, nbhs))
343 346
344 347 if len(nbhs) > 1:
345 348 # Case B: There is more than 1 other anonymous heads
346 349 #
347 350 # This means that there will be more than 1 candidate. This is
348 351 # ambiguous. We abort asking the user to pick as explicit destination
349 352 # instead.
350 353 msg, hint = msgdestmerge[b'toomanyheads'][action]
351 354 msg %= (branch, len(bheads) + 1)
352 355 raise error.ManyMergeDestAbort(msg, hint=hint)
353 356 elif not nbhs:
354 357 # Case B: There is no other anonymous heads
355 358 #
356 359 # This means that there is no natural candidate to merge with.
357 360 # We abort, with various messages for various cases.
358 361 if bheads:
359 362 msg, hint = msgdestmerge[b'bookmarkedheads'][action]
360 363 elif len(repo.heads()) > 1:
361 364 msg, hint = msgdestmerge[b'nootherbranchheads'][action]
362 365 msg %= branch
363 366 elif not onhead:
364 367 # if 'onheadcheck == False' (rebase case),
365 368 # this was not caught in Case A.
366 369 msg, hint = msgdestmerge[b'nootherheadsbehind'][action]
367 370 else:
368 371 msg, hint = msgdestmerge[b'nootherheads'][action]
369 372 raise error.NoMergeDestAbort(msg, hint=hint)
370 373 else:
371 374 node = nbhs[0]
372 375 assert node is not None
373 376 return node
374 377
375 378
376 379 def destmerge(
377 380 repo, action=b'merge', sourceset=None, onheadcheck=True, destspace=None
378 381 ):
379 382 """return the default destination for a merge
380 383
381 384 (or raise exception about why it can't pick one)
382 385
383 386 :action: the action being performed, controls emitted error message
384 387 """
385 388 # destspace is here to work around issues with `hg pull --rebase` see
386 389 # issue5214 for details
387 390 if repo._activebookmark:
388 391 node = _destmergebook(
389 392 repo, action=action, sourceset=sourceset, destspace=destspace
390 393 )
391 394 else:
392 395 node = _destmergebranch(
393 396 repo,
394 397 action=action,
395 398 sourceset=sourceset,
396 399 onheadcheck=onheadcheck,
397 400 destspace=destspace,
398 401 )
399 402 return repo[node].rev()
400 403
401 404
402 405 def desthistedit(ui, repo):
403 406 """Default base revision to edit for `hg histedit`."""
404 407 default = ui.config(b'histedit', b'defaultrev')
405 408
406 409 if default is None:
407 410 revs = stack.getstack(repo)
408 411 elif default:
409 412 revs = scmutil.revrange(repo, [default])
410 413 else:
411 414 raise error.ConfigError(
412 415 _(b"config option histedit.defaultrev can't be empty")
413 416 )
414 417
415 418 if revs:
416 419 # Take the first revision of the revset as the root
417 420 return revs.min()
418 421
419 422 return None
420 423
421 424
422 425 def stackbase(ui, repo):
423 426 revs = stack.getstack(repo)
424 427 return revs.first() if revs else None
425 428
426 429
427 430 def _statusotherbook(ui, repo):
428 431 bmheads = bookmarks.headsforactive(repo)
429 432 curhead = repo._bookmarks[repo._activebookmark]
430 433 if repo.revs(b'%n and parents()', curhead):
431 434 # we are on the active bookmark
432 435 bmheads = [b for b in bmheads if curhead != b]
433 436 if bmheads:
434 437 msg = _(b'%i other divergent bookmarks for "%s"\n')
435 438 ui.status(msg % (len(bmheads), repo._activebookmark))
436 439
437 440
438 441 def _statusotherbranchheads(ui, repo):
439 442 currentbranch = repo.dirstate.branch()
440 443 allheads = repo.branchheads(currentbranch, closed=True)
441 444 heads = repo.branchheads(currentbranch)
442 445 if repo.revs(b'%ln and parents()', allheads):
443 446 # we are on a head, even though it might be closed
444 447 #
445 448 # on closed otherheads
446 449 # ========= ==========
447 450 # o 0 all heads for current branch are closed
448 451 # N only descendant branch heads are closed
449 452 # x 0 there is only one non-closed branch head
450 453 # N there are some non-closed branch heads
451 454 # ========= ==========
452 455 otherheads = repo.revs(b'%ln - parents()', heads)
453 456 if repo[b'.'].closesbranch():
454 457 ui.warn(
455 458 _(
456 459 b'no open descendant heads on branch "%s", '
457 460 b'updating to a closed head\n'
458 461 )
459 462 % currentbranch
460 463 )
461 464 if otherheads:
462 465 ui.warn(
463 466 _(
464 467 b"(committing will reopen the head, "
465 468 b"use 'hg heads .' to see %i other heads)\n"
466 469 )
467 470 % (len(otherheads))
468 471 )
469 472 else:
470 473 ui.warn(
471 474 _(b'(committing will reopen branch "%s")\n') % currentbranch
472 475 )
473 476 elif otherheads:
474 477 curhead = repo[b'.']
475 478 ui.status(
476 479 _(b'updated to "%s: %s"\n')
477 480 % (curhead, curhead.description().split(b'\n')[0])
478 481 )
479 482 ui.status(
480 483 _(b'%i other heads for branch "%s"\n')
481 484 % (len(otherheads), currentbranch)
482 485 )
483 486
484 487
485 488 def statusotherdests(ui, repo):
486 489 """Print message about other head"""
487 490 # XXX we should probably include a hint:
488 491 # - about what to do
489 492 # - how to see such heads
490 493 if repo._activebookmark:
491 494 _statusotherbook(ui, repo)
492 495 else:
493 496 _statusotherbranchheads(ui, repo)
@@ -1,726 +1,722 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [commands]
3 3 > status.verbose=1
4 4 > EOF
5 5
6 6 # Construct the following history tree:
7 7 #
8 8 # @ 5:e1bb631146ca b1
9 9 # |
10 10 # o 4:a4fdb3b883c4 0:b608b9236435 b1
11 11 # |
12 12 # | o 3:4b57d2520816 1:44592833ba9f
13 13 # | |
14 14 # | | o 2:063f31070f65
15 15 # | |/
16 16 # | o 1:44592833ba9f
17 17 # |/
18 18 # o 0:b608b9236435
19 19
20 20 $ mkdir b1
21 21 $ cd b1
22 22 $ hg init
23 23 $ echo foo > foo
24 24 $ echo zero > a
25 25 $ hg init sub
26 26 $ echo suba > sub/suba
27 27 $ hg --cwd sub ci -Am addsuba
28 28 adding suba
29 29 $ echo 'sub = sub' > .hgsub
30 30 $ hg ci -qAm0
31 31 $ echo one > a ; hg ci -m1
32 32 $ echo two > a ; hg ci -m2
33 33 $ hg up -q 1
34 34 $ echo three > a ; hg ci -qm3
35 35 $ hg up -q 0
36 36 $ hg branch -q b1
37 37 $ echo four > a ; hg ci -qm4
38 38 $ echo five > a ; hg ci -qm5
39 39
40 40 Initial repo state:
41 41
42 42 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
43 43 @ 5:ff252e8273df b1
44 44 |
45 45 o 4:d047485b3896 0:60829823a42a b1
46 46 |
47 47 | o 3:6efa171f091b 1:0786582aa4b1
48 48 | |
49 49 | | o 2:bd10386d478c
50 50 | |/
51 51 | o 1:0786582aa4b1
52 52 |/
53 53 o 0:60829823a42a
54 54
55 55
56 56 Make sure update doesn't assume b1 is a repository if invoked from outside:
57 57
58 58 $ cd ..
59 59 $ hg update b1
60 60 abort: no repository found in '$TESTTMP' (.hg not found)
61 61 [10]
62 62 $ cd b1
63 63
64 64 Test helper functions:
65 65
66 66 $ revtest () {
67 67 > msg=$1
68 68 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
69 69 > startrev=$3
70 70 > targetrev=$4
71 71 > opt=$5
72 72 > hg up -qC $startrev
73 73 > test $dirtyflag = dirty && echo dirty > foo
74 74 > test $dirtyflag = dirtysub && echo dirty > sub/suba
75 75 > hg up $opt $targetrev
76 76 > hg parent --template 'parent={rev}\n'
77 77 > hg stat -S
78 78 > }
79 79
80 80 $ norevtest () {
81 81 > msg=$1
82 82 > dirtyflag=$2 # 'clean', 'dirty' or 'dirtysub'
83 83 > startrev=$3
84 84 > opt=$4
85 85 > hg up -qC $startrev
86 86 > test $dirtyflag = dirty && echo dirty > foo
87 87 > test $dirtyflag = dirtysub && echo dirty > sub/suba
88 88 > hg up $opt
89 89 > hg parent --template 'parent={rev}\n'
90 90 > hg stat -S
91 91 > }
92 92
93 93 Test cases are documented in a table in the update function of merge.py.
94 94 Cases are run as shown in that table, row by row.
95 95
96 96 $ norevtest 'none clean linear' clean 4
97 97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 98 parent=5
99 99
100 100 $ norevtest 'none clean same' clean 2
101 101 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 102 updated to "bd10386d478c: 2"
103 103 1 other heads for branch "default"
104 104 parent=2
105 105
106 106
107 107 $ revtest 'none clean linear' clean 1 2
108 108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 109 parent=2
110 110
111 111 $ revtest 'none clean same' clean 2 3
112 112 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 113 parent=3
114 114
115 115 $ revtest 'none clean cross' clean 3 4
116 116 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 117 parent=4
118 118
119 119
120 120 $ revtest 'none dirty linear' dirty 1 2
121 121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 122 parent=2
123 123 M foo
124 124
125 125 $ revtest 'none dirtysub linear' dirtysub 1 2
126 126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 127 parent=2
128 128 M sub/suba
129 129
130 130 $ revtest 'none dirty same' dirty 2 3
131 131 abort: uncommitted changes
132 132 (commit or update --clean to discard changes)
133 133 parent=2
134 134 M foo
135 135
136 136 $ revtest 'none dirtysub same' dirtysub 2 3
137 137 abort: uncommitted changes
138 138 (commit or update --clean to discard changes)
139 139 parent=2
140 140 M sub/suba
141 141
142 142 $ revtest 'none dirty cross' dirty 3 4
143 143 abort: uncommitted changes
144 144 (commit or update --clean to discard changes)
145 145 parent=3
146 146 M foo
147 147
148 148 $ norevtest 'none dirty cross' dirty 2
149 149 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 150 updated to "bd10386d478c: 2"
151 151 1 other heads for branch "default"
152 152 parent=2
153 153 M foo
154 154
155 155 $ revtest 'none dirtysub cross' dirtysub 3 4
156 156 abort: uncommitted changes
157 157 (commit or update --clean to discard changes)
158 158 parent=3
159 159 M sub/suba
160 160
161 161 $ revtest '--clean dirty linear' dirty 1 2 --clean
162 162 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 163 parent=2
164 164
165 165 $ revtest '--check dirty linear' dirty 1 2 --check
166 166 abort: uncommitted changes
167 167 parent=1
168 168 M foo
169 169
170 170 $ revtest '--merge dirty linear' dirty 1 2 --merge
171 171 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
172 172 parent=2
173 173 M foo
174 174
175 175 $ revtest '--merge dirty cross' dirty 3 4 --merge
176 176 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
177 177 parent=4
178 178 M foo
179 179
180 180 $ revtest '--check dirtysub linear' dirtysub 1 2 --check
181 181 abort: uncommitted changes in subrepository "sub"
182 182 parent=1
183 183 M sub/suba
184 184
185 185 $ norevtest '--check clean same' clean 2 -c
186 186 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 187 updated to "bd10386d478c: 2"
188 188 1 other heads for branch "default"
189 189 parent=2
190 190
191 191 $ revtest '--check --clean dirty linear' dirty 1 2 "--check --clean"
192 192 abort: cannot specify both --clean and --check
193 193 parent=1
194 194 M foo
195 195
196 196 $ revtest '--merge -checkc dirty linear' dirty 1 2 "--merge --check"
197 197 abort: cannot specify both --check and --merge
198 198 parent=1
199 199 M foo
200 200
201 201 $ revtest '--merge -clean dirty linear' dirty 1 2 "--merge --clean"
202 202 abort: cannot specify both --clean and --merge
203 203 parent=1
204 204 M foo
205 205
206 206 $ echo '[commands]' >> .hg/hgrc
207 207 $ echo 'update.check = abort' >> .hg/hgrc
208 208
209 209 $ revtest 'none dirty linear' dirty 1 2
210 210 abort: uncommitted changes
211 211 parent=1
212 212 M foo
213 213
214 214 $ revtest 'none dirty linear' dirty 1 2 --check
215 215 abort: uncommitted changes
216 216 parent=1
217 217 M foo
218 218
219 219 $ revtest '--merge none dirty linear' dirty 1 2 --check
220 220 abort: uncommitted changes
221 221 parent=1
222 222 M foo
223 223
224 224 $ revtest '--merge none dirty linear' dirty 1 2 --merge
225 225 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 226 parent=2
227 227 M foo
228 228
229 229 $ revtest '--merge none dirty linear' dirty 1 2 --no-check
230 230 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 231 parent=2
232 232 M foo
233 233
234 234 $ revtest 'none dirty linear' dirty 1 2 --clean
235 235 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 236 parent=2
237 237
238 238 $ echo 'update.check = none' >> .hg/hgrc
239 239
240 240 $ revtest 'none dirty cross' dirty 3 4
241 241 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 242 parent=4
243 243 M foo
244 244
245 245 $ revtest 'none dirty linear' dirty 1 2
246 246 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 247 parent=2
248 248 M foo
249 249
250 250 $ revtest 'none dirty linear' dirty 1 2 --check
251 251 abort: uncommitted changes
252 252 parent=1
253 253 M foo
254 254
255 255 $ revtest 'none dirty linear' dirty 1 2 --no-merge
256 256 abort: uncommitted changes
257 257 parent=1
258 258 M foo
259 259
260 260 $ revtest 'none dirty linear' dirty 1 2 --clean
261 261 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
262 262 parent=2
263 263
264 264 $ hg co -qC 3
265 265 $ echo dirty >> a
266 266 $ hg co --tool :merge3 4
267 267 merging a
268 268 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
269 269 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
270 270 use 'hg resolve' to retry unresolved file merges
271 271 [1]
272 272 $ hg log -G --template '{rev}:{node|short} {parents} {branches}\n'
273 273 o 5:ff252e8273df b1
274 274 |
275 275 @ 4:d047485b3896 0:60829823a42a b1
276 276 |
277 277 | % 3:6efa171f091b 1:0786582aa4b1
278 278 | |
279 279 | | o 2:bd10386d478c
280 280 | |/
281 281 | o 1:0786582aa4b1
282 282 |/
283 283 o 0:60829823a42a
284 284
285 285 $ hg st
286 286 M a
287 287 ? a.orig
288 288 # Unresolved merge conflicts:
289 289 #
290 290 # a
291 291 #
292 292 # To mark files as resolved: hg resolve --mark FILE
293 293
294 294 $ cat a
295 295 <<<<<<< working copy: 6efa171f091b - test: 3
296 296 three
297 297 dirty
298 298 ||||||| working copy parent: 6efa171f091b - test: 3
299 299 three
300 300 =======
301 301 four
302 302 >>>>>>> destination: d047485b3896 b1 - test: 4
303 303 $ rm a.orig
304 304
305 305 $ echo 'update.check = noconflict' >> .hg/hgrc
306 306
307 307 $ revtest 'none dirty cross' dirty 3 4
308 308 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
309 309 parent=4
310 310 M foo
311 311
312 312 $ revtest 'none dirty linear' dirty 1 2
313 313 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
314 314 parent=2
315 315 M foo
316 316
317 317 $ revtest 'none dirty linear' dirty 1 2 -c
318 318 abort: uncommitted changes
319 319 parent=1
320 320 M foo
321 321
322 322 $ revtest 'none dirty linear' dirty 1 2 -C
323 323 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
324 324 parent=2
325 325
326 326 Locally added file is allowed
327 327 $ hg up -qC 3
328 328 $ echo a > bar
329 329 $ hg add bar
330 330 $ hg up -q 4
331 331 $ hg st
332 332 A bar
333 333 $ hg forget bar
334 334 $ rm bar
335 335
336 336 Locally removed file is allowed
337 337 $ hg up -qC 3
338 338 $ hg rm foo
339 339 $ hg up -q 4
340 340
341 341 File conflict is not allowed
342 342 $ hg up -qC 3
343 343 $ echo dirty >> a
344 344 $ hg up -q 4
345 345 abort: conflicting changes
346 346 (commit or update --clean to discard changes)
347 347 [20]
348 348 $ hg up -m 4
349 349 merging a
350 350 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
351 351 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
352 352 use 'hg resolve' to retry unresolved file merges
353 353 [1]
354 354 $ rm a.orig
355 355 $ hg status
356 356 M a
357 357 # Unresolved merge conflicts:
358 358 #
359 359 # a
360 360 #
361 361 # To mark files as resolved: hg resolve --mark FILE
362 362
363 363 $ hg resolve -l
364 364 U a
365 365
366 366 Try to make empty commit while there are conflicts
367 367 $ hg revert -r . a
368 368 $ rm a.orig
369 369 $ hg ci -m empty
370 370 abort: unresolved merge conflicts (see 'hg help resolve')
371 371 [20]
372 372 $ hg resolve -m a
373 373 (no more unresolved files)
374 374 $ hg resolve -l
375 375 R a
376 376 $ hg ci -m empty
377 377 nothing changed
378 378 [1]
379 379 $ hg resolve -l
380 380
381 381 Change/delete conflict is not allowed
382 382 $ hg up -qC 3
383 383 $ hg rm foo
384 384 $ hg up -q 4
385 385
386 386 Uses default value of "linear" when value is misspelled
387 387 $ echo 'update.check = linyar' >> .hg/hgrc
388 388
389 389 $ revtest 'dirty cross' dirty 3 4
390 390 abort: uncommitted changes
391 391 (commit or update --clean to discard changes)
392 392 parent=3
393 393 M foo
394 394
395 395 Setup for later tests
396 396 $ revtest 'none dirty linear' dirty 1 2 -c
397 397 abort: uncommitted changes
398 398 parent=1
399 399 M foo
400 400
401 401 $ cd ..
402 402
403 403 Test updating to null revision
404 404
405 405 $ hg init null-repo
406 406 $ cd null-repo
407 407 $ echo a > a
408 408 $ hg add a
409 409 $ hg ci -m a
410 410 $ hg up -qC 0
411 411 $ echo b > b
412 412 $ hg add b
413 413 $ hg up null
414 414 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
415 415 $ hg st
416 416 A b
417 417 $ hg up -q 0
418 418 $ hg st
419 419 A b
420 420 $ hg up -qC null
421 421 $ hg st
422 422 ? b
423 423 $ cd ..
424 424
425 425 Test updating with closed head
426 426 ---------------------------------------------------------------------
427 427
428 428 $ hg clone -U -q b1 closed-heads
429 429 $ cd closed-heads
430 430
431 431 Test updating if at least one non-closed branch head exists
432 432
433 433 if on the closed branch head:
434 434 - update to "."
435 435 - "updated to a closed branch head ...." message is displayed
436 436 - "N other heads for ...." message is displayed
437 437
438 438 $ hg update -q -C 3
439 439 $ hg commit --close-branch -m 6
440 440 $ norevtest "on closed branch head" clean 6
441 441 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
442 442 no open descendant heads on branch "default", updating to a closed head
443 443 (committing will reopen the head, use 'hg heads .' to see 1 other heads)
444 444 parent=6
445 445
446 446 if descendant non-closed branch head exists, and it is only one branch head:
447 447 - update to it, even if its revision is less than closed one
448 448 - "N other heads for ...." message isn't displayed
449 449
450 450 $ norevtest "non-closed 2 should be chosen" clean 1
451 451 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 452 parent=2
453 453
454 454 if all descendant branch heads are closed, but there is another branch head:
455 455 - update to the tipmost descendant head
456 456 - "updated to a closed branch head ...." message is displayed
457 457 - "N other heads for ...." message is displayed
458 458
459 459 $ norevtest "all descendant branch heads are closed" clean 3
460 460 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
461 461 no open descendant heads on branch "default", updating to a closed head
462 462 (committing will reopen the head, use 'hg heads .' to see 1 other heads)
463 463 parent=6
464 464
465 465 Test updating if all branch heads are closed
466 466
467 467 if on the closed branch head:
468 468 - update to "."
469 469 - "updated to a closed branch head ...." message is displayed
470 470 - "all heads of branch ...." message is displayed
471 471
472 472 $ hg update -q -C 2
473 473 $ hg commit --close-branch -m 7
474 474 $ norevtest "all heads of branch default are closed" clean 6
475 475 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
476 476 no open descendant heads on branch "default", updating to a closed head
477 477 (committing will reopen branch "default")
478 478 parent=6
479 479
480 480 if not on the closed branch head:
481 481 - update to the tipmost descendant (closed) head
482 482 - "updated to a closed branch head ...." message is displayed
483 483 - "all heads of branch ...." message is displayed
484 484
485 485 $ norevtest "all heads of branch default are closed" clean 1
486 486 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
487 487 no open descendant heads on branch "default", updating to a closed head
488 488 (committing will reopen branch "default")
489 489 parent=7
490 490
491 491 $ cd ..
492 492
493 493 Test updating if "default" branch doesn't exist and no revision is
494 494 checked out (= "default" is used as current branch)
495 495
496 496 $ hg init no-default-branch
497 497 $ cd no-default-branch
498 498
499 499 $ hg branch foobar
500 500 marked working directory as branch foobar
501 501 (branches are permanent and global, did you want a bookmark?)
502 502 $ echo a > a
503 503 $ hg commit -m "#0" -A
504 504 adding a
505 505 $ echo 1 >> a
506 506 $ hg commit -m "#1"
507 507 $ hg update -q 0
508 508 $ echo 3 >> a
509 509 $ hg commit -m "#2"
510 510 created new head
511 511 $ hg commit --close-branch -m "#3"
512 512
513 513 if there is at least one non-closed branch head:
514 514 - update to the tipmost branch head
515 515
516 516 $ norevtest "non-closed 1 should be chosen" clean null
517 517 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
518 518 parent=1
519 519
520 520 if all branch heads are closed
521 521 - update to "tip"
522 522 - "updated to a closed branch head ...." message is displayed
523 523 - "all heads for branch "XXXX" are closed" message is displayed
524 524
525 525 $ hg update -q -C 1
526 526 $ hg commit --close-branch -m "#4"
527 527
528 528 $ norevtest "all branches are closed" clean null
529 529 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 530 no open descendant heads on branch "foobar", updating to a closed head
531 531 (committing will reopen branch "foobar")
532 532 parent=4
533 533
534 534 $ cd ../b1
535 535
536 536 Test obsolescence behavior
537 537 ---------------------------------------------------------------------
538 538
539 539 successors should be taken in account when checking head destination
540 540
541 541 $ cat << EOF >> $HGRCPATH
542 542 > [ui]
543 543 > logtemplate={rev}:{node|short} {desc|firstline}
544 544 > [experimental]
545 545 > evolution.createmarkers=True
546 546 > EOF
547 547
548 548 Test no-argument update to a successor of an obsoleted changeset
549 549
550 550 $ hg log -G
551 551 o 5:ff252e8273df 5
552 552 |
553 553 o 4:d047485b3896 4
554 554 |
555 555 | o 3:6efa171f091b 3
556 556 | |
557 557 | | o 2:bd10386d478c 2
558 558 | |/
559 559 | @ 1:0786582aa4b1 1
560 560 |/
561 561 o 0:60829823a42a 0
562 562
563 563 $ hg book bm -r 3
564 564 $ hg status
565 565 M foo
566 566
567 567 We add simple obsolescence marker between 3 and 4 (indirect successors)
568 568
569 569 $ hg id --debug -i -r 3
570 570 6efa171f091b00a3c35edc15d48c52a498929953
571 571 $ hg id --debug -i -r 4
572 572 d047485b3896813b2a624e86201983520f003206
573 573 $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
574 574 1 new obsolescence markers
575 575 obsoleted 1 changesets
576 576 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206
577 577 1 new obsolescence markers
578 578
579 579 Test that 5 is detected as a valid destination from 3 and also accepts moving
580 580 the bookmark (issue4015)
581 581
582 582 $ hg up --quiet --hidden 3
583 583 $ hg up 5
584 584 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
585 585 $ hg book bm
586 586 moving bookmark 'bm' forward from 6efa171f091b
587 587 $ hg bookmarks
588 588 * bm 5:ff252e8273df
589 589
590 590 Test that we abort before we warn about the hidden commit if the working
591 591 directory is dirty
592 592 $ echo conflict > a
593 593 $ hg up --hidden 3
594 594 abort: uncommitted changes
595 595 (commit or update --clean to discard changes)
596 596 [255]
597 597
598 598 Test that we still warn also when there are conflicts
599 599 $ hg up -m --hidden 3
600 600 merging a
601 601 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
602 602 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
603 603 use 'hg resolve' to retry unresolved file merges
604 604 (leaving bookmark bm)
605 605 updated to hidden changeset 6efa171f091b
606 606 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
607 607 [1]
608 608
609 609 Test that statuses are reported properly before and after merge resolution.
610 610 $ rm a.orig
611 611 $ hg resolve -l
612 612 U a
613 613 $ hg status
614 614 M a
615 615 M foo
616 616 # Unresolved merge conflicts:
617 617 #
618 618 # a
619 619 #
620 620 # To mark files as resolved: hg resolve --mark FILE
621 621
622 622
623 623 $ hg revert -r . a
624 624
625 625 $ rm a.orig
626 626 $ hg resolve -l
627 627 U a
628 628 $ hg status
629 629 M foo
630 630 # Unresolved merge conflicts:
631 631 #
632 632 # a
633 633 #
634 634 # To mark files as resolved: hg resolve --mark FILE
635 635
636 636 $ hg status -Tjson
637 637 [
638 638 {
639 639 "itemtype": "file",
640 640 "path": "foo",
641 641 "status": "M"
642 642 },
643 643 {
644 644 "itemtype": "file",
645 645 "path": "a",
646 646 "unresolved": true
647 647 }
648 648 ]
649 649
650 650 $ hg resolve -m
651 651 (no more unresolved files)
652 652
653 653 $ hg resolve -l
654 654 R a
655 655 $ hg status
656 656 M foo
657 657 # No unresolved merge conflicts.
658 658
659 659 $ hg status -Tjson
660 660 [
661 661 {
662 662 "itemtype": "file",
663 663 "path": "foo",
664 664 "status": "M"
665 665 }
666 666 ]
667 667
668 668 Test that 4 is detected as the no-argument destination from 3 and also moves
669 669 the bookmark with it
670 670 $ hg up --quiet 0 # we should be able to update to 3 directly
671 671 $ hg status
672 672 M foo
673 673 $ hg up --quiet --hidden 3 # but not implemented yet.
674 674 updated to hidden changeset 6efa171f091b
675 675 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
676 676 $ hg book -f bm
677 677 $ hg up
678 678 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
679 679 updating bookmark bm
680 680 $ hg book
681 681 * bm 4:d047485b3896
682 682
683 683 Test that 5 is detected as a valid destination from 1
684 684 $ hg up --quiet 0 # we should be able to update to 3 directly
685 685 $ hg up --quiet --hidden 3 # but not implemented yet.
686 686 updated to hidden changeset 6efa171f091b
687 687 (hidden revision '6efa171f091b' was rewritten as: d047485b3896)
688 688 $ hg up 5
689 689 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
690 690
691 691 Test that 5 is not detected as a valid destination from 2
692 692 $ hg up --quiet 0
693 693 $ hg up --quiet 2
694 694 $ hg up 5
695 695 abort: uncommitted changes
696 696 (commit or update --clean to discard changes)
697 697 [255]
698 698
699 Test that we don't crash when updating from a pruned changeset (i.e. has no
700 successors). Behavior should probably be that we update to the first
701 non-obsolete parent but that will be decided later.
699 Test that we update to the closest non-obsolete ancestor when updating from a
700 pruned changeset (i.e. that has no successors)
702 701 $ hg id --debug -r 2
703 702 bd10386d478cd5a9faf2e604114c8e6da62d3889
704 703 $ hg up --quiet 0
705 704 $ hg up --quiet 2
706 705 $ hg debugobsolete bd10386d478cd5a9faf2e604114c8e6da62d3889
707 706 1 new obsolescence markers
708 707 obsoleted 1 changesets
708 $ hg log -r '_destupdate()'
709 1:0786582aa4b1 1 (no-eol)
709 710 $ hg up
710 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
711
712 Test experimental revset support
713
714 $ hg log -r '_destupdate()'
715 2:bd10386d478c 2 (no-eol)
711 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
716 712
717 713 Test that boolean flags allow --no-flag specification to override [defaults]
718 714 $ cat >> $HGRCPATH <<EOF
719 715 > [defaults]
720 716 > update = --check
721 717 > EOF
722 $ hg co 2
718 $ hg co 1
723 719 abort: uncommitted changes
724 720 [20]
725 $ hg co --no-check 2
721 $ hg co --no-check 1
726 722 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
General Comments 0
You need to be logged in to leave comments. Login now