##// END OF EJS Templates
merge: handle directory renames...
Matt Mackall -
r3733:9e67fecb default
parent child Browse files
Show More
@@ -0,0 +1,32 b''
1 #!/bin/sh
2
3 mkdir t
4 cd t
5 hg init
6
7 mkdir a
8 echo foo > a/a
9 echo bar > a/b
10
11 hg add a
12 hg ci -m "0" -d "0 0"
13
14 hg co -C 0
15 hg mv a b
16 hg ci -m "1 mv a/ b/" -d "0 0"
17
18 hg co -C 0
19 echo baz > a/c
20 hg add a/c
21 hg ci -m "2 add a/c" -d "0 0"
22
23 hg merge --debug 1
24 ls a/ b/
25 hg st -C
26 hg ci -m "3 merge 2+1" -d "0 0"
27
28 hg co -C 1
29 hg merge --debug 2
30 ls a/ b/
31 hg st -C
32 hg ci -m "4 merge 1+2" -d "0 0"
@@ -553,9 +553,11 b' class localrepository(repo.repository):'
553 fp2 = nullid
553 fp2 = nullid
554 elif fp2 != nullid: # copied on remote side
554 elif fp2 != nullid: # copied on remote side
555 meta["copyrev"] = hex(manifest1.get(cp, nullid))
555 meta["copyrev"] = hex(manifest1.get(cp, nullid))
556 else: # copied on local side, reversed
556 elif fp1 != nullid: # copied on local side, reversed
557 meta["copyrev"] = hex(manifest2.get(cp))
557 meta["copyrev"] = hex(manifest2.get(cp))
558 fp2 = nullid
558 fp2 = nullid
559 else: # directory rename
560 meta["copyrev"] = hex(manifest1.get(cp, nullid))
559 self.ui.debug(_(" %s: copy %s:%s\n") %
561 self.ui.debug(_(" %s: copy %s:%s\n") %
560 (fn, cp, meta["copyrev"]))
562 (fn, cp, meta["copyrev"]))
561 fp1 = nullid
563 fp1 = nullid
@@ -122,11 +122,20 b' def findcopies(repo, m1, m2, ma, limit):'
122 return
122 return
123 c2 = ctx(of, man[of])
123 c2 = ctx(of, man[of])
124 ca = c.ancestor(c2)
124 ca = c.ancestor(c2)
125 if not ca or c == ca or c2 == ca:
125 if not ca: # unrelated
126 return
126 return
127 if ca.path() == c.path() or ca.path() == c2.path():
127 if ca.path() == c.path() or ca.path() == c2.path():
128 fullcopy[c.path()] = of
129 if c == ca or c2 == ca: # no merge needed, ignore copy
130 return
128 copy[c.path()] = of
131 copy[c.path()] = of
129
132
133 def dirs(files):
134 d = {}
135 for f in files:
136 d[os.path.dirname(f)] = True
137 return d
138
130 if not repo.ui.configbool("merge", "followcopies", True):
139 if not repo.ui.configbool("merge", "followcopies", True):
131 return {}
140 return {}
132
141
@@ -136,6 +145,7 b' def findcopies(repo, m1, m2, ma, limit):'
136
145
137 dcopies = repo.dirstate.copies()
146 dcopies = repo.dirstate.copies()
138 copy = {}
147 copy = {}
148 fullcopy = {}
139 u1 = nonoverlap(m1, m2, ma)
149 u1 = nonoverlap(m1, m2, ma)
140 u2 = nonoverlap(m2, m1, ma)
150 u2 = nonoverlap(m2, m1, ma)
141 ctx = util.cachefunc(lambda f, n: repo.filectx(f, fileid=n[:20]))
151 ctx = util.cachefunc(lambda f, n: repo.filectx(f, fileid=n[:20]))
@@ -146,6 +156,38 b' def findcopies(repo, m1, m2, ma, limit):'
146 for f in u2:
156 for f in u2:
147 checkcopies(ctx(f, m2[f]), m1)
157 checkcopies(ctx(f, m2[f]), m1)
148
158
159 if not fullcopy or not repo.ui.configbool("merge", "followdirs", True):
160 return copy
161
162 # generate a directory move map
163 d1, d2 = dirs(m1), dirs(m2)
164 invalid = {}
165 dirmove = {}
166
167 for dst, src in fullcopy.items():
168 dsrc, ddst = os.path.dirname(src), os.path.dirname(dst)
169 if dsrc in invalid:
170 continue
171 elif (dsrc in d1 and ddst in d1) or (dsrc in d2 and ddst in d2):
172 invalid[dsrc] = True
173 elif dsrc in dirmove and dirmove[dsrc] != ddst:
174 invalid[dsrc] = True
175 del dirmove[dsrc]
176 else:
177 dirmove[dsrc] = ddst
178
179 del d1, d2, invalid
180
181 if not dirmove:
182 return copy
183
184 # check unaccounted nonoverlapping files
185 for f in u1 + u2:
186 if f not in fullcopy:
187 d = os.path.dirname(f)
188 if d in dirmove:
189 copy[f] = dirmove[d] + "/" + os.path.basename(f)
190
149 return copy
191 return copy
150
192
151 def manifestmerge(repo, p1, p2, pa, overwrite, partial):
193 def manifestmerge(repo, p1, p2, pa, overwrite, partial):
@@ -210,7 +252,10 b' def manifestmerge(repo, p1, p2, pa, over'
210 continue
252 continue
211 elif f in copy:
253 elif f in copy:
212 f2 = copy[f]
254 f2 = copy[f]
213 if f2 in m1: # case 2 A,B/B/B
255 if f2 not in m2: # directory rename
256 act("remote renamed directory to " + f2, "d",
257 f, None, f2, m1.execf(f))
258 elif f2 in m1: # case 2 A,B/B/B
214 act("local copied to " + f2, "m",
259 act("local copied to " + f2, "m",
215 f, f2, f, fmerge(f, f2, f2), False)
260 f, f2, f, fmerge(f, f2, f2), False)
216 else: # case 4,21 A/B/B
261 else: # case 4,21 A/B/B
@@ -238,7 +283,10 b' def manifestmerge(repo, p1, p2, pa, over'
238 continue
283 continue
239 if f in copy:
284 if f in copy:
240 f2 = copy[f]
285 f2 = copy[f]
241 if f2 in m2: # rename case 1, A/A,B/A
286 if f2 not in m1: # directory rename
287 act("local renamed directory to " + f2, "d",
288 None, f, f2, m2.execf(f))
289 elif f2 in m2: # rename case 1, A/A,B/A
242 act("remote copied to " + f, "m",
290 act("remote copied to " + f, "m",
243 f2, f, f, fmerge(f2, f, f2), False)
291 f2, f, f, fmerge(f2, f, f2), False)
244 else: # case 3,20 A/B/A
292 else: # case 3,20 A/B/A
@@ -264,7 +312,7 b' def applyupdates(repo, action, wctx, mct'
264 action.sort()
312 action.sort()
265 for a in action:
313 for a in action:
266 f, m = a[:2]
314 f, m = a[:2]
267 if f[0] == "/":
315 if f and f[0] == "/":
268 continue
316 continue
269 if m == "r": # remove
317 if m == "r": # remove
270 repo.ui.note(_("removing %s\n") % f)
318 repo.ui.note(_("removing %s\n") % f)
@@ -300,6 +348,20 b' def applyupdates(repo, action, wctx, mct'
300 repo.wwrite(f, t)
348 repo.wwrite(f, t)
301 util.set_exec(repo.wjoin(f), flag)
349 util.set_exec(repo.wjoin(f), flag)
302 updated += 1
350 updated += 1
351 elif m == "d": # directory rename
352 f2, fd, flag = a[2:]
353 if f:
354 repo.ui.note(_("moving %s to %s\n") % (f, fd))
355 t = wctx.filectx(f).data()
356 repo.wwrite(fd, t)
357 util.set_exec(repo.wjoin(fd), flag)
358 util.unlink(repo.wjoin(f))
359 if f2:
360 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
361 t = mctx.filectx(f2).data()
362 repo.wwrite(fd, t)
363 util.set_exec(repo.wjoin(fd), flag)
364 updated += 1
303 elif m == "e": # exec
365 elif m == "e": # exec
304 flag = a[2]
366 flag = a[2]
305 util.set_exec(repo.wjoin(f), flag)
367 util.set_exec(repo.wjoin(f), flag)
@@ -345,6 +407,19 b' def recordupdates(repo, action, branchme'
345 repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1)
407 repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1)
346 if move:
408 if move:
347 repo.dirstate.forget([f])
409 repo.dirstate.forget([f])
410 elif m == "d": # directory rename
411 f2, fd, flag = a[2:]
412 if branchmerge:
413 repo.dirstate.update([fd], 'a')
414 if f:
415 repo.dirstate.update([f], 'r')
416 repo.dirstate.copy(f, fd)
417 if f2:
418 repo.dirstate.copy(f2, fd)
419 else:
420 repo.dirstate.update([fd], 'n')
421 if f:
422 repo.dirstate.forget([f])
348
423
349 def update(repo, node, branchmerge, force, partial, wlock):
424 def update(repo, node, branchmerge, force, partial, wlock):
350 """
425 """
General Comments 0
You need to be logged in to leave comments. Login now