##// END OF EJS Templates
copies: separate moves via directory renames from explicit copies...
Siddharth Agarwal -
r18134:6c35b53c default
parent child Browse files
Show More
@@ -170,11 +170,17 b' def mergecopies(repo, c1, c2, ca):'
170 Find moves and copies between context c1 and c2 that are relevant
170 Find moves and copies between context c1 and c2 that are relevant
171 for merging.
171 for merging.
172
172
173 Returns two dicts, "copy" and "diverge".
173 Returns four dicts: "copy", "movewithdir", "diverge", and
174 "renamedelete".
174
175
175 "copy" is a mapping from destination name -> source name,
176 "copy" is a mapping from destination name -> source name,
176 where source is in c1 and destination is in c2 or vice-versa.
177 where source is in c1 and destination is in c2 or vice-versa.
177
178
179 "movewithdir" is a mapping from source name -> destination name,
180 where the file at source present in one context but not the other
181 needs to be moved to destination by the merge process, because the
182 other context moved the directory it is in.
183
178 "diverge" is a mapping of source name -> list of destination names
184 "diverge" is a mapping of source name -> list of destination names
179 for divergent renames.
185 for divergent renames.
180
186
@@ -183,16 +189,16 b' def mergecopies(repo, c1, c2, ca):'
183 """
189 """
184 # avoid silly behavior for update from empty dir
190 # avoid silly behavior for update from empty dir
185 if not c1 or not c2 or c1 == c2:
191 if not c1 or not c2 or c1 == c2:
186 return {}, {}, {}
192 return {}, {}, {}, {}
187
193
188 # avoid silly behavior for parent -> working dir
194 # avoid silly behavior for parent -> working dir
189 if c2.node() is None and c1.node() == repo.dirstate.p1():
195 if c2.node() is None and c1.node() == repo.dirstate.p1():
190 return repo.dirstate.copies(), {}, {}
196 return repo.dirstate.copies(), {}, {}, {}
191
197
192 limit = _findlimit(repo, c1.rev(), c2.rev())
198 limit = _findlimit(repo, c1.rev(), c2.rev())
193 if limit is None:
199 if limit is None:
194 # no common ancestor, no copies
200 # no common ancestor, no copies
195 return {}, {}, {}
201 return {}, {}, {}, {}
196 m1 = c1.manifest()
202 m1 = c1.manifest()
197 m2 = c2.manifest()
203 m2 = c2.manifest()
198 ma = ca.manifest()
204 ma = ca.manifest()
@@ -206,6 +212,7 b' def mergecopies(repo, c1, c2, ca):'
206
212
207 ctx = util.lrucachefunc(makectx)
213 ctx = util.lrucachefunc(makectx)
208 copy = {}
214 copy = {}
215 movewithdir = {}
209 fullcopy = {}
216 fullcopy = {}
210 diverge = {}
217 diverge = {}
211
218
@@ -315,7 +322,7 b' def mergecopies(repo, c1, c2, ca):'
315 del diverge2
322 del diverge2
316
323
317 if not fullcopy:
324 if not fullcopy:
318 return copy, diverge, renamedelete
325 return copy, movewithdir, diverge, renamedelete
319
326
320 repo.ui.debug(" checking for directory renames\n")
327 repo.ui.debug(" checking for directory renames\n")
321
328
@@ -352,7 +359,7 b' def mergecopies(repo, c1, c2, ca):'
352 del d1, d2, invalid
359 del d1, d2, invalid
353
360
354 if not dirmove:
361 if not dirmove:
355 return copy, diverge, renamedelete
362 return copy, movewithdir, diverge, renamedelete
356
363
357 for d in dirmove:
364 for d in dirmove:
358 repo.ui.debug(" dir %s -> %s\n" % (d, dirmove[d]))
365 repo.ui.debug(" dir %s -> %s\n" % (d, dirmove[d]))
@@ -365,8 +372,8 b' def mergecopies(repo, c1, c2, ca):'
365 # new file added in a directory that was moved, move it
372 # new file added in a directory that was moved, move it
366 df = dirmove[d] + f[len(d):]
373 df = dirmove[d] + f[len(d):]
367 if df not in copy:
374 if df not in copy:
368 copy[f] = df
375 movewithdir[f] = df
369 repo.ui.debug(" file %s -> %s\n" % (f, copy[f]))
376 repo.ui.debug(" file %s -> %s\n" % (f, df))
370 break
377 break
371
378
372 return copy, diverge, renamedelete
379 return copy, movewithdir, diverge, renamedelete
@@ -213,14 +213,15 b' def manifestmerge(repo, p1, p2, pa, over'
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():
@@ -233,6 +234,7 b' def manifestmerge(repo, p1, p2, pa, over'
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
@@ -259,14 +261,14 b' def manifestmerge(repo, p1, p2, pa, over'
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(
@@ -286,12 +288,13 b' def manifestmerge(repo, p1, p2, pa, over'
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
General Comments 0
You need to be logged in to leave comments. Login now