comparison mercurial/merge.py @ 3255:f05c182430a0

merge: add rename following Currently disabled by default, enable with [merge] followcopies = 1
author Matt Mackall <mpm@selenic.com>
date Wed, 04 Oct 2006 15:43:27 -0500
parents 751840e739a1
children c93ce7f10f85
comparison
equal deleted inserted replaced
3254:751840e739a1 3255:f05c182430a0
52 environ={'HG_FILE': fw, 52 environ={'HG_FILE': fw,
53 'HG_MY_NODE': p1, 53 'HG_MY_NODE': p1,
54 'HG_OTHER_NODE': p2}) 54 'HG_OTHER_NODE': p2})
55 if r: 55 if r:
56 repo.ui.warn(_("merging %s failed!\n") % fw) 56 repo.ui.warn(_("merging %s failed!\n") % fw)
57 else:
58 if fd != fw:
59 repo.ui.debug(_("copying %s to %s\n") % (fw, fd))
60 repo.wwrite(fd, repo.wread(fw))
61 if move:
62 repo.ui.debug(_("removing %s\n") % fw)
63 os.unlink(a)
57 64
58 os.unlink(b) 65 os.unlink(b)
59 os.unlink(c) 66 os.unlink(c)
60 return r 67 return r
61 68
124 def findcopies(repo, m1, m2, limit): 131 def findcopies(repo, m1, m2, limit):
125 """ 132 """
126 Find moves and copies between m1 and m2 back to limit linkrev 133 Find moves and copies between m1 and m2 back to limit linkrev
127 """ 134 """
128 135
136 if not repo.ui.config("merge", "followcopies"):
137 return {}
138
129 # avoid silly behavior for update from empty dir 139 # avoid silly behavior for update from empty dir
130 if not m1: 140 if not m1:
131 return {} 141 return {}
132 142
133 dcopies = repo.dirstate.copies() 143 dcopies = repo.dirstate.copies()
162 for mf in match[of]: 172 for mf in match[of]:
163 checkpair(c, mf, m1) 173 checkpair(c, mf, m1)
164 174
165 return copy 175 return copy
166 176
167 def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial): 177 def manifestmerge(ui, m1, m2, ma, copy, overwrite, backwards, partial):
168 """ 178 """
169 Merge manifest m1 with m2 using ancestor ma and generate merge action list 179 Merge manifest m1 with m2 using ancestor ma and generate merge action list
170 """ 180 """
171 181
172 def fmerge(f): 182 def fmerge(f, f2=None, fa=None):
173 """merge executable flags""" 183 """merge executable flags"""
174 a, b, c = ma.execf(f), m1.execf(f), m2.execf(f) 184 if not f2:
185 f2 = f
186 fa = f
187 a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2)
175 return ((a^b) | (a^c)) ^ a 188 return ((a^b) | (a^c)) ^ a
176 189
177 action = [] 190 action = []
178 191
179 def act(msg, f, m, *args): 192 def act(msg, f, m, *args):
201 act("update permissions", f, "e", m2.execf(f)) 214 act("update permissions", f, "e", m2.execf(f))
202 # contents same, check mode bits 215 # contents same, check mode bits
203 elif m1.execf(f) != m2.execf(f): 216 elif m1.execf(f) != m2.execf(f):
204 if overwrite or fmerge(f) != m1.execf(f): 217 if overwrite or fmerge(f) != m1.execf(f):
205 act("update permissions", f, "e", m2.execf(f)) 218 act("update permissions", f, "e", m2.execf(f))
219 elif f in copy:
220 f2 = copy[f]
221 if f in ma: # case 3,20 A/B/A
222 act("remote moved",
223 f, "c", f2, f2, m1[f], m2[f2], fmerge(f, f2, f), True)
224 else:
225 if f2 in m1: # case 2 A,B/B/B
226 act("local copied",
227 f, "c", f2, f, m1[f], m2[f2], fmerge(f, f2, f2), False)
228 else: # case 4,21 A/B/B
229 act("local moved",
230 f, "c", f2, f, m1[f], m2[f2], fmerge(f, f2, f2), False)
206 elif f in ma: 231 elif f in ma:
207 if n != ma[f] and not overwrite: 232 if n != ma[f] and not overwrite:
208 if ui.prompt( 233 if ui.prompt(
209 (_(" local changed %s which remote deleted\n") % f) + 234 (_(" local changed %s which remote deleted\n") % f) +
210 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("d"): 235 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("d"):
219 for f, n in m2.iteritems(): 244 for f, n in m2.iteritems():
220 if partial and not partial(f): 245 if partial and not partial(f):
221 continue 246 continue
222 if f in m1: 247 if f in m1:
223 continue 248 continue
224 if f in ma: 249 if f in copy:
250 f2 = copy[f]
251 if f2 in ma or f2 in m1: # already seen
252 continue
253 # rename case 1, A/A,B/A
254 act("remote copied",
255 f, "c", f2, f, m1[f2], m2[f], fmerge(f2, f, f2), False)
256 elif f in ma:
225 if overwrite or backwards: 257 if overwrite or backwards:
226 act("recreating", f, "g", m2.execf(f), n) 258 act("recreating", f, "g", m2.execf(f), n)
227 elif n != ma[f]: 259 elif n != ma[f]:
228 if ui.prompt( 260 if ui.prompt(
229 (_("remote changed %s which local deleted\n") % f) + 261 (_("remote changed %s which local deleted\n") % f) +
249 except OSError, inst: 281 except OSError, inst:
250 if inst.errno != errno.ENOENT: 282 if inst.errno != errno.ENOENT:
251 repo.ui.warn(_("update failed to remove %s: %s!\n") % 283 repo.ui.warn(_("update failed to remove %s: %s!\n") %
252 (f, inst.strerror)) 284 (f, inst.strerror))
253 removed +=1 285 removed +=1
286 elif m == "c": # copy
287 f2, fd, my, other, flag, remove = a[2:]
288 if filemerge(repo, f, f2, fd, my, other, xp1, xp2, remove):
289 unresolved += 1
290 util.set_exec(repo.wjoin(fd), flag)
291 merged += 1
254 elif m == "m": # merge 292 elif m == "m": # merge
255 flag, my, other = a[2:] 293 flag, my, other = a[2:]
256 repo.ui.status(_("merging %s\n") % f) 294 repo.ui.status(_("merging %s\n") % f)
257 if filemerge(repo, f, f, f, my, other, xp1, xp2, False): 295 if filemerge(repo, f, f, f, my, other, xp1, xp2, False):
258 unresolved += 1 296 unresolved += 1
356 if not branchmerge: 394 if not branchmerge:
357 action += forgetremoved(m2, wc) 395 action += forgetremoved(m2, wc)
358 if not (backwards or overwrite): 396 if not (backwards or overwrite):
359 copy = findcopies(repo, m1, m2, pa.rev()) 397 copy = findcopies(repo, m1, m2, pa.rev())
360 398
361 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial) 399 action += manifestmerge(repo.ui, m1, m2, ma, copy,
400 overwrite, backwards, partial)
362 401
363 ### apply phase 402 ### apply phase
364 403
365 if not branchmerge: 404 if not branchmerge:
366 # we don't need to do any magic, just jump to the new rev 405 # we don't need to do any magic, just jump to the new rev