comparison mercurial/merge.py @ 4674:723e0ddb6ada

merge: warn user about divergent renames
author Matt Mackall <mpm@selenic.com>
date Thu, 21 Jun 2007 18:02:03 -0500
parents 63b9d2deed48
children dc5920ea12f8
comparison
equal deleted inserted replaced
4673:d8442fc0da8d 4674:723e0ddb6ada
153 old.sort() 153 old.sort()
154 return old 154 return old
155 155
156 copy = {} 156 copy = {}
157 fullcopy = {} 157 fullcopy = {}
158 diverge = {}
158 159
159 def checkcopies(c, man): 160 def checkcopies(c, man):
160 '''check possible copies for filectx c''' 161 '''check possible copies for filectx c'''
161 for of in findold(c): 162 for of in findold(c):
163 fullcopy[c.path()] = of # remember for dir rename detection
162 if of not in man: # original file not in other manifest? 164 if of not in man: # original file not in other manifest?
165 if of in ma:
166 diverge.setdefault(of, []).append(c.path())
163 continue 167 continue
164 c2 = ctx(of, man[of]) 168 c2 = ctx(of, man[of])
165 ca = c.ancestor(c2) 169 ca = c.ancestor(c2)
166 if not ca: # unrelated? 170 if not ca: # unrelated?
167 continue 171 continue
168 # named changed on only one side? 172 # named changed on only one side?
169 if ca.path() == c.path() or ca.path() == c2.path(): 173 if ca.path() == c.path() or ca.path() == c2.path():
170 fullcopy[c.path()] = of # remember for dir rename detection
171 if c == ca or c2 == ca: # no merge needed, ignore copy 174 if c == ca or c2 == ca: # no merge needed, ignore copy
172 continue 175 continue
173 copy[c.path()] = of 176 copy[c.path()] = of
174 177
175 if not repo.ui.configbool("merge", "followcopies", True): 178 if not repo.ui.configbool("merge", "followcopies", True):
176 return {} 179 return {}, {}
177 180
178 # avoid silly behavior for update from empty dir 181 # avoid silly behavior for update from empty dir
179 if not m1 or not m2 or not ma: 182 if not m1 or not m2 or not ma:
180 return {} 183 return {}, {}
181 184
182 u1 = nonoverlap(m1, m2, ma) 185 u1 = nonoverlap(m1, m2, ma)
183 u2 = nonoverlap(m2, m1, ma) 186 u2 = nonoverlap(m2, m1, ma)
184 187
185 for f in u1: 188 for f in u1:
186 checkcopies(ctx(f, m1[f]), m2) 189 checkcopies(ctx(f, m1[f]), m2)
187 190
188 for f in u2: 191 for f in u2:
189 checkcopies(ctx(f, m2[f]), m1) 192 checkcopies(ctx(f, m2[f]), m1)
190 193
194 d2 = {}
195 for of, fl in diverge.items():
196 for f in fl:
197 fo = list(fl)
198 fo.remove(f)
199 d2[f] = (of, fo)
200 #diverge = d2
201
191 if not fullcopy or not repo.ui.configbool("merge", "followdirs", True): 202 if not fullcopy or not repo.ui.configbool("merge", "followdirs", True):
192 return copy 203 return copy, diverge
193 204
194 # generate a directory move map 205 # generate a directory move map
195 d1, d2 = dirs(m1), dirs(m2) 206 d1, d2 = dirs(m1), dirs(m2)
196 invalid = {} 207 invalid = {}
197 dirmove = {} 208 dirmove = {}
221 del dirmove[i] 232 del dirmove[i]
222 233
223 del d1, d2, invalid 234 del d1, d2, invalid
224 235
225 if not dirmove: 236 if not dirmove:
226 return copy 237 return copy, diverge
227 238
228 # check unaccounted nonoverlapping files against directory moves 239 # check unaccounted nonoverlapping files against directory moves
229 for f in u1 + u2: 240 for f in u1 + u2:
230 if f not in fullcopy: 241 if f not in fullcopy:
231 for d in dirmove: 242 for d in dirmove:
232 if f.startswith(d): 243 if f.startswith(d):
233 # new file added in a directory that was moved, move it 244 # new file added in a directory that was moved, move it
234 copy[f] = dirmove[d] + f[len(d):] 245 copy[f] = dirmove[d] + f[len(d):]
235 break 246 break
236 247
237 return copy 248 return copy, diverge
238 249
239 def manifestmerge(repo, p1, p2, pa, overwrite, partial): 250 def manifestmerge(repo, p1, p2, pa, overwrite, partial):
240 """ 251 """
241 Merge p1 and p2 with ancestor ma and generate merge action list 252 Merge p1 and p2 with ancestor ma and generate merge action list
242 253
252 m2 = p2.manifest() 263 m2 = p2.manifest()
253 ma = pa.manifest() 264 ma = pa.manifest()
254 backwards = (pa == p2) 265 backwards = (pa == p2)
255 action = [] 266 action = []
256 copy = {} 267 copy = {}
268 diverge = {}
257 269
258 def fmerge(f, f2=None, fa=None): 270 def fmerge(f, f2=None, fa=None):
259 """merge flags""" 271 """merge flags"""
260 if not f2: 272 if not f2:
261 f2 = f 273 f2 = f
271 def act(msg, m, f, *args): 283 def act(msg, m, f, *args):
272 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m)) 284 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
273 action.append((f, m) + args) 285 action.append((f, m) + args)
274 286
275 if not (backwards or overwrite): 287 if not (backwards or overwrite):
276 copy = findcopies(repo, m1, m2, ma, pa.rev()) 288 copy, diverge = findcopies(repo, m1, m2, ma, pa.rev())
289
290 for of, fl in diverge.items():
291 act("divergent renames", "dr", of, fl)
292
277 copied = dict.fromkeys(copy.values()) 293 copied = dict.fromkeys(copy.values())
278 294
279 # Compare manifests 295 # Compare manifests
280 for f, n in m1.iteritems(): 296 for f, n in m1.iteritems():
281 if partial and not partial(f): 297 if partial and not partial(f):
408 if f2: 424 if f2:
409 repo.ui.note(_("getting %s to %s\n") % (f2, fd)) 425 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
410 t = mctx.filectx(f2).data() 426 t = mctx.filectx(f2).data()
411 repo.wwrite(fd, t, flags) 427 repo.wwrite(fd, t, flags)
412 updated += 1 428 updated += 1
429 elif m == "dr": # divergent renames
430 fl = a[2]
431 repo.ui.warn("warning: detected divergent renames of %s to:\n" % f)
432 for nf in fl:
433 repo.ui.warn(" %s\n" % nf)
413 elif m == "e": # exec 434 elif m == "e": # exec
414 flags = a[2] 435 flags = a[2]
415 util.set_exec(repo.wjoin(f), flags) 436 util.set_exec(repo.wjoin(f), flags)
416 437
417 return updated, merged, removed, unresolved 438 return updated, merged, removed, unresolved