##// END OF EJS Templates
merge: back out single-parent fast-forward merge...
Matt Mackall -
r13550:1792b8a9 stable
parent child Browse files
Show More
@@ -1,560 +1,560 b''
1 1 # merge.py - directory-level update/merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
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 node import nullid, nullrev, hex, bin
9 9 from i18n import _
10 10 import util, filemerge, copies, subrepo
11 11 import errno, os, shutil
12 12
13 13 class mergestate(object):
14 14 '''track 3-way merge state of individual files'''
15 15 def __init__(self, repo):
16 16 self._repo = repo
17 17 self._dirty = False
18 18 self._read()
19 19 def reset(self, node=None):
20 20 self._state = {}
21 21 if node:
22 22 self._local = node
23 23 shutil.rmtree(self._repo.join("merge"), True)
24 24 self._dirty = False
25 25 def _read(self):
26 26 self._state = {}
27 27 try:
28 28 f = self._repo.opener("merge/state")
29 29 for i, l in enumerate(f):
30 30 if i == 0:
31 31 self._local = bin(l[:-1])
32 32 else:
33 33 bits = l[:-1].split("\0")
34 34 self._state[bits[0]] = bits[1:]
35 35 f.close()
36 36 except IOError, err:
37 37 if err.errno != errno.ENOENT:
38 38 raise
39 39 self._dirty = False
40 40 def commit(self):
41 41 if self._dirty:
42 42 f = self._repo.opener("merge/state", "w")
43 43 f.write(hex(self._local) + "\n")
44 44 for d, v in self._state.iteritems():
45 45 f.write("\0".join([d] + v) + "\n")
46 46 f.close()
47 47 self._dirty = False
48 48 def add(self, fcl, fco, fca, fd, flags):
49 49 hash = util.sha1(fcl.path()).hexdigest()
50 50 self._repo.opener("merge/" + hash, "w").write(fcl.data())
51 51 self._state[fd] = ['u', hash, fcl.path(), fca.path(),
52 52 hex(fca.filenode()), fco.path(), flags]
53 53 self._dirty = True
54 54 def __contains__(self, dfile):
55 55 return dfile in self._state
56 56 def __getitem__(self, dfile):
57 57 return self._state[dfile][0]
58 58 def __iter__(self):
59 59 l = self._state.keys()
60 60 l.sort()
61 61 for f in l:
62 62 yield f
63 63 def mark(self, dfile, state):
64 64 self._state[dfile][0] = state
65 65 self._dirty = True
66 66 def resolve(self, dfile, wctx, octx):
67 67 if self[dfile] == 'r':
68 68 return 0
69 69 state, hash, lfile, afile, anode, ofile, flags = self._state[dfile]
70 70 f = self._repo.opener("merge/" + hash)
71 71 self._repo.wwrite(dfile, f.read(), flags)
72 72 f.close()
73 73 fcd = wctx[dfile]
74 74 fco = octx[ofile]
75 75 fca = self._repo.filectx(afile, fileid=anode)
76 76 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
77 77 if r is None:
78 78 # no real conflict
79 79 del self._state[dfile]
80 80 elif not r:
81 81 self.mark(dfile, 'r')
82 82 return r
83 83
84 84 def _checkunknown(wctx, mctx):
85 85 "check for collisions between unknown files and files in mctx"
86 86 for f in wctx.unknown():
87 87 if f in mctx and mctx[f].cmp(wctx[f]):
88 88 raise util.Abort(_("untracked file in working directory differs"
89 89 " from file in requested revision: '%s'") % f)
90 90
91 91 def _checkcollision(mctx):
92 92 "check for case folding collisions in the destination context"
93 93 folded = {}
94 94 for fn in mctx:
95 95 fold = fn.lower()
96 96 if fold in folded:
97 97 raise util.Abort(_("case-folding collision between %s and %s")
98 98 % (fn, folded[fold]))
99 99 folded[fold] = fn
100 100
101 101 def _forgetremoved(wctx, mctx, branchmerge):
102 102 """
103 103 Forget removed files
104 104
105 105 If we're jumping between revisions (as opposed to merging), and if
106 106 neither the working directory nor the target rev has the file,
107 107 then we need to remove it from the dirstate, to prevent the
108 108 dirstate from listing the file when it is no longer in the
109 109 manifest.
110 110
111 111 If we're merging, and the other revision has removed a file
112 112 that is not present in the working directory, we need to mark it
113 113 as removed.
114 114 """
115 115
116 116 action = []
117 117 state = branchmerge and 'r' or 'f'
118 118 for f in wctx.deleted():
119 119 if f not in mctx:
120 120 action.append((f, state))
121 121
122 122 if not branchmerge:
123 123 for f in wctx.removed():
124 124 if f not in mctx:
125 125 action.append((f, "f"))
126 126
127 127 return action
128 128
129 129 def manifestmerge(repo, p1, p2, pa, overwrite, partial):
130 130 """
131 131 Merge p1 and p2 with ancestor pa and generate merge action list
132 132
133 133 overwrite = whether we clobber working files
134 134 partial = function to filter file lists
135 135 """
136 136
137 137 def fmerge(f, f2, fa):
138 138 """merge flags"""
139 139 a, m, n = ma.flags(fa), m1.flags(f), m2.flags(f2)
140 140 if m == n: # flags agree
141 141 return m # unchanged
142 142 if m and n and not a: # flags set, don't agree, differ from parent
143 143 r = repo.ui.promptchoice(
144 144 _(" conflicting flags for %s\n"
145 145 "(n)one, e(x)ec or sym(l)ink?") % f,
146 146 (_("&None"), _("E&xec"), _("Sym&link")), 0)
147 147 if r == 1:
148 148 return "x" # Exec
149 149 if r == 2:
150 150 return "l" # Symlink
151 151 return ""
152 152 if m and m != a: # changed from a to m
153 153 return m
154 154 if n and n != a: # changed from a to n
155 155 return n
156 156 return '' # flag was cleared
157 157
158 158 def act(msg, m, f, *args):
159 159 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
160 160 action.append((f, m) + args)
161 161
162 162 action, copy = [], {}
163 163
164 164 if overwrite:
165 165 pa = p1
166 166 elif pa == p2: # backwards
167 167 pa = p1.p1()
168 168 elif pa and repo.ui.configbool("merge", "followcopies", True):
169 169 dirs = repo.ui.configbool("merge", "followdirs", True)
170 170 copy, diverge = copies.copies(repo, p1, p2, pa, dirs)
171 171 for of, fl in diverge.iteritems():
172 172 act("divergent renames", "dr", of, fl)
173 173
174 174 repo.ui.note(_("resolving manifests\n"))
175 175 repo.ui.debug(" overwrite %s partial %s\n" % (overwrite, bool(partial)))
176 176 repo.ui.debug(" ancestor %s local %s remote %s\n" % (pa, p1, p2))
177 177
178 178 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
179 179 copied = set(copy.values())
180 180
181 181 if '.hgsubstate' in m1:
182 182 # check whether sub state is modified
183 183 for s in p1.substate:
184 184 if p1.sub(s).dirty():
185 185 m1['.hgsubstate'] += "+"
186 186 break
187 187
188 188 # Compare manifests
189 189 for f, n in m1.iteritems():
190 190 if partial and not partial(f):
191 191 continue
192 192 if f in m2:
193 193 rflags = fmerge(f, f, f)
194 194 a = ma.get(f, nullid)
195 195 if n == m2[f] or m2[f] == a: # same or local newer
196 196 # is file locally modified or flags need changing?
197 197 # dirstate flags may need to be made current
198 198 if m1.flags(f) != rflags or n[20:]:
199 199 act("update permissions", "e", f, rflags)
200 200 elif n == a: # remote newer
201 201 act("remote is newer", "g", f, rflags)
202 202 else: # both changed
203 203 act("versions differ", "m", f, f, f, rflags, False)
204 204 elif f in copied: # files we'll deal with on m2 side
205 205 pass
206 206 elif f in copy:
207 207 f2 = copy[f]
208 208 if f2 not in m2: # directory rename
209 209 act("remote renamed directory to " + f2, "d",
210 210 f, None, f2, m1.flags(f))
211 211 else: # case 2 A,B/B/B or case 4,21 A/B/B
212 212 act("local copied/moved to " + f2, "m",
213 213 f, f2, f, fmerge(f, f2, f2), False)
214 214 elif f in ma: # clean, a different, no remote
215 215 if n != ma[f]:
216 216 if repo.ui.promptchoice(
217 217 _(" local changed %s which remote deleted\n"
218 218 "use (c)hanged version or (d)elete?") % f,
219 219 (_("&Changed"), _("&Delete")), 0):
220 220 act("prompt delete", "r", f)
221 221 else:
222 222 act("prompt keep", "a", f)
223 223 elif n[20:] == "a": # added, no remote
224 224 act("remote deleted", "f", f)
225 225 elif n[20:] != "u":
226 226 act("other deleted", "r", f)
227 227
228 228 for f, n in m2.iteritems():
229 229 if partial and not partial(f):
230 230 continue
231 231 if f in m1 or f in copied: # files already visited
232 232 continue
233 233 if f in copy:
234 234 f2 = copy[f]
235 235 if f2 not in m1: # directory rename
236 236 act("local renamed directory to " + f2, "d",
237 237 None, f, f2, m2.flags(f))
238 238 elif f2 in m2: # rename case 1, A/A,B/A
239 239 act("remote copied to " + f, "m",
240 240 f2, f, f, fmerge(f2, f, f2), False)
241 241 else: # case 3,20 A/B/A
242 242 act("remote moved to " + f, "m",
243 243 f2, f, f, fmerge(f2, f, f2), True)
244 244 elif f not in ma:
245 245 act("remote created", "g", f, m2.flags(f))
246 246 elif n != ma[f]:
247 247 if repo.ui.promptchoice(
248 248 _("remote changed %s which local deleted\n"
249 249 "use (c)hanged version or leave (d)eleted?") % f,
250 250 (_("&Changed"), _("&Deleted")), 0) == 0:
251 251 act("prompt recreating", "g", f, m2.flags(f))
252 252
253 253 return action
254 254
255 255 def actionkey(a):
256 256 return a[1] == 'r' and -1 or 0, a
257 257
258 258 def applyupdates(repo, action, wctx, mctx, actx, overwrite):
259 259 """apply the merge action list to the working directory
260 260
261 261 wctx is the working copy context
262 262 mctx is the context to be merged into the working copy
263 263 actx is the context of the common ancestor
264 264
265 265 Return a tuple of counts (updated, merged, removed, unresolved) that
266 266 describes how many files were affected by the update.
267 267 """
268 268
269 269 updated, merged, removed, unresolved = 0, 0, 0, 0
270 270 ms = mergestate(repo)
271 271 ms.reset(wctx.parents()[0].node())
272 272 moves = []
273 273 action.sort(key=actionkey)
274 274 substate = wctx.substate # prime
275 275
276 276 # prescan for merges
277 277 u = repo.ui
278 278 for a in action:
279 279 f, m = a[:2]
280 280 if m == 'm': # merge
281 281 f2, fd, flags, move = a[2:]
282 282 if f == '.hgsubstate': # merged internally
283 283 continue
284 284 repo.ui.debug("preserving %s for resolve of %s\n" % (f, fd))
285 285 fcl = wctx[f]
286 286 fco = mctx[f2]
287 287 if mctx == actx: # backwards, use working dir parent as ancestor
288 288 if fcl.parents():
289 289 fca = fcl.parents()[0]
290 290 else:
291 291 fca = repo.filectx(f, fileid=nullrev)
292 292 else:
293 293 fca = fcl.ancestor(fco, actx)
294 294 if not fca:
295 295 fca = repo.filectx(f, fileid=nullrev)
296 296 ms.add(fcl, fco, fca, fd, flags)
297 297 if f != fd and move:
298 298 moves.append(f)
299 299
300 300 # remove renamed files after safely stored
301 301 for f in moves:
302 302 if os.path.lexists(repo.wjoin(f)):
303 303 repo.ui.debug("removing %s\n" % f)
304 304 os.unlink(repo.wjoin(f))
305 305
306 306 audit_path = util.path_auditor(repo.root)
307 307
308 308 numupdates = len(action)
309 309 for i, a in enumerate(action):
310 310 f, m = a[:2]
311 311 u.progress(_('updating'), i + 1, item=f, total=numupdates,
312 312 unit=_('files'))
313 313 if f and f[0] == "/":
314 314 continue
315 315 if m == "r": # remove
316 316 repo.ui.note(_("removing %s\n") % f)
317 317 audit_path(f)
318 318 if f == '.hgsubstate': # subrepo states need updating
319 319 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
320 320 try:
321 321 util.unlinkpath(repo.wjoin(f))
322 322 except OSError, inst:
323 323 if inst.errno != errno.ENOENT:
324 324 repo.ui.warn(_("update failed to remove %s: %s!\n") %
325 325 (f, inst.strerror))
326 326 removed += 1
327 327 elif m == "m": # merge
328 328 if f == '.hgsubstate': # subrepo states need updating
329 329 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx), overwrite)
330 330 continue
331 331 f2, fd, flags, move = a[2:]
332 332 r = ms.resolve(fd, wctx, mctx)
333 333 if r is not None and r > 0:
334 334 unresolved += 1
335 335 else:
336 336 if r is None:
337 337 updated += 1
338 338 else:
339 339 merged += 1
340 340 util.set_flags(repo.wjoin(fd), 'l' in flags, 'x' in flags)
341 341 if f != fd and move and os.path.lexists(repo.wjoin(f)):
342 342 repo.ui.debug("removing %s\n" % f)
343 343 os.unlink(repo.wjoin(f))
344 344 elif m == "g": # get
345 345 flags = a[2]
346 346 repo.ui.note(_("getting %s\n") % f)
347 347 t = mctx.filectx(f).data()
348 348 repo.wwrite(f, t, flags)
349 349 t = None
350 350 updated += 1
351 351 if f == '.hgsubstate': # subrepo states need updating
352 352 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
353 353 elif m == "d": # directory rename
354 354 f2, fd, flags = a[2:]
355 355 if f:
356 356 repo.ui.note(_("moving %s to %s\n") % (f, fd))
357 357 t = wctx.filectx(f).data()
358 358 repo.wwrite(fd, t, flags)
359 359 util.unlinkpath(repo.wjoin(f))
360 360 if f2:
361 361 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
362 362 t = mctx.filectx(f2).data()
363 363 repo.wwrite(fd, t, flags)
364 364 updated += 1
365 365 elif m == "dr": # divergent renames
366 366 fl = a[2]
367 367 repo.ui.warn(_("note: possible conflict - %s was renamed "
368 368 "multiple times to:\n") % f)
369 369 for nf in fl:
370 370 repo.ui.warn(" %s\n" % nf)
371 371 elif m == "e": # exec
372 372 flags = a[2]
373 373 util.set_flags(repo.wjoin(f), 'l' in flags, 'x' in flags)
374 374 ms.commit()
375 375 u.progress(_('updating'), None, total=numupdates, unit=_('files'))
376 376
377 377 return updated, merged, removed, unresolved
378 378
379 379 def recordupdates(repo, action, branchmerge):
380 380 "record merge actions to the dirstate"
381 381
382 382 for a in action:
383 383 f, m = a[:2]
384 384 if m == "r": # remove
385 385 if branchmerge:
386 386 repo.dirstate.remove(f)
387 387 else:
388 388 repo.dirstate.forget(f)
389 389 elif m == "a": # re-add
390 390 if not branchmerge:
391 391 repo.dirstate.add(f)
392 392 elif m == "f": # forget
393 393 repo.dirstate.forget(f)
394 394 elif m == "e": # exec change
395 395 repo.dirstate.normallookup(f)
396 396 elif m == "g": # get
397 397 if branchmerge:
398 398 repo.dirstate.otherparent(f)
399 399 else:
400 400 repo.dirstate.normal(f)
401 401 elif m == "m": # merge
402 402 f2, fd, flag, move = a[2:]
403 403 if branchmerge:
404 404 # We've done a branch merge, mark this file as merged
405 405 # so that we properly record the merger later
406 406 repo.dirstate.merge(fd)
407 407 if f != f2: # copy/rename
408 408 if move:
409 409 repo.dirstate.remove(f)
410 410 if f != fd:
411 411 repo.dirstate.copy(f, fd)
412 412 else:
413 413 repo.dirstate.copy(f2, fd)
414 414 else:
415 415 # We've update-merged a locally modified file, so
416 416 # we set the dirstate to emulate a normal checkout
417 417 # of that file some time in the past. Thus our
418 418 # merge will appear as a normal local file
419 419 # modification.
420 420 if f2 == fd: # file not locally copied/moved
421 421 repo.dirstate.normallookup(fd)
422 422 if move:
423 423 repo.dirstate.forget(f)
424 424 elif m == "d": # directory rename
425 425 f2, fd, flag = a[2:]
426 426 if not f2 and f not in repo.dirstate:
427 427 # untracked file moved
428 428 continue
429 429 if branchmerge:
430 430 repo.dirstate.add(fd)
431 431 if f:
432 432 repo.dirstate.remove(f)
433 433 repo.dirstate.copy(f, fd)
434 434 if f2:
435 435 repo.dirstate.copy(f2, fd)
436 436 else:
437 437 repo.dirstate.normal(fd)
438 438 if f:
439 439 repo.dirstate.forget(f)
440 440
441 441 def update(repo, node, branchmerge, force, partial):
442 442 """
443 443 Perform a merge between the working directory and the given node
444 444
445 445 node = the node to update to, or None if unspecified
446 446 branchmerge = whether to merge between branches
447 447 force = whether to force branch merging or file overwriting
448 448 partial = a function to filter file lists (dirstate not updated)
449 449
450 450 The table below shows all the behaviors of the update command
451 451 given the -c and -C or no options, whether the working directory
452 452 is dirty, whether a revision is specified, and the relationship of
453 453 the parent rev to the target rev (linear, on the same named
454 454 branch, or on another named branch).
455 455
456 456 This logic is tested by test-update-branches.t.
457 457
458 458 -c -C dirty rev | linear same cross
459 459 n n n n | ok (1) x
460 460 n n n y | ok ok ok
461 461 n n y * | merge (2) (2)
462 462 n y * * | --- discard ---
463 463 y n y * | --- (3) ---
464 464 y n n * | --- ok ---
465 465 y y * * | --- (4) ---
466 466
467 467 x = can't happen
468 468 * = don't-care
469 469 1 = abort: crosses branches (use 'hg merge' or 'hg update -c')
470 470 2 = abort: crosses branches (use 'hg merge' to merge or
471 471 use 'hg update -C' to discard changes)
472 472 3 = abort: uncommitted local changes
473 473 4 = incompatible options (checked in commands.py)
474 474
475 475 Return the same tuple as applyupdates().
476 476 """
477 477
478 478 onode = node
479 479 wlock = repo.wlock()
480 480 try:
481 481 wc = repo[None]
482 482 if node is None:
483 483 # tip of current branch
484 484 try:
485 485 node = repo.branchtags()[wc.branch()]
486 486 except KeyError:
487 487 if wc.branch() == "default": # no default branch!
488 488 node = repo.lookup("tip") # update to tip
489 489 else:
490 490 raise util.Abort(_("branch %s not found") % wc.branch())
491 491 overwrite = force and not branchmerge
492 492 pl = wc.parents()
493 493 p1, p2 = pl[0], repo[node]
494 494 pa = p1.ancestor(p2)
495 495 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
496 496 fastforward = False
497 497
498 498 ### check phase
499 499 if not overwrite and len(pl) > 1:
500 500 raise util.Abort(_("outstanding uncommitted merges"))
501 501 if branchmerge:
502 502 if pa == p2:
503 503 raise util.Abort(_("merging with a working directory ancestor"
504 504 " has no effect"))
505 505 elif pa == p1:
506 506 if p1.branch() != p2.branch():
507 507 fastforward = True
508 508 else:
509 509 raise util.Abort(_("nothing to merge (use 'hg update'"
510 510 " or check 'hg heads')"))
511 511 if not force and (wc.files() or wc.deleted()):
512 512 raise util.Abort(_("outstanding uncommitted changes "
513 513 "(use 'hg status' to list changes)"))
514 514 for s in wc.substate:
515 515 if wc.sub(s).dirty():
516 516 raise util.Abort(_("outstanding uncommitted changes in "
517 517 "subrepository '%s'") % s)
518 518
519 519 elif not overwrite:
520 520 if pa == p1 or pa == p2: # linear
521 521 pass # all good
522 522 elif wc.files() or wc.deleted():
523 523 raise util.Abort(_("crosses branches (merge branches or use"
524 524 " --clean to discard changes)"))
525 525 elif onode is None:
526 526 raise util.Abort(_("crosses branches (merge branches or use"
527 527 " --check to force update)"))
528 528 else:
529 529 # Allow jumping branches if clean and specific rev given
530 530 overwrite = True
531 531
532 532 ### calculate phase
533 533 action = []
534 534 wc.status(unknown=True) # prime cache
535 535 if not force:
536 536 _checkunknown(wc, p2)
537 537 if not util.checkcase(repo.path):
538 538 _checkcollision(p2)
539 539 action += _forgetremoved(wc, p2, branchmerge)
540 540 action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
541 541
542 542 ### apply phase
543 if not branchmerge or fastforward: # just jump to the new rev
543 if not branchmerge: # just jump to the new rev
544 544 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
545 545 if not partial:
546 546 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
547 547
548 548 stats = applyupdates(repo, action, wc, p2, pa, overwrite)
549 549
550 550 if not partial:
551 551 repo.dirstate.setparents(fp1, fp2)
552 recordupdates(repo, action, branchmerge and not fastforward)
552 recordupdates(repo, action, branchmerge)
553 553 if not branchmerge and not fastforward:
554 554 repo.dirstate.setbranch(p2.branch())
555 555 finally:
556 556 wlock.release()
557 557
558 558 if not partial:
559 559 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
560 560 return stats
@@ -1,34 +1,29 b''
1 1 http://mercurial.selenic.com/bts/issue619
2 2
3 3 $ hg init
4 4 $ echo a > a
5 5 $ hg ci -Ama
6 6 adding a
7 7
8 8 $ echo b > b
9 9 $ hg branch b
10 10 marked working directory as branch b
11 11 $ hg ci -Amb
12 12 adding b
13 13
14 14 $ hg co -C 0
15 15 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
16 16
17 17 Fast-forward:
18 18
19 19 $ hg merge b
20 20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 21 (branch merge, don't forget to commit)
22 $ hg branch
23 default
24 $ hg parent --template '{rev}:{node|short} {branches}: {desc}\n'
25 1:06c2121185be b: b
26 22 $ hg ci -Ammerge
27 created new head
28 23
29 24 Bogus fast-forward should fail:
30 25
31 26 $ hg merge b
32 27 abort: merging with a working directory ancestor has no effect
33 28 [255]
34 29
@@ -1,320 +1,321 b''
1 1 $ branchcache=.hg/cache/branchheads
2 2
3 3 $ hg init t
4 4 $ cd t
5 5
6 6 $ hg branches
7 7 $ echo foo > a
8 8 $ hg add a
9 9 $ hg ci -m "initial"
10 10 $ hg branch foo
11 11 marked working directory as branch foo
12 12 $ hg branch
13 13 foo
14 14 $ hg ci -m "add branch name"
15 15 $ hg branch bar
16 16 marked working directory as branch bar
17 17 $ hg ci -m "change branch name"
18 18
19 19 Branch shadowing:
20 20
21 21 $ hg branch default
22 22 abort: a branch of the same name already exists (use 'hg update' to switch to it)
23 23 [255]
24 24
25 25 $ hg branch -f default
26 26 marked working directory as branch default
27 27
28 28 $ hg ci -m "clear branch name"
29 29 created new head
30 30
31 31 There should be only one default branch head
32 32
33 33 $ hg heads .
34 34 changeset: 3:9d567d0b51f9
35 35 tag: tip
36 36 user: test
37 37 date: Thu Jan 01 00:00:00 1970 +0000
38 38 summary: clear branch name
39 39
40 40
41 41 $ hg co foo
42 42 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 43 $ hg branch
44 44 foo
45 45 $ echo bleah > a
46 46 $ hg ci -m "modify a branch"
47 47
48 48 $ hg merge default
49 49 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 50 (branch merge, don't forget to commit)
51 51
52 52 $ hg branch
53 53 foo
54 54 $ hg ci -m "merge"
55 55
56 56 $ hg log
57 57 changeset: 5:dc140083783b
58 58 branch: foo
59 59 tag: tip
60 60 parent: 4:98d14f698afe
61 61 parent: 3:9d567d0b51f9
62 62 user: test
63 63 date: Thu Jan 01 00:00:00 1970 +0000
64 64 summary: merge
65 65
66 66 changeset: 4:98d14f698afe
67 67 branch: foo
68 68 parent: 1:0079f24813e2
69 69 user: test
70 70 date: Thu Jan 01 00:00:00 1970 +0000
71 71 summary: modify a branch
72 72
73 73 changeset: 3:9d567d0b51f9
74 74 user: test
75 75 date: Thu Jan 01 00:00:00 1970 +0000
76 76 summary: clear branch name
77 77
78 78 changeset: 2:ed2bbf4e0102
79 79 branch: bar
80 80 user: test
81 81 date: Thu Jan 01 00:00:00 1970 +0000
82 82 summary: change branch name
83 83
84 84 changeset: 1:0079f24813e2
85 85 branch: foo
86 86 user: test
87 87 date: Thu Jan 01 00:00:00 1970 +0000
88 88 summary: add branch name
89 89
90 90 changeset: 0:db01e8ea3388
91 91 user: test
92 92 date: Thu Jan 01 00:00:00 1970 +0000
93 93 summary: initial
94 94
95 95 $ hg branches
96 96 foo 5:dc140083783b
97 97 default 3:9d567d0b51f9 (inactive)
98 98 bar 2:ed2bbf4e0102 (inactive)
99 99
100 100 $ hg branches -q
101 101 foo
102 102 default
103 103 bar
104 104
105 105 Test for invalid branch cache:
106 106
107 107 $ hg rollback
108 108 repository tip rolled back to revision 4 (undo commit)
109 109 working directory now based on revisions 4 and 3
110 110
111 111 $ cp $branchcache .hg/bc-invalid
112 112
113 113 $ hg log -r foo
114 114 changeset: 4:98d14f698afe
115 115 branch: foo
116 116 tag: tip
117 117 parent: 1:0079f24813e2
118 118 user: test
119 119 date: Thu Jan 01 00:00:00 1970 +0000
120 120 summary: modify a branch
121 121
122 122 $ cp .hg/bc-invalid $branchcache
123 123
124 124 $ hg --debug log -r foo
125 125 invalidating branch cache (tip differs)
126 126 changeset: 4:98d14f698afeaff8cb612dcf215ce95e639effc3
127 127 branch: foo
128 128 tag: tip
129 129 parent: 1:0079f24813e2b73a891577c243684c5066347bc8
130 130 parent: -1:0000000000000000000000000000000000000000
131 131 manifest: 4:d01b250baaa05909152f7ae07d7a649deea0df9a
132 132 user: test
133 133 date: Thu Jan 01 00:00:00 1970 +0000
134 134 files: a
135 135 extra: branch=foo
136 136 description:
137 137 modify a branch
138 138
139 139
140 140 $ rm $branchcache
141 141 $ echo corrupted > $branchcache
142 142
143 143 $ hg log -qr foo
144 144 4:98d14f698afe
145 145
146 146 $ cat $branchcache
147 147 98d14f698afeaff8cb612dcf215ce95e639effc3 4
148 148 9d567d0b51f9e2068b054e1948e1a927f99b5874 default
149 149 98d14f698afeaff8cb612dcf215ce95e639effc3 foo
150 150 ed2bbf4e01029020711be82ca905283e883f0e11 bar
151 151
152 152 Push should update the branch cache:
153 153
154 154 $ hg init ../target
155 155
156 156 Pushing just rev 0:
157 157
158 158 $ hg push -qr 0 ../target
159 159
160 160 $ cat ../target/$branchcache
161 161 db01e8ea3388fd3c7c94e1436ea2bd6a53d581c5 0
162 162 db01e8ea3388fd3c7c94e1436ea2bd6a53d581c5 default
163 163
164 164 Pushing everything:
165 165
166 166 $ hg push -qf ../target
167 167
168 168 $ cat ../target/$branchcache
169 169 98d14f698afeaff8cb612dcf215ce95e639effc3 4
170 170 9d567d0b51f9e2068b054e1948e1a927f99b5874 default
171 171 98d14f698afeaff8cb612dcf215ce95e639effc3 foo
172 172 ed2bbf4e01029020711be82ca905283e883f0e11 bar
173 173
174 174 Update with no arguments: tipmost revision of the current branch:
175 175
176 176 $ hg up -q -C 0
177 177 $ hg up -q
178 178 $ hg id
179 179 9d567d0b51f9
180 180
181 181 $ hg up -q 1
182 182 $ hg up -q
183 183 $ hg id
184 184 98d14f698afe (foo) tip
185 185
186 186 $ hg branch foobar
187 187 marked working directory as branch foobar
188 188
189 189 $ hg up
190 190 abort: branch foobar not found
191 191 [255]
192 192
193 193 Fastforward merge:
194 194
195 195 $ hg branch ff
196 196 marked working directory as branch ff
197 197
198 198 $ echo ff > ff
199 199 $ hg ci -Am'fast forward'
200 200 adding ff
201 201
202 202 $ hg up foo
203 203 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
204 204
205 205 $ hg merge ff
206 206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 207 (branch merge, don't forget to commit)
208 208
209 209 $ hg branch
210 210 foo
211 211 $ hg commit -m'Merge ff into foo'
212 created new head
213 212 $ hg parents
214 changeset: 6:6af8030670c9
213 changeset: 6:917eb54e1b4b
215 214 branch: foo
216 215 tag: tip
216 parent: 4:98d14f698afe
217 parent: 5:6683a60370cb
217 218 user: test
218 219 date: Thu Jan 01 00:00:00 1970 +0000
219 220 summary: Merge ff into foo
220 221
221 222 $ hg manifest
222 223 a
223 224 ff
224 225
225 226
226 227 Test merging, add 3 default heads and one test head:
227 228
228 229 $ cd ..
229 230 $ hg init merges
230 231 $ cd merges
231 232 $ echo a > a
232 233 $ hg ci -Ama
233 234 adding a
234 235
235 236 $ echo b > b
236 237 $ hg ci -Amb
237 238 adding b
238 239
239 240 $ hg up 0
240 241 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
241 242 $ echo c > c
242 243 $ hg ci -Amc
243 244 adding c
244 245 created new head
245 246
246 247 $ hg up 0
247 248 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
248 249 $ echo d > d
249 250 $ hg ci -Amd
250 251 adding d
251 252 created new head
252 253
253 254 $ hg up 0
254 255 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
255 256 $ hg branch test
256 257 marked working directory as branch test
257 258 $ echo e >> e
258 259 $ hg ci -Ame
259 260 adding e
260 261
261 262 $ hg log
262 263 changeset: 4:3a1e01ed1df4
263 264 branch: test
264 265 tag: tip
265 266 parent: 0:cb9a9f314b8b
266 267 user: test
267 268 date: Thu Jan 01 00:00:00 1970 +0000
268 269 summary: e
269 270
270 271 changeset: 3:980f7dc84c29
271 272 parent: 0:cb9a9f314b8b
272 273 user: test
273 274 date: Thu Jan 01 00:00:00 1970 +0000
274 275 summary: d
275 276
276 277 changeset: 2:d36c0562f908
277 278 parent: 0:cb9a9f314b8b
278 279 user: test
279 280 date: Thu Jan 01 00:00:00 1970 +0000
280 281 summary: c
281 282
282 283 changeset: 1:d2ae7f538514
283 284 user: test
284 285 date: Thu Jan 01 00:00:00 1970 +0000
285 286 summary: b
286 287
287 288 changeset: 0:cb9a9f314b8b
288 289 user: test
289 290 date: Thu Jan 01 00:00:00 1970 +0000
290 291 summary: a
291 292
292 293 Implicit merge with test branch as parent:
293 294
294 295 $ hg merge
295 296 abort: branch 'test' has one head - please merge with an explicit rev
296 297 (run 'hg heads' to see all heads)
297 298 [255]
298 299 $ hg up -C default
299 300 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
300 301
301 302 Implicit merge with default branch as parent:
302 303
303 304 $ hg merge
304 305 abort: branch 'default' has 3 heads - please merge with an explicit rev
305 306 (run 'hg heads .' to see heads)
306 307 [255]
307 308
308 309 3 branch heads, explicit merge required:
309 310
310 311 $ hg merge 2
311 312 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 313 (branch merge, don't forget to commit)
313 314 $ hg ci -m merge
314 315
315 316 2 branch heads, implicit merge works:
316 317
317 318 $ hg merge
318 319 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
319 320 (branch merge, don't forget to commit)
320 321
@@ -1,719 +1,718 b''
1 1 $ echo "[extensions]" >> $HGRCPATH
2 2 $ echo "graphlog=" >> $HGRCPATH
3 3
4 4 $ mkdir a
5 5 $ cd a
6 6 $ hg init
7 7 $ echo foo > t1
8 8 $ hg add t1
9 9 $ hg commit -m "1"
10 10
11 11 $ cd ..
12 12 $ hg clone a b
13 13 updating to branch default
14 14 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 15
16 16 $ cd a
17 17 $ echo foo > t2
18 18 $ hg add t2
19 19 $ hg commit -m "2"
20 20
21 21 $ cd ../b
22 22 $ echo foo > t3
23 23 $ hg add t3
24 24 $ hg commit -m "3"
25 25
26 26 $ hg push ../a
27 27 pushing to ../a
28 28 searching for changes
29 29 abort: push creates new remote heads on branch 'default'!
30 30 (you should pull and merge or use push -f to force)
31 31 [255]
32 32
33 33 $ hg push --debug ../a
34 34 pushing to ../a
35 35 searching for changes
36 36 examining 1c9246a22a0a:d8d565842d04
37 37 found incomplete branch 1c9246a22a0a:d8d565842d04
38 38 searching: 1 queries
39 39 narrowing 1:1 d8d565842d04
40 40 found new branch changeset 1c9246a22a0a
41 41 found new changesets starting at 1c9246a22a0a
42 42 1 total queries
43 43 common changesets up to d8d565842d04
44 44 new remote heads on branch 'default'
45 45 new remote head 1e108cc5548c
46 46 abort: push creates new remote heads on branch 'default'!
47 47 (you should pull and merge or use push -f to force)
48 48 [255]
49 49
50 50 $ hg pull ../a
51 51 pulling from ../a
52 52 searching for changes
53 53 adding changesets
54 54 adding manifests
55 55 adding file changes
56 56 added 1 changesets with 1 changes to 1 files (+1 heads)
57 57 (run 'hg heads' to see heads, 'hg merge' to merge)
58 58
59 59 $ hg push ../a
60 60 pushing to ../a
61 61 searching for changes
62 62 abort: push creates new remote heads on branch 'default'!
63 63 (did you forget to merge? use push -f to force)
64 64 [255]
65 65
66 66 $ hg merge
67 67 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 68 (branch merge, don't forget to commit)
69 69
70 70 $ hg commit -m "4"
71 71 $ hg push ../a
72 72 pushing to ../a
73 73 searching for changes
74 74 adding changesets
75 75 adding manifests
76 76 adding file changes
77 77 added 2 changesets with 1 changes to 1 files
78 78
79 79 $ cd ..
80 80
81 81 $ hg init c
82 82 $ cd c
83 83 $ for i in 0 1 2; do
84 84 > echo $i >> foo
85 85 > hg ci -Am $i
86 86 > done
87 87 adding foo
88 88 $ cd ..
89 89
90 90 $ hg clone c d
91 91 updating to branch default
92 92 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 93
94 94 $ cd d
95 95 $ for i in 0 1; do
96 96 > hg co -C $i
97 97 > echo d-$i >> foo
98 98 > hg ci -m d-$i
99 99 > done
100 100 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 101 created new head
102 102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 103 created new head
104 104
105 105 $ HGMERGE=true hg merge 3
106 106 merging foo
107 107 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
108 108 (branch merge, don't forget to commit)
109 109
110 110 $ hg ci -m c-d
111 111
112 112 $ hg push ../c
113 113 pushing to ../c
114 114 searching for changes
115 115 abort: push creates new remote heads on branch 'default'!
116 116 (did you forget to merge? use push -f to force)
117 117 [255]
118 118
119 119 $ hg push -r 2 ../c
120 120 pushing to ../c
121 121 searching for changes
122 122 no changes found
123 123
124 124 $ hg push -r 3 ../c
125 125 pushing to ../c
126 126 searching for changes
127 127 abort: push creates new remote heads on branch 'default'!
128 128 (did you forget to merge? use push -f to force)
129 129 [255]
130 130
131 131 $ hg push -r 3 -r 4 ../c
132 132 pushing to ../c
133 133 searching for changes
134 134 abort: push creates new remote heads on branch 'default'!
135 135 (did you forget to merge? use push -f to force)
136 136 [255]
137 137
138 138 $ hg push -f -r 3 -r 4 ../c
139 139 pushing to ../c
140 140 searching for changes
141 141 adding changesets
142 142 adding manifests
143 143 adding file changes
144 144 added 2 changesets with 2 changes to 1 files (+2 heads)
145 145
146 146 $ hg push -r 5 ../c
147 147 pushing to ../c
148 148 searching for changes
149 149 adding changesets
150 150 adding manifests
151 151 adding file changes
152 152 added 1 changesets with 1 changes to 1 files (-1 heads)
153 153
154 154 $ hg in ../c
155 155 comparing with ../c
156 156 searching for changes
157 157 no changes found
158 158 [1]
159 159
160 160
161 161 Issue450: push -r warns about remote head creation even if no heads
162 162 will be created
163 163
164 164 $ hg init ../e
165 165 $ hg push -r 0 ../e
166 166 pushing to ../e
167 167 searching for changes
168 168 adding changesets
169 169 adding manifests
170 170 adding file changes
171 171 added 1 changesets with 1 changes to 1 files
172 172
173 173 $ hg push -r 1 ../e
174 174 pushing to ../e
175 175 searching for changes
176 176 adding changesets
177 177 adding manifests
178 178 adding file changes
179 179 added 1 changesets with 1 changes to 1 files
180 180
181 181 $ cd ..
182 182
183 183
184 184 Issue736: named branches are not considered for detection of
185 185 unmerged heads in "hg push"
186 186
187 187 $ hg init f
188 188 $ cd f
189 189 $ hg -q branch a
190 190 $ echo 0 > foo
191 191 $ hg -q ci -Am 0
192 192 $ echo 1 > foo
193 193 $ hg -q ci -m 1
194 194 $ hg -q up 0
195 195 $ echo 2 > foo
196 196 $ hg -q ci -m 2
197 197 $ hg -q up 0
198 198 $ hg -q branch b
199 199 $ echo 3 > foo
200 200 $ hg -q ci -m 3
201 201 $ cd ..
202 202
203 203 $ hg -q clone f g
204 204 $ cd g
205 205
206 206 Push on existing branch and new branch:
207 207
208 208 $ hg -q up 1
209 209 $ echo 4 > foo
210 210 $ hg -q ci -m 4
211 211 $ hg -q up 0
212 212 $ echo 5 > foo
213 213 $ hg -q branch c
214 214 $ hg -q ci -m 5
215 215
216 216 $ hg push ../f
217 217 pushing to ../f
218 218 searching for changes
219 219 abort: push creates new remote branches: c!
220 220 (use 'hg push --new-branch' to create new remote branches)
221 221 [255]
222 222
223 223 $ hg push -r 4 -r 5 ../f
224 224 pushing to ../f
225 225 searching for changes
226 226 abort: push creates new remote branches: c!
227 227 (use 'hg push --new-branch' to create new remote branches)
228 228 [255]
229 229
230 230
231 231 Multiple new branches:
232 232
233 233 $ hg -q branch d
234 234 $ echo 6 > foo
235 235 $ hg -q ci -m 6
236 236
237 237 $ hg push ../f
238 238 pushing to ../f
239 239 searching for changes
240 240 abort: push creates new remote branches: c, d!
241 241 (use 'hg push --new-branch' to create new remote branches)
242 242 [255]
243 243
244 244 $ hg push -r 4 -r 6 ../f
245 245 pushing to ../f
246 246 searching for changes
247 247 abort: push creates new remote branches: c, d!
248 248 (use 'hg push --new-branch' to create new remote branches)
249 249 [255]
250 250
251 251 $ cd ../g
252 252
253 253
254 254 Fail on multiple head push:
255 255
256 256 $ hg -q up 1
257 257 $ echo 7 > foo
258 258 $ hg -q ci -m 7
259 259
260 260 $ hg push -r 4 -r 7 ../f
261 261 pushing to ../f
262 262 searching for changes
263 263 abort: push creates new remote heads on branch 'a'!
264 264 (did you forget to merge? use push -f to force)
265 265 [255]
266 266
267 267 Push replacement head on existing branches:
268 268
269 269 $ hg -q up 3
270 270 $ echo 8 > foo
271 271 $ hg -q ci -m 8
272 272
273 273 $ hg push -r 7 -r 8 ../f
274 274 pushing to ../f
275 275 searching for changes
276 276 adding changesets
277 277 adding manifests
278 278 adding file changes
279 279 added 2 changesets with 2 changes to 1 files
280 280
281 281
282 282 Merge of branch a to other branch b followed by unrelated push
283 283 on branch a:
284 284
285 285 $ hg -q up 7
286 286 $ HGMERGE=true hg -q merge 8
287 287 $ hg -q ci -m 9
288 288 $ hg -q up 8
289 289 $ echo 10 > foo
290 290 $ hg -q ci -m 10
291 291
292 292 $ hg push -r 9 ../f
293 293 pushing to ../f
294 294 searching for changes
295 295 adding changesets
296 296 adding manifests
297 297 adding file changes
298 298 added 1 changesets with 1 changes to 1 files (-1 heads)
299 299
300 300 $ hg push -r 10 ../f
301 301 pushing to ../f
302 302 searching for changes
303 303 adding changesets
304 304 adding manifests
305 305 adding file changes
306 306 added 1 changesets with 1 changes to 1 files (+1 heads)
307 307
308 308
309 309 Cheating the counting algorithm:
310 310
311 311 $ hg -q up 9
312 312 $ HGMERGE=true hg -q merge 2
313 313 $ hg -q ci -m 11
314 314 $ hg -q up 1
315 315 $ echo 12 > foo
316 316 $ hg -q ci -m 12
317 317
318 318 $ hg push -r 11 -r 12 ../f
319 319 pushing to ../f
320 320 searching for changes
321 321 adding changesets
322 322 adding manifests
323 323 adding file changes
324 324 added 2 changesets with 2 changes to 1 files
325 325
326 326
327 327 Failed push of new named branch:
328 328
329 329 $ echo 12 > foo
330 330 $ hg -q ci -m 12a
331 331 [1]
332 332 $ hg -q up 11
333 333 $ echo 13 > foo
334 334 $ hg -q branch e
335 335 $ hg -q ci -m 13d
336 336
337 337 $ hg push -r 12 -r 13 ../f
338 338 pushing to ../f
339 339 searching for changes
340 340 abort: push creates new remote branches: e!
341 341 (use 'hg push --new-branch' to create new remote branches)
342 342 [255]
343 343
344 344
345 345 Using --new-branch to push new named branch:
346 346
347 347 $ hg push --new-branch -r 12 -r 13 ../f
348 348 pushing to ../f
349 349 searching for changes
350 350 adding changesets
351 351 adding manifests
352 352 adding file changes
353 353 added 1 changesets with 1 changes to 1 files
354 354
355 355
356 356 Checking prepush logic does not allow silently pushing
357 357 multiple new heads:
358 358
359 359 $ cd ..
360 360 $ hg init h
361 361 $ echo init > h/init
362 362 $ hg -R h ci -Am init
363 363 adding init
364 364 $ echo a > h/a
365 365 $ hg -R h ci -Am a
366 366 adding a
367 367 $ hg clone h i
368 368 updating to branch default
369 369 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
370 370 $ hg -R h up 0
371 371 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
372 372 $ echo b > h/b
373 373 $ hg -R h ci -Am b
374 374 adding b
375 375 created new head
376 376 $ hg -R i up 0
377 377 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
378 378 $ echo c > i/c
379 379 $ hg -R i ci -Am c
380 380 adding c
381 381 created new head
382 382
383 383 $ hg -R i push h
384 384 pushing to h
385 385 searching for changes
386 386 abort: push creates new remote heads on branch 'default'!
387 387 (you should pull and merge or use push -f to force)
388 388 [255]
389 389
390 390
391 391 Check prepush logic with merged branches:
392 392
393 393 $ hg init j
394 394 $ hg -R j branch a
395 395 marked working directory as branch a
396 396 $ echo init > j/foo
397 397 $ hg -R j ci -Am init
398 398 adding foo
399 399 $ hg clone j k
400 400 updating to branch a
401 401 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 402 $ echo a1 > j/foo
403 403 $ hg -R j ci -m a1
404 404 $ hg -R k branch b
405 405 marked working directory as branch b
406 406 $ echo b > k/foo
407 407 $ hg -R k ci -m b
408 408 $ hg -R k up 0
409 409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 410
411 411 $ hg -R k merge b
412 412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 413 (branch merge, don't forget to commit)
414 414
415 415 $ hg -R k ci -m merge
416 created new head
417 416
418 417 $ hg -R k push -r a j
419 418 pushing to j
420 419 searching for changes
421 420 abort: push creates new remote branches: b!
422 421 (use 'hg push --new-branch' to create new remote branches)
423 422 [255]
424 423
425 424
426 425 Prepush -r should not allow you to sneak in new heads:
427 426
428 427 $ hg init l
429 428 $ cd l
430 429 $ echo a >> foo
431 430 $ hg -q add foo
432 431 $ hg -q branch a
433 432 $ hg -q ci -ma
434 433 $ hg -q up null
435 434 $ echo a >> foo
436 435 $ hg -q add foo
437 436 $ hg -q branch b
438 437 $ hg -q ci -mb
439 438 $ cd ..
440 439 $ hg -q clone l m -u a
441 440 $ cd m
442 441 $ hg -q merge b
443 442 $ hg -q ci -mmb
444 443 $ hg -q up 0
445 444 $ echo a >> foo
446 445 $ hg -q ci -ma2
447 446 $ hg -q up 2
448 447 $ echo a >> foo
449 448 $ hg -q branch -f b
450 449 $ hg -q ci -mb2
451 450 $ hg -q merge 3
452 451 $ hg -q ci -mma
453 452
454 453 $ hg push ../l -b b
455 454 pushing to ../l
456 455 searching for changes
457 456 abort: push creates new remote heads on branch 'a'!
458 457 (did you forget to merge? use push -f to force)
459 458 [255]
460 459
461 460 $ cd ..
462 461
463 462
464 463 Check prepush with new branch head on former topo non-head:
465 464
466 465 $ hg init n
467 466 $ cd n
468 467 $ hg branch A
469 468 marked working directory as branch A
470 469 $ echo a >a
471 470 $ hg ci -Ama
472 471 adding a
473 472 $ hg branch B
474 473 marked working directory as branch B
475 474 $ echo b >b
476 475 $ hg ci -Amb
477 476 adding b
478 477
479 478 b is now branch head of B, and a topological head
480 479 a is now branch head of A, but not a topological head
481 480
482 481 $ hg clone . inner
483 482 updating to branch B
484 483 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
485 484 $ cd inner
486 485 $ hg up B
487 486 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
488 487 $ echo b1 >b1
489 488 $ hg ci -Amb1
490 489 adding b1
491 490
492 491 in the clone b1 is now the head of B
493 492
494 493 $ cd ..
495 494 $ hg up 0
496 495 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
497 496 $ echo a2 >a2
498 497 $ hg ci -Ama2
499 498 adding a2
500 499
501 500 a2 is now the new branch head of A, and a new topological head
502 501 it replaces a former inner branch head, so it should at most warn about
503 502 A, not B
504 503
505 504 glog of local:
506 505
507 506 $ hg glog --template "{rev}: {branches} {desc}\n"
508 507 @ 2: A a2
509 508 |
510 509 | o 1: B b
511 510 |/
512 511 o 0: A a
513 512
514 513 glog of remote:
515 514
516 515 $ hg glog -R inner --template "{rev}: {branches} {desc}\n"
517 516 @ 2: B b1
518 517 |
519 518 o 1: B b
520 519 |
521 520 o 0: A a
522 521
523 522 outgoing:
524 523
525 524 $ hg out inner --template "{rev}: {branches} {desc}\n"
526 525 comparing with inner
527 526 searching for changes
528 527 2: A a2
529 528
530 529 $ hg push inner
531 530 pushing to inner
532 531 searching for changes
533 532 adding changesets
534 533 adding manifests
535 534 adding file changes
536 535 added 1 changesets with 1 changes to 1 files (+1 heads)
537 536
538 537 $ cd ..
539 538
540 539
541 540 Check prepush with new branch head on former topo head:
542 541
543 542 $ hg init o
544 543 $ cd o
545 544 $ hg branch A
546 545 marked working directory as branch A
547 546 $ echo a >a
548 547 $ hg ci -Ama
549 548 adding a
550 549 $ hg branch B
551 550 marked working directory as branch B
552 551 $ echo b >b
553 552 $ hg ci -Amb
554 553 adding b
555 554
556 555 b is now branch head of B, and a topological head
557 556
558 557 $ hg up 0
559 558 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
560 559 $ echo a1 >a1
561 560 $ hg ci -Ama1
562 561 adding a1
563 562
564 563 a1 is now branch head of A, and a topological head
565 564
566 565 $ hg clone . inner
567 566 updating to branch A
568 567 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
569 568 $ cd inner
570 569 $ hg up B
571 570 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
572 571 $ echo b1 >b1
573 572 $ hg ci -Amb1
574 573 adding b1
575 574
576 575 in the clone b1 is now the head of B
577 576
578 577 $ cd ..
579 578 $ echo a2 >a2
580 579 $ hg ci -Ama2
581 580 adding a2
582 581
583 582 a2 is now the new branch head of A, and a topological head
584 583 it replaces a former topological and branch head, so this should not warn
585 584
586 585 glog of local:
587 586
588 587 $ hg glog --template "{rev}: {branches} {desc}\n"
589 588 @ 3: A a2
590 589 |
591 590 o 2: A a1
592 591 |
593 592 | o 1: B b
594 593 |/
595 594 o 0: A a
596 595
597 596 glog of remote:
598 597
599 598 $ hg glog -R inner --template "{rev}: {branches} {desc}\n"
600 599 @ 3: B b1
601 600 |
602 601 | o 2: A a1
603 602 | |
604 603 o | 1: B b
605 604 |/
606 605 o 0: A a
607 606
608 607 outgoing:
609 608
610 609 $ hg out inner --template "{rev}: {branches} {desc}\n"
611 610 comparing with inner
612 611 searching for changes
613 612 3: A a2
614 613
615 614 $ hg push inner
616 615 pushing to inner
617 616 searching for changes
618 617 adding changesets
619 618 adding manifests
620 619 adding file changes
621 620 added 1 changesets with 1 changes to 1 files
622 621
623 622 $ cd ..
624 623
625 624
626 625 Check prepush with new branch head and new child of former branch head
627 626 but child is on different branch:
628 627
629 628 $ hg init p
630 629 $ cd p
631 630 $ hg branch A
632 631 marked working directory as branch A
633 632 $ echo a0 >a
634 633 $ hg ci -Ama0
635 634 adding a
636 635 $ echo a1 >a
637 636 $ hg ci -ma1
638 637 $ hg up null
639 638 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
640 639 $ hg branch B
641 640 marked working directory as branch B
642 641 $ echo b0 >b
643 642 $ hg ci -Amb0
644 643 adding b
645 644 $ echo b1 >b
646 645 $ hg ci -mb1
647 646
648 647 $ hg clone . inner
649 648 updating to branch B
650 649 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
651 650
652 651 $ hg up A
653 652 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
654 653 $ hg branch -f B
655 654 marked working directory as branch B
656 655 $ echo a3 >a
657 656 $ hg ci -ma3
658 657 created new head
659 658 $ hg up 3
660 659 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
661 660 $ hg branch -f A
662 661 marked working directory as branch A
663 662 $ echo b3 >b
664 663 $ hg ci -mb3
665 664 created new head
666 665
667 666 glog of local:
668 667
669 668 $ hg glog --template "{rev}: {branches} {desc}\n"
670 669 @ 5: A b3
671 670 |
672 671 | o 4: B a3
673 672 | |
674 673 o | 3: B b1
675 674 | |
676 675 o | 2: B b0
677 676 /
678 677 o 1: A a1
679 678 |
680 679 o 0: A a0
681 680
682 681 glog of remote:
683 682
684 683 $ hg glog -R inner --template "{rev}: {branches} {desc}\n"
685 684 @ 3: B b1
686 685 |
687 686 o 2: B b0
688 687
689 688 o 1: A a1
690 689 |
691 690 o 0: A a0
692 691
693 692 outgoing:
694 693
695 694 $ hg out inner --template "{rev}: {branches} {desc}\n"
696 695 comparing with inner
697 696 searching for changes
698 697 4: B a3
699 698 5: A b3
700 699
701 700 $ hg push inner
702 701 pushing to inner
703 702 searching for changes
704 703 abort: push creates new remote heads on branch 'A'!
705 704 (did you forget to merge? use push -f to force)
706 705 [255]
707 706
708 707 $ hg push inner -r4 -r5
709 708 pushing to inner
710 709 searching for changes
711 710 abort: push creates new remote heads on branch 'A'!
712 711 (did you forget to merge? use push -f to force)
713 712 [255]
714 713
715 714 $ hg in inner
716 715 comparing with inner
717 716 searching for changes
718 717 no changes found
719 718 [1]
General Comments 0
You need to be logged in to leave comments. Login now