##// END OF EJS Templates
merge: do early copy to deal with issue636...
Matt Mackall -
r5042:f191bc39 default
parent child Browse files
Show More
@@ -0,0 +1,30 b''
1 #!/bin/sh
2
3 hg init repo
4 cd repo
5
6 echo line 1 > foo
7 hg ci -qAm 'add foo' -d "1000000 0"
8
9 # copy foo to bar and change both files
10 hg cp foo bar
11 echo line 2-1 >> foo
12 echo line 2-2 >> bar
13 hg ci -m 'cp foo bar; change both' -d "1000000 0"
14
15 # in another branch, change foo in a way that doesn't conflict with
16 # the other changes
17 hg up -qC 0
18 echo line 0 >| foo
19 hg cat foo >> foo
20 hg ci -m 'change foo' -d "1000000 0"
21
22 # we get conflicts that shouldn't be there
23 hg merge --debug
24
25 echo "-- foo --"
26 cat foo
27
28 echo "-- bar --"
29 cat bar
30
@@ -0,0 +1,20 b''
1 resolving manifests
2 overwrite None partial False
3 ancestor 310fd17130da local 2092631ce82b+ remote 7731dad1c2b9
4 foo: versions differ -> m
5 foo: remote copied to bar -> m
6 copying foo to bar
7 merging foo and bar
8 my foo@2092631ce82b+ other bar@7731dad1c2b9 ancestor foo@310fd17130da
9 merging foo
10 my foo@2092631ce82b+ other foo@7731dad1c2b9 ancestor foo@310fd17130da
11 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
12 (branch merge, don't forget to commit)
13 -- foo --
14 line 0
15 line 1
16 line 2-1
17 -- bar --
18 line 0
19 line 1
20 line 2-2
@@ -1,570 +1,578 b''
1 # merge.py - directory-level update/merge handling for Mercurial
1 # merge.py - directory-level update/merge handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import errno, util, os, tempfile, context
10 import errno, util, os, tempfile, context
11
11
12 def filemerge(repo, fw, fo, wctx, mctx):
12 def filemerge(repo, fw, fd, fo, wctx, mctx):
13 """perform a 3-way merge in the working directory
13 """perform a 3-way merge in the working directory
14
14
15 fw = filename in the working directory
15 fw = original filename in the working directory
16 fd = destination filename in the working directory
16 fo = filename in other parent
17 fo = filename in other parent
17 wctx, mctx = working and merge changecontexts
18 wctx, mctx = working and merge changecontexts
18 """
19 """
19
20
20 def temp(prefix, ctx):
21 def temp(prefix, ctx):
21 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
22 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
22 (fd, name) = tempfile.mkstemp(prefix=pre)
23 (fd, name) = tempfile.mkstemp(prefix=pre)
23 data = repo.wwritedata(ctx.path(), ctx.data())
24 data = repo.wwritedata(ctx.path(), ctx.data())
24 f = os.fdopen(fd, "wb")
25 f = os.fdopen(fd, "wb")
25 f.write(data)
26 f.write(data)
26 f.close()
27 f.close()
27 return name
28 return name
28
29
29 fcm = wctx.filectx(fw)
30 fcm = wctx.filectx(fw)
31 fcmdata = wctx.filectx(fd).data()
30 fco = mctx.filectx(fo)
32 fco = mctx.filectx(fo)
31
33
32 if not fco.cmp(fcm.data()): # files identical?
34 if not fco.cmp(fcmdata): # files identical?
33 return None
35 return None
34
36
35 fca = fcm.ancestor(fco)
37 fca = fcm.ancestor(fco)
36 if not fca:
38 if not fca:
37 fca = repo.filectx(fw, fileid=nullrev)
39 fca = repo.filectx(fw, fileid=nullrev)
38 a = repo.wjoin(fw)
40 a = repo.wjoin(fd)
39 b = temp("base", fca)
41 b = temp("base", fca)
40 c = temp("other", fco)
42 c = temp("other", fco)
41
43
42 if fw != fo:
44 if fw != fo:
43 repo.ui.status(_("merging %s and %s\n") % (fw, fo))
45 repo.ui.status(_("merging %s and %s\n") % (fw, fo))
44 else:
46 else:
45 repo.ui.status(_("merging %s\n") % fw)
47 repo.ui.status(_("merging %s\n") % fw)
46
48
47 repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca))
49 repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca))
48
50
49 cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge")
51 cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge")
50 or "hgmerge")
52 or "hgmerge")
51 r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root,
53 r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root,
52 environ={'HG_FILE': fw,
54 environ={'HG_FILE': fd,
53 'HG_MY_NODE': str(wctx.parents()[0]),
55 'HG_MY_NODE': str(wctx.parents()[0]),
54 'HG_OTHER_NODE': str(mctx)})
56 'HG_OTHER_NODE': str(mctx)})
55 if r:
57 if r:
56 repo.ui.warn(_("merging %s failed!\n") % fw)
58 repo.ui.warn(_("merging %s failed!\n") % fd)
57
59
58 os.unlink(b)
60 os.unlink(b)
59 os.unlink(c)
61 os.unlink(c)
60 return r
62 return r
61
63
62 def checkunknown(wctx, mctx):
64 def checkunknown(wctx, mctx):
63 "check for collisions between unknown files and files in mctx"
65 "check for collisions between unknown files and files in mctx"
64 man = mctx.manifest()
66 man = mctx.manifest()
65 for f in wctx.unknown():
67 for f in wctx.unknown():
66 if f in man:
68 if f in man:
67 if mctx.filectx(f).cmp(wctx.filectx(f).data()):
69 if mctx.filectx(f).cmp(wctx.filectx(f).data()):
68 raise util.Abort(_("untracked local file '%s' differs"
70 raise util.Abort(_("untracked local file '%s' differs"
69 " from remote version") % f)
71 " from remote version") % f)
70
72
71 def checkcollision(mctx):
73 def checkcollision(mctx):
72 "check for case folding collisions in the destination context"
74 "check for case folding collisions in the destination context"
73 folded = {}
75 folded = {}
74 for fn in mctx.manifest():
76 for fn in mctx.manifest():
75 fold = fn.lower()
77 fold = fn.lower()
76 if fold in folded:
78 if fold in folded:
77 raise util.Abort(_("case-folding collision between %s and %s")
79 raise util.Abort(_("case-folding collision between %s and %s")
78 % (fn, folded[fold]))
80 % (fn, folded[fold]))
79 folded[fold] = fn
81 folded[fold] = fn
80
82
81 def forgetremoved(wctx, mctx):
83 def forgetremoved(wctx, mctx):
82 """
84 """
83 Forget removed files
85 Forget removed files
84
86
85 If we're jumping between revisions (as opposed to merging), and if
87 If we're jumping between revisions (as opposed to merging), and if
86 neither the working directory nor the target rev has the file,
88 neither the working directory nor the target rev has the file,
87 then we need to remove it from the dirstate, to prevent the
89 then we need to remove it from the dirstate, to prevent the
88 dirstate from listing the file when it is no longer in the
90 dirstate from listing the file when it is no longer in the
89 manifest.
91 manifest.
90 """
92 """
91
93
92 action = []
94 action = []
93 man = mctx.manifest()
95 man = mctx.manifest()
94 for f in wctx.deleted() + wctx.removed():
96 for f in wctx.deleted() + wctx.removed():
95 if f not in man:
97 if f not in man:
96 action.append((f, "f"))
98 action.append((f, "f"))
97
99
98 return action
100 return action
99
101
100 def findcopies(repo, m1, m2, ma, limit):
102 def findcopies(repo, m1, m2, ma, limit):
101 """
103 """
102 Find moves and copies between m1 and m2 back to limit linkrev
104 Find moves and copies between m1 and m2 back to limit linkrev
103 """
105 """
104
106
105 def nonoverlap(d1, d2, d3):
107 def nonoverlap(d1, d2, d3):
106 "Return list of elements in d1 not in d2 or d3"
108 "Return list of elements in d1 not in d2 or d3"
107 l = [d for d in d1 if d not in d3 and d not in d2]
109 l = [d for d in d1 if d not in d3 and d not in d2]
108 l.sort()
110 l.sort()
109 return l
111 return l
110
112
111 def dirname(f):
113 def dirname(f):
112 s = f.rfind("/")
114 s = f.rfind("/")
113 if s == -1:
115 if s == -1:
114 return ""
116 return ""
115 return f[:s]
117 return f[:s]
116
118
117 def dirs(files):
119 def dirs(files):
118 d = {}
120 d = {}
119 for f in files:
121 for f in files:
120 f = dirname(f)
122 f = dirname(f)
121 while f not in d:
123 while f not in d:
122 d[f] = True
124 d[f] = True
123 f = dirname(f)
125 f = dirname(f)
124 return d
126 return d
125
127
126 wctx = repo.workingctx()
128 wctx = repo.workingctx()
127
129
128 def makectx(f, n):
130 def makectx(f, n):
129 if len(n) == 20:
131 if len(n) == 20:
130 return repo.filectx(f, fileid=n)
132 return repo.filectx(f, fileid=n)
131 return wctx.filectx(f)
133 return wctx.filectx(f)
132 ctx = util.cachefunc(makectx)
134 ctx = util.cachefunc(makectx)
133
135
134 def findold(fctx):
136 def findold(fctx):
135 "find files that path was copied from, back to linkrev limit"
137 "find files that path was copied from, back to linkrev limit"
136 old = {}
138 old = {}
137 seen = {}
139 seen = {}
138 orig = fctx.path()
140 orig = fctx.path()
139 visit = [fctx]
141 visit = [fctx]
140 while visit:
142 while visit:
141 fc = visit.pop()
143 fc = visit.pop()
142 s = str(fc)
144 s = str(fc)
143 if s in seen:
145 if s in seen:
144 continue
146 continue
145 seen[s] = 1
147 seen[s] = 1
146 if fc.path() != orig and fc.path() not in old:
148 if fc.path() != orig and fc.path() not in old:
147 old[fc.path()] = 1
149 old[fc.path()] = 1
148 if fc.rev() < limit:
150 if fc.rev() < limit:
149 continue
151 continue
150 visit += fc.parents()
152 visit += fc.parents()
151
153
152 old = old.keys()
154 old = old.keys()
153 old.sort()
155 old.sort()
154 return old
156 return old
155
157
156 copy = {}
158 copy = {}
157 fullcopy = {}
159 fullcopy = {}
158 diverge = {}
160 diverge = {}
159
161
160 def checkcopies(c, man, aman):
162 def checkcopies(c, man, aman):
161 '''check possible copies for filectx c'''
163 '''check possible copies for filectx c'''
162 for of in findold(c):
164 for of in findold(c):
163 fullcopy[c.path()] = of # remember for dir rename detection
165 fullcopy[c.path()] = of # remember for dir rename detection
164 if of not in man: # original file not in other manifest?
166 if of not in man: # original file not in other manifest?
165 if of in ma:
167 if of in ma:
166 diverge.setdefault(of, []).append(c.path())
168 diverge.setdefault(of, []).append(c.path())
167 continue
169 continue
168 # if the original file is unchanged on the other branch,
170 # if the original file is unchanged on the other branch,
169 # no merge needed
171 # no merge needed
170 if man[of] == aman.get(of):
172 if man[of] == aman.get(of):
171 continue
173 continue
172 c2 = ctx(of, man[of])
174 c2 = ctx(of, man[of])
173 ca = c.ancestor(c2)
175 ca = c.ancestor(c2)
174 if not ca: # unrelated?
176 if not ca: # unrelated?
175 continue
177 continue
176 # named changed on only one side?
178 # named changed on only one side?
177 if ca.path() == c.path() or ca.path() == c2.path():
179 if ca.path() == c.path() or ca.path() == c2.path():
178 if c == ca or c2 == ca: # no merge needed, ignore copy
180 if c == ca or c2 == ca: # no merge needed, ignore copy
179 continue
181 continue
180 copy[c.path()] = of
182 copy[c.path()] = of
181
183
182 if not repo.ui.configbool("merge", "followcopies", True):
184 if not repo.ui.configbool("merge", "followcopies", True):
183 return {}, {}
185 return {}, {}
184
186
185 # avoid silly behavior for update from empty dir
187 # avoid silly behavior for update from empty dir
186 if not m1 or not m2 or not ma:
188 if not m1 or not m2 or not ma:
187 return {}, {}
189 return {}, {}
188
190
189 u1 = nonoverlap(m1, m2, ma)
191 u1 = nonoverlap(m1, m2, ma)
190 u2 = nonoverlap(m2, m1, ma)
192 u2 = nonoverlap(m2, m1, ma)
191
193
192 for f in u1:
194 for f in u1:
193 checkcopies(ctx(f, m1[f]), m2, ma)
195 checkcopies(ctx(f, m1[f]), m2, ma)
194
196
195 for f in u2:
197 for f in u2:
196 checkcopies(ctx(f, m2[f]), m1, ma)
198 checkcopies(ctx(f, m2[f]), m1, ma)
197
199
198 d2 = {}
200 d2 = {}
199 for of, fl in diverge.items():
201 for of, fl in diverge.items():
200 for f in fl:
202 for f in fl:
201 fo = list(fl)
203 fo = list(fl)
202 fo.remove(f)
204 fo.remove(f)
203 d2[f] = (of, fo)
205 d2[f] = (of, fo)
204
206
205 if not fullcopy or not repo.ui.configbool("merge", "followdirs", True):
207 if not fullcopy or not repo.ui.configbool("merge", "followdirs", True):
206 return copy, diverge
208 return copy, diverge
207
209
208 # generate a directory move map
210 # generate a directory move map
209 d1, d2 = dirs(m1), dirs(m2)
211 d1, d2 = dirs(m1), dirs(m2)
210 invalid = {}
212 invalid = {}
211 dirmove = {}
213 dirmove = {}
212
214
213 # examine each file copy for a potential directory move, which is
215 # examine each file copy for a potential directory move, which is
214 # when all the files in a directory are moved to a new directory
216 # when all the files in a directory are moved to a new directory
215 for dst, src in fullcopy.items():
217 for dst, src in fullcopy.items():
216 dsrc, ddst = dirname(src), dirname(dst)
218 dsrc, ddst = dirname(src), dirname(dst)
217 if dsrc in invalid:
219 if dsrc in invalid:
218 # already seen to be uninteresting
220 # already seen to be uninteresting
219 continue
221 continue
220 elif dsrc in d1 and ddst in d1:
222 elif dsrc in d1 and ddst in d1:
221 # directory wasn't entirely moved locally
223 # directory wasn't entirely moved locally
222 invalid[dsrc] = True
224 invalid[dsrc] = True
223 elif dsrc in d2 and ddst in d2:
225 elif dsrc in d2 and ddst in d2:
224 # directory wasn't entirely moved remotely
226 # directory wasn't entirely moved remotely
225 invalid[dsrc] = True
227 invalid[dsrc] = True
226 elif dsrc in dirmove and dirmove[dsrc] != ddst:
228 elif dsrc in dirmove and dirmove[dsrc] != ddst:
227 # files from the same directory moved to two different places
229 # files from the same directory moved to two different places
228 invalid[dsrc] = True
230 invalid[dsrc] = True
229 else:
231 else:
230 # looks good so far
232 # looks good so far
231 dirmove[dsrc + "/"] = ddst + "/"
233 dirmove[dsrc + "/"] = ddst + "/"
232
234
233 for i in invalid:
235 for i in invalid:
234 if i in dirmove:
236 if i in dirmove:
235 del dirmove[i]
237 del dirmove[i]
236
238
237 del d1, d2, invalid
239 del d1, d2, invalid
238
240
239 if not dirmove:
241 if not dirmove:
240 return copy, diverge
242 return copy, diverge
241
243
242 # check unaccounted nonoverlapping files against directory moves
244 # check unaccounted nonoverlapping files against directory moves
243 for f in u1 + u2:
245 for f in u1 + u2:
244 if f not in fullcopy:
246 if f not in fullcopy:
245 for d in dirmove:
247 for d in dirmove:
246 if f.startswith(d):
248 if f.startswith(d):
247 # new file added in a directory that was moved, move it
249 # new file added in a directory that was moved, move it
248 copy[f] = dirmove[d] + f[len(d):]
250 copy[f] = dirmove[d] + f[len(d):]
249 break
251 break
250
252
251 return copy, diverge
253 return copy, diverge
252
254
253 def manifestmerge(repo, p1, p2, pa, overwrite, partial):
255 def manifestmerge(repo, p1, p2, pa, overwrite, partial):
254 """
256 """
255 Merge p1 and p2 with ancestor ma and generate merge action list
257 Merge p1 and p2 with ancestor ma and generate merge action list
256
258
257 overwrite = whether we clobber working files
259 overwrite = whether we clobber working files
258 partial = function to filter file lists
260 partial = function to filter file lists
259 """
261 """
260
262
261 repo.ui.note(_("resolving manifests\n"))
263 repo.ui.note(_("resolving manifests\n"))
262 repo.ui.debug(_(" overwrite %s partial %s\n") % (overwrite, bool(partial)))
264 repo.ui.debug(_(" overwrite %s partial %s\n") % (overwrite, bool(partial)))
263 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (pa, p1, p2))
265 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (pa, p1, p2))
264
266
265 m1 = p1.manifest()
267 m1 = p1.manifest()
266 m2 = p2.manifest()
268 m2 = p2.manifest()
267 ma = pa.manifest()
269 ma = pa.manifest()
268 backwards = (pa == p2)
270 backwards = (pa == p2)
269 action = []
271 action = []
270 copy = {}
272 copy = {}
271 diverge = {}
273 diverge = {}
272
274
273 def fmerge(f, f2=None, fa=None):
275 def fmerge(f, f2=None, fa=None):
274 """merge flags"""
276 """merge flags"""
275 if not f2:
277 if not f2:
276 f2 = f
278 f2 = f
277 fa = f
279 fa = f
278 a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2)
280 a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2)
279 if ((a^b) | (a^c)) ^ a:
281 if ((a^b) | (a^c)) ^ a:
280 return 'x'
282 return 'x'
281 a, b, c = ma.linkf(fa), m1.linkf(f), m2.linkf(f2)
283 a, b, c = ma.linkf(fa), m1.linkf(f), m2.linkf(f2)
282 if ((a^b) | (a^c)) ^ a:
284 if ((a^b) | (a^c)) ^ a:
283 return 'l'
285 return 'l'
284 return ''
286 return ''
285
287
286 def act(msg, m, f, *args):
288 def act(msg, m, f, *args):
287 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
289 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
288 action.append((f, m) + args)
290 action.append((f, m) + args)
289
291
290 if not (backwards or overwrite):
292 if not (backwards or overwrite):
291 copy, diverge = findcopies(repo, m1, m2, ma, pa.rev())
293 copy, diverge = findcopies(repo, m1, m2, ma, pa.rev())
292
294
293 for of, fl in diverge.items():
295 for of, fl in diverge.items():
294 act("divergent renames", "dr", of, fl)
296 act("divergent renames", "dr", of, fl)
295
297
296 copied = dict.fromkeys(copy.values())
298 copied = dict.fromkeys(copy.values())
297
299
298 # Compare manifests
300 # Compare manifests
299 for f, n in m1.iteritems():
301 for f, n in m1.iteritems():
300 if partial and not partial(f):
302 if partial and not partial(f):
301 continue
303 continue
302 if f in m2:
304 if f in m2:
303 # are files different?
305 # are files different?
304 if n != m2[f]:
306 if n != m2[f]:
305 a = ma.get(f, nullid)
307 a = ma.get(f, nullid)
306 # are both different from the ancestor?
308 # are both different from the ancestor?
307 if not overwrite and n != a and m2[f] != a:
309 if not overwrite and n != a and m2[f] != a:
308 act("versions differ", "m", f, f, f, fmerge(f), False)
310 act("versions differ", "m", f, f, f, fmerge(f), False)
309 # are we clobbering?
311 # are we clobbering?
310 # is remote's version newer?
312 # is remote's version newer?
311 # or are we going back in time and clean?
313 # or are we going back in time and clean?
312 elif overwrite or m2[f] != a or (backwards and not n[20:]):
314 elif overwrite or m2[f] != a or (backwards and not n[20:]):
313 act("remote is newer", "g", f, m2.flags(f))
315 act("remote is newer", "g", f, m2.flags(f))
314 # local is newer, not overwrite, check mode bits
316 # local is newer, not overwrite, check mode bits
315 elif fmerge(f) != m1.flags(f):
317 elif fmerge(f) != m1.flags(f):
316 act("update permissions", "e", f, m2.flags(f))
318 act("update permissions", "e", f, m2.flags(f))
317 # contents same, check mode bits
319 # contents same, check mode bits
318 elif m1.flags(f) != m2.flags(f):
320 elif m1.flags(f) != m2.flags(f):
319 if overwrite or fmerge(f) != m1.flags(f):
321 if overwrite or fmerge(f) != m1.flags(f):
320 act("update permissions", "e", f, m2.flags(f))
322 act("update permissions", "e", f, m2.flags(f))
321 elif f in copied:
323 elif f in copied:
322 continue
324 continue
323 elif f in copy:
325 elif f in copy:
324 f2 = copy[f]
326 f2 = copy[f]
325 if f2 not in m2: # directory rename
327 if f2 not in m2: # directory rename
326 act("remote renamed directory to " + f2, "d",
328 act("remote renamed directory to " + f2, "d",
327 f, None, f2, m1.flags(f))
329 f, None, f2, m1.flags(f))
328 elif f2 in m1: # case 2 A,B/B/B
330 elif f2 in m1: # case 2 A,B/B/B
329 act("local copied to " + f2, "m",
331 act("local copied to " + f2, "m",
330 f, f2, f, fmerge(f, f2, f2), False)
332 f, f2, f, fmerge(f, f2, f2), False)
331 else: # case 4,21 A/B/B
333 else: # case 4,21 A/B/B
332 act("local moved to " + f2, "m",
334 act("local moved to " + f2, "m",
333 f, f2, f, fmerge(f, f2, f2), False)
335 f, f2, f, fmerge(f, f2, f2), False)
334 elif f in ma:
336 elif f in ma:
335 if n != ma[f] and not overwrite:
337 if n != ma[f] and not overwrite:
336 if repo.ui.prompt(
338 if repo.ui.prompt(
337 (_(" local changed %s which remote deleted\n") % f) +
339 (_(" local changed %s which remote deleted\n") % f) +
338 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("d"):
340 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("d"):
339 act("prompt delete", "r", f)
341 act("prompt delete", "r", f)
340 else:
342 else:
341 act("other deleted", "r", f)
343 act("other deleted", "r", f)
342 else:
344 else:
343 # file is created on branch or in working directory
345 # file is created on branch or in working directory
344 if (overwrite and n[20:] != "u") or (backwards and not n[20:]):
346 if (overwrite and n[20:] != "u") or (backwards and not n[20:]):
345 act("remote deleted", "r", f)
347 act("remote deleted", "r", f)
346
348
347 for f, n in m2.iteritems():
349 for f, n in m2.iteritems():
348 if partial and not partial(f):
350 if partial and not partial(f):
349 continue
351 continue
350 if f in m1:
352 if f in m1:
351 continue
353 continue
352 if f in copied:
354 if f in copied:
353 continue
355 continue
354 if f in copy:
356 if f in copy:
355 f2 = copy[f]
357 f2 = copy[f]
356 if f2 not in m1: # directory rename
358 if f2 not in m1: # directory rename
357 act("local renamed directory to " + f2, "d",
359 act("local renamed directory to " + f2, "d",
358 None, f, f2, m2.flags(f))
360 None, f, f2, m2.flags(f))
359 elif f2 in m2: # rename case 1, A/A,B/A
361 elif f2 in m2: # rename case 1, A/A,B/A
360 act("remote copied to " + f, "m",
362 act("remote copied to " + f, "m",
361 f2, f, f, fmerge(f2, f, f2), False)
363 f2, f, f, fmerge(f2, f, f2), False)
362 else: # case 3,20 A/B/A
364 else: # case 3,20 A/B/A
363 act("remote moved to " + f, "m",
365 act("remote moved to " + f, "m",
364 f2, f, f, fmerge(f2, f, f2), True)
366 f2, f, f, fmerge(f2, f, f2), True)
365 elif f in ma:
367 elif f in ma:
366 if overwrite or backwards:
368 if overwrite or backwards:
367 act("recreating", "g", f, m2.flags(f))
369 act("recreating", "g", f, m2.flags(f))
368 elif n != ma[f]:
370 elif n != ma[f]:
369 if repo.ui.prompt(
371 if repo.ui.prompt(
370 (_("remote changed %s which local deleted\n") % f) +
372 (_("remote changed %s which local deleted\n") % f) +
371 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("k"):
373 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("k"):
372 act("prompt recreating", "g", f, m2.flags(f))
374 act("prompt recreating", "g", f, m2.flags(f))
373 else:
375 else:
374 act("remote created", "g", f, m2.flags(f))
376 act("remote created", "g", f, m2.flags(f))
375
377
376 return action
378 return action
377
379
378 def applyupdates(repo, action, wctx, mctx):
380 def applyupdates(repo, action, wctx, mctx):
379 "apply the merge action list to the working directory"
381 "apply the merge action list to the working directory"
380
382
381 updated, merged, removed, unresolved = 0, 0, 0, 0
383 updated, merged, removed, unresolved = 0, 0, 0, 0
382 action.sort()
384 action.sort()
385 # prescan for copy/renames
386 for a in action:
387 f, m = a[:2]
388 if m == 'm': # merge
389 f2, fd, flags, move = a[2:]
390 if f != fd:
391 repo.ui.debug(_("copying %s to %s\n") % (f, fd))
392 repo.wwrite(fd, repo.wread(f), flags)
393
383 for a in action:
394 for a in action:
384 f, m = a[:2]
395 f, m = a[:2]
385 if f and f[0] == "/":
396 if f and f[0] == "/":
386 continue
397 continue
387 if m == "r": # remove
398 if m == "r": # remove
388 repo.ui.note(_("removing %s\n") % f)
399 repo.ui.note(_("removing %s\n") % f)
389 util.audit_path(f)
400 util.audit_path(f)
390 try:
401 try:
391 util.unlink(repo.wjoin(f))
402 util.unlink(repo.wjoin(f))
392 except OSError, inst:
403 except OSError, inst:
393 if inst.errno != errno.ENOENT:
404 if inst.errno != errno.ENOENT:
394 repo.ui.warn(_("update failed to remove %s: %s!\n") %
405 repo.ui.warn(_("update failed to remove %s: %s!\n") %
395 (f, inst.strerror))
406 (f, inst.strerror))
396 removed += 1
407 removed += 1
397 elif m == "m": # merge
408 elif m == "m": # merge
398 f2, fd, flags, move = a[2:]
409 f2, fd, flags, move = a[2:]
399 r = filemerge(repo, f, f2, wctx, mctx)
410 r = filemerge(repo, f, fd, f2, wctx, mctx)
400 if r > 0:
411 if r > 0:
401 unresolved += 1
412 unresolved += 1
402 else:
413 else:
403 if r is None:
414 if r is None:
404 updated += 1
415 updated += 1
405 else:
416 else:
406 merged += 1
417 merged += 1
407 if f != fd:
418 if f != fd and move:
408 repo.ui.debug(_("copying %s to %s\n") % (f, fd))
419 repo.ui.debug(_("removing %s\n") % f)
409 repo.wwrite(fd, repo.wread(f), flags)
420 os.unlink(repo.wjoin(f))
410 if move:
411 repo.ui.debug(_("removing %s\n") % f)
412 os.unlink(repo.wjoin(f))
413 util.set_exec(repo.wjoin(fd), "x" in flags)
421 util.set_exec(repo.wjoin(fd), "x" in flags)
414 elif m == "g": # get
422 elif m == "g": # get
415 flags = a[2]
423 flags = a[2]
416 repo.ui.note(_("getting %s\n") % f)
424 repo.ui.note(_("getting %s\n") % f)
417 t = mctx.filectx(f).data()
425 t = mctx.filectx(f).data()
418 repo.wwrite(f, t, flags)
426 repo.wwrite(f, t, flags)
419 updated += 1
427 updated += 1
420 elif m == "d": # directory rename
428 elif m == "d": # directory rename
421 f2, fd, flags = a[2:]
429 f2, fd, flags = a[2:]
422 if f:
430 if f:
423 repo.ui.note(_("moving %s to %s\n") % (f, fd))
431 repo.ui.note(_("moving %s to %s\n") % (f, fd))
424 t = wctx.filectx(f).data()
432 t = wctx.filectx(f).data()
425 repo.wwrite(fd, t, flags)
433 repo.wwrite(fd, t, flags)
426 util.unlink(repo.wjoin(f))
434 util.unlink(repo.wjoin(f))
427 if f2:
435 if f2:
428 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
436 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
429 t = mctx.filectx(f2).data()
437 t = mctx.filectx(f2).data()
430 repo.wwrite(fd, t, flags)
438 repo.wwrite(fd, t, flags)
431 updated += 1
439 updated += 1
432 elif m == "dr": # divergent renames
440 elif m == "dr": # divergent renames
433 fl = a[2]
441 fl = a[2]
434 repo.ui.warn("warning: detected divergent renames of %s to:\n" % f)
442 repo.ui.warn("warning: detected divergent renames of %s to:\n" % f)
435 for nf in fl:
443 for nf in fl:
436 repo.ui.warn(" %s\n" % nf)
444 repo.ui.warn(" %s\n" % nf)
437 elif m == "e": # exec
445 elif m == "e": # exec
438 flags = a[2]
446 flags = a[2]
439 util.set_exec(repo.wjoin(f), flags)
447 util.set_exec(repo.wjoin(f), flags)
440
448
441 return updated, merged, removed, unresolved
449 return updated, merged, removed, unresolved
442
450
443 def recordupdates(repo, action, branchmerge):
451 def recordupdates(repo, action, branchmerge):
444 "record merge actions to the dirstate"
452 "record merge actions to the dirstate"
445
453
446 for a in action:
454 for a in action:
447 f, m = a[:2]
455 f, m = a[:2]
448 if m == "r": # remove
456 if m == "r": # remove
449 if branchmerge:
457 if branchmerge:
450 repo.dirstate.update([f], 'r')
458 repo.dirstate.update([f], 'r')
451 else:
459 else:
452 repo.dirstate.forget([f])
460 repo.dirstate.forget([f])
453 elif m == "f": # forget
461 elif m == "f": # forget
454 repo.dirstate.forget([f])
462 repo.dirstate.forget([f])
455 elif m in "ge": # get or exec change
463 elif m in "ge": # get or exec change
456 if branchmerge:
464 if branchmerge:
457 repo.dirstate.update([f], 'n', st_mtime=-1)
465 repo.dirstate.update([f], 'n', st_mtime=-1)
458 else:
466 else:
459 repo.dirstate.update([f], 'n')
467 repo.dirstate.update([f], 'n')
460 elif m == "m": # merge
468 elif m == "m": # merge
461 f2, fd, flag, move = a[2:]
469 f2, fd, flag, move = a[2:]
462 if branchmerge:
470 if branchmerge:
463 # We've done a branch merge, mark this file as merged
471 # We've done a branch merge, mark this file as merged
464 # so that we properly record the merger later
472 # so that we properly record the merger later
465 repo.dirstate.update([fd], 'm')
473 repo.dirstate.update([fd], 'm')
466 if f != f2: # copy/rename
474 if f != f2: # copy/rename
467 if move:
475 if move:
468 repo.dirstate.update([f], 'r')
476 repo.dirstate.update([f], 'r')
469 if f != fd:
477 if f != fd:
470 repo.dirstate.copy(f, fd)
478 repo.dirstate.copy(f, fd)
471 else:
479 else:
472 repo.dirstate.copy(f2, fd)
480 repo.dirstate.copy(f2, fd)
473 else:
481 else:
474 # We've update-merged a locally modified file, so
482 # We've update-merged a locally modified file, so
475 # we set the dirstate to emulate a normal checkout
483 # we set the dirstate to emulate a normal checkout
476 # of that file some time in the past. Thus our
484 # of that file some time in the past. Thus our
477 # merge will appear as a normal local file
485 # merge will appear as a normal local file
478 # modification.
486 # modification.
479 repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1)
487 repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1)
480 if move:
488 if move:
481 repo.dirstate.forget([f])
489 repo.dirstate.forget([f])
482 elif m == "d": # directory rename
490 elif m == "d": # directory rename
483 f2, fd, flag = a[2:]
491 f2, fd, flag = a[2:]
484 if not f2 and f not in repo.dirstate:
492 if not f2 and f not in repo.dirstate:
485 # untracked file moved
493 # untracked file moved
486 continue
494 continue
487 if branchmerge:
495 if branchmerge:
488 repo.dirstate.update([fd], 'a')
496 repo.dirstate.update([fd], 'a')
489 if f:
497 if f:
490 repo.dirstate.update([f], 'r')
498 repo.dirstate.update([f], 'r')
491 repo.dirstate.copy(f, fd)
499 repo.dirstate.copy(f, fd)
492 if f2:
500 if f2:
493 repo.dirstate.copy(f2, fd)
501 repo.dirstate.copy(f2, fd)
494 else:
502 else:
495 repo.dirstate.update([fd], 'n')
503 repo.dirstate.update([fd], 'n')
496 if f:
504 if f:
497 repo.dirstate.forget([f])
505 repo.dirstate.forget([f])
498
506
499 def update(repo, node, branchmerge, force, partial, wlock):
507 def update(repo, node, branchmerge, force, partial, wlock):
500 """
508 """
501 Perform a merge between the working directory and the given node
509 Perform a merge between the working directory and the given node
502
510
503 branchmerge = whether to merge between branches
511 branchmerge = whether to merge between branches
504 force = whether to force branch merging or file overwriting
512 force = whether to force branch merging or file overwriting
505 partial = a function to filter file lists (dirstate not updated)
513 partial = a function to filter file lists (dirstate not updated)
506 wlock = working dir lock, if already held
514 wlock = working dir lock, if already held
507 """
515 """
508
516
509 if not wlock:
517 if not wlock:
510 wlock = repo.wlock()
518 wlock = repo.wlock()
511
519
512 wc = repo.workingctx()
520 wc = repo.workingctx()
513 if node is None:
521 if node is None:
514 # tip of current branch
522 # tip of current branch
515 try:
523 try:
516 node = repo.branchtags()[wc.branch()]
524 node = repo.branchtags()[wc.branch()]
517 except KeyError:
525 except KeyError:
518 raise util.Abort(_("branch %s not found") % wc.branch())
526 raise util.Abort(_("branch %s not found") % wc.branch())
519 overwrite = force and not branchmerge
527 overwrite = force and not branchmerge
520 forcemerge = force and branchmerge
528 forcemerge = force and branchmerge
521 pl = wc.parents()
529 pl = wc.parents()
522 p1, p2 = pl[0], repo.changectx(node)
530 p1, p2 = pl[0], repo.changectx(node)
523 pa = p1.ancestor(p2)
531 pa = p1.ancestor(p2)
524 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
532 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
525 fastforward = False
533 fastforward = False
526
534
527 ### check phase
535 ### check phase
528 if not overwrite and len(pl) > 1:
536 if not overwrite and len(pl) > 1:
529 raise util.Abort(_("outstanding uncommitted merges"))
537 raise util.Abort(_("outstanding uncommitted merges"))
530 if pa == p1 or pa == p2: # is there a linear path from p1 to p2?
538 if pa == p1 or pa == p2: # is there a linear path from p1 to p2?
531 if branchmerge:
539 if branchmerge:
532 if p1.branch() != p2.branch() and pa != p2:
540 if p1.branch() != p2.branch() and pa != p2:
533 fastforward = True
541 fastforward = True
534 else:
542 else:
535 raise util.Abort(_("there is nothing to merge, just use "
543 raise util.Abort(_("there is nothing to merge, just use "
536 "'hg update' or look at 'hg heads'"))
544 "'hg update' or look at 'hg heads'"))
537 elif not (overwrite or branchmerge):
545 elif not (overwrite or branchmerge):
538 raise util.Abort(_("update spans branches, use 'hg merge' "
546 raise util.Abort(_("update spans branches, use 'hg merge' "
539 "or 'hg update -C' to lose changes"))
547 "or 'hg update -C' to lose changes"))
540 if branchmerge and not forcemerge:
548 if branchmerge and not forcemerge:
541 if wc.files():
549 if wc.files():
542 raise util.Abort(_("outstanding uncommitted changes"))
550 raise util.Abort(_("outstanding uncommitted changes"))
543
551
544 ### calculate phase
552 ### calculate phase
545 action = []
553 action = []
546 if not force:
554 if not force:
547 checkunknown(wc, p2)
555 checkunknown(wc, p2)
548 if not util.checkfolding(repo.path):
556 if not util.checkfolding(repo.path):
549 checkcollision(p2)
557 checkcollision(p2)
550 if not branchmerge:
558 if not branchmerge:
551 action += forgetremoved(wc, p2)
559 action += forgetremoved(wc, p2)
552 action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
560 action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
553
561
554 ### apply phase
562 ### apply phase
555 if not branchmerge: # just jump to the new rev
563 if not branchmerge: # just jump to the new rev
556 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
564 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
557 if not partial:
565 if not partial:
558 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
566 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
559
567
560 stats = applyupdates(repo, action, wc, p2)
568 stats = applyupdates(repo, action, wc, p2)
561
569
562 if not partial:
570 if not partial:
563 recordupdates(repo, action, branchmerge)
571 recordupdates(repo, action, branchmerge)
564 repo.dirstate.setparents(fp1, fp2)
572 repo.dirstate.setparents(fp1, fp2)
565 if not branchmerge and not fastforward:
573 if not branchmerge and not fastforward:
566 repo.dirstate.setbranch(p2.branch())
574 repo.dirstate.setbranch(p2.branch())
567 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
575 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
568
576
569 return stats
577 return stats
570
578
@@ -1,21 +1,21 b''
1 adding bar
1 adding bar
2 adding foo
2 adding foo
3 adding quux1
3 adding quux1
4 adding quux2
4 adding quux2
5 merging bar
5 merging bar
6 merging bar failed!
6 merging bar failed!
7 merging foo and baz
7 merging foo and baz
8 merging foo failed!
8 merging baz failed!
9 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
9 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
10 There are unresolved merges, you can redo the full merge using:
10 There are unresolved merges, you can redo the full merge using:
11 hg update -C 2
11 hg update -C 2
12 hg merge 1
12 hg merge 1
13 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
13 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
14 merging bar
14 merging bar
15 merging bar failed!
15 merging bar failed!
16 merging baz and foo
16 merging baz and foo
17 merging baz failed!
17 merging baz failed!
18 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
18 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
19 There are unresolved merges, you can redo the full merge using:
19 There are unresolved merges, you can redo the full merge using:
20 hg update -C 1
20 hg update -C 1
21 hg merge 2
21 hg merge 2
@@ -1,29 +1,29 b''
1 checkout
1 checkout
2 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
2 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
3 merge
3 merge
4 resolving manifests
4 resolving manifests
5 overwrite None partial False
5 overwrite None partial False
6 ancestor af1939970a1c local f26ec4fc3fa3+ remote 8e765a822af2
6 ancestor af1939970a1c local f26ec4fc3fa3+ remote 8e765a822af2
7 a2: divergent renames -> dr
7 a2: divergent renames -> dr
8 a: remote moved to b -> m
8 a: remote moved to b -> m
9 b2: remote created -> g
9 b2: remote created -> g
10 copying a to b
10 merging a and b
11 merging a and b
11 my a@f26ec4fc3fa3+ other b@8e765a822af2 ancestor a@af1939970a1c
12 my a@f26ec4fc3fa3+ other b@8e765a822af2 ancestor a@af1939970a1c
12 copying a to b
13 removing a
13 removing a
14 warning: detected divergent renames of a2 to:
14 warning: detected divergent renames of a2 to:
15 c2
15 c2
16 b2
16 b2
17 getting b2
17 getting b2
18 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
18 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
19 (branch merge, don't forget to commit)
19 (branch merge, don't forget to commit)
20 M b
20 M b
21 a
21 a
22 M b2
22 M b2
23 R a
23 R a
24 C c2
24 C c2
25 blahblah
25 blahblah
26 rev offset length base linkrev nodeid p1 p2
26 rev offset length base linkrev nodeid p1 p2
27 0 0 67 0 1 dc51707dfc98 000000000000 000000000000
27 0 0 67 0 1 dc51707dfc98 000000000000 000000000000
28 1 67 72 1 3 b2494a44f0a9 000000000000 dc51707dfc98
28 1 67 72 1 3 b2494a44f0a9 000000000000 dc51707dfc98
29 b renamed from a:dd03b83622e78778b403775d0d074b9ac7387a66
29 b renamed from a:dd03b83622e78778b403775d0d074b9ac7387a66
@@ -1,413 +1,413 b''
1 --------------
1 --------------
2 test L:up a R:nc a b W: - 1 get local a to b
2 test L:up a R:nc a b W: - 1 get local a to b
3 --------------
3 --------------
4 resolving manifests
4 resolving manifests
5 overwrite None partial False
5 overwrite None partial False
6 ancestor 924404dff337 local e300d1c794ec+ remote 735846fee2d7
6 ancestor 924404dff337 local e300d1c794ec+ remote 735846fee2d7
7 rev: versions differ -> m
7 rev: versions differ -> m
8 a: remote copied to b -> m
8 a: remote copied to b -> m
9 copying a to b
9 merging a and b
10 merging a and b
10 my a@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337
11 my a@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337
11 copying a to b
12 merging rev
12 merging rev
13 my rev@e300d1c794ec+ other rev@735846fee2d7 ancestor rev@924404dff337
13 my rev@e300d1c794ec+ other rev@735846fee2d7 ancestor rev@924404dff337
14 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
14 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
15 (branch merge, don't forget to commit)
15 (branch merge, don't forget to commit)
16 --------------
16 --------------
17 M a
18 M b
17 M b
19 a
18 a
19 C a
20 --------------
20 --------------
21
21
22 --------------
22 --------------
23 test L:nc a b R:up a W: - 2 get rem change to a and b
23 test L:nc a b R:up a W: - 2 get rem change to a and b
24 --------------
24 --------------
25 resolving manifests
25 resolving manifests
26 overwrite None partial False
26 overwrite None partial False
27 ancestor 924404dff337 local ac809aeed39a+ remote f4db7e329e71
27 ancestor 924404dff337 local ac809aeed39a+ remote f4db7e329e71
28 a: remote is newer -> g
28 a: remote is newer -> g
29 b: local copied to a -> m
29 b: local copied to a -> m
30 rev: versions differ -> m
30 rev: versions differ -> m
31 getting a
31 getting a
32 merging b and a
32 merging b and a
33 my b@ac809aeed39a+ other a@f4db7e329e71 ancestor a@924404dff337
33 my b@ac809aeed39a+ other a@f4db7e329e71 ancestor a@924404dff337
34 merging rev
34 merging rev
35 my rev@ac809aeed39a+ other rev@f4db7e329e71 ancestor rev@924404dff337
35 my rev@ac809aeed39a+ other rev@f4db7e329e71 ancestor rev@924404dff337
36 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
36 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
37 (branch merge, don't forget to commit)
37 (branch merge, don't forget to commit)
38 --------------
38 --------------
39 M a
39 M a
40 M b
40 M b
41 a
41 a
42 --------------
42 --------------
43
43
44 --------------
44 --------------
45 test L:up a R:nm a b W: - 3 get local a change to b, remove a
45 test L:up a R:nm a b W: - 3 get local a change to b, remove a
46 --------------
46 --------------
47 resolving manifests
47 resolving manifests
48 overwrite None partial False
48 overwrite None partial False
49 ancestor 924404dff337 local e300d1c794ec+ remote e03727d2d66b
49 ancestor 924404dff337 local e300d1c794ec+ remote e03727d2d66b
50 rev: versions differ -> m
50 rev: versions differ -> m
51 a: remote moved to b -> m
51 a: remote moved to b -> m
52 copying a to b
52 merging a and b
53 merging a and b
53 my a@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337
54 my a@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337
54 copying a to b
55 removing a
55 removing a
56 merging rev
56 merging rev
57 my rev@e300d1c794ec+ other rev@e03727d2d66b ancestor rev@924404dff337
57 my rev@e300d1c794ec+ other rev@e03727d2d66b ancestor rev@924404dff337
58 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
58 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
59 (branch merge, don't forget to commit)
59 (branch merge, don't forget to commit)
60 --------------
60 --------------
61 M b
61 M b
62 a
62 a
63 --------------
63 --------------
64
64
65 --------------
65 --------------
66 test L:nm a b R:up a W: - 4 get remote change to b
66 test L:nm a b R:up a W: - 4 get remote change to b
67 --------------
67 --------------
68 resolving manifests
68 resolving manifests
69 overwrite None partial False
69 overwrite None partial False
70 ancestor 924404dff337 local ecf3cb2a4219+ remote f4db7e329e71
70 ancestor 924404dff337 local ecf3cb2a4219+ remote f4db7e329e71
71 b: local moved to a -> m
71 b: local moved to a -> m
72 rev: versions differ -> m
72 rev: versions differ -> m
73 merging b and a
73 merging b and a
74 my b@ecf3cb2a4219+ other a@f4db7e329e71 ancestor a@924404dff337
74 my b@ecf3cb2a4219+ other a@f4db7e329e71 ancestor a@924404dff337
75 merging rev
75 merging rev
76 my rev@ecf3cb2a4219+ other rev@f4db7e329e71 ancestor rev@924404dff337
76 my rev@ecf3cb2a4219+ other rev@f4db7e329e71 ancestor rev@924404dff337
77 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
77 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
78 (branch merge, don't forget to commit)
78 (branch merge, don't forget to commit)
79 --------------
79 --------------
80 M b
80 M b
81 a
81 a
82 --------------
82 --------------
83
83
84 --------------
84 --------------
85 test L: R:nc a b W: - 5 get b
85 test L: R:nc a b W: - 5 get b
86 --------------
86 --------------
87 resolving manifests
87 resolving manifests
88 overwrite None partial False
88 overwrite None partial False
89 ancestor 924404dff337 local 94b33a1b7f2d+ remote 735846fee2d7
89 ancestor 924404dff337 local 94b33a1b7f2d+ remote 735846fee2d7
90 rev: versions differ -> m
90 rev: versions differ -> m
91 b: remote created -> g
91 b: remote created -> g
92 getting b
92 getting b
93 merging rev
93 merging rev
94 my rev@94b33a1b7f2d+ other rev@735846fee2d7 ancestor rev@924404dff337
94 my rev@94b33a1b7f2d+ other rev@735846fee2d7 ancestor rev@924404dff337
95 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
95 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
96 (branch merge, don't forget to commit)
96 (branch merge, don't forget to commit)
97 --------------
97 --------------
98 M b
98 M b
99 C a
99 C a
100 --------------
100 --------------
101
101
102 --------------
102 --------------
103 test L:nc a b R: W: - 6 nothing
103 test L:nc a b R: W: - 6 nothing
104 --------------
104 --------------
105 resolving manifests
105 resolving manifests
106 overwrite None partial False
106 overwrite None partial False
107 ancestor 924404dff337 local ac809aeed39a+ remote 97c705ade336
107 ancestor 924404dff337 local ac809aeed39a+ remote 97c705ade336
108 rev: versions differ -> m
108 rev: versions differ -> m
109 merging rev
109 merging rev
110 my rev@ac809aeed39a+ other rev@97c705ade336 ancestor rev@924404dff337
110 my rev@ac809aeed39a+ other rev@97c705ade336 ancestor rev@924404dff337
111 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
111 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
112 (branch merge, don't forget to commit)
112 (branch merge, don't forget to commit)
113 --------------
113 --------------
114 C a
114 C a
115 C b
115 C b
116 --------------
116 --------------
117
117
118 --------------
118 --------------
119 test L: R:nm a b W: - 7 get b
119 test L: R:nm a b W: - 7 get b
120 --------------
120 --------------
121 resolving manifests
121 resolving manifests
122 overwrite None partial False
122 overwrite None partial False
123 ancestor 924404dff337 local 94b33a1b7f2d+ remote e03727d2d66b
123 ancestor 924404dff337 local 94b33a1b7f2d+ remote e03727d2d66b
124 a: other deleted -> r
124 a: other deleted -> r
125 rev: versions differ -> m
125 rev: versions differ -> m
126 b: remote created -> g
126 b: remote created -> g
127 removing a
127 removing a
128 getting b
128 getting b
129 merging rev
129 merging rev
130 my rev@94b33a1b7f2d+ other rev@e03727d2d66b ancestor rev@924404dff337
130 my rev@94b33a1b7f2d+ other rev@e03727d2d66b ancestor rev@924404dff337
131 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
131 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
132 (branch merge, don't forget to commit)
132 (branch merge, don't forget to commit)
133 --------------
133 --------------
134 M b
134 M b
135 --------------
135 --------------
136
136
137 --------------
137 --------------
138 test L:nm a b R: W: - 8 nothing
138 test L:nm a b R: W: - 8 nothing
139 --------------
139 --------------
140 resolving manifests
140 resolving manifests
141 overwrite None partial False
141 overwrite None partial False
142 ancestor 924404dff337 local ecf3cb2a4219+ remote 97c705ade336
142 ancestor 924404dff337 local ecf3cb2a4219+ remote 97c705ade336
143 rev: versions differ -> m
143 rev: versions differ -> m
144 merging rev
144 merging rev
145 my rev@ecf3cb2a4219+ other rev@97c705ade336 ancestor rev@924404dff337
145 my rev@ecf3cb2a4219+ other rev@97c705ade336 ancestor rev@924404dff337
146 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
146 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
147 (branch merge, don't forget to commit)
147 (branch merge, don't forget to commit)
148 --------------
148 --------------
149 C b
149 C b
150 --------------
150 --------------
151
151
152 --------------
152 --------------
153 test L:um a b R:um a b W: - 9 do merge with ancestor in a
153 test L:um a b R:um a b W: - 9 do merge with ancestor in a
154 --------------
154 --------------
155 resolving manifests
155 resolving manifests
156 overwrite None partial False
156 overwrite None partial False
157 ancestor 924404dff337 local ec03c2ca8642+ remote 79cc6877a3b7
157 ancestor 924404dff337 local ec03c2ca8642+ remote 79cc6877a3b7
158 b: versions differ -> m
158 b: versions differ -> m
159 rev: versions differ -> m
159 rev: versions differ -> m
160 merging b
160 merging b
161 my b@ec03c2ca8642+ other b@79cc6877a3b7 ancestor a@924404dff337
161 my b@ec03c2ca8642+ other b@79cc6877a3b7 ancestor a@924404dff337
162 merging rev
162 merging rev
163 my rev@ec03c2ca8642+ other rev@79cc6877a3b7 ancestor rev@924404dff337
163 my rev@ec03c2ca8642+ other rev@79cc6877a3b7 ancestor rev@924404dff337
164 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
164 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
165 (branch merge, don't forget to commit)
165 (branch merge, don't forget to commit)
166 --------------
166 --------------
167 M b
167 M b
168 --------------
168 --------------
169
169
170 --------------
170 --------------
171 test L:nm a b R:nm a c W: - 11 get c, keep b
171 test L:nm a b R:nm a c W: - 11 get c, keep b
172 --------------
172 --------------
173 resolving manifests
173 resolving manifests
174 overwrite None partial False
174 overwrite None partial False
175 ancestor 924404dff337 local ecf3cb2a4219+ remote e6abcc1a30c2
175 ancestor 924404dff337 local ecf3cb2a4219+ remote e6abcc1a30c2
176 a: divergent renames -> dr
176 a: divergent renames -> dr
177 rev: versions differ -> m
177 rev: versions differ -> m
178 c: remote created -> g
178 c: remote created -> g
179 warning: detected divergent renames of a to:
179 warning: detected divergent renames of a to:
180 b
180 b
181 c
181 c
182 getting c
182 getting c
183 merging rev
183 merging rev
184 my rev@ecf3cb2a4219+ other rev@e6abcc1a30c2 ancestor rev@924404dff337
184 my rev@ecf3cb2a4219+ other rev@e6abcc1a30c2 ancestor rev@924404dff337
185 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
185 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
186 (branch merge, don't forget to commit)
186 (branch merge, don't forget to commit)
187 --------------
187 --------------
188 M c
188 M c
189 C b
189 C b
190 --------------
190 --------------
191
191
192 --------------
192 --------------
193 test L:nc a b R:up b W: - 12 merge b no ancestor
193 test L:nc a b R:up b W: - 12 merge b no ancestor
194 --------------
194 --------------
195 resolving manifests
195 resolving manifests
196 overwrite None partial False
196 overwrite None partial False
197 ancestor 924404dff337 local ac809aeed39a+ remote af30c7647fc7
197 ancestor 924404dff337 local ac809aeed39a+ remote af30c7647fc7
198 b: versions differ -> m
198 b: versions differ -> m
199 rev: versions differ -> m
199 rev: versions differ -> m
200 merging b
200 merging b
201 my b@ac809aeed39a+ other b@af30c7647fc7 ancestor b@000000000000
201 my b@ac809aeed39a+ other b@af30c7647fc7 ancestor b@000000000000
202 merging rev
202 merging rev
203 my rev@ac809aeed39a+ other rev@af30c7647fc7 ancestor rev@924404dff337
203 my rev@ac809aeed39a+ other rev@af30c7647fc7 ancestor rev@924404dff337
204 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
204 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
205 (branch merge, don't forget to commit)
205 (branch merge, don't forget to commit)
206 --------------
206 --------------
207 M b
207 M b
208 C a
208 C a
209 --------------
209 --------------
210
210
211 --------------
211 --------------
212 test L:up b R:nm a b W: - 13 merge b no ancestor
212 test L:up b R:nm a b W: - 13 merge b no ancestor
213 --------------
213 --------------
214 resolving manifests
214 resolving manifests
215 overwrite None partial False
215 overwrite None partial False
216 ancestor 924404dff337 local 59318016310c+ remote e03727d2d66b
216 ancestor 924404dff337 local 59318016310c+ remote e03727d2d66b
217 a: other deleted -> r
217 a: other deleted -> r
218 b: versions differ -> m
218 b: versions differ -> m
219 rev: versions differ -> m
219 rev: versions differ -> m
220 removing a
220 removing a
221 merging b
221 merging b
222 my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000
222 my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000
223 merging rev
223 merging rev
224 my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337
224 my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337
225 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
225 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
226 (branch merge, don't forget to commit)
226 (branch merge, don't forget to commit)
227 --------------
227 --------------
228 M b
228 M b
229 --------------
229 --------------
230
230
231 --------------
231 --------------
232 test L:nc a b R:up a b W: - 14 merge b no ancestor
232 test L:nc a b R:up a b W: - 14 merge b no ancestor
233 --------------
233 --------------
234 resolving manifests
234 resolving manifests
235 overwrite None partial False
235 overwrite None partial False
236 ancestor 924404dff337 local ac809aeed39a+ remote 8dbce441892a
236 ancestor 924404dff337 local ac809aeed39a+ remote 8dbce441892a
237 a: remote is newer -> g
237 a: remote is newer -> g
238 b: versions differ -> m
238 b: versions differ -> m
239 rev: versions differ -> m
239 rev: versions differ -> m
240 getting a
240 getting a
241 merging b
241 merging b
242 my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000
242 my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000
243 merging rev
243 merging rev
244 my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337
244 my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337
245 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
245 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
246 (branch merge, don't forget to commit)
246 (branch merge, don't forget to commit)
247 --------------
247 --------------
248 M a
248 M a
249 M b
249 M b
250 --------------
250 --------------
251
251
252 --------------
252 --------------
253 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
253 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
254 --------------
254 --------------
255 resolving manifests
255 resolving manifests
256 overwrite None partial False
256 overwrite None partial False
257 ancestor 924404dff337 local 59318016310c+ remote e03727d2d66b
257 ancestor 924404dff337 local 59318016310c+ remote e03727d2d66b
258 a: other deleted -> r
258 a: other deleted -> r
259 b: versions differ -> m
259 b: versions differ -> m
260 rev: versions differ -> m
260 rev: versions differ -> m
261 removing a
261 removing a
262 merging b
262 merging b
263 my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000
263 my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000
264 merging rev
264 merging rev
265 my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337
265 my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337
266 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
266 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
267 (branch merge, don't forget to commit)
267 (branch merge, don't forget to commit)
268 --------------
268 --------------
269 M b
269 M b
270 --------------
270 --------------
271
271
272 --------------
272 --------------
273 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
273 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
274 --------------
274 --------------
275 resolving manifests
275 resolving manifests
276 overwrite None partial False
276 overwrite None partial False
277 ancestor 924404dff337 local ac809aeed39a+ remote 8dbce441892a
277 ancestor 924404dff337 local ac809aeed39a+ remote 8dbce441892a
278 a: remote is newer -> g
278 a: remote is newer -> g
279 b: versions differ -> m
279 b: versions differ -> m
280 rev: versions differ -> m
280 rev: versions differ -> m
281 getting a
281 getting a
282 merging b
282 merging b
283 my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000
283 my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000
284 merging rev
284 merging rev
285 my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337
285 my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337
286 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
286 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
287 (branch merge, don't forget to commit)
287 (branch merge, don't forget to commit)
288 --------------
288 --------------
289 M a
289 M a
290 M b
290 M b
291 --------------
291 --------------
292
292
293 --------------
293 --------------
294 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
294 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
295 --------------
295 --------------
296 resolving manifests
296 resolving manifests
297 overwrite None partial False
297 overwrite None partial False
298 ancestor 924404dff337 local 0b76e65c8289+ remote 735846fee2d7
298 ancestor 924404dff337 local 0b76e65c8289+ remote 735846fee2d7
299 b: versions differ -> m
299 b: versions differ -> m
300 rev: versions differ -> m
300 rev: versions differ -> m
301 merging b
301 merging b
302 my b@0b76e65c8289+ other b@735846fee2d7 ancestor b@000000000000
302 my b@0b76e65c8289+ other b@735846fee2d7 ancestor b@000000000000
303 merging rev
303 merging rev
304 my rev@0b76e65c8289+ other rev@735846fee2d7 ancestor rev@924404dff337
304 my rev@0b76e65c8289+ other rev@735846fee2d7 ancestor rev@924404dff337
305 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
305 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
306 (branch merge, don't forget to commit)
306 (branch merge, don't forget to commit)
307 --------------
307 --------------
308 M b
308 M b
309 C a
309 C a
310 --------------
310 --------------
311
311
312 --------------
312 --------------
313 test L:nm a b R:up a b W: - 18 merge b no ancestor
313 test L:nm a b R:up a b W: - 18 merge b no ancestor
314 --------------
314 --------------
315 resolving manifests
315 resolving manifests
316 overwrite None partial False
316 overwrite None partial False
317 ancestor 924404dff337 local ecf3cb2a4219+ remote 8dbce441892a
317 ancestor 924404dff337 local ecf3cb2a4219+ remote 8dbce441892a
318 b: versions differ -> m
318 b: versions differ -> m
319 rev: versions differ -> m
319 rev: versions differ -> m
320 a: prompt recreating -> g
320 a: prompt recreating -> g
321 getting a
321 getting a
322 merging b
322 merging b
323 my b@ecf3cb2a4219+ other b@8dbce441892a ancestor b@000000000000
323 my b@ecf3cb2a4219+ other b@8dbce441892a ancestor b@000000000000
324 merging rev
324 merging rev
325 my rev@ecf3cb2a4219+ other rev@8dbce441892a ancestor rev@924404dff337
325 my rev@ecf3cb2a4219+ other rev@8dbce441892a ancestor rev@924404dff337
326 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
326 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
327 (branch merge, don't forget to commit)
327 (branch merge, don't forget to commit)
328 --------------
328 --------------
329 M a
329 M a
330 M b
330 M b
331 --------------
331 --------------
332
332
333 --------------
333 --------------
334 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
334 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
335 --------------
335 --------------
336 resolving manifests
336 resolving manifests
337 overwrite None partial False
337 overwrite None partial False
338 ancestor 924404dff337 local 0b76e65c8289+ remote e03727d2d66b
338 ancestor 924404dff337 local 0b76e65c8289+ remote e03727d2d66b
339 b: versions differ -> m
339 b: versions differ -> m
340 rev: versions differ -> m
340 rev: versions differ -> m
341 merging b
341 merging b
342 my b@0b76e65c8289+ other b@e03727d2d66b ancestor b@000000000000
342 my b@0b76e65c8289+ other b@e03727d2d66b ancestor b@000000000000
343 merging rev
343 merging rev
344 my rev@0b76e65c8289+ other rev@e03727d2d66b ancestor rev@924404dff337
344 my rev@0b76e65c8289+ other rev@e03727d2d66b ancestor rev@924404dff337
345 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
345 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
346 (branch merge, don't forget to commit)
346 (branch merge, don't forget to commit)
347 --------------
347 --------------
348 M b
348 M b
349 C a
349 C a
350 --------------
350 --------------
351
351
352 --------------
352 --------------
353 test L:up a R:um a b W: - 20 merge a and b to b, remove a
353 test L:up a R:um a b W: - 20 merge a and b to b, remove a
354 --------------
354 --------------
355 resolving manifests
355 resolving manifests
356 overwrite None partial False
356 overwrite None partial False
357 ancestor 924404dff337 local e300d1c794ec+ remote 79cc6877a3b7
357 ancestor 924404dff337 local e300d1c794ec+ remote 79cc6877a3b7
358 rev: versions differ -> m
358 rev: versions differ -> m
359 a: remote moved to b -> m
359 a: remote moved to b -> m
360 copying a to b
360 merging a and b
361 merging a and b
361 my a@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337
362 my a@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337
362 copying a to b
363 removing a
363 removing a
364 merging rev
364 merging rev
365 my rev@e300d1c794ec+ other rev@79cc6877a3b7 ancestor rev@924404dff337
365 my rev@e300d1c794ec+ other rev@79cc6877a3b7 ancestor rev@924404dff337
366 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
366 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
367 (branch merge, don't forget to commit)
367 (branch merge, don't forget to commit)
368 --------------
368 --------------
369 M b
369 M b
370 a
370 a
371 --------------
371 --------------
372
372
373 --------------
373 --------------
374 test L:um a b R:up a W: - 21 merge a and b to b
374 test L:um a b R:up a W: - 21 merge a and b to b
375 --------------
375 --------------
376 resolving manifests
376 resolving manifests
377 overwrite None partial False
377 overwrite None partial False
378 ancestor 924404dff337 local ec03c2ca8642+ remote f4db7e329e71
378 ancestor 924404dff337 local ec03c2ca8642+ remote f4db7e329e71
379 b: local moved to a -> m
379 b: local moved to a -> m
380 rev: versions differ -> m
380 rev: versions differ -> m
381 merging b and a
381 merging b and a
382 my b@ec03c2ca8642+ other a@f4db7e329e71 ancestor a@924404dff337
382 my b@ec03c2ca8642+ other a@f4db7e329e71 ancestor a@924404dff337
383 merging rev
383 merging rev
384 my rev@ec03c2ca8642+ other rev@f4db7e329e71 ancestor rev@924404dff337
384 my rev@ec03c2ca8642+ other rev@f4db7e329e71 ancestor rev@924404dff337
385 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
385 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
386 (branch merge, don't forget to commit)
386 (branch merge, don't forget to commit)
387 --------------
387 --------------
388 M b
388 M b
389 a
389 a
390 --------------
390 --------------
391
391
392 --------------
392 --------------
393 test L:nm a b R:up a c W: - 23 get c, keep b
393 test L:nm a b R:up a c W: - 23 get c, keep b
394 --------------
394 --------------
395 resolving manifests
395 resolving manifests
396 overwrite None partial False
396 overwrite None partial False
397 ancestor 924404dff337 local ecf3cb2a4219+ remote 2b958612230f
397 ancestor 924404dff337 local ecf3cb2a4219+ remote 2b958612230f
398 b: local moved to a -> m
398 b: local moved to a -> m
399 rev: versions differ -> m
399 rev: versions differ -> m
400 c: remote created -> g
400 c: remote created -> g
401 merging b and a
401 merging b and a
402 my b@ecf3cb2a4219+ other a@2b958612230f ancestor a@924404dff337
402 my b@ecf3cb2a4219+ other a@2b958612230f ancestor a@924404dff337
403 getting c
403 getting c
404 merging rev
404 merging rev
405 my rev@ecf3cb2a4219+ other rev@2b958612230f ancestor rev@924404dff337
405 my rev@ecf3cb2a4219+ other rev@2b958612230f ancestor rev@924404dff337
406 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
406 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
407 (branch merge, don't forget to commit)
407 (branch merge, don't forget to commit)
408 --------------
408 --------------
409 M b
409 M b
410 a
410 a
411 M c
411 M c
412 --------------
412 --------------
413
413
General Comments 0
You need to be logged in to leave comments. Login now