Mercurial > public > mercurial-scm > hg
comparison mercurial/merge.py @ 18134:6c35b53cd28b
copies: separate moves via directory renames from explicit copies
Currently the "copy" dict contains both explicit copies/moves made by a
context and pending moves that need to happen because the other context moved
the directory the file was in. For explicit copies, the dict stores a
destination to source map, while for pending moves via directory renames, it
stores a source to destination map. The merge code uses this fact in a non-
obvious way to differentiate between these two cases.
We make this explicit by storing these pending moves in a separate dict. The
dict still has a source to destination map, but that is called out in the
docstring.
author | Siddharth Agarwal <sid0@fb.com> |
---|---|
date | Wed, 26 Dec 2012 14:50:17 -0800 |
parents | 551e2901192e |
children | 242d2f4ec01c |
comparison
equal
deleted
inserted
replaced
18133:7f5a0eba3768 | 18134:6c35b53cd28b |
---|---|
211 | 211 |
212 def act(msg, m, f, *args): | 212 def act(msg, m, f, *args): |
213 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m)) | 213 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m)) |
214 action.append((f, m) + args) | 214 action.append((f, m) + args) |
215 | 215 |
216 action, copy = [], {} | 216 action, copy, movewithdir = [], {}, {} |
217 | 217 |
218 if overwrite: | 218 if overwrite: |
219 pa = p1 | 219 pa = p1 |
220 elif pa == p2: # backwards | 220 elif pa == p2: # backwards |
221 pa = p1.p1() | 221 pa = p1.p1() |
222 elif pa and repo.ui.configbool("merge", "followcopies", True): | 222 elif pa and repo.ui.configbool("merge", "followcopies", True): |
223 copy, diverge, renamedelete = copies.mergecopies(repo, p1, p2, pa) | 223 ret = copies.mergecopies(repo, p1, p2, pa) |
224 copy, movewithdir, diverge, renamedelete = ret | |
224 for of, fl in diverge.iteritems(): | 225 for of, fl in diverge.iteritems(): |
225 act("divergent renames", "dr", of, fl) | 226 act("divergent renames", "dr", of, fl) |
226 for of, fl in renamedelete.iteritems(): | 227 for of, fl in renamedelete.iteritems(): |
227 act("rename and delete", "rd", of, fl) | 228 act("rename and delete", "rd", of, fl) |
228 | 229 |
231 % (bool(overwrite), bool(partial))) | 232 % (bool(overwrite), bool(partial))) |
232 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, p1, p2)) | 233 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, p1, p2)) |
233 | 234 |
234 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest() | 235 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest() |
235 copied = set(copy.values()) | 236 copied = set(copy.values()) |
237 copied.update(movewithdir.values()) | |
236 | 238 |
237 if '.hgsubstate' in m1: | 239 if '.hgsubstate' in m1: |
238 # check whether sub state is modified | 240 # check whether sub state is modified |
239 for s in p1.substate: | 241 for s in p1.substate: |
240 if p1.sub(s).dirty(): | 242 if p1.sub(s).dirty(): |
257 act("remote is newer", "g", f, rflags) | 259 act("remote is newer", "g", f, rflags) |
258 else: # both changed | 260 else: # both changed |
259 act("versions differ", "m", f, f, f, rflags, False) | 261 act("versions differ", "m", f, f, f, rflags, False) |
260 elif f in copied: # files we'll deal with on m2 side | 262 elif f in copied: # files we'll deal with on m2 side |
261 pass | 263 pass |
262 elif f in copy: | 264 elif f in movewithdir: # directory rename |
265 f2 = movewithdir[f] | |
266 act("remote renamed directory to " + f2, "d", f, None, f2, | |
267 m1.flags(f)) | |
268 elif f in copy: # case 2 A,B/B/B or case 4,21 A/B/B | |
263 f2 = copy[f] | 269 f2 = copy[f] |
264 if f2 not in m2: # directory rename | 270 act("local copied/moved to " + f2, "m", f, f2, f, |
265 act("remote renamed directory to " + f2, "d", | 271 fmerge(f, f2, f2), False) |
266 f, None, f2, m1.flags(f)) | |
267 else: # case 2 A,B/B/B or case 4,21 A/B/B | |
268 act("local copied/moved to " + f2, "m", | |
269 f, f2, f, fmerge(f, f2, f2), False) | |
270 elif f in ma: # clean, a different, no remote | 272 elif f in ma: # clean, a different, no remote |
271 if n != ma[f]: | 273 if n != ma[f]: |
272 if repo.ui.promptchoice( | 274 if repo.ui.promptchoice( |
273 _(" local changed %s which remote deleted\n" | 275 _(" local changed %s which remote deleted\n" |
274 "use (c)hanged version or (d)elete?") % f, | 276 "use (c)hanged version or (d)elete?") % f, |
284 for f, n in m2.iteritems(): | 286 for f, n in m2.iteritems(): |
285 if partial and not partial(f): | 287 if partial and not partial(f): |
286 continue | 288 continue |
287 if f in m1 or f in copied: # files already visited | 289 if f in m1 or f in copied: # files already visited |
288 continue | 290 continue |
289 if f in copy: | 291 if f in movewithdir: |
292 f2 = movewithdir[f] | |
293 act("local renamed directory to " + f2, "d", None, f, f2, | |
294 m2.flags(f)) | |
295 elif f in copy: | |
290 f2 = copy[f] | 296 f2 = copy[f] |
291 if f2 not in m1: # directory rename | 297 if f2 in m2: # rename case 1, A/A,B/A |
292 act("local renamed directory to " + f2, "d", | |
293 None, f, f2, m2.flags(f)) | |
294 elif f2 in m2: # rename case 1, A/A,B/A | |
295 act("remote copied to " + f, "m", | 298 act("remote copied to " + f, "m", |
296 f2, f, f, fmerge(f2, f, f2), False) | 299 f2, f, f, fmerge(f2, f, f2), False) |
297 else: # case 3,20 A/B/A | 300 else: # case 3,20 A/B/A |
298 act("remote moved to " + f, "m", | 301 act("remote moved to " + f, "m", |
299 f2, f, f, fmerge(f2, f, f2), True) | 302 f2, f, f, fmerge(f2, f, f2), True) |