##// END OF EJS Templates
merge: mark kept local files as readded on linear update (issue539)
Matt Mackall -
r7768:5bf5fd1e default
parent child Browse files
Show More
@@ -1,502 +1,506 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
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import nullid, nullrev, hex, bin
9 9 from i18n import _
10 10 import errno, util, os, filemerge, copies, shutil
11 11
12 12 class mergestate(object):
13 13 '''track 3-way merge state of individual files'''
14 14 def __init__(self, repo):
15 15 self._repo = repo
16 16 self._read()
17 17 def reset(self, node):
18 18 self._state = {}
19 19 self._local = node
20 20 shutil.rmtree(self._repo.join("merge"), True)
21 21 def _read(self):
22 22 self._state = {}
23 23 try:
24 24 localnode = None
25 25 f = self._repo.opener("merge/state")
26 26 for i, l in enumerate(f):
27 27 if i == 0:
28 28 localnode = l[:-1]
29 29 else:
30 30 bits = l[:-1].split("\0")
31 31 self._state[bits[0]] = bits[1:]
32 32 self._local = bin(localnode)
33 33 except IOError, err:
34 34 if err.errno != errno.ENOENT:
35 35 raise
36 36 def _write(self):
37 37 f = self._repo.opener("merge/state", "w")
38 38 f.write(hex(self._local) + "\n")
39 39 for d, v in self._state.iteritems():
40 40 f.write("\0".join([d] + v) + "\n")
41 41 def add(self, fcl, fco, fca, fd, flags):
42 42 hash = util.sha1(fcl.path()).hexdigest()
43 43 self._repo.opener("merge/" + hash, "w").write(fcl.data())
44 44 self._state[fd] = ['u', hash, fcl.path(), fca.path(),
45 45 hex(fca.filenode()), fco.path(), flags]
46 46 self._write()
47 47 def __contains__(self, dfile):
48 48 return dfile in self._state
49 49 def __getitem__(self, dfile):
50 50 return self._state[dfile][0]
51 51 def __iter__(self):
52 52 l = self._state.keys()
53 53 l.sort()
54 54 for f in l:
55 55 yield f
56 56 def mark(self, dfile, state):
57 57 self._state[dfile][0] = state
58 58 self._write()
59 59 def resolve(self, dfile, wctx, octx):
60 60 if self[dfile] == 'r':
61 61 return 0
62 62 state, hash, lfile, afile, anode, ofile, flags = self._state[dfile]
63 63 f = self._repo.opener("merge/" + hash)
64 64 self._repo.wwrite(dfile, f.read(), flags)
65 65 fcd = wctx[dfile]
66 66 fco = octx[ofile]
67 67 fca = self._repo.filectx(afile, fileid=anode)
68 68 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
69 69 if not r:
70 70 self.mark(dfile, 'r')
71 71 return r
72 72
73 73 def _checkunknown(wctx, mctx):
74 74 "check for collisions between unknown files and files in mctx"
75 75 for f in wctx.unknown():
76 76 if f in mctx and mctx[f].cmp(wctx[f].data()):
77 77 raise util.Abort(_("untracked file in working directory differs"
78 78 " from file in requested revision: '%s'") % f)
79 79
80 80 def _checkcollision(mctx):
81 81 "check for case folding collisions in the destination context"
82 82 folded = {}
83 83 for fn in mctx:
84 84 fold = fn.lower()
85 85 if fold in folded:
86 86 raise util.Abort(_("case-folding collision between %s and %s")
87 87 % (fn, folded[fold]))
88 88 folded[fold] = fn
89 89
90 90 def _forgetremoved(wctx, mctx, branchmerge):
91 91 """
92 92 Forget removed files
93 93
94 94 If we're jumping between revisions (as opposed to merging), and if
95 95 neither the working directory nor the target rev has the file,
96 96 then we need to remove it from the dirstate, to prevent the
97 97 dirstate from listing the file when it is no longer in the
98 98 manifest.
99 99
100 100 If we're merging, and the other revision has removed a file
101 101 that is not present in the working directory, we need to mark it
102 102 as removed.
103 103 """
104 104
105 105 action = []
106 106 state = branchmerge and 'r' or 'f'
107 107 for f in wctx.deleted():
108 108 if f not in mctx:
109 109 action.append((f, state))
110 110
111 111 if not branchmerge:
112 112 for f in wctx.removed():
113 113 if f not in mctx:
114 114 action.append((f, "f"))
115 115
116 116 return action
117 117
118 118 def manifestmerge(repo, p1, p2, pa, overwrite, partial):
119 119 """
120 120 Merge p1 and p2 with ancestor ma and generate merge action list
121 121
122 122 overwrite = whether we clobber working files
123 123 partial = function to filter file lists
124 124 """
125 125
126 126 repo.ui.note(_("resolving manifests\n"))
127 127 repo.ui.debug(_(" overwrite %s partial %s\n") % (overwrite, bool(partial)))
128 128 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (pa, p1, p2))
129 129
130 130 m1 = p1.manifest()
131 131 m2 = p2.manifest()
132 132 ma = pa.manifest()
133 133 backwards = (pa == p2)
134 134 action = []
135 135 copy, copied, diverge = {}, {}, {}
136 136
137 137 def fmerge(f, f2=None, fa=None):
138 138 """merge flags"""
139 139 if not f2:
140 140 f2 = f
141 141 fa = f
142 142 a, m, n = ma.flags(fa), m1.flags(f), m2.flags(f2)
143 143 if m == n: # flags agree
144 144 return m # unchanged
145 145 if m and n: # flags are set but don't agree
146 146 if not a: # both differ from parent
147 147 r = repo.ui.prompt(
148 148 _(" conflicting flags for %s\n"
149 149 "(n)one, e(x)ec or sym(l)ink?") % f, "[nxl]", "n")
150 150 return r != "n" and r or ''
151 151 if m == a:
152 152 return n # changed from m to n
153 153 return m # changed from n to m
154 154 if m and m != a: # changed from a to m
155 155 return m
156 156 if n and n != a: # changed from a to n
157 157 return n
158 158 return '' # flag was cleared
159 159
160 160 def act(msg, m, f, *args):
161 161 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
162 162 action.append((f, m) + args)
163 163
164 164 if pa and not (backwards or overwrite):
165 165 if repo.ui.configbool("merge", "followcopies", True):
166 166 dirs = repo.ui.configbool("merge", "followdirs", True)
167 167 copy, diverge = copies.copies(repo, p1, p2, pa, dirs)
168 168 copied = dict.fromkeys(copy.values())
169 169 for of, fl in diverge.iteritems():
170 170 act("divergent renames", "dr", of, fl)
171 171
172 172 # Compare manifests
173 173 for f, n in m1.iteritems():
174 174 if partial and not partial(f):
175 175 continue
176 176 if f in m2:
177 177 if overwrite or backwards:
178 178 rflags = m2.flags(f)
179 179 else:
180 180 rflags = fmerge(f)
181 181 # are files different?
182 182 if n != m2[f]:
183 183 a = ma.get(f, nullid)
184 184 # are we clobbering?
185 185 if overwrite:
186 186 act("clobbering", "g", f, rflags)
187 187 # or are we going back in time and clean?
188 188 elif backwards:
189 189 if not n[20:] or not p2[f].cmp(p1[f].data()):
190 190 act("reverting", "g", f, rflags)
191 191 # are both different from the ancestor?
192 192 elif n != a and m2[f] != a:
193 193 act("versions differ", "m", f, f, f, rflags, False)
194 194 # is remote's version newer?
195 195 elif m2[f] != a:
196 196 act("remote is newer", "g", f, rflags)
197 197 # local is newer, not overwrite, check mode bits
198 198 elif m1.flags(f) != rflags:
199 199 act("update permissions", "e", f, rflags)
200 200 # contents same, check mode bits
201 201 elif m1.flags(f) != rflags:
202 202 act("update permissions", "e", f, rflags)
203 203 elif f in copied:
204 204 continue
205 205 elif f in copy:
206 206 f2 = copy[f]
207 207 if f2 not in m2: # directory rename
208 208 act("remote renamed directory to " + f2, "d",
209 209 f, None, f2, m1.flags(f))
210 210 elif f2 in m1: # case 2 A,B/B/B
211 211 act("local copied to " + f2, "m",
212 212 f, f2, f, fmerge(f, f2, f2), False)
213 213 else: # case 4,21 A/B/B
214 214 act("local moved to " + f2, "m",
215 215 f, f2, f, fmerge(f, f2, f2), False)
216 216 elif f in ma:
217 217 if n != ma[f] and not overwrite:
218 218 if repo.ui.prompt(
219 219 _(" local changed %s which remote deleted\n"
220 220 "use (c)hanged version or (d)elete?") % f,
221 221 _("[cd]"), _("c")) == _("d"):
222 222 act("prompt delete", "r", f)
223 act("prompt keep", "a", f)
223 224 else:
224 225 act("other deleted", "r", f)
225 226 else:
226 227 # file is created on branch or in working directory
227 228 if (overwrite and n[20:] != "u") or (backwards and not n[20:]):
228 229 act("remote deleted", "r", f)
229 230
230 231 for f, n in m2.iteritems():
231 232 if partial and not partial(f):
232 233 continue
233 234 if f in m1:
234 235 continue
235 236 if f in copied:
236 237 continue
237 238 if f in copy:
238 239 f2 = copy[f]
239 240 if f2 not in m1: # directory rename
240 241 act("local renamed directory to " + f2, "d",
241 242 None, f, f2, m2.flags(f))
242 243 elif f2 in m2: # rename case 1, A/A,B/A
243 244 act("remote copied to " + f, "m",
244 245 f2, f, f, fmerge(f2, f, f2), False)
245 246 else: # case 3,20 A/B/A
246 247 act("remote moved to " + f, "m",
247 248 f2, f, f, fmerge(f2, f, f2), True)
248 249 elif f in ma:
249 250 if overwrite or backwards:
250 251 act("recreating", "g", f, m2.flags(f))
251 252 elif n != ma[f]:
252 253 if repo.ui.prompt(
253 254 _("remote changed %s which local deleted\n"
254 255 "use (c)hanged version or leave (d)eleted?") % f,
255 256 _("[cd]"), _("c")) == _("c"):
256 257 act("prompt recreating", "g", f, m2.flags(f))
257 258 else:
258 259 act("remote created", "g", f, m2.flags(f))
259 260
260 261 return action
261 262
262 263 def actioncmp(a1, a2):
263 264 m1 = a1[1]
264 265 m2 = a2[1]
265 266 if m1 == m2:
266 267 return cmp(a1, a2)
267 268 if m1 == 'r':
268 269 return -1
269 270 if m2 == 'r':
270 271 return 1
271 272 return cmp(a1, a2)
272 273
273 274 def applyupdates(repo, action, wctx, mctx):
274 275 "apply the merge action list to the working directory"
275 276
276 277 updated, merged, removed, unresolved = 0, 0, 0, 0
277 278 ms = mergestate(repo)
278 279 ms.reset(wctx.parents()[0].node())
279 280 moves = []
280 281 action.sort(actioncmp)
281 282
282 283 # prescan for merges
283 284 for a in action:
284 285 f, m = a[:2]
285 286 if m == 'm': # merge
286 287 f2, fd, flags, move = a[2:]
287 288 repo.ui.debug(_("preserving %s for resolve of %s\n") % (f, fd))
288 289 fcl = wctx[f]
289 290 fco = mctx[f2]
290 291 fca = fcl.ancestor(fco) or repo.filectx(f, fileid=nullrev)
291 292 ms.add(fcl, fco, fca, fd, flags)
292 293 if f != fd and move:
293 294 moves.append(f)
294 295
295 296 # remove renamed files after safely stored
296 297 for f in moves:
297 298 if util.lexists(repo.wjoin(f)):
298 299 repo.ui.debug(_("removing %s\n") % f)
299 300 os.unlink(repo.wjoin(f))
300 301
301 302 audit_path = util.path_auditor(repo.root)
302 303
303 304 for a in action:
304 305 f, m = a[:2]
305 306 if f and f[0] == "/":
306 307 continue
307 308 if m == "r": # remove
308 309 repo.ui.note(_("removing %s\n") % f)
309 310 audit_path(f)
310 311 try:
311 312 util.unlink(repo.wjoin(f))
312 313 except OSError, inst:
313 314 if inst.errno != errno.ENOENT:
314 315 repo.ui.warn(_("update failed to remove %s: %s!\n") %
315 316 (f, inst.strerror))
316 317 removed += 1
317 318 elif m == "m": # merge
318 319 f2, fd, flags, move = a[2:]
319 320 r = ms.resolve(fd, wctx, mctx)
320 321 if r > 0:
321 322 unresolved += 1
322 323 else:
323 324 if r is None:
324 325 updated += 1
325 326 else:
326 327 merged += 1
327 328 util.set_flags(repo.wjoin(fd), 'l' in flags, 'x' in flags)
328 329 if f != fd and move and util.lexists(repo.wjoin(f)):
329 330 repo.ui.debug(_("removing %s\n") % f)
330 331 os.unlink(repo.wjoin(f))
331 332 elif m == "g": # get
332 333 flags = a[2]
333 334 repo.ui.note(_("getting %s\n") % f)
334 335 t = mctx.filectx(f).data()
335 336 repo.wwrite(f, t, flags)
336 337 updated += 1
337 338 elif m == "d": # directory rename
338 339 f2, fd, flags = a[2:]
339 340 if f:
340 341 repo.ui.note(_("moving %s to %s\n") % (f, fd))
341 342 t = wctx.filectx(f).data()
342 343 repo.wwrite(fd, t, flags)
343 344 util.unlink(repo.wjoin(f))
344 345 if f2:
345 346 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
346 347 t = mctx.filectx(f2).data()
347 348 repo.wwrite(fd, t, flags)
348 349 updated += 1
349 350 elif m == "dr": # divergent renames
350 351 fl = a[2]
351 352 repo.ui.warn(_("warning: detected divergent renames of %s to:\n") % f)
352 353 for nf in fl:
353 354 repo.ui.warn(" %s\n" % nf)
354 355 elif m == "e": # exec
355 356 flags = a[2]
356 357 util.set_flags(repo.wjoin(f), 'l' in flags, 'x' in flags)
357 358
358 359 return updated, merged, removed, unresolved
359 360
360 361 def recordupdates(repo, action, branchmerge):
361 362 "record merge actions to the dirstate"
362 363
363 364 for a in action:
364 365 f, m = a[:2]
365 366 if m == "r": # remove
366 367 if branchmerge:
367 368 repo.dirstate.remove(f)
368 369 else:
369 370 repo.dirstate.forget(f)
371 elif m == "a": # re-add
372 if not branchmerge:
373 repo.dirstate.add(f)
370 374 elif m == "f": # forget
371 375 repo.dirstate.forget(f)
372 376 elif m == "e": # exec change
373 377 repo.dirstate.normallookup(f)
374 378 elif m == "g": # get
375 379 if branchmerge:
376 380 repo.dirstate.normaldirty(f)
377 381 else:
378 382 repo.dirstate.normal(f)
379 383 elif m == "m": # merge
380 384 f2, fd, flag, move = a[2:]
381 385 if branchmerge:
382 386 # We've done a branch merge, mark this file as merged
383 387 # so that we properly record the merger later
384 388 repo.dirstate.merge(fd)
385 389 if f != f2: # copy/rename
386 390 if move:
387 391 repo.dirstate.remove(f)
388 392 if f != fd:
389 393 repo.dirstate.copy(f, fd)
390 394 else:
391 395 repo.dirstate.copy(f2, fd)
392 396 else:
393 397 # We've update-merged a locally modified file, so
394 398 # we set the dirstate to emulate a normal checkout
395 399 # of that file some time in the past. Thus our
396 400 # merge will appear as a normal local file
397 401 # modification.
398 402 repo.dirstate.normallookup(fd)
399 403 if move:
400 404 repo.dirstate.forget(f)
401 405 elif m == "d": # directory rename
402 406 f2, fd, flag = a[2:]
403 407 if not f2 and f not in repo.dirstate:
404 408 # untracked file moved
405 409 continue
406 410 if branchmerge:
407 411 repo.dirstate.add(fd)
408 412 if f:
409 413 repo.dirstate.remove(f)
410 414 repo.dirstate.copy(f, fd)
411 415 if f2:
412 416 repo.dirstate.copy(f2, fd)
413 417 else:
414 418 repo.dirstate.normal(fd)
415 419 if f:
416 420 repo.dirstate.forget(f)
417 421
418 422 def update(repo, node, branchmerge, force, partial):
419 423 """
420 424 Perform a merge between the working directory and the given node
421 425
422 426 branchmerge = whether to merge between branches
423 427 force = whether to force branch merging or file overwriting
424 428 partial = a function to filter file lists (dirstate not updated)
425 429 """
426 430
427 431 wlock = repo.wlock()
428 432 try:
429 433 wc = repo[None]
430 434 if node is None:
431 435 # tip of current branch
432 436 try:
433 437 node = repo.branchtags()[wc.branch()]
434 438 except KeyError:
435 439 if wc.branch() == "default": # no default branch!
436 440 node = repo.lookup("tip") # update to tip
437 441 else:
438 442 raise util.Abort(_("branch %s not found") % wc.branch())
439 443 overwrite = force and not branchmerge
440 444 pl = wc.parents()
441 445 p1, p2 = pl[0], repo[node]
442 446 pa = p1.ancestor(p2)
443 447 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
444 448 fastforward = False
445 449
446 450 ### check phase
447 451 if not overwrite and len(pl) > 1:
448 452 raise util.Abort(_("outstanding uncommitted merges"))
449 453 if branchmerge:
450 454 if pa == p2:
451 455 raise util.Abort(_("can't merge with ancestor"))
452 456 elif pa == p1:
453 457 if p1.branch() != p2.branch():
454 458 fastforward = True
455 459 else:
456 460 raise util.Abort(_("nothing to merge (use 'hg update'"
457 461 " or check 'hg heads')"))
458 462 if not force and (wc.files() or wc.deleted()):
459 463 raise util.Abort(_("outstanding uncommitted changes"))
460 464 elif not overwrite:
461 465 if pa == p1 or pa == p2: # linear
462 466 pass # all good
463 467 elif p1.branch() == p2.branch():
464 468 if wc.files() or wc.deleted():
465 469 raise util.Abort(_("crosses branches (use 'hg merge' or "
466 470 "'hg update -C' to discard changes)"))
467 471 raise util.Abort(_("crosses branches (use 'hg merge' "
468 472 "or 'hg update -C')"))
469 473 elif wc.files() or wc.deleted():
470 474 raise util.Abort(_("crosses named branches (use "
471 475 "'hg update -C' to discard changes)"))
472 476 else:
473 477 # Allow jumping branches if there are no changes
474 478 overwrite = True
475 479
476 480 ### calculate phase
477 481 action = []
478 482 if not force:
479 483 _checkunknown(wc, p2)
480 484 if not util.checkcase(repo.path):
481 485 _checkcollision(p2)
482 486 action += _forgetremoved(wc, p2, branchmerge)
483 487 action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
484 488
485 489 ### apply phase
486 490 if not branchmerge: # just jump to the new rev
487 491 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
488 492 if not partial:
489 493 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
490 494
491 495 stats = applyupdates(repo, action, wc, p2)
492 496
493 497 if not partial:
494 498 recordupdates(repo, action, branchmerge)
495 499 repo.dirstate.setparents(fp1, fp2)
496 500 if not branchmerge and not fastforward:
497 501 repo.dirstate.setbranch(p2.branch())
498 502 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
499 503
500 504 return stats
501 505 finally:
502 506 del wlock
@@ -1,600 +1,601 b''
1 1 created new head
2 2 --------------
3 3 test L:up a R:nc a b W: - 1 get local a to b
4 4 --------------
5 5 resolving manifests
6 6 overwrite None partial False
7 7 ancestor 924404dff337 local e300d1c794ec+ remote 735846fee2d7
8 8 searching for copies back to rev 1
9 9 unmatched files in other:
10 10 b
11 11 all copies found (* = to merge, ! = divergent):
12 12 b -> a *
13 13 checking for directory renames
14 14 rev: versions differ -> m
15 15 a: remote copied to b -> m
16 16 preserving a for resolve of b
17 17 preserving rev for resolve of rev
18 18 picked tool 'python ../merge' for b (binary False symlink False)
19 19 merging a and b to b
20 20 my b@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337
21 21 premerge successful
22 22 picked tool 'python ../merge' for rev (binary False symlink False)
23 23 merging rev
24 24 my rev@e300d1c794ec+ other rev@735846fee2d7 ancestor rev@924404dff337
25 25 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
26 26 (branch merge, don't forget to commit)
27 27 --------------
28 28 M b
29 29 a
30 30 C a
31 31 --------------
32 32
33 33 created new head
34 34 --------------
35 35 test L:nc a b R:up a W: - 2 get rem change to a and b
36 36 --------------
37 37 resolving manifests
38 38 overwrite None partial False
39 39 ancestor 924404dff337 local ac809aeed39a+ remote f4db7e329e71
40 40 searching for copies back to rev 1
41 41 unmatched files in local:
42 42 b
43 43 all copies found (* = to merge, ! = divergent):
44 44 b -> a *
45 45 checking for directory renames
46 46 a: remote is newer -> g
47 47 b: local copied to a -> m
48 48 rev: versions differ -> m
49 49 preserving b for resolve of b
50 50 preserving rev for resolve of rev
51 51 getting a
52 52 picked tool 'python ../merge' for b (binary False symlink False)
53 53 merging b and a to b
54 54 my b@ac809aeed39a+ other a@f4db7e329e71 ancestor a@924404dff337
55 55 premerge successful
56 56 picked tool 'python ../merge' for rev (binary False symlink False)
57 57 merging rev
58 58 my rev@ac809aeed39a+ other rev@f4db7e329e71 ancestor rev@924404dff337
59 59 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
60 60 (branch merge, don't forget to commit)
61 61 --------------
62 62 M a
63 63 M b
64 64 a
65 65 --------------
66 66
67 67 created new head
68 68 --------------
69 69 test L:up a R:nm a b W: - 3 get local a change to b, remove a
70 70 --------------
71 71 resolving manifests
72 72 overwrite None partial False
73 73 ancestor 924404dff337 local e300d1c794ec+ remote e03727d2d66b
74 74 searching for copies back to rev 1
75 75 unmatched files in other:
76 76 b
77 77 all copies found (* = to merge, ! = divergent):
78 78 b -> a *
79 79 checking for directory renames
80 80 rev: versions differ -> m
81 81 a: remote moved to b -> m
82 82 preserving a for resolve of b
83 83 preserving rev for resolve of rev
84 84 removing a
85 85 picked tool 'python ../merge' for b (binary False symlink False)
86 86 merging a and b to b
87 87 my b@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337
88 88 premerge successful
89 89 picked tool 'python ../merge' for rev (binary False symlink False)
90 90 merging rev
91 91 my rev@e300d1c794ec+ other rev@e03727d2d66b ancestor rev@924404dff337
92 92 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
93 93 (branch merge, don't forget to commit)
94 94 --------------
95 95 M b
96 96 a
97 97 --------------
98 98
99 99 created new head
100 100 --------------
101 101 test L:nm a b R:up a W: - 4 get remote change to b
102 102 --------------
103 103 resolving manifests
104 104 overwrite None partial False
105 105 ancestor 924404dff337 local ecf3cb2a4219+ remote f4db7e329e71
106 106 searching for copies back to rev 1
107 107 unmatched files in local:
108 108 b
109 109 all copies found (* = to merge, ! = divergent):
110 110 b -> a *
111 111 checking for directory renames
112 112 b: local moved to a -> m
113 113 rev: versions differ -> m
114 114 preserving b for resolve of b
115 115 preserving rev for resolve of rev
116 116 picked tool 'python ../merge' for b (binary False symlink False)
117 117 merging b and a to b
118 118 my b@ecf3cb2a4219+ other a@f4db7e329e71 ancestor a@924404dff337
119 119 premerge successful
120 120 picked tool 'python ../merge' for rev (binary False symlink False)
121 121 merging rev
122 122 my rev@ecf3cb2a4219+ other rev@f4db7e329e71 ancestor rev@924404dff337
123 123 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
124 124 (branch merge, don't forget to commit)
125 125 --------------
126 126 M b
127 127 a
128 128 --------------
129 129
130 130 created new head
131 131 --------------
132 132 test L: R:nc a b W: - 5 get b
133 133 --------------
134 134 resolving manifests
135 135 overwrite None partial False
136 136 ancestor 924404dff337 local 94b33a1b7f2d+ remote 735846fee2d7
137 137 searching for copies back to rev 1
138 138 unmatched files in other:
139 139 b
140 140 all copies found (* = to merge, ! = divergent):
141 141 b -> a
142 142 checking for directory renames
143 143 rev: versions differ -> m
144 144 b: remote created -> g
145 145 preserving rev for resolve of rev
146 146 getting b
147 147 picked tool 'python ../merge' for rev (binary False symlink False)
148 148 merging rev
149 149 my rev@94b33a1b7f2d+ other rev@735846fee2d7 ancestor rev@924404dff337
150 150 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
151 151 (branch merge, don't forget to commit)
152 152 --------------
153 153 M b
154 154 C a
155 155 --------------
156 156
157 157 created new head
158 158 --------------
159 159 test L:nc a b R: W: - 6 nothing
160 160 --------------
161 161 resolving manifests
162 162 overwrite None partial False
163 163 ancestor 924404dff337 local ac809aeed39a+ remote 97c705ade336
164 164 searching for copies back to rev 1
165 165 unmatched files in local:
166 166 b
167 167 all copies found (* = to merge, ! = divergent):
168 168 b -> a
169 169 checking for directory renames
170 170 rev: versions differ -> m
171 171 preserving rev for resolve of rev
172 172 picked tool 'python ../merge' for rev (binary False symlink False)
173 173 merging rev
174 174 my rev@ac809aeed39a+ other rev@97c705ade336 ancestor rev@924404dff337
175 175 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
176 176 (branch merge, don't forget to commit)
177 177 --------------
178 178 C a
179 179 C b
180 180 --------------
181 181
182 182 created new head
183 183 --------------
184 184 test L: R:nm a b W: - 7 get b
185 185 --------------
186 186 resolving manifests
187 187 overwrite None partial False
188 188 ancestor 924404dff337 local 94b33a1b7f2d+ remote e03727d2d66b
189 189 searching for copies back to rev 1
190 190 unmatched files in other:
191 191 b
192 192 all copies found (* = to merge, ! = divergent):
193 193 b -> a
194 194 checking for directory renames
195 195 a: other deleted -> r
196 196 rev: versions differ -> m
197 197 b: remote created -> g
198 198 preserving rev for resolve of rev
199 199 removing a
200 200 getting b
201 201 picked tool 'python ../merge' for rev (binary False symlink False)
202 202 merging rev
203 203 my rev@94b33a1b7f2d+ other rev@e03727d2d66b ancestor rev@924404dff337
204 204 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
205 205 (branch merge, don't forget to commit)
206 206 --------------
207 207 M b
208 208 --------------
209 209
210 210 created new head
211 211 --------------
212 212 test L:nm a b R: W: - 8 nothing
213 213 --------------
214 214 resolving manifests
215 215 overwrite None partial False
216 216 ancestor 924404dff337 local ecf3cb2a4219+ remote 97c705ade336
217 217 searching for copies back to rev 1
218 218 unmatched files in local:
219 219 b
220 220 all copies found (* = to merge, ! = divergent):
221 221 b -> a
222 222 checking for directory renames
223 223 rev: versions differ -> m
224 224 preserving rev for resolve of rev
225 225 picked tool 'python ../merge' for rev (binary False symlink False)
226 226 merging rev
227 227 my rev@ecf3cb2a4219+ other rev@97c705ade336 ancestor rev@924404dff337
228 228 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
229 229 (branch merge, don't forget to commit)
230 230 --------------
231 231 C b
232 232 --------------
233 233
234 234 created new head
235 235 --------------
236 236 test L:um a b R:um a b W: - 9 do merge with ancestor in a
237 237 --------------
238 238 resolving manifests
239 239 overwrite None partial False
240 240 ancestor 924404dff337 local ec03c2ca8642+ remote 79cc6877a3b7
241 241 searching for copies back to rev 1
242 242 b: versions differ -> m
243 243 rev: versions differ -> m
244 244 preserving b for resolve of b
245 245 preserving rev for resolve of rev
246 246 picked tool 'python ../merge' for b (binary False symlink False)
247 247 merging b
248 248 my b@ec03c2ca8642+ other b@79cc6877a3b7 ancestor a@924404dff337
249 249 picked tool 'python ../merge' for rev (binary False symlink False)
250 250 merging rev
251 251 my rev@ec03c2ca8642+ other rev@79cc6877a3b7 ancestor rev@924404dff337
252 252 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
253 253 (branch merge, don't forget to commit)
254 254 --------------
255 255 M b
256 256 --------------
257 257
258 258 created new head
259 259 --------------
260 260 test L:nm a b R:nm a c W: - 11 get c, keep b
261 261 --------------
262 262 resolving manifests
263 263 overwrite None partial False
264 264 ancestor 924404dff337 local ecf3cb2a4219+ remote e6abcc1a30c2
265 265 searching for copies back to rev 1
266 266 unmatched files in local:
267 267 b
268 268 unmatched files in other:
269 269 c
270 270 all copies found (* = to merge, ! = divergent):
271 271 c -> a !
272 272 b -> a !
273 273 checking for directory renames
274 274 a: divergent renames -> dr
275 275 rev: versions differ -> m
276 276 c: remote created -> g
277 277 preserving rev for resolve of rev
278 278 warning: detected divergent renames of a to:
279 279 b
280 280 c
281 281 getting c
282 282 picked tool 'python ../merge' for rev (binary False symlink False)
283 283 merging rev
284 284 my rev@ecf3cb2a4219+ other rev@e6abcc1a30c2 ancestor rev@924404dff337
285 285 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
286 286 (branch merge, don't forget to commit)
287 287 --------------
288 288 M c
289 289 C b
290 290 --------------
291 291
292 292 created new head
293 293 --------------
294 294 test L:nc a b R:up b W: - 12 merge b no ancestor
295 295 --------------
296 296 resolving manifests
297 297 overwrite None partial False
298 298 ancestor 924404dff337 local ac809aeed39a+ remote af30c7647fc7
299 299 searching for copies back to rev 1
300 300 b: versions differ -> m
301 301 rev: versions differ -> m
302 302 preserving b for resolve of b
303 303 preserving rev for resolve of rev
304 304 picked tool 'python ../merge' for b (binary False symlink False)
305 305 merging b
306 306 my b@ac809aeed39a+ other b@af30c7647fc7 ancestor b@000000000000
307 307 picked tool 'python ../merge' for rev (binary False symlink False)
308 308 merging rev
309 309 my rev@ac809aeed39a+ other rev@af30c7647fc7 ancestor rev@924404dff337
310 310 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
311 311 (branch merge, don't forget to commit)
312 312 --------------
313 313 M b
314 314 C a
315 315 --------------
316 316
317 317 created new head
318 318 --------------
319 319 test L:up b R:nm a b W: - 13 merge b no ancestor
320 320 --------------
321 321 resolving manifests
322 322 overwrite None partial False
323 323 ancestor 924404dff337 local 59318016310c+ remote e03727d2d66b
324 324 searching for copies back to rev 1
325 325 a: other deleted -> r
326 326 b: versions differ -> m
327 327 rev: versions differ -> m
328 328 preserving b for resolve of b
329 329 preserving rev for resolve of rev
330 330 removing a
331 331 picked tool 'python ../merge' for b (binary False symlink False)
332 332 merging b
333 333 my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000
334 334 picked tool 'python ../merge' for rev (binary False symlink False)
335 335 merging rev
336 336 my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337
337 337 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
338 338 (branch merge, don't forget to commit)
339 339 --------------
340 340 M b
341 341 --------------
342 342
343 343 created new head
344 344 --------------
345 345 test L:nc a b R:up a b W: - 14 merge b no ancestor
346 346 --------------
347 347 resolving manifests
348 348 overwrite None partial False
349 349 ancestor 924404dff337 local ac809aeed39a+ remote 8dbce441892a
350 350 searching for copies back to rev 1
351 351 a: remote is newer -> g
352 352 b: versions differ -> m
353 353 rev: versions differ -> m
354 354 preserving b for resolve of b
355 355 preserving rev for resolve of rev
356 356 getting a
357 357 picked tool 'python ../merge' for b (binary False symlink False)
358 358 merging b
359 359 my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000
360 360 picked tool 'python ../merge' for rev (binary False symlink False)
361 361 merging rev
362 362 my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337
363 363 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
364 364 (branch merge, don't forget to commit)
365 365 --------------
366 366 M a
367 367 M b
368 368 --------------
369 369
370 370 created new head
371 371 --------------
372 372 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
373 373 --------------
374 374 resolving manifests
375 375 overwrite None partial False
376 376 ancestor 924404dff337 local 59318016310c+ remote e03727d2d66b
377 377 searching for copies back to rev 1
378 378 a: other deleted -> r
379 379 b: versions differ -> m
380 380 rev: versions differ -> m
381 381 preserving b for resolve of b
382 382 preserving rev for resolve of rev
383 383 removing a
384 384 picked tool 'python ../merge' for b (binary False symlink False)
385 385 merging b
386 386 my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000
387 387 picked tool 'python ../merge' for rev (binary False symlink False)
388 388 merging rev
389 389 my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337
390 390 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
391 391 (branch merge, don't forget to commit)
392 392 --------------
393 393 M b
394 394 --------------
395 395
396 396 created new head
397 397 --------------
398 398 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
399 399 --------------
400 400 resolving manifests
401 401 overwrite None partial False
402 402 ancestor 924404dff337 local ac809aeed39a+ remote 8dbce441892a
403 403 searching for copies back to rev 1
404 404 a: remote is newer -> g
405 405 b: versions differ -> m
406 406 rev: versions differ -> m
407 407 preserving b for resolve of b
408 408 preserving rev for resolve of rev
409 409 getting a
410 410 picked tool 'python ../merge' for b (binary False symlink False)
411 411 merging b
412 412 my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000
413 413 picked tool 'python ../merge' for rev (binary False symlink False)
414 414 merging rev
415 415 my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337
416 416 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
417 417 (branch merge, don't forget to commit)
418 418 --------------
419 419 M a
420 420 M b
421 421 --------------
422 422
423 423 created new head
424 424 --------------
425 425 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
426 426 --------------
427 427 resolving manifests
428 428 overwrite None partial False
429 429 ancestor 924404dff337 local 0b76e65c8289+ remote 735846fee2d7
430 430 searching for copies back to rev 1
431 431 b: versions differ -> m
432 432 rev: versions differ -> m
433 433 preserving b for resolve of b
434 434 preserving rev for resolve of rev
435 435 picked tool 'python ../merge' for b (binary False symlink False)
436 436 merging b
437 437 my b@0b76e65c8289+ other b@735846fee2d7 ancestor b@000000000000
438 438 picked tool 'python ../merge' for rev (binary False symlink False)
439 439 merging rev
440 440 my rev@0b76e65c8289+ other rev@735846fee2d7 ancestor rev@924404dff337
441 441 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
442 442 (branch merge, don't forget to commit)
443 443 --------------
444 444 M b
445 445 C a
446 446 --------------
447 447
448 448 created new head
449 449 --------------
450 450 test L:nm a b R:up a b W: - 18 merge b no ancestor
451 451 --------------
452 452 resolving manifests
453 453 overwrite None partial False
454 454 ancestor 924404dff337 local ecf3cb2a4219+ remote 8dbce441892a
455 455 searching for copies back to rev 1
456 456 b: versions differ -> m
457 457 rev: versions differ -> m
458 458 remote changed a which local deleted
459 459 use (c)hanged version or leave (d)eleted? c
460 460 a: prompt recreating -> g
461 461 preserving b for resolve of b
462 462 preserving rev for resolve of rev
463 463 getting a
464 464 picked tool 'python ../merge' for b (binary False symlink False)
465 465 merging b
466 466 my b@ecf3cb2a4219+ other b@8dbce441892a ancestor b@000000000000
467 467 picked tool 'python ../merge' for rev (binary False symlink False)
468 468 merging rev
469 469 my rev@ecf3cb2a4219+ other rev@8dbce441892a ancestor rev@924404dff337
470 470 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
471 471 (branch merge, don't forget to commit)
472 472 --------------
473 473 M a
474 474 M b
475 475 --------------
476 476
477 477 created new head
478 478 --------------
479 479 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
480 480 --------------
481 481 resolving manifests
482 482 overwrite None partial False
483 483 ancestor 924404dff337 local 0b76e65c8289+ remote e03727d2d66b
484 484 searching for copies back to rev 1
485 485 local changed a which remote deleted
486 486 use (c)hanged version or (d)elete? c
487 a: prompt keep -> a
487 488 b: versions differ -> m
488 489 rev: versions differ -> m
489 490 preserving b for resolve of b
490 491 preserving rev for resolve of rev
491 492 picked tool 'python ../merge' for b (binary False symlink False)
492 493 merging b
493 494 my b@0b76e65c8289+ other b@e03727d2d66b ancestor b@000000000000
494 495 picked tool 'python ../merge' for rev (binary False symlink False)
495 496 merging rev
496 497 my rev@0b76e65c8289+ other rev@e03727d2d66b ancestor rev@924404dff337
497 498 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
498 499 (branch merge, don't forget to commit)
499 500 --------------
500 501 M b
501 502 C a
502 503 --------------
503 504
504 505 created new head
505 506 --------------
506 507 test L:up a R:um a b W: - 20 merge a and b to b, remove a
507 508 --------------
508 509 resolving manifests
509 510 overwrite None partial False
510 511 ancestor 924404dff337 local e300d1c794ec+ remote 79cc6877a3b7
511 512 searching for copies back to rev 1
512 513 unmatched files in other:
513 514 b
514 515 all copies found (* = to merge, ! = divergent):
515 516 b -> a *
516 517 checking for directory renames
517 518 rev: versions differ -> m
518 519 a: remote moved to b -> m
519 520 preserving a for resolve of b
520 521 preserving rev for resolve of rev
521 522 removing a
522 523 picked tool 'python ../merge' for b (binary False symlink False)
523 524 merging a and b to b
524 525 my b@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337
525 526 picked tool 'python ../merge' for rev (binary False symlink False)
526 527 merging rev
527 528 my rev@e300d1c794ec+ other rev@79cc6877a3b7 ancestor rev@924404dff337
528 529 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
529 530 (branch merge, don't forget to commit)
530 531 --------------
531 532 M b
532 533 a
533 534 --------------
534 535
535 536 created new head
536 537 --------------
537 538 test L:um a b R:up a W: - 21 merge a and b to b
538 539 --------------
539 540 resolving manifests
540 541 overwrite None partial False
541 542 ancestor 924404dff337 local ec03c2ca8642+ remote f4db7e329e71
542 543 searching for copies back to rev 1
543 544 unmatched files in local:
544 545 b
545 546 all copies found (* = to merge, ! = divergent):
546 547 b -> a *
547 548 checking for directory renames
548 549 b: local moved to a -> m
549 550 rev: versions differ -> m
550 551 preserving b for resolve of b
551 552 preserving rev for resolve of rev
552 553 picked tool 'python ../merge' for b (binary False symlink False)
553 554 merging b and a to b
554 555 my b@ec03c2ca8642+ other a@f4db7e329e71 ancestor a@924404dff337
555 556 picked tool 'python ../merge' for rev (binary False symlink False)
556 557 merging rev
557 558 my rev@ec03c2ca8642+ other rev@f4db7e329e71 ancestor rev@924404dff337
558 559 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
559 560 (branch merge, don't forget to commit)
560 561 --------------
561 562 M b
562 563 a
563 564 --------------
564 565
565 566 created new head
566 567 --------------
567 568 test L:nm a b R:up a c W: - 23 get c, keep b
568 569 --------------
569 570 resolving manifests
570 571 overwrite None partial False
571 572 ancestor 924404dff337 local ecf3cb2a4219+ remote 2b958612230f
572 573 searching for copies back to rev 1
573 574 unmatched files in local:
574 575 b
575 576 unmatched files in other:
576 577 c
577 578 all copies found (* = to merge, ! = divergent):
578 579 b -> a *
579 580 checking for directory renames
580 581 b: local moved to a -> m
581 582 rev: versions differ -> m
582 583 c: remote created -> g
583 584 preserving b for resolve of b
584 585 preserving rev for resolve of rev
585 586 picked tool 'python ../merge' for b (binary False symlink False)
586 587 merging b and a to b
587 588 my b@ecf3cb2a4219+ other a@2b958612230f ancestor a@924404dff337
588 589 premerge successful
589 590 getting c
590 591 picked tool 'python ../merge' for rev (binary False symlink False)
591 592 merging rev
592 593 my rev@ecf3cb2a4219+ other rev@2b958612230f ancestor rev@924404dff337
593 594 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
594 595 (branch merge, don't forget to commit)
595 596 --------------
596 597 M b
597 598 a
598 599 M c
599 600 --------------
600 601
General Comments 0
You need to be logged in to leave comments. Login now