##// END OF EJS Templates
copies: make sure deleted copy info do not overwriting unrelated ones...
marmoute -
r46388:46347041 default draft
parent child Browse files
Show More
@@ -1,1109 +1,1112 b''
1 # copies.py - copy detection for Mercurial
1 # copies.py - copy detection for Mercurial
2 #
2 #
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import collections
10 import collections
11 import os
11 import os
12
12
13 from .i18n import _
13 from .i18n import _
14
14
15
15
16 from . import (
16 from . import (
17 match as matchmod,
17 match as matchmod,
18 node,
18 node,
19 pathutil,
19 pathutil,
20 pycompat,
20 pycompat,
21 util,
21 util,
22 )
22 )
23
23
24
24
25 from .utils import stringutil
25 from .utils import stringutil
26
26
27 from .revlogutils import flagutil
27 from .revlogutils import flagutil
28
28
29
29
30 def _filter(src, dst, t):
30 def _filter(src, dst, t):
31 """filters out invalid copies after chaining"""
31 """filters out invalid copies after chaining"""
32
32
33 # When _chain()'ing copies in 'a' (from 'src' via some other commit 'mid')
33 # When _chain()'ing copies in 'a' (from 'src' via some other commit 'mid')
34 # with copies in 'b' (from 'mid' to 'dst'), we can get the different cases
34 # with copies in 'b' (from 'mid' to 'dst'), we can get the different cases
35 # in the following table (not including trivial cases). For example, case 2
35 # in the following table (not including trivial cases). For example, case 2
36 # is where a file existed in 'src' and remained under that name in 'mid' and
36 # is where a file existed in 'src' and remained under that name in 'mid' and
37 # then was renamed between 'mid' and 'dst'.
37 # then was renamed between 'mid' and 'dst'.
38 #
38 #
39 # case src mid dst result
39 # case src mid dst result
40 # 1 x y - -
40 # 1 x y - -
41 # 2 x y y x->y
41 # 2 x y y x->y
42 # 3 x y x -
42 # 3 x y x -
43 # 4 x y z x->z
43 # 4 x y z x->z
44 # 5 - x y -
44 # 5 - x y -
45 # 6 x x y x->y
45 # 6 x x y x->y
46 #
46 #
47 # _chain() takes care of chaining the copies in 'a' and 'b', but it
47 # _chain() takes care of chaining the copies in 'a' and 'b', but it
48 # cannot tell the difference between cases 1 and 2, between 3 and 4, or
48 # cannot tell the difference between cases 1 and 2, between 3 and 4, or
49 # between 5 and 6, so it includes all cases in its result.
49 # between 5 and 6, so it includes all cases in its result.
50 # Cases 1, 3, and 5 are then removed by _filter().
50 # Cases 1, 3, and 5 are then removed by _filter().
51
51
52 for k, v in list(t.items()):
52 for k, v in list(t.items()):
53 # remove copies from files that didn't exist
53 # remove copies from files that didn't exist
54 if v not in src:
54 if v not in src:
55 del t[k]
55 del t[k]
56 # remove criss-crossed copies
56 # remove criss-crossed copies
57 elif k in src and v in dst:
57 elif k in src and v in dst:
58 del t[k]
58 del t[k]
59 # remove copies to files that were then removed
59 # remove copies to files that were then removed
60 elif k not in dst:
60 elif k not in dst:
61 del t[k]
61 del t[k]
62
62
63
63
64 def _chain(prefix, suffix):
64 def _chain(prefix, suffix):
65 """chain two sets of copies 'prefix' and 'suffix'"""
65 """chain two sets of copies 'prefix' and 'suffix'"""
66 result = prefix.copy()
66 result = prefix.copy()
67 for key, value in pycompat.iteritems(suffix):
67 for key, value in pycompat.iteritems(suffix):
68 result[key] = prefix.get(value, value)
68 result[key] = prefix.get(value, value)
69 return result
69 return result
70
70
71
71
72 def _tracefile(fctx, am, basemf):
72 def _tracefile(fctx, am, basemf):
73 """return file context that is the ancestor of fctx present in ancestor
73 """return file context that is the ancestor of fctx present in ancestor
74 manifest am
74 manifest am
75
75
76 Note: we used to try and stop after a given limit, however checking if that
76 Note: we used to try and stop after a given limit, however checking if that
77 limit is reached turned out to be very expensive. we are better off
77 limit is reached turned out to be very expensive. we are better off
78 disabling that feature."""
78 disabling that feature."""
79
79
80 for f in fctx.ancestors():
80 for f in fctx.ancestors():
81 path = f.path()
81 path = f.path()
82 if am.get(path, None) == f.filenode():
82 if am.get(path, None) == f.filenode():
83 return path
83 return path
84 if basemf and basemf.get(path, None) == f.filenode():
84 if basemf and basemf.get(path, None) == f.filenode():
85 return path
85 return path
86
86
87
87
88 def _dirstatecopies(repo, match=None):
88 def _dirstatecopies(repo, match=None):
89 ds = repo.dirstate
89 ds = repo.dirstate
90 c = ds.copies().copy()
90 c = ds.copies().copy()
91 for k in list(c):
91 for k in list(c):
92 if ds[k] not in b'anm' or (match and not match(k)):
92 if ds[k] not in b'anm' or (match and not match(k)):
93 del c[k]
93 del c[k]
94 return c
94 return c
95
95
96
96
97 def _computeforwardmissing(a, b, match=None):
97 def _computeforwardmissing(a, b, match=None):
98 """Computes which files are in b but not a.
98 """Computes which files are in b but not a.
99 This is its own function so extensions can easily wrap this call to see what
99 This is its own function so extensions can easily wrap this call to see what
100 files _forwardcopies is about to process.
100 files _forwardcopies is about to process.
101 """
101 """
102 ma = a.manifest()
102 ma = a.manifest()
103 mb = b.manifest()
103 mb = b.manifest()
104 return mb.filesnotin(ma, match=match)
104 return mb.filesnotin(ma, match=match)
105
105
106
106
107 def usechangesetcentricalgo(repo):
107 def usechangesetcentricalgo(repo):
108 """Checks if we should use changeset-centric copy algorithms"""
108 """Checks if we should use changeset-centric copy algorithms"""
109 if repo.filecopiesmode == b'changeset-sidedata':
109 if repo.filecopiesmode == b'changeset-sidedata':
110 return True
110 return True
111 readfrom = repo.ui.config(b'experimental', b'copies.read-from')
111 readfrom = repo.ui.config(b'experimental', b'copies.read-from')
112 changesetsource = (b'changeset-only', b'compatibility')
112 changesetsource = (b'changeset-only', b'compatibility')
113 return readfrom in changesetsource
113 return readfrom in changesetsource
114
114
115
115
116 def _committedforwardcopies(a, b, base, match):
116 def _committedforwardcopies(a, b, base, match):
117 """Like _forwardcopies(), but b.rev() cannot be None (working copy)"""
117 """Like _forwardcopies(), but b.rev() cannot be None (working copy)"""
118 # files might have to be traced back to the fctx parent of the last
118 # files might have to be traced back to the fctx parent of the last
119 # one-side-only changeset, but not further back than that
119 # one-side-only changeset, but not further back than that
120 repo = a._repo
120 repo = a._repo
121
121
122 if usechangesetcentricalgo(repo):
122 if usechangesetcentricalgo(repo):
123 return _changesetforwardcopies(a, b, match)
123 return _changesetforwardcopies(a, b, match)
124
124
125 debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies')
125 debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies')
126 dbg = repo.ui.debug
126 dbg = repo.ui.debug
127 if debug:
127 if debug:
128 dbg(b'debug.copies: looking into rename from %s to %s\n' % (a, b))
128 dbg(b'debug.copies: looking into rename from %s to %s\n' % (a, b))
129 am = a.manifest()
129 am = a.manifest()
130 basemf = None if base is None else base.manifest()
130 basemf = None if base is None else base.manifest()
131
131
132 # find where new files came from
132 # find where new files came from
133 # we currently don't try to find where old files went, too expensive
133 # we currently don't try to find where old files went, too expensive
134 # this means we can miss a case like 'hg rm b; hg cp a b'
134 # this means we can miss a case like 'hg rm b; hg cp a b'
135 cm = {}
135 cm = {}
136
136
137 # Computing the forward missing is quite expensive on large manifests, since
137 # Computing the forward missing is quite expensive on large manifests, since
138 # it compares the entire manifests. We can optimize it in the common use
138 # it compares the entire manifests. We can optimize it in the common use
139 # case of computing what copies are in a commit versus its parent (like
139 # case of computing what copies are in a commit versus its parent (like
140 # during a rebase or histedit). Note, we exclude merge commits from this
140 # during a rebase or histedit). Note, we exclude merge commits from this
141 # optimization, since the ctx.files() for a merge commit is not correct for
141 # optimization, since the ctx.files() for a merge commit is not correct for
142 # this comparison.
142 # this comparison.
143 forwardmissingmatch = match
143 forwardmissingmatch = match
144 if b.p1() == a and b.p2().node() == node.nullid:
144 if b.p1() == a and b.p2().node() == node.nullid:
145 filesmatcher = matchmod.exact(b.files())
145 filesmatcher = matchmod.exact(b.files())
146 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher)
146 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher)
147 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
147 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
148
148
149 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
149 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
150
150
151 if debug:
151 if debug:
152 dbg(b'debug.copies: missing files to search: %d\n' % len(missing))
152 dbg(b'debug.copies: missing files to search: %d\n' % len(missing))
153
153
154 for f in sorted(missing):
154 for f in sorted(missing):
155 if debug:
155 if debug:
156 dbg(b'debug.copies: tracing file: %s\n' % f)
156 dbg(b'debug.copies: tracing file: %s\n' % f)
157 fctx = b[f]
157 fctx = b[f]
158 fctx._ancestrycontext = ancestrycontext
158 fctx._ancestrycontext = ancestrycontext
159
159
160 if debug:
160 if debug:
161 start = util.timer()
161 start = util.timer()
162 opath = _tracefile(fctx, am, basemf)
162 opath = _tracefile(fctx, am, basemf)
163 if opath:
163 if opath:
164 if debug:
164 if debug:
165 dbg(b'debug.copies: rename of: %s\n' % opath)
165 dbg(b'debug.copies: rename of: %s\n' % opath)
166 cm[f] = opath
166 cm[f] = opath
167 if debug:
167 if debug:
168 dbg(
168 dbg(
169 b'debug.copies: time: %f seconds\n'
169 b'debug.copies: time: %f seconds\n'
170 % (util.timer() - start)
170 % (util.timer() - start)
171 )
171 )
172 return cm
172 return cm
173
173
174
174
175 def _revinfo_getter(repo):
175 def _revinfo_getter(repo):
176 """returns a function that returns the following data given a <rev>"
176 """returns a function that returns the following data given a <rev>"
177
177
178 * p1: revision number of first parent
178 * p1: revision number of first parent
179 * p2: revision number of first parent
179 * p2: revision number of first parent
180 * changes: a ChangingFiles object
180 * changes: a ChangingFiles object
181 """
181 """
182 cl = repo.changelog
182 cl = repo.changelog
183 parents = cl.parentrevs
183 parents = cl.parentrevs
184 flags = cl.flags
184 flags = cl.flags
185
185
186 HASCOPIESINFO = flagutil.REVIDX_HASCOPIESINFO
186 HASCOPIESINFO = flagutil.REVIDX_HASCOPIESINFO
187
187
188 changelogrevision = cl.changelogrevision
188 changelogrevision = cl.changelogrevision
189
189
190 # A small cache to avoid doing the work twice for merges
190 # A small cache to avoid doing the work twice for merges
191 #
191 #
192 # In the vast majority of cases, if we ask information for a revision
192 # In the vast majority of cases, if we ask information for a revision
193 # about 1 parent, we'll later ask it for the other. So it make sense to
193 # about 1 parent, we'll later ask it for the other. So it make sense to
194 # keep the information around when reaching the first parent of a merge
194 # keep the information around when reaching the first parent of a merge
195 # and dropping it after it was provided for the second parents.
195 # and dropping it after it was provided for the second parents.
196 #
196 #
197 # It exists cases were only one parent of the merge will be walked. It
197 # It exists cases were only one parent of the merge will be walked. It
198 # happens when the "destination" the copy tracing is descendant from a
198 # happens when the "destination" the copy tracing is descendant from a
199 # new root, not common with the "source". In that case, we will only walk
199 # new root, not common with the "source". In that case, we will only walk
200 # through merge parents that are descendant of changesets common
200 # through merge parents that are descendant of changesets common
201 # between "source" and "destination".
201 # between "source" and "destination".
202 #
202 #
203 # With the current case implementation if such changesets have a copy
203 # With the current case implementation if such changesets have a copy
204 # information, we'll keep them in memory until the end of
204 # information, we'll keep them in memory until the end of
205 # _changesetforwardcopies. We don't expect the case to be frequent
205 # _changesetforwardcopies. We don't expect the case to be frequent
206 # enough to matters.
206 # enough to matters.
207 #
207 #
208 # In addition, it would be possible to reach pathological case, were
208 # In addition, it would be possible to reach pathological case, were
209 # many first parent are met before any second parent is reached. In
209 # many first parent are met before any second parent is reached. In
210 # that case the cache could grow. If this even become an issue one can
210 # that case the cache could grow. If this even become an issue one can
211 # safely introduce a maximum cache size. This would trade extra CPU/IO
211 # safely introduce a maximum cache size. This would trade extra CPU/IO
212 # time to save memory.
212 # time to save memory.
213 merge_caches = {}
213 merge_caches = {}
214
214
215 def revinfo(rev):
215 def revinfo(rev):
216 p1, p2 = parents(rev)
216 p1, p2 = parents(rev)
217 value = None
217 value = None
218 e = merge_caches.pop(rev, None)
218 e = merge_caches.pop(rev, None)
219 if e is not None:
219 if e is not None:
220 return e
220 return e
221 changes = None
221 changes = None
222 if flags(rev) & HASCOPIESINFO:
222 if flags(rev) & HASCOPIESINFO:
223 changes = changelogrevision(rev).changes
223 changes = changelogrevision(rev).changes
224 value = (p1, p2, changes)
224 value = (p1, p2, changes)
225 if p1 != node.nullrev and p2 != node.nullrev:
225 if p1 != node.nullrev and p2 != node.nullrev:
226 # XXX some case we over cache, IGNORE
226 # XXX some case we over cache, IGNORE
227 merge_caches[rev] = value
227 merge_caches[rev] = value
228 return value
228 return value
229
229
230 return revinfo
230 return revinfo
231
231
232
232
233 def _changesetforwardcopies(a, b, match):
233 def _changesetforwardcopies(a, b, match):
234 if a.rev() in (node.nullrev, b.rev()):
234 if a.rev() in (node.nullrev, b.rev()):
235 return {}
235 return {}
236
236
237 repo = a.repo().unfiltered()
237 repo = a.repo().unfiltered()
238 children = {}
238 children = {}
239
239
240 cl = repo.changelog
240 cl = repo.changelog
241 isancestor = cl.isancestorrev # XXX we should had chaching to this.
241 isancestor = cl.isancestorrev # XXX we should had chaching to this.
242 missingrevs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()])
242 missingrevs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()])
243 mrset = set(missingrevs)
243 mrset = set(missingrevs)
244 roots = set()
244 roots = set()
245 for r in missingrevs:
245 for r in missingrevs:
246 for p in cl.parentrevs(r):
246 for p in cl.parentrevs(r):
247 if p == node.nullrev:
247 if p == node.nullrev:
248 continue
248 continue
249 if p not in children:
249 if p not in children:
250 children[p] = [r]
250 children[p] = [r]
251 else:
251 else:
252 children[p].append(r)
252 children[p].append(r)
253 if p not in mrset:
253 if p not in mrset:
254 roots.add(p)
254 roots.add(p)
255 if not roots:
255 if not roots:
256 # no common revision to track copies from
256 # no common revision to track copies from
257 return {}
257 return {}
258 min_root = min(roots)
258 min_root = min(roots)
259
259
260 from_head = set(
260 from_head = set(
261 cl.reachableroots(min_root, [b.rev()], list(roots), includepath=True)
261 cl.reachableroots(min_root, [b.rev()], list(roots), includepath=True)
262 )
262 )
263
263
264 iterrevs = set(from_head)
264 iterrevs = set(from_head)
265 iterrevs &= mrset
265 iterrevs &= mrset
266 iterrevs.update(roots)
266 iterrevs.update(roots)
267 iterrevs.remove(b.rev())
267 iterrevs.remove(b.rev())
268 revs = sorted(iterrevs)
268 revs = sorted(iterrevs)
269
269
270 if repo.filecopiesmode == b'changeset-sidedata':
270 if repo.filecopiesmode == b'changeset-sidedata':
271 revinfo = _revinfo_getter(repo)
271 revinfo = _revinfo_getter(repo)
272 return _combine_changeset_copies(
272 return _combine_changeset_copies(
273 revs, children, b.rev(), revinfo, match, isancestor
273 revs, children, b.rev(), revinfo, match, isancestor
274 )
274 )
275 else:
275 else:
276 revinfo = _revinfo_getter_extra(repo)
276 revinfo = _revinfo_getter_extra(repo)
277 return _combine_changeset_copies_extra(
277 return _combine_changeset_copies_extra(
278 revs, children, b.rev(), revinfo, match, isancestor
278 revs, children, b.rev(), revinfo, match, isancestor
279 )
279 )
280
280
281
281
282 def _combine_changeset_copies(
282 def _combine_changeset_copies(
283 revs, children, targetrev, revinfo, match, isancestor
283 revs, children, targetrev, revinfo, match, isancestor
284 ):
284 ):
285 """combine the copies information for each item of iterrevs
285 """combine the copies information for each item of iterrevs
286
286
287 revs: sorted iterable of revision to visit
287 revs: sorted iterable of revision to visit
288 children: a {parent: [children]} mapping.
288 children: a {parent: [children]} mapping.
289 targetrev: the final copies destination revision (not in iterrevs)
289 targetrev: the final copies destination revision (not in iterrevs)
290 revinfo(rev): a function that return (p1, p2, p1copies, p2copies, removed)
290 revinfo(rev): a function that return (p1, p2, p1copies, p2copies, removed)
291 match: a matcher
291 match: a matcher
292
292
293 It returns the aggregated copies information for `targetrev`.
293 It returns the aggregated copies information for `targetrev`.
294 """
294 """
295 all_copies = {}
295 all_copies = {}
296 alwaysmatch = match.always()
296 alwaysmatch = match.always()
297 for r in revs:
297 for r in revs:
298 copies = all_copies.pop(r, None)
298 copies = all_copies.pop(r, None)
299 if copies is None:
299 if copies is None:
300 # this is a root
300 # this is a root
301 copies = {}
301 copies = {}
302 for i, c in enumerate(children[r]):
302 for i, c in enumerate(children[r]):
303 p1, p2, changes = revinfo(c)
303 p1, p2, changes = revinfo(c)
304 childcopies = {}
304 childcopies = {}
305 if r == p1:
305 if r == p1:
306 parent = 1
306 parent = 1
307 if changes is not None:
307 if changes is not None:
308 childcopies = changes.copied_from_p1
308 childcopies = changes.copied_from_p1
309 else:
309 else:
310 assert r == p2
310 assert r == p2
311 parent = 2
311 parent = 2
312 if changes is not None:
312 if changes is not None:
313 childcopies = changes.copied_from_p2
313 childcopies = changes.copied_from_p2
314 if not alwaysmatch:
314 if not alwaysmatch:
315 childcopies = {
315 childcopies = {
316 dst: src for dst, src in childcopies.items() if match(dst)
316 dst: src for dst, src in childcopies.items() if match(dst)
317 }
317 }
318 newcopies = copies
318 newcopies = copies
319 if childcopies:
319 if childcopies:
320 newcopies = copies.copy()
320 newcopies = copies.copy()
321 for dest, source in pycompat.iteritems(childcopies):
321 for dest, source in pycompat.iteritems(childcopies):
322 prev = copies.get(source)
322 prev = copies.get(source)
323 if prev is not None and prev[1] is not None:
323 if prev is not None and prev[1] is not None:
324 source = prev[1]
324 source = prev[1]
325 newcopies[dest] = (c, source)
325 newcopies[dest] = (c, source)
326 assert newcopies is not copies
326 assert newcopies is not copies
327 if changes is not None:
327 if changes is not None:
328 for f in changes.removed:
328 for f in changes.removed:
329 if f in newcopies:
329 if f in newcopies:
330 if newcopies is copies:
330 if newcopies is copies:
331 # copy on write to avoid affecting potential other
331 # copy on write to avoid affecting potential other
332 # branches. when there are no other branches, this
332 # branches. when there are no other branches, this
333 # could be avoided.
333 # could be avoided.
334 newcopies = copies.copy()
334 newcopies = copies.copy()
335 newcopies[f] = (c, None)
335 newcopies[f] = (c, None)
336 othercopies = all_copies.get(c)
336 othercopies = all_copies.get(c)
337 if othercopies is None:
337 if othercopies is None:
338 all_copies[c] = newcopies
338 all_copies[c] = newcopies
339 else:
339 else:
340 # we are the second parent to work on c, we need to merge our
340 # we are the second parent to work on c, we need to merge our
341 # work with the other.
341 # work with the other.
342 #
342 #
343 # In case of conflict, parent 1 take precedence over parent 2.
343 # In case of conflict, parent 1 take precedence over parent 2.
344 # This is an arbitrary choice made anew when implementing
344 # This is an arbitrary choice made anew when implementing
345 # changeset based copies. It was made without regards with
345 # changeset based copies. It was made without regards with
346 # potential filelog related behavior.
346 # potential filelog related behavior.
347 if parent == 1:
347 if parent == 1:
348 _merge_copies_dict(
348 _merge_copies_dict(
349 othercopies, newcopies, isancestor, changes
349 othercopies, newcopies, isancestor, changes
350 )
350 )
351 else:
351 else:
352 _merge_copies_dict(
352 _merge_copies_dict(
353 newcopies, othercopies, isancestor, changes
353 newcopies, othercopies, isancestor, changes
354 )
354 )
355 all_copies[c] = newcopies
355 all_copies[c] = newcopies
356
356
357 final_copies = {}
357 final_copies = {}
358 for dest, (tt, source) in all_copies[targetrev].items():
358 for dest, (tt, source) in all_copies[targetrev].items():
359 if source is not None:
359 if source is not None:
360 final_copies[dest] = source
360 final_copies[dest] = source
361 return final_copies
361 return final_copies
362
362
363
363
364 def _merge_copies_dict(minor, major, isancestor, changes):
364 def _merge_copies_dict(minor, major, isancestor, changes):
365 """merge two copies-mapping together, minor and major
365 """merge two copies-mapping together, minor and major
366
366
367 In case of conflict, value from "major" will be picked.
367 In case of conflict, value from "major" will be picked.
368
368
369 - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an
369 - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an
370 ancestors of `high_rev`,
370 ancestors of `high_rev`,
371
371
372 - `ismerged(path)`: callable return True if `path` have been merged in the
372 - `ismerged(path)`: callable return True if `path` have been merged in the
373 current revision,
373 current revision,
374 """
374 """
375 for dest, value in major.items():
375 for dest, value in major.items():
376 other = minor.get(dest)
376 other = minor.get(dest)
377 if other is None:
377 if other is None:
378 minor[dest] = value
378 minor[dest] = value
379 else:
379 else:
380 new_tt = value[0]
380 new_tt = value[0]
381 other_tt = other[0]
381 other_tt = other[0]
382 if value[1] == other[1]:
382 if value[1] == other[1]:
383 continue
383 continue
384 # content from "major" wins, unless it is older
384 # content from "major" wins, unless it is older
385 # than the branch point or there is a merge
385 # than the branch point or there is a merge
386 if new_tt == other_tt:
386 if new_tt == other_tt:
387 minor[dest] = value
387 minor[dest] = value
388 elif (
388 elif (
389 changes is not None
389 changes is not None
390 and value[1] is None
390 and value[1] is None
391 and dest in changes.salvaged
391 and dest in changes.salvaged
392 ):
392 ):
393 pass
393 pass
394 elif (
394 elif (
395 changes is not None
395 changes is not None
396 and other[1] is None
396 and other[1] is None
397 and dest in changes.salvaged
397 and dest in changes.salvaged
398 ):
398 ):
399 minor[dest] = value
399 minor[dest] = value
400 elif changes is not None and dest in changes.merged:
400 elif changes is not None and dest in changes.merged:
401 minor[dest] = value
401 minor[dest] = value
402 elif not isancestor(new_tt, other_tt):
402 elif not isancestor(new_tt, other_tt):
403 minor[dest] = value
403 if value[1] is not None:
404 minor[dest] = value
405 elif isancestor(other_tt, new_tt):
406 minor[dest] = value
404
407
405
408
406 def _revinfo_getter_extra(repo):
409 def _revinfo_getter_extra(repo):
407 """return a function that return multiple data given a <rev>"i
410 """return a function that return multiple data given a <rev>"i
408
411
409 * p1: revision number of first parent
412 * p1: revision number of first parent
410 * p2: revision number of first parent
413 * p2: revision number of first parent
411 * p1copies: mapping of copies from p1
414 * p1copies: mapping of copies from p1
412 * p2copies: mapping of copies from p2
415 * p2copies: mapping of copies from p2
413 * removed: a list of removed files
416 * removed: a list of removed files
414 * ismerged: a callback to know if file was merged in that revision
417 * ismerged: a callback to know if file was merged in that revision
415 """
418 """
416 cl = repo.changelog
419 cl = repo.changelog
417 parents = cl.parentrevs
420 parents = cl.parentrevs
418
421
419 def get_ismerged(rev):
422 def get_ismerged(rev):
420 ctx = repo[rev]
423 ctx = repo[rev]
421
424
422 def ismerged(path):
425 def ismerged(path):
423 if path not in ctx.files():
426 if path not in ctx.files():
424 return False
427 return False
425 fctx = ctx[path]
428 fctx = ctx[path]
426 parents = fctx._filelog.parents(fctx._filenode)
429 parents = fctx._filelog.parents(fctx._filenode)
427 nb_parents = 0
430 nb_parents = 0
428 for n in parents:
431 for n in parents:
429 if n != node.nullid:
432 if n != node.nullid:
430 nb_parents += 1
433 nb_parents += 1
431 return nb_parents >= 2
434 return nb_parents >= 2
432
435
433 return ismerged
436 return ismerged
434
437
435 def revinfo(rev):
438 def revinfo(rev):
436 p1, p2 = parents(rev)
439 p1, p2 = parents(rev)
437 ctx = repo[rev]
440 ctx = repo[rev]
438 p1copies, p2copies = ctx._copies
441 p1copies, p2copies = ctx._copies
439 removed = ctx.filesremoved()
442 removed = ctx.filesremoved()
440 return p1, p2, p1copies, p2copies, removed, get_ismerged(rev)
443 return p1, p2, p1copies, p2copies, removed, get_ismerged(rev)
441
444
442 return revinfo
445 return revinfo
443
446
444
447
445 def _combine_changeset_copies_extra(
448 def _combine_changeset_copies_extra(
446 revs, children, targetrev, revinfo, match, isancestor
449 revs, children, targetrev, revinfo, match, isancestor
447 ):
450 ):
448 """version of `_combine_changeset_copies` that works with the Google
451 """version of `_combine_changeset_copies` that works with the Google
449 specific "extra" based storage for copy information"""
452 specific "extra" based storage for copy information"""
450 all_copies = {}
453 all_copies = {}
451 alwaysmatch = match.always()
454 alwaysmatch = match.always()
452 for r in revs:
455 for r in revs:
453 copies = all_copies.pop(r, None)
456 copies = all_copies.pop(r, None)
454 if copies is None:
457 if copies is None:
455 # this is a root
458 # this is a root
456 copies = {}
459 copies = {}
457 for i, c in enumerate(children[r]):
460 for i, c in enumerate(children[r]):
458 p1, p2, p1copies, p2copies, removed, ismerged = revinfo(c)
461 p1, p2, p1copies, p2copies, removed, ismerged = revinfo(c)
459 if r == p1:
462 if r == p1:
460 parent = 1
463 parent = 1
461 childcopies = p1copies
464 childcopies = p1copies
462 else:
465 else:
463 assert r == p2
466 assert r == p2
464 parent = 2
467 parent = 2
465 childcopies = p2copies
468 childcopies = p2copies
466 if not alwaysmatch:
469 if not alwaysmatch:
467 childcopies = {
470 childcopies = {
468 dst: src for dst, src in childcopies.items() if match(dst)
471 dst: src for dst, src in childcopies.items() if match(dst)
469 }
472 }
470 newcopies = copies
473 newcopies = copies
471 if childcopies:
474 if childcopies:
472 newcopies = copies.copy()
475 newcopies = copies.copy()
473 for dest, source in pycompat.iteritems(childcopies):
476 for dest, source in pycompat.iteritems(childcopies):
474 prev = copies.get(source)
477 prev = copies.get(source)
475 if prev is not None and prev[1] is not None:
478 if prev is not None and prev[1] is not None:
476 source = prev[1]
479 source = prev[1]
477 newcopies[dest] = (c, source)
480 newcopies[dest] = (c, source)
478 assert newcopies is not copies
481 assert newcopies is not copies
479 for f in removed:
482 for f in removed:
480 if f in newcopies:
483 if f in newcopies:
481 if newcopies is copies:
484 if newcopies is copies:
482 # copy on write to avoid affecting potential other
485 # copy on write to avoid affecting potential other
483 # branches. when there are no other branches, this
486 # branches. when there are no other branches, this
484 # could be avoided.
487 # could be avoided.
485 newcopies = copies.copy()
488 newcopies = copies.copy()
486 newcopies[f] = (c, None)
489 newcopies[f] = (c, None)
487 othercopies = all_copies.get(c)
490 othercopies = all_copies.get(c)
488 if othercopies is None:
491 if othercopies is None:
489 all_copies[c] = newcopies
492 all_copies[c] = newcopies
490 else:
493 else:
491 # we are the second parent to work on c, we need to merge our
494 # we are the second parent to work on c, we need to merge our
492 # work with the other.
495 # work with the other.
493 #
496 #
494 # In case of conflict, parent 1 take precedence over parent 2.
497 # In case of conflict, parent 1 take precedence over parent 2.
495 # This is an arbitrary choice made anew when implementing
498 # This is an arbitrary choice made anew when implementing
496 # changeset based copies. It was made without regards with
499 # changeset based copies. It was made without regards with
497 # potential filelog related behavior.
500 # potential filelog related behavior.
498 if parent == 1:
501 if parent == 1:
499 _merge_copies_dict_extra(
502 _merge_copies_dict_extra(
500 othercopies, newcopies, isancestor, ismerged
503 othercopies, newcopies, isancestor, ismerged
501 )
504 )
502 else:
505 else:
503 _merge_copies_dict_extra(
506 _merge_copies_dict_extra(
504 newcopies, othercopies, isancestor, ismerged
507 newcopies, othercopies, isancestor, ismerged
505 )
508 )
506 all_copies[c] = newcopies
509 all_copies[c] = newcopies
507
510
508 final_copies = {}
511 final_copies = {}
509 for dest, (tt, source) in all_copies[targetrev].items():
512 for dest, (tt, source) in all_copies[targetrev].items():
510 if source is not None:
513 if source is not None:
511 final_copies[dest] = source
514 final_copies[dest] = source
512 return final_copies
515 return final_copies
513
516
514
517
515 def _merge_copies_dict_extra(minor, major, isancestor, ismerged):
518 def _merge_copies_dict_extra(minor, major, isancestor, ismerged):
516 """version of `_merge_copies_dict` that works with the Google
519 """version of `_merge_copies_dict` that works with the Google
517 specific "extra" based storage for copy information"""
520 specific "extra" based storage for copy information"""
518 for dest, value in major.items():
521 for dest, value in major.items():
519 other = minor.get(dest)
522 other = minor.get(dest)
520 if other is None:
523 if other is None:
521 minor[dest] = value
524 minor[dest] = value
522 else:
525 else:
523 new_tt = value[0]
526 new_tt = value[0]
524 other_tt = other[0]
527 other_tt = other[0]
525 if value[1] == other[1]:
528 if value[1] == other[1]:
526 continue
529 continue
527 # content from "major" wins, unless it is older
530 # content from "major" wins, unless it is older
528 # than the branch point or there is a merge
531 # than the branch point or there is a merge
529 if (
532 if (
530 new_tt == other_tt
533 new_tt == other_tt
531 or not isancestor(new_tt, other_tt)
534 or not isancestor(new_tt, other_tt)
532 or ismerged(dest)
535 or ismerged(dest)
533 ):
536 ):
534 minor[dest] = value
537 minor[dest] = value
535
538
536
539
537 def _forwardcopies(a, b, base=None, match=None):
540 def _forwardcopies(a, b, base=None, match=None):
538 """find {dst@b: src@a} copy mapping where a is an ancestor of b"""
541 """find {dst@b: src@a} copy mapping where a is an ancestor of b"""
539
542
540 if base is None:
543 if base is None:
541 base = a
544 base = a
542 match = a.repo().narrowmatch(match)
545 match = a.repo().narrowmatch(match)
543 # check for working copy
546 # check for working copy
544 if b.rev() is None:
547 if b.rev() is None:
545 cm = _committedforwardcopies(a, b.p1(), base, match)
548 cm = _committedforwardcopies(a, b.p1(), base, match)
546 # combine copies from dirstate if necessary
549 # combine copies from dirstate if necessary
547 copies = _chain(cm, _dirstatecopies(b._repo, match))
550 copies = _chain(cm, _dirstatecopies(b._repo, match))
548 else:
551 else:
549 copies = _committedforwardcopies(a, b, base, match)
552 copies = _committedforwardcopies(a, b, base, match)
550 return copies
553 return copies
551
554
552
555
553 def _backwardrenames(a, b, match):
556 def _backwardrenames(a, b, match):
554 if a._repo.ui.config(b'experimental', b'copytrace') == b'off':
557 if a._repo.ui.config(b'experimental', b'copytrace') == b'off':
555 return {}
558 return {}
556
559
557 # Even though we're not taking copies into account, 1:n rename situations
560 # Even though we're not taking copies into account, 1:n rename situations
558 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
561 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
559 # arbitrarily pick one of the renames.
562 # arbitrarily pick one of the renames.
560 # We don't want to pass in "match" here, since that would filter
563 # We don't want to pass in "match" here, since that would filter
561 # the destination by it. Since we're reversing the copies, we want
564 # the destination by it. Since we're reversing the copies, we want
562 # to filter the source instead.
565 # to filter the source instead.
563 f = _forwardcopies(b, a)
566 f = _forwardcopies(b, a)
564 r = {}
567 r = {}
565 for k, v in sorted(pycompat.iteritems(f)):
568 for k, v in sorted(pycompat.iteritems(f)):
566 if match and not match(v):
569 if match and not match(v):
567 continue
570 continue
568 # remove copies
571 # remove copies
569 if v in a:
572 if v in a:
570 continue
573 continue
571 r[v] = k
574 r[v] = k
572 return r
575 return r
573
576
574
577
575 def pathcopies(x, y, match=None):
578 def pathcopies(x, y, match=None):
576 """find {dst@y: src@x} copy mapping for directed compare"""
579 """find {dst@y: src@x} copy mapping for directed compare"""
577 repo = x._repo
580 repo = x._repo
578 debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies')
581 debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies')
579 if debug:
582 if debug:
580 repo.ui.debug(
583 repo.ui.debug(
581 b'debug.copies: searching copies from %s to %s\n' % (x, y)
584 b'debug.copies: searching copies from %s to %s\n' % (x, y)
582 )
585 )
583 if x == y or not x or not y:
586 if x == y or not x or not y:
584 return {}
587 return {}
585 if y.rev() is None and x == y.p1():
588 if y.rev() is None and x == y.p1():
586 if debug:
589 if debug:
587 repo.ui.debug(b'debug.copies: search mode: dirstate\n')
590 repo.ui.debug(b'debug.copies: search mode: dirstate\n')
588 # short-circuit to avoid issues with merge states
591 # short-circuit to avoid issues with merge states
589 return _dirstatecopies(repo, match)
592 return _dirstatecopies(repo, match)
590 a = y.ancestor(x)
593 a = y.ancestor(x)
591 if a == x:
594 if a == x:
592 if debug:
595 if debug:
593 repo.ui.debug(b'debug.copies: search mode: forward\n')
596 repo.ui.debug(b'debug.copies: search mode: forward\n')
594 copies = _forwardcopies(x, y, match=match)
597 copies = _forwardcopies(x, y, match=match)
595 elif a == y:
598 elif a == y:
596 if debug:
599 if debug:
597 repo.ui.debug(b'debug.copies: search mode: backward\n')
600 repo.ui.debug(b'debug.copies: search mode: backward\n')
598 copies = _backwardrenames(x, y, match=match)
601 copies = _backwardrenames(x, y, match=match)
599 else:
602 else:
600 if debug:
603 if debug:
601 repo.ui.debug(b'debug.copies: search mode: combined\n')
604 repo.ui.debug(b'debug.copies: search mode: combined\n')
602 base = None
605 base = None
603 if a.rev() != node.nullrev:
606 if a.rev() != node.nullrev:
604 base = x
607 base = x
605 copies = _chain(
608 copies = _chain(
606 _backwardrenames(x, a, match=match),
609 _backwardrenames(x, a, match=match),
607 _forwardcopies(a, y, base, match=match),
610 _forwardcopies(a, y, base, match=match),
608 )
611 )
609 _filter(x, y, copies)
612 _filter(x, y, copies)
610 return copies
613 return copies
611
614
612
615
613 def mergecopies(repo, c1, c2, base):
616 def mergecopies(repo, c1, c2, base):
614 """
617 """
615 Finds moves and copies between context c1 and c2 that are relevant for
618 Finds moves and copies between context c1 and c2 that are relevant for
616 merging. 'base' will be used as the merge base.
619 merging. 'base' will be used as the merge base.
617
620
618 Copytracing is used in commands like rebase, merge, unshelve, etc to merge
621 Copytracing is used in commands like rebase, merge, unshelve, etc to merge
619 files that were moved/ copied in one merge parent and modified in another.
622 files that were moved/ copied in one merge parent and modified in another.
620 For example:
623 For example:
621
624
622 o ---> 4 another commit
625 o ---> 4 another commit
623 |
626 |
624 | o ---> 3 commit that modifies a.txt
627 | o ---> 3 commit that modifies a.txt
625 | /
628 | /
626 o / ---> 2 commit that moves a.txt to b.txt
629 o / ---> 2 commit that moves a.txt to b.txt
627 |/
630 |/
628 o ---> 1 merge base
631 o ---> 1 merge base
629
632
630 If we try to rebase revision 3 on revision 4, since there is no a.txt in
633 If we try to rebase revision 3 on revision 4, since there is no a.txt in
631 revision 4, and if user have copytrace disabled, we prints the following
634 revision 4, and if user have copytrace disabled, we prints the following
632 message:
635 message:
633
636
634 ```other changed <file> which local deleted```
637 ```other changed <file> which local deleted```
635
638
636 Returns a tuple where:
639 Returns a tuple where:
637
640
638 "branch_copies" an instance of branch_copies.
641 "branch_copies" an instance of branch_copies.
639
642
640 "diverge" is a mapping of source name -> list of destination names
643 "diverge" is a mapping of source name -> list of destination names
641 for divergent renames.
644 for divergent renames.
642
645
643 This function calls different copytracing algorithms based on config.
646 This function calls different copytracing algorithms based on config.
644 """
647 """
645 # avoid silly behavior for update from empty dir
648 # avoid silly behavior for update from empty dir
646 if not c1 or not c2 or c1 == c2:
649 if not c1 or not c2 or c1 == c2:
647 return branch_copies(), branch_copies(), {}
650 return branch_copies(), branch_copies(), {}
648
651
649 narrowmatch = c1.repo().narrowmatch()
652 narrowmatch = c1.repo().narrowmatch()
650
653
651 # avoid silly behavior for parent -> working dir
654 # avoid silly behavior for parent -> working dir
652 if c2.node() is None and c1.node() == repo.dirstate.p1():
655 if c2.node() is None and c1.node() == repo.dirstate.p1():
653 return (
656 return (
654 branch_copies(_dirstatecopies(repo, narrowmatch)),
657 branch_copies(_dirstatecopies(repo, narrowmatch)),
655 branch_copies(),
658 branch_copies(),
656 {},
659 {},
657 )
660 )
658
661
659 copytracing = repo.ui.config(b'experimental', b'copytrace')
662 copytracing = repo.ui.config(b'experimental', b'copytrace')
660 if stringutil.parsebool(copytracing) is False:
663 if stringutil.parsebool(copytracing) is False:
661 # stringutil.parsebool() returns None when it is unable to parse the
664 # stringutil.parsebool() returns None when it is unable to parse the
662 # value, so we should rely on making sure copytracing is on such cases
665 # value, so we should rely on making sure copytracing is on such cases
663 return branch_copies(), branch_copies(), {}
666 return branch_copies(), branch_copies(), {}
664
667
665 if usechangesetcentricalgo(repo):
668 if usechangesetcentricalgo(repo):
666 # The heuristics don't make sense when we need changeset-centric algos
669 # The heuristics don't make sense when we need changeset-centric algos
667 return _fullcopytracing(repo, c1, c2, base)
670 return _fullcopytracing(repo, c1, c2, base)
668
671
669 # Copy trace disabling is explicitly below the node == p1 logic above
672 # Copy trace disabling is explicitly below the node == p1 logic above
670 # because the logic above is required for a simple copy to be kept across a
673 # because the logic above is required for a simple copy to be kept across a
671 # rebase.
674 # rebase.
672 if copytracing == b'heuristics':
675 if copytracing == b'heuristics':
673 # Do full copytracing if only non-public revisions are involved as
676 # Do full copytracing if only non-public revisions are involved as
674 # that will be fast enough and will also cover the copies which could
677 # that will be fast enough and will also cover the copies which could
675 # be missed by heuristics
678 # be missed by heuristics
676 if _isfullcopytraceable(repo, c1, base):
679 if _isfullcopytraceable(repo, c1, base):
677 return _fullcopytracing(repo, c1, c2, base)
680 return _fullcopytracing(repo, c1, c2, base)
678 return _heuristicscopytracing(repo, c1, c2, base)
681 return _heuristicscopytracing(repo, c1, c2, base)
679 else:
682 else:
680 return _fullcopytracing(repo, c1, c2, base)
683 return _fullcopytracing(repo, c1, c2, base)
681
684
682
685
683 def _isfullcopytraceable(repo, c1, base):
686 def _isfullcopytraceable(repo, c1, base):
684 """ Checks that if base, source and destination are all no-public branches,
687 """ Checks that if base, source and destination are all no-public branches,
685 if yes let's use the full copytrace algorithm for increased capabilities
688 if yes let's use the full copytrace algorithm for increased capabilities
686 since it will be fast enough.
689 since it will be fast enough.
687
690
688 `experimental.copytrace.sourcecommitlimit` can be used to set a limit for
691 `experimental.copytrace.sourcecommitlimit` can be used to set a limit for
689 number of changesets from c1 to base such that if number of changesets are
692 number of changesets from c1 to base such that if number of changesets are
690 more than the limit, full copytracing algorithm won't be used.
693 more than the limit, full copytracing algorithm won't be used.
691 """
694 """
692 if c1.rev() is None:
695 if c1.rev() is None:
693 c1 = c1.p1()
696 c1 = c1.p1()
694 if c1.mutable() and base.mutable():
697 if c1.mutable() and base.mutable():
695 sourcecommitlimit = repo.ui.configint(
698 sourcecommitlimit = repo.ui.configint(
696 b'experimental', b'copytrace.sourcecommitlimit'
699 b'experimental', b'copytrace.sourcecommitlimit'
697 )
700 )
698 commits = len(repo.revs(b'%d::%d', base.rev(), c1.rev()))
701 commits = len(repo.revs(b'%d::%d', base.rev(), c1.rev()))
699 return commits < sourcecommitlimit
702 return commits < sourcecommitlimit
700 return False
703 return False
701
704
702
705
703 def _checksinglesidecopies(
706 def _checksinglesidecopies(
704 src, dsts1, m1, m2, mb, c2, base, copy, renamedelete
707 src, dsts1, m1, m2, mb, c2, base, copy, renamedelete
705 ):
708 ):
706 if src not in m2:
709 if src not in m2:
707 # deleted on side 2
710 # deleted on side 2
708 if src not in m1:
711 if src not in m1:
709 # renamed on side 1, deleted on side 2
712 # renamed on side 1, deleted on side 2
710 renamedelete[src] = dsts1
713 renamedelete[src] = dsts1
711 elif src not in mb:
714 elif src not in mb:
712 # Work around the "short-circuit to avoid issues with merge states"
715 # Work around the "short-circuit to avoid issues with merge states"
713 # thing in pathcopies(): pathcopies(x, y) can return a copy where the
716 # thing in pathcopies(): pathcopies(x, y) can return a copy where the
714 # destination doesn't exist in y.
717 # destination doesn't exist in y.
715 pass
718 pass
716 elif mb[src] != m2[src] and not _related(c2[src], base[src]):
719 elif mb[src] != m2[src] and not _related(c2[src], base[src]):
717 return
720 return
718 elif mb[src] != m2[src] or mb.flags(src) != m2.flags(src):
721 elif mb[src] != m2[src] or mb.flags(src) != m2.flags(src):
719 # modified on side 2
722 # modified on side 2
720 for dst in dsts1:
723 for dst in dsts1:
721 copy[dst] = src
724 copy[dst] = src
722
725
723
726
724 class branch_copies(object):
727 class branch_copies(object):
725 """Information about copies made on one side of a merge/graft.
728 """Information about copies made on one side of a merge/graft.
726
729
727 "copy" is a mapping from destination name -> source name,
730 "copy" is a mapping from destination name -> source name,
728 where source is in c1 and destination is in c2 or vice-versa.
731 where source is in c1 and destination is in c2 or vice-versa.
729
732
730 "movewithdir" is a mapping from source name -> destination name,
733 "movewithdir" is a mapping from source name -> destination name,
731 where the file at source present in one context but not the other
734 where the file at source present in one context but not the other
732 needs to be moved to destination by the merge process, because the
735 needs to be moved to destination by the merge process, because the
733 other context moved the directory it is in.
736 other context moved the directory it is in.
734
737
735 "renamedelete" is a mapping of source name -> list of destination
738 "renamedelete" is a mapping of source name -> list of destination
736 names for files deleted in c1 that were renamed in c2 or vice-versa.
739 names for files deleted in c1 that were renamed in c2 or vice-versa.
737
740
738 "dirmove" is a mapping of detected source dir -> destination dir renames.
741 "dirmove" is a mapping of detected source dir -> destination dir renames.
739 This is needed for handling changes to new files previously grafted into
742 This is needed for handling changes to new files previously grafted into
740 renamed directories.
743 renamed directories.
741 """
744 """
742
745
743 def __init__(
746 def __init__(
744 self, copy=None, renamedelete=None, dirmove=None, movewithdir=None
747 self, copy=None, renamedelete=None, dirmove=None, movewithdir=None
745 ):
748 ):
746 self.copy = {} if copy is None else copy
749 self.copy = {} if copy is None else copy
747 self.renamedelete = {} if renamedelete is None else renamedelete
750 self.renamedelete = {} if renamedelete is None else renamedelete
748 self.dirmove = {} if dirmove is None else dirmove
751 self.dirmove = {} if dirmove is None else dirmove
749 self.movewithdir = {} if movewithdir is None else movewithdir
752 self.movewithdir = {} if movewithdir is None else movewithdir
750
753
751 def __repr__(self):
754 def __repr__(self):
752 return (
755 return (
753 '<branch_copies\n copy=%r\n renamedelete=%r\n dirmove=%r\n movewithdir=%r\n>'
756 '<branch_copies\n copy=%r\n renamedelete=%r\n dirmove=%r\n movewithdir=%r\n>'
754 % (self.copy, self.renamedelete, self.dirmove, self.movewithdir,)
757 % (self.copy, self.renamedelete, self.dirmove, self.movewithdir,)
755 )
758 )
756
759
757
760
758 def _fullcopytracing(repo, c1, c2, base):
761 def _fullcopytracing(repo, c1, c2, base):
759 """ The full copytracing algorithm which finds all the new files that were
762 """ The full copytracing algorithm which finds all the new files that were
760 added from merge base up to the top commit and for each file it checks if
763 added from merge base up to the top commit and for each file it checks if
761 this file was copied from another file.
764 this file was copied from another file.
762
765
763 This is pretty slow when a lot of changesets are involved but will track all
766 This is pretty slow when a lot of changesets are involved but will track all
764 the copies.
767 the copies.
765 """
768 """
766 m1 = c1.manifest()
769 m1 = c1.manifest()
767 m2 = c2.manifest()
770 m2 = c2.manifest()
768 mb = base.manifest()
771 mb = base.manifest()
769
772
770 copies1 = pathcopies(base, c1)
773 copies1 = pathcopies(base, c1)
771 copies2 = pathcopies(base, c2)
774 copies2 = pathcopies(base, c2)
772
775
773 if not (copies1 or copies2):
776 if not (copies1 or copies2):
774 return branch_copies(), branch_copies(), {}
777 return branch_copies(), branch_copies(), {}
775
778
776 inversecopies1 = {}
779 inversecopies1 = {}
777 inversecopies2 = {}
780 inversecopies2 = {}
778 for dst, src in copies1.items():
781 for dst, src in copies1.items():
779 inversecopies1.setdefault(src, []).append(dst)
782 inversecopies1.setdefault(src, []).append(dst)
780 for dst, src in copies2.items():
783 for dst, src in copies2.items():
781 inversecopies2.setdefault(src, []).append(dst)
784 inversecopies2.setdefault(src, []).append(dst)
782
785
783 copy1 = {}
786 copy1 = {}
784 copy2 = {}
787 copy2 = {}
785 diverge = {}
788 diverge = {}
786 renamedelete1 = {}
789 renamedelete1 = {}
787 renamedelete2 = {}
790 renamedelete2 = {}
788 allsources = set(inversecopies1) | set(inversecopies2)
791 allsources = set(inversecopies1) | set(inversecopies2)
789 for src in allsources:
792 for src in allsources:
790 dsts1 = inversecopies1.get(src)
793 dsts1 = inversecopies1.get(src)
791 dsts2 = inversecopies2.get(src)
794 dsts2 = inversecopies2.get(src)
792 if dsts1 and dsts2:
795 if dsts1 and dsts2:
793 # copied/renamed on both sides
796 # copied/renamed on both sides
794 if src not in m1 and src not in m2:
797 if src not in m1 and src not in m2:
795 # renamed on both sides
798 # renamed on both sides
796 dsts1 = set(dsts1)
799 dsts1 = set(dsts1)
797 dsts2 = set(dsts2)
800 dsts2 = set(dsts2)
798 # If there's some overlap in the rename destinations, we
801 # If there's some overlap in the rename destinations, we
799 # consider it not divergent. For example, if side 1 copies 'a'
802 # consider it not divergent. For example, if side 1 copies 'a'
800 # to 'b' and 'c' and deletes 'a', and side 2 copies 'a' to 'c'
803 # to 'b' and 'c' and deletes 'a', and side 2 copies 'a' to 'c'
801 # and 'd' and deletes 'a'.
804 # and 'd' and deletes 'a'.
802 if dsts1 & dsts2:
805 if dsts1 & dsts2:
803 for dst in dsts1 & dsts2:
806 for dst in dsts1 & dsts2:
804 copy1[dst] = src
807 copy1[dst] = src
805 copy2[dst] = src
808 copy2[dst] = src
806 else:
809 else:
807 diverge[src] = sorted(dsts1 | dsts2)
810 diverge[src] = sorted(dsts1 | dsts2)
808 elif src in m1 and src in m2:
811 elif src in m1 and src in m2:
809 # copied on both sides
812 # copied on both sides
810 dsts1 = set(dsts1)
813 dsts1 = set(dsts1)
811 dsts2 = set(dsts2)
814 dsts2 = set(dsts2)
812 for dst in dsts1 & dsts2:
815 for dst in dsts1 & dsts2:
813 copy1[dst] = src
816 copy1[dst] = src
814 copy2[dst] = src
817 copy2[dst] = src
815 # TODO: Handle cases where it was renamed on one side and copied
818 # TODO: Handle cases where it was renamed on one side and copied
816 # on the other side
819 # on the other side
817 elif dsts1:
820 elif dsts1:
818 # copied/renamed only on side 1
821 # copied/renamed only on side 1
819 _checksinglesidecopies(
822 _checksinglesidecopies(
820 src, dsts1, m1, m2, mb, c2, base, copy1, renamedelete1
823 src, dsts1, m1, m2, mb, c2, base, copy1, renamedelete1
821 )
824 )
822 elif dsts2:
825 elif dsts2:
823 # copied/renamed only on side 2
826 # copied/renamed only on side 2
824 _checksinglesidecopies(
827 _checksinglesidecopies(
825 src, dsts2, m2, m1, mb, c1, base, copy2, renamedelete2
828 src, dsts2, m2, m1, mb, c1, base, copy2, renamedelete2
826 )
829 )
827
830
828 # find interesting file sets from manifests
831 # find interesting file sets from manifests
829 addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
832 addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
830 addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
833 addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
831 u1 = sorted(addedinm1 - addedinm2)
834 u1 = sorted(addedinm1 - addedinm2)
832 u2 = sorted(addedinm2 - addedinm1)
835 u2 = sorted(addedinm2 - addedinm1)
833
836
834 header = b" unmatched files in %s"
837 header = b" unmatched files in %s"
835 if u1:
838 if u1:
836 repo.ui.debug(b"%s:\n %s\n" % (header % b'local', b"\n ".join(u1)))
839 repo.ui.debug(b"%s:\n %s\n" % (header % b'local', b"\n ".join(u1)))
837 if u2:
840 if u2:
838 repo.ui.debug(b"%s:\n %s\n" % (header % b'other', b"\n ".join(u2)))
841 repo.ui.debug(b"%s:\n %s\n" % (header % b'other', b"\n ".join(u2)))
839
842
840 if repo.ui.debugflag:
843 if repo.ui.debugflag:
841 renamedeleteset = set()
844 renamedeleteset = set()
842 divergeset = set()
845 divergeset = set()
843 for dsts in diverge.values():
846 for dsts in diverge.values():
844 divergeset.update(dsts)
847 divergeset.update(dsts)
845 for dsts in renamedelete1.values():
848 for dsts in renamedelete1.values():
846 renamedeleteset.update(dsts)
849 renamedeleteset.update(dsts)
847 for dsts in renamedelete2.values():
850 for dsts in renamedelete2.values():
848 renamedeleteset.update(dsts)
851 renamedeleteset.update(dsts)
849
852
850 repo.ui.debug(
853 repo.ui.debug(
851 b" all copies found (* = to merge, ! = divergent, "
854 b" all copies found (* = to merge, ! = divergent, "
852 b"% = renamed and deleted):\n"
855 b"% = renamed and deleted):\n"
853 )
856 )
854 for side, copies in ((b"local", copies1), (b"remote", copies2)):
857 for side, copies in ((b"local", copies1), (b"remote", copies2)):
855 if not copies:
858 if not copies:
856 continue
859 continue
857 repo.ui.debug(b" on %s side:\n" % side)
860 repo.ui.debug(b" on %s side:\n" % side)
858 for f in sorted(copies):
861 for f in sorted(copies):
859 note = b""
862 note = b""
860 if f in copy1 or f in copy2:
863 if f in copy1 or f in copy2:
861 note += b"*"
864 note += b"*"
862 if f in divergeset:
865 if f in divergeset:
863 note += b"!"
866 note += b"!"
864 if f in renamedeleteset:
867 if f in renamedeleteset:
865 note += b"%"
868 note += b"%"
866 repo.ui.debug(
869 repo.ui.debug(
867 b" src: '%s' -> dst: '%s' %s\n" % (copies[f], f, note)
870 b" src: '%s' -> dst: '%s' %s\n" % (copies[f], f, note)
868 )
871 )
869 del renamedeleteset
872 del renamedeleteset
870 del divergeset
873 del divergeset
871
874
872 repo.ui.debug(b" checking for directory renames\n")
875 repo.ui.debug(b" checking for directory renames\n")
873
876
874 dirmove1, movewithdir2 = _dir_renames(repo, c1, copy1, copies1, u2)
877 dirmove1, movewithdir2 = _dir_renames(repo, c1, copy1, copies1, u2)
875 dirmove2, movewithdir1 = _dir_renames(repo, c2, copy2, copies2, u1)
878 dirmove2, movewithdir1 = _dir_renames(repo, c2, copy2, copies2, u1)
876
879
877 branch_copies1 = branch_copies(copy1, renamedelete1, dirmove1, movewithdir1)
880 branch_copies1 = branch_copies(copy1, renamedelete1, dirmove1, movewithdir1)
878 branch_copies2 = branch_copies(copy2, renamedelete2, dirmove2, movewithdir2)
881 branch_copies2 = branch_copies(copy2, renamedelete2, dirmove2, movewithdir2)
879
882
880 return branch_copies1, branch_copies2, diverge
883 return branch_copies1, branch_copies2, diverge
881
884
882
885
883 def _dir_renames(repo, ctx, copy, fullcopy, addedfiles):
886 def _dir_renames(repo, ctx, copy, fullcopy, addedfiles):
884 """Finds moved directories and files that should move with them.
887 """Finds moved directories and files that should move with them.
885
888
886 ctx: the context for one of the sides
889 ctx: the context for one of the sides
887 copy: files copied on the same side (as ctx)
890 copy: files copied on the same side (as ctx)
888 fullcopy: files copied on the same side (as ctx), including those that
891 fullcopy: files copied on the same side (as ctx), including those that
889 merge.manifestmerge() won't care about
892 merge.manifestmerge() won't care about
890 addedfiles: added files on the other side (compared to ctx)
893 addedfiles: added files on the other side (compared to ctx)
891 """
894 """
892 # generate a directory move map
895 # generate a directory move map
893 d = ctx.dirs()
896 d = ctx.dirs()
894 invalid = set()
897 invalid = set()
895 dirmove = {}
898 dirmove = {}
896
899
897 # examine each file copy for a potential directory move, which is
900 # examine each file copy for a potential directory move, which is
898 # when all the files in a directory are moved to a new directory
901 # when all the files in a directory are moved to a new directory
899 for dst, src in pycompat.iteritems(fullcopy):
902 for dst, src in pycompat.iteritems(fullcopy):
900 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
903 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
901 if dsrc in invalid:
904 if dsrc in invalid:
902 # already seen to be uninteresting
905 # already seen to be uninteresting
903 continue
906 continue
904 elif dsrc in d and ddst in d:
907 elif dsrc in d and ddst in d:
905 # directory wasn't entirely moved locally
908 # directory wasn't entirely moved locally
906 invalid.add(dsrc)
909 invalid.add(dsrc)
907 elif dsrc in dirmove and dirmove[dsrc] != ddst:
910 elif dsrc in dirmove and dirmove[dsrc] != ddst:
908 # files from the same directory moved to two different places
911 # files from the same directory moved to two different places
909 invalid.add(dsrc)
912 invalid.add(dsrc)
910 else:
913 else:
911 # looks good so far
914 # looks good so far
912 dirmove[dsrc] = ddst
915 dirmove[dsrc] = ddst
913
916
914 for i in invalid:
917 for i in invalid:
915 if i in dirmove:
918 if i in dirmove:
916 del dirmove[i]
919 del dirmove[i]
917 del d, invalid
920 del d, invalid
918
921
919 if not dirmove:
922 if not dirmove:
920 return {}, {}
923 return {}, {}
921
924
922 dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)}
925 dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)}
923
926
924 for d in dirmove:
927 for d in dirmove:
925 repo.ui.debug(
928 repo.ui.debug(
926 b" discovered dir src: '%s' -> dst: '%s'\n" % (d, dirmove[d])
929 b" discovered dir src: '%s' -> dst: '%s'\n" % (d, dirmove[d])
927 )
930 )
928
931
929 movewithdir = {}
932 movewithdir = {}
930 # check unaccounted nonoverlapping files against directory moves
933 # check unaccounted nonoverlapping files against directory moves
931 for f in addedfiles:
934 for f in addedfiles:
932 if f not in fullcopy:
935 if f not in fullcopy:
933 for d in dirmove:
936 for d in dirmove:
934 if f.startswith(d):
937 if f.startswith(d):
935 # new file added in a directory that was moved, move it
938 # new file added in a directory that was moved, move it
936 df = dirmove[d] + f[len(d) :]
939 df = dirmove[d] + f[len(d) :]
937 if df not in copy:
940 if df not in copy:
938 movewithdir[f] = df
941 movewithdir[f] = df
939 repo.ui.debug(
942 repo.ui.debug(
940 b" pending file src: '%s' -> dst: '%s'\n"
943 b" pending file src: '%s' -> dst: '%s'\n"
941 % (f, df)
944 % (f, df)
942 )
945 )
943 break
946 break
944
947
945 return dirmove, movewithdir
948 return dirmove, movewithdir
946
949
947
950
948 def _heuristicscopytracing(repo, c1, c2, base):
951 def _heuristicscopytracing(repo, c1, c2, base):
949 """ Fast copytracing using filename heuristics
952 """ Fast copytracing using filename heuristics
950
953
951 Assumes that moves or renames are of following two types:
954 Assumes that moves or renames are of following two types:
952
955
953 1) Inside a directory only (same directory name but different filenames)
956 1) Inside a directory only (same directory name but different filenames)
954 2) Move from one directory to another
957 2) Move from one directory to another
955 (same filenames but different directory names)
958 (same filenames but different directory names)
956
959
957 Works only when there are no merge commits in the "source branch".
960 Works only when there are no merge commits in the "source branch".
958 Source branch is commits from base up to c2 not including base.
961 Source branch is commits from base up to c2 not including base.
959
962
960 If merge is involved it fallbacks to _fullcopytracing().
963 If merge is involved it fallbacks to _fullcopytracing().
961
964
962 Can be used by setting the following config:
965 Can be used by setting the following config:
963
966
964 [experimental]
967 [experimental]
965 copytrace = heuristics
968 copytrace = heuristics
966
969
967 In some cases the copy/move candidates found by heuristics can be very large
970 In some cases the copy/move candidates found by heuristics can be very large
968 in number and that will make the algorithm slow. The number of possible
971 in number and that will make the algorithm slow. The number of possible
969 candidates to check can be limited by using the config
972 candidates to check can be limited by using the config
970 `experimental.copytrace.movecandidateslimit` which defaults to 100.
973 `experimental.copytrace.movecandidateslimit` which defaults to 100.
971 """
974 """
972
975
973 if c1.rev() is None:
976 if c1.rev() is None:
974 c1 = c1.p1()
977 c1 = c1.p1()
975 if c2.rev() is None:
978 if c2.rev() is None:
976 c2 = c2.p1()
979 c2 = c2.p1()
977
980
978 changedfiles = set()
981 changedfiles = set()
979 m1 = c1.manifest()
982 m1 = c1.manifest()
980 if not repo.revs(b'%d::%d', base.rev(), c2.rev()):
983 if not repo.revs(b'%d::%d', base.rev(), c2.rev()):
981 # If base is not in c2 branch, we switch to fullcopytracing
984 # If base is not in c2 branch, we switch to fullcopytracing
982 repo.ui.debug(
985 repo.ui.debug(
983 b"switching to full copytracing as base is not "
986 b"switching to full copytracing as base is not "
984 b"an ancestor of c2\n"
987 b"an ancestor of c2\n"
985 )
988 )
986 return _fullcopytracing(repo, c1, c2, base)
989 return _fullcopytracing(repo, c1, c2, base)
987
990
988 ctx = c2
991 ctx = c2
989 while ctx != base:
992 while ctx != base:
990 if len(ctx.parents()) == 2:
993 if len(ctx.parents()) == 2:
991 # To keep things simple let's not handle merges
994 # To keep things simple let's not handle merges
992 repo.ui.debug(b"switching to full copytracing because of merges\n")
995 repo.ui.debug(b"switching to full copytracing because of merges\n")
993 return _fullcopytracing(repo, c1, c2, base)
996 return _fullcopytracing(repo, c1, c2, base)
994 changedfiles.update(ctx.files())
997 changedfiles.update(ctx.files())
995 ctx = ctx.p1()
998 ctx = ctx.p1()
996
999
997 copies2 = {}
1000 copies2 = {}
998 cp = _forwardcopies(base, c2)
1001 cp = _forwardcopies(base, c2)
999 for dst, src in pycompat.iteritems(cp):
1002 for dst, src in pycompat.iteritems(cp):
1000 if src in m1:
1003 if src in m1:
1001 copies2[dst] = src
1004 copies2[dst] = src
1002
1005
1003 # file is missing if it isn't present in the destination, but is present in
1006 # file is missing if it isn't present in the destination, but is present in
1004 # the base and present in the source.
1007 # the base and present in the source.
1005 # Presence in the base is important to exclude added files, presence in the
1008 # Presence in the base is important to exclude added files, presence in the
1006 # source is important to exclude removed files.
1009 # source is important to exclude removed files.
1007 filt = lambda f: f not in m1 and f in base and f in c2
1010 filt = lambda f: f not in m1 and f in base and f in c2
1008 missingfiles = [f for f in changedfiles if filt(f)]
1011 missingfiles = [f for f in changedfiles if filt(f)]
1009
1012
1010 copies1 = {}
1013 copies1 = {}
1011 if missingfiles:
1014 if missingfiles:
1012 basenametofilename = collections.defaultdict(list)
1015 basenametofilename = collections.defaultdict(list)
1013 dirnametofilename = collections.defaultdict(list)
1016 dirnametofilename = collections.defaultdict(list)
1014
1017
1015 for f in m1.filesnotin(base.manifest()):
1018 for f in m1.filesnotin(base.manifest()):
1016 basename = os.path.basename(f)
1019 basename = os.path.basename(f)
1017 dirname = os.path.dirname(f)
1020 dirname = os.path.dirname(f)
1018 basenametofilename[basename].append(f)
1021 basenametofilename[basename].append(f)
1019 dirnametofilename[dirname].append(f)
1022 dirnametofilename[dirname].append(f)
1020
1023
1021 for f in missingfiles:
1024 for f in missingfiles:
1022 basename = os.path.basename(f)
1025 basename = os.path.basename(f)
1023 dirname = os.path.dirname(f)
1026 dirname = os.path.dirname(f)
1024 samebasename = basenametofilename[basename]
1027 samebasename = basenametofilename[basename]
1025 samedirname = dirnametofilename[dirname]
1028 samedirname = dirnametofilename[dirname]
1026 movecandidates = samebasename + samedirname
1029 movecandidates = samebasename + samedirname
1027 # f is guaranteed to be present in c2, that's why
1030 # f is guaranteed to be present in c2, that's why
1028 # c2.filectx(f) won't fail
1031 # c2.filectx(f) won't fail
1029 f2 = c2.filectx(f)
1032 f2 = c2.filectx(f)
1030 # we can have a lot of candidates which can slow down the heuristics
1033 # we can have a lot of candidates which can slow down the heuristics
1031 # config value to limit the number of candidates moves to check
1034 # config value to limit the number of candidates moves to check
1032 maxcandidates = repo.ui.configint(
1035 maxcandidates = repo.ui.configint(
1033 b'experimental', b'copytrace.movecandidateslimit'
1036 b'experimental', b'copytrace.movecandidateslimit'
1034 )
1037 )
1035
1038
1036 if len(movecandidates) > maxcandidates:
1039 if len(movecandidates) > maxcandidates:
1037 repo.ui.status(
1040 repo.ui.status(
1038 _(
1041 _(
1039 b"skipping copytracing for '%s', more "
1042 b"skipping copytracing for '%s', more "
1040 b"candidates than the limit: %d\n"
1043 b"candidates than the limit: %d\n"
1041 )
1044 )
1042 % (f, len(movecandidates))
1045 % (f, len(movecandidates))
1043 )
1046 )
1044 continue
1047 continue
1045
1048
1046 for candidate in movecandidates:
1049 for candidate in movecandidates:
1047 f1 = c1.filectx(candidate)
1050 f1 = c1.filectx(candidate)
1048 if _related(f1, f2):
1051 if _related(f1, f2):
1049 # if there are a few related copies then we'll merge
1052 # if there are a few related copies then we'll merge
1050 # changes into all of them. This matches the behaviour
1053 # changes into all of them. This matches the behaviour
1051 # of upstream copytracing
1054 # of upstream copytracing
1052 copies1[candidate] = f
1055 copies1[candidate] = f
1053
1056
1054 return branch_copies(copies1), branch_copies(copies2), {}
1057 return branch_copies(copies1), branch_copies(copies2), {}
1055
1058
1056
1059
1057 def _related(f1, f2):
1060 def _related(f1, f2):
1058 """return True if f1 and f2 filectx have a common ancestor
1061 """return True if f1 and f2 filectx have a common ancestor
1059
1062
1060 Walk back to common ancestor to see if the two files originate
1063 Walk back to common ancestor to see if the two files originate
1061 from the same file. Since workingfilectx's rev() is None it messes
1064 from the same file. Since workingfilectx's rev() is None it messes
1062 up the integer comparison logic, hence the pre-step check for
1065 up the integer comparison logic, hence the pre-step check for
1063 None (f1 and f2 can only be workingfilectx's initially).
1066 None (f1 and f2 can only be workingfilectx's initially).
1064 """
1067 """
1065
1068
1066 if f1 == f2:
1069 if f1 == f2:
1067 return True # a match
1070 return True # a match
1068
1071
1069 g1, g2 = f1.ancestors(), f2.ancestors()
1072 g1, g2 = f1.ancestors(), f2.ancestors()
1070 try:
1073 try:
1071 f1r, f2r = f1.linkrev(), f2.linkrev()
1074 f1r, f2r = f1.linkrev(), f2.linkrev()
1072
1075
1073 if f1r is None:
1076 if f1r is None:
1074 f1 = next(g1)
1077 f1 = next(g1)
1075 if f2r is None:
1078 if f2r is None:
1076 f2 = next(g2)
1079 f2 = next(g2)
1077
1080
1078 while True:
1081 while True:
1079 f1r, f2r = f1.linkrev(), f2.linkrev()
1082 f1r, f2r = f1.linkrev(), f2.linkrev()
1080 if f1r > f2r:
1083 if f1r > f2r:
1081 f1 = next(g1)
1084 f1 = next(g1)
1082 elif f2r > f1r:
1085 elif f2r > f1r:
1083 f2 = next(g2)
1086 f2 = next(g2)
1084 else: # f1 and f2 point to files in the same linkrev
1087 else: # f1 and f2 point to files in the same linkrev
1085 return f1 == f2 # true if they point to the same file
1088 return f1 == f2 # true if they point to the same file
1086 except StopIteration:
1089 except StopIteration:
1087 return False
1090 return False
1088
1091
1089
1092
1090 def graftcopies(wctx, ctx, base):
1093 def graftcopies(wctx, ctx, base):
1091 """reproduce copies between base and ctx in the wctx
1094 """reproduce copies between base and ctx in the wctx
1092
1095
1093 Unlike mergecopies(), this function will only consider copies between base
1096 Unlike mergecopies(), this function will only consider copies between base
1094 and ctx; it will ignore copies between base and wctx. Also unlike
1097 and ctx; it will ignore copies between base and wctx. Also unlike
1095 mergecopies(), this function will apply copies to the working copy (instead
1098 mergecopies(), this function will apply copies to the working copy (instead
1096 of just returning information about the copies). That makes it cheaper
1099 of just returning information about the copies). That makes it cheaper
1097 (especially in the common case of base==ctx.p1()) and useful also when
1100 (especially in the common case of base==ctx.p1()) and useful also when
1098 experimental.copytrace=off.
1101 experimental.copytrace=off.
1099
1102
1100 merge.update() will have already marked most copies, but it will only
1103 merge.update() will have already marked most copies, but it will only
1101 mark copies if it thinks the source files are related (see
1104 mark copies if it thinks the source files are related (see
1102 merge._related()). It will also not mark copies if the file wasn't modified
1105 merge._related()). It will also not mark copies if the file wasn't modified
1103 on the local side. This function adds the copies that were "missed"
1106 on the local side. This function adds the copies that were "missed"
1104 by merge.update().
1107 by merge.update().
1105 """
1108 """
1106 new_copies = pathcopies(base, ctx)
1109 new_copies = pathcopies(base, ctx)
1107 _filter(wctx.p1(), wctx, new_copies)
1110 _filter(wctx.p1(), wctx, new_copies)
1108 for dst, src in pycompat.iteritems(new_copies):
1111 for dst, src in pycompat.iteritems(new_copies):
1109 wctx[dst].markcopied(src)
1112 wctx[dst].markcopied(src)
@@ -1,1560 +1,1666 b''
1 #testcases filelog compatibility changeset sidedata upgraded
1 #testcases filelog compatibility changeset sidedata upgraded
2
2
3 =====================================================
3 =====================================================
4 Test Copy tracing for chain of copies involving merge
4 Test Copy tracing for chain of copies involving merge
5 =====================================================
5 =====================================================
6
6
7 This test files covers copies/rename case for a chains of commit where merges
7 This test files covers copies/rename case for a chains of commit where merges
8 are involved. It cheks we do not have unwanted update of behavior and that the
8 are involved. It cheks we do not have unwanted update of behavior and that the
9 different options to retrieve copies behave correctly.
9 different options to retrieve copies behave correctly.
10
10
11
11
12 Setup
12 Setup
13 =====
13 =====
14
14
15 use git diff to see rename
15 use git diff to see rename
16
16
17 $ cat << EOF >> $HGRCPATH
17 $ cat << EOF >> $HGRCPATH
18 > [diff]
18 > [diff]
19 > git=yes
19 > git=yes
20 > [command-templates]
20 > [command-templates]
21 > log={rev} {desc}\n
21 > log={rev} {desc}\n
22 > EOF
22 > EOF
23
23
24 #if compatibility
24 #if compatibility
25 $ cat >> $HGRCPATH << EOF
25 $ cat >> $HGRCPATH << EOF
26 > [experimental]
26 > [experimental]
27 > copies.read-from = compatibility
27 > copies.read-from = compatibility
28 > EOF
28 > EOF
29 #endif
29 #endif
30
30
31 #if changeset
31 #if changeset
32 $ cat >> $HGRCPATH << EOF
32 $ cat >> $HGRCPATH << EOF
33 > [experimental]
33 > [experimental]
34 > copies.read-from = changeset-only
34 > copies.read-from = changeset-only
35 > copies.write-to = changeset-only
35 > copies.write-to = changeset-only
36 > EOF
36 > EOF
37 #endif
37 #endif
38
38
39 #if sidedata
39 #if sidedata
40 $ cat >> $HGRCPATH << EOF
40 $ cat >> $HGRCPATH << EOF
41 > [format]
41 > [format]
42 > exp-use-side-data = yes
42 > exp-use-side-data = yes
43 > exp-use-copies-side-data-changeset = yes
43 > exp-use-copies-side-data-changeset = yes
44 > EOF
44 > EOF
45 #endif
45 #endif
46
46
47
47
48 $ hg init repo-chain
48 $ hg init repo-chain
49 $ cd repo-chain
49 $ cd repo-chain
50
50
51 Add some linear rename initialy
51 Add some linear rename initialy
52
52
53 $ echo a > a
53 $ echo a > a
54 $ echo b > b
54 $ echo b > b
55 $ echo h > h
55 $ echo h > h
56 $ hg ci -Am 'i-0 initial commit: a b h'
56 $ hg ci -Am 'i-0 initial commit: a b h'
57 adding a
57 adding a
58 adding b
58 adding b
59 adding h
59 adding h
60 $ hg mv a c
60 $ hg mv a c
61 $ hg ci -Am 'i-1: a -move-> c'
61 $ hg ci -Am 'i-1: a -move-> c'
62 $ hg mv c d
62 $ hg mv c d
63 $ hg ci -Am 'i-2: c -move-> d'
63 $ hg ci -Am 'i-2: c -move-> d'
64 $ hg log -G
64 $ hg log -G
65 @ 2 i-2: c -move-> d
65 @ 2 i-2: c -move-> d
66 |
66 |
67 o 1 i-1: a -move-> c
67 o 1 i-1: a -move-> c
68 |
68 |
69 o 0 i-0 initial commit: a b h
69 o 0 i-0 initial commit: a b h
70
70
71
71
72 And having another branch with renames on the other side
72 And having another branch with renames on the other side
73
73
74 $ hg mv d e
74 $ hg mv d e
75 $ hg ci -Am 'a-1: d -move-> e'
75 $ hg ci -Am 'a-1: d -move-> e'
76 $ hg mv e f
76 $ hg mv e f
77 $ hg ci -Am 'a-2: e -move-> f'
77 $ hg ci -Am 'a-2: e -move-> f'
78 $ hg log -G --rev '::.'
78 $ hg log -G --rev '::.'
79 @ 4 a-2: e -move-> f
79 @ 4 a-2: e -move-> f
80 |
80 |
81 o 3 a-1: d -move-> e
81 o 3 a-1: d -move-> e
82 |
82 |
83 o 2 i-2: c -move-> d
83 o 2 i-2: c -move-> d
84 |
84 |
85 o 1 i-1: a -move-> c
85 o 1 i-1: a -move-> c
86 |
86 |
87 o 0 i-0 initial commit: a b h
87 o 0 i-0 initial commit: a b h
88
88
89
89
90 Have a branching with nothing on one side
90 Have a branching with nothing on one side
91
91
92 $ hg up 'desc("i-2")'
92 $ hg up 'desc("i-2")'
93 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
93 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
94 $ echo foo > b
94 $ echo foo > b
95 $ hg ci -m 'b-1: b update'
95 $ hg ci -m 'b-1: b update'
96 created new head
96 created new head
97 $ hg log -G --rev '::.'
97 $ hg log -G --rev '::.'
98 @ 5 b-1: b update
98 @ 5 b-1: b update
99 |
99 |
100 o 2 i-2: c -move-> d
100 o 2 i-2: c -move-> d
101 |
101 |
102 o 1 i-1: a -move-> c
102 o 1 i-1: a -move-> c
103 |
103 |
104 o 0 i-0 initial commit: a b h
104 o 0 i-0 initial commit: a b h
105
105
106
106
107 Create a branch that delete a file previous renamed
107 Create a branch that delete a file previous renamed
108
108
109 $ hg up 'desc("i-2")'
109 $ hg up 'desc("i-2")'
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 $ hg rm d
111 $ hg rm d
112 $ hg ci -m 'c-1 delete d'
112 $ hg ci -m 'c-1 delete d'
113 created new head
113 created new head
114 $ hg log -G --rev '::.'
114 $ hg log -G --rev '::.'
115 @ 6 c-1 delete d
115 @ 6 c-1 delete d
116 |
116 |
117 o 2 i-2: c -move-> d
117 o 2 i-2: c -move-> d
118 |
118 |
119 o 1 i-1: a -move-> c
119 o 1 i-1: a -move-> c
120 |
120 |
121 o 0 i-0 initial commit: a b h
121 o 0 i-0 initial commit: a b h
122
122
123
123
124 Create a branch that delete a file previous renamed and recreate it
124 Create a branch that delete a file previous renamed and recreate it
125
125
126 $ hg up 'desc("i-2")'
126 $ hg up 'desc("i-2")'
127 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
128 $ hg rm d
128 $ hg rm d
129 $ hg ci -m 'd-1 delete d'
129 $ hg ci -m 'd-1 delete d'
130 created new head
130 created new head
131 $ echo bar > d
131 $ echo bar > d
132 $ hg add d
132 $ hg add d
133 $ hg ci -m 'd-2 re-add d'
133 $ hg ci -m 'd-2 re-add d'
134 $ hg log -G --rev '::.'
134 $ hg log -G --rev '::.'
135 @ 8 d-2 re-add d
135 @ 8 d-2 re-add d
136 |
136 |
137 o 7 d-1 delete d
137 o 7 d-1 delete d
138 |
138 |
139 o 2 i-2: c -move-> d
139 o 2 i-2: c -move-> d
140 |
140 |
141 o 1 i-1: a -move-> c
141 o 1 i-1: a -move-> c
142 |
142 |
143 o 0 i-0 initial commit: a b h
143 o 0 i-0 initial commit: a b h
144
144
145
145
146 Having another branch renaming a different file to the same filename as another
146 Having another branch renaming a different file to the same filename as another
147
147
148 $ hg up 'desc("i-2")'
148 $ hg up 'desc("i-2")'
149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 $ hg mv b g
150 $ hg mv b g
151 $ hg ci -m 'e-1 b -move-> g'
151 $ hg ci -m 'e-1 b -move-> g'
152 created new head
152 created new head
153 $ hg mv g f
153 $ hg mv g f
154 $ hg ci -m 'e-2 g -move-> f'
154 $ hg ci -m 'e-2 g -move-> f'
155 $ hg log -G --rev '::.'
155 $ hg log -G --rev '::.'
156 @ 10 e-2 g -move-> f
156 @ 10 e-2 g -move-> f
157 |
157 |
158 o 9 e-1 b -move-> g
158 o 9 e-1 b -move-> g
159 |
159 |
160 o 2 i-2: c -move-> d
160 o 2 i-2: c -move-> d
161 |
161 |
162 o 1 i-1: a -move-> c
162 o 1 i-1: a -move-> c
163 |
163 |
164 o 0 i-0 initial commit: a b h
164 o 0 i-0 initial commit: a b h
165
165
166
166
167 Setup all merge
167 Setup all merge
168 ===============
168 ===============
169
169
170 This is done beforehand to validate that the upgrade process creates valid copy
170 This is done beforehand to validate that the upgrade process creates valid copy
171 information.
171 information.
172
172
173 merging with unrelated change does not interfere with the renames
173 merging with unrelated change does not interfere with the renames
174 ---------------------------------------------------------------
174 ---------------------------------------------------------------
175
175
176 - rename on one side
176 - rename on one side
177 - unrelated change on the other side
177 - unrelated change on the other side
178
178
179 $ hg up 'desc("b-1")'
179 $ hg up 'desc("b-1")'
180 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
180 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
181 $ hg merge 'desc("a-2")'
181 $ hg merge 'desc("a-2")'
182 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
182 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
183 (branch merge, don't forget to commit)
183 (branch merge, don't forget to commit)
184 $ hg ci -m 'mBAm-0 simple merge - one way'
184 $ hg ci -m 'mBAm-0 simple merge - one way'
185 $ hg up 'desc("a-2")'
185 $ hg up 'desc("a-2")'
186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 $ hg merge 'desc("b-1")'
187 $ hg merge 'desc("b-1")'
188 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
188 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 (branch merge, don't forget to commit)
189 (branch merge, don't forget to commit)
190 $ hg ci -m 'mABm-0 simple merge - the other way'
190 $ hg ci -m 'mABm-0 simple merge - the other way'
191 created new head
191 created new head
192 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
192 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
193 @ 12 mABm-0 simple merge - the other way
193 @ 12 mABm-0 simple merge - the other way
194 |\
194 |\
195 +---o 11 mBAm-0 simple merge - one way
195 +---o 11 mBAm-0 simple merge - one way
196 | |/
196 | |/
197 | o 5 b-1: b update
197 | o 5 b-1: b update
198 | |
198 | |
199 o | 4 a-2: e -move-> f
199 o | 4 a-2: e -move-> f
200 | |
200 | |
201 o | 3 a-1: d -move-> e
201 o | 3 a-1: d -move-> e
202 |/
202 |/
203 o 2 i-2: c -move-> d
203 o 2 i-2: c -move-> d
204 |
204 |
205 o 1 i-1: a -move-> c
205 o 1 i-1: a -move-> c
206 |
206 |
207 o 0 i-0 initial commit: a b h
207 o 0 i-0 initial commit: a b h
208
208
209
209
210
210
211 merging with the side having a delete
211 merging with the side having a delete
212 -------------------------------------
212 -------------------------------------
213
213
214 case summary:
214 case summary:
215 - one with change to an unrelated file
215 - one with change to an unrelated file
216 - one deleting the change
216 - one deleting the change
217 and recreate an unrelated file after the merge
217 and recreate an unrelated file after the merge
218
218
219 $ hg up 'desc("b-1")'
219 $ hg up 'desc("b-1")'
220 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
220 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
221 $ hg merge 'desc("c-1")'
221 $ hg merge 'desc("c-1")'
222 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
222 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
223 (branch merge, don't forget to commit)
223 (branch merge, don't forget to commit)
224 $ hg ci -m 'mBCm-0 simple merge - one way'
224 $ hg ci -m 'mBCm-0 simple merge - one way'
225 $ echo bar > d
225 $ echo bar > d
226 $ hg add d
226 $ hg add d
227 $ hg ci -m 'mBCm-1 re-add d'
227 $ hg ci -m 'mBCm-1 re-add d'
228 $ hg up 'desc("c-1")'
228 $ hg up 'desc("c-1")'
229 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
229 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
230 $ hg merge 'desc("b-1")'
230 $ hg merge 'desc("b-1")'
231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 (branch merge, don't forget to commit)
232 (branch merge, don't forget to commit)
233 $ hg ci -m 'mCBm-0 simple merge - the other way'
233 $ hg ci -m 'mCBm-0 simple merge - the other way'
234 created new head
234 created new head
235 $ echo bar > d
235 $ echo bar > d
236 $ hg add d
236 $ hg add d
237 $ hg ci -m 'mCBm-1 re-add d'
237 $ hg ci -m 'mCBm-1 re-add d'
238 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
238 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
239 @ 16 mCBm-1 re-add d
239 @ 16 mCBm-1 re-add d
240 |
240 |
241 o 15 mCBm-0 simple merge - the other way
241 o 15 mCBm-0 simple merge - the other way
242 |\
242 |\
243 | | o 14 mBCm-1 re-add d
243 | | o 14 mBCm-1 re-add d
244 | | |
244 | | |
245 +---o 13 mBCm-0 simple merge - one way
245 +---o 13 mBCm-0 simple merge - one way
246 | |/
246 | |/
247 | o 6 c-1 delete d
247 | o 6 c-1 delete d
248 | |
248 | |
249 o | 5 b-1: b update
249 o | 5 b-1: b update
250 |/
250 |/
251 o 2 i-2: c -move-> d
251 o 2 i-2: c -move-> d
252 |
252 |
253 o 1 i-1: a -move-> c
253 o 1 i-1: a -move-> c
254 |
254 |
255 o 0 i-0 initial commit: a b h
255 o 0 i-0 initial commit: a b h
256
256
257
257
258 Comparing with a merge re-adding the file afterward
258 Comparing with a merge re-adding the file afterward
259 ---------------------------------------------------
259 ---------------------------------------------------
260
260
261 Merge:
261 Merge:
262 - one with change to an unrelated file
262 - one with change to an unrelated file
263 - one deleting and recreating the change
263 - one deleting and recreating the change
264
264
265 $ hg up 'desc("b-1")'
265 $ hg up 'desc("b-1")'
266 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
267 $ hg merge 'desc("d-2")'
267 $ hg merge 'desc("d-2")'
268 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
268 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
269 (branch merge, don't forget to commit)
269 (branch merge, don't forget to commit)
270 $ hg ci -m 'mBDm-0 simple merge - one way'
270 $ hg ci -m 'mBDm-0 simple merge - one way'
271 $ hg up 'desc("d-2")'
271 $ hg up 'desc("d-2")'
272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
273 $ hg merge 'desc("b-1")'
273 $ hg merge 'desc("b-1")'
274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 (branch merge, don't forget to commit)
275 (branch merge, don't forget to commit)
276 $ hg ci -m 'mDBm-0 simple merge - the other way'
276 $ hg ci -m 'mDBm-0 simple merge - the other way'
277 created new head
277 created new head
278 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
278 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
279 @ 18 mDBm-0 simple merge - the other way
279 @ 18 mDBm-0 simple merge - the other way
280 |\
280 |\
281 +---o 17 mBDm-0 simple merge - one way
281 +---o 17 mBDm-0 simple merge - one way
282 | |/
282 | |/
283 | o 8 d-2 re-add d
283 | o 8 d-2 re-add d
284 | |
284 | |
285 | o 7 d-1 delete d
285 | o 7 d-1 delete d
286 | |
286 | |
287 o | 5 b-1: b update
287 o | 5 b-1: b update
288 |/
288 |/
289 o 2 i-2: c -move-> d
289 o 2 i-2: c -move-> d
290 |
290 |
291 o 1 i-1: a -move-> c
291 o 1 i-1: a -move-> c
292 |
292 |
293 o 0 i-0 initial commit: a b h
293 o 0 i-0 initial commit: a b h
294
294
295
295
296
296
297 Comparing with a merge with colliding rename
297 Comparing with a merge with colliding rename
298 --------------------------------------------
298 --------------------------------------------
299
299
300 - the "e-" branch renaming b to f (through 'g')
300 - the "e-" branch renaming b to f (through 'g')
301 - the "a-" branch renaming d to f (through e)
301 - the "a-" branch renaming d to f (through e)
302
302
303 $ hg up 'desc("a-2")'
303 $ hg up 'desc("a-2")'
304 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
304 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
305 $ hg merge 'desc("e-2")' --tool :union
305 $ hg merge 'desc("e-2")' --tool :union
306 merging f
306 merging f
307 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
307 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
308 (branch merge, don't forget to commit)
308 (branch merge, don't forget to commit)
309 $ hg ci -m 'mAEm-0 simple merge - one way'
309 $ hg ci -m 'mAEm-0 simple merge - one way'
310 $ hg up 'desc("e-2")'
310 $ hg up 'desc("e-2")'
311 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
311 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 $ hg merge 'desc("a-2")' --tool :union
312 $ hg merge 'desc("a-2")' --tool :union
313 merging f
313 merging f
314 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
314 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
315 (branch merge, don't forget to commit)
315 (branch merge, don't forget to commit)
316 $ hg ci -m 'mEAm-0 simple merge - the other way'
316 $ hg ci -m 'mEAm-0 simple merge - the other way'
317 created new head
317 created new head
318 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
318 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
319 @ 20 mEAm-0 simple merge - the other way
319 @ 20 mEAm-0 simple merge - the other way
320 |\
320 |\
321 +---o 19 mAEm-0 simple merge - one way
321 +---o 19 mAEm-0 simple merge - one way
322 | |/
322 | |/
323 | o 10 e-2 g -move-> f
323 | o 10 e-2 g -move-> f
324 | |
324 | |
325 | o 9 e-1 b -move-> g
325 | o 9 e-1 b -move-> g
326 | |
326 | |
327 o | 4 a-2: e -move-> f
327 o | 4 a-2: e -move-> f
328 | |
328 | |
329 o | 3 a-1: d -move-> e
329 o | 3 a-1: d -move-> e
330 |/
330 |/
331 o 2 i-2: c -move-> d
331 o 2 i-2: c -move-> d
332 |
332 |
333 o 1 i-1: a -move-> c
333 o 1 i-1: a -move-> c
334 |
334 |
335 o 0 i-0 initial commit: a b h
335 o 0 i-0 initial commit: a b h
336
336
337
337
338
338
339 Merge:
339 Merge:
340 - one with change to an unrelated file (b)
340 - one with change to an unrelated file (b)
341 - one overwriting a file (d) with a rename (from h to i to d)
341 - one overwriting a file (d) with a rename (from h to i to d)
342
342
343 $ hg up 'desc("i-2")'
343 $ hg up 'desc("i-2")'
344 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
344 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
345 $ hg mv h i
345 $ hg mv h i
346 $ hg commit -m "f-1: rename h -> i"
346 $ hg commit -m "f-1: rename h -> i"
347 created new head
347 created new head
348 $ hg mv --force i d
348 $ hg mv --force i d
349 $ hg commit -m "f-2: rename i -> d"
349 $ hg commit -m "f-2: rename i -> d"
350 $ hg debugindex d
350 $ hg debugindex d
351 rev linkrev nodeid p1 p2
351 rev linkrev nodeid p1 p2
352 0 2 169be882533b 000000000000 000000000000 (no-changeset !)
352 0 2 169be882533b 000000000000 000000000000 (no-changeset !)
353 0 2 b789fdd96dc2 000000000000 000000000000 (changeset !)
353 0 2 b789fdd96dc2 000000000000 000000000000 (changeset !)
354 1 8 b004912a8510 000000000000 000000000000
354 1 8 b004912a8510 000000000000 000000000000
355 2 22 4a067cf8965d 000000000000 000000000000 (no-changeset !)
355 2 22 4a067cf8965d 000000000000 000000000000 (no-changeset !)
356 2 22 fe6f8b4f507f 000000000000 000000000000 (changeset !)
356 2 22 fe6f8b4f507f 000000000000 000000000000 (changeset !)
357 $ hg up 'desc("b-1")'
357 $ hg up 'desc("b-1")'
358 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
358 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 $ hg merge 'desc("f-2")'
359 $ hg merge 'desc("f-2")'
360 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
360 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
361 (branch merge, don't forget to commit)
361 (branch merge, don't forget to commit)
362 $ hg ci -m 'mBFm-0 simple merge - one way'
362 $ hg ci -m 'mBFm-0 simple merge - one way'
363 $ hg up 'desc("f-2")'
363 $ hg up 'desc("f-2")'
364 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
364 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
365 $ hg merge 'desc("b-1")'
365 $ hg merge 'desc("b-1")'
366 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 (branch merge, don't forget to commit)
367 (branch merge, don't forget to commit)
368 $ hg ci -m 'mFBm-0 simple merge - the other way'
368 $ hg ci -m 'mFBm-0 simple merge - the other way'
369 created new head
369 created new head
370 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
370 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
371 @ 24 mFBm-0 simple merge - the other way
371 @ 24 mFBm-0 simple merge - the other way
372 |\
372 |\
373 +---o 23 mBFm-0 simple merge - one way
373 +---o 23 mBFm-0 simple merge - one way
374 | |/
374 | |/
375 | o 22 f-2: rename i -> d
375 | o 22 f-2: rename i -> d
376 | |
376 | |
377 | o 21 f-1: rename h -> i
377 | o 21 f-1: rename h -> i
378 | |
378 | |
379 o | 5 b-1: b update
379 o | 5 b-1: b update
380 |/
380 |/
381 o 2 i-2: c -move-> d
381 o 2 i-2: c -move-> d
382 |
382 |
383 o 1 i-1: a -move-> c
383 o 1 i-1: a -move-> c
384 |
384 |
385 o 0 i-0 initial commit: a b h
385 o 0 i-0 initial commit: a b h
386
386
387
387
388
388
389 Merge:
389 Merge:
390 - one with change to a file
390 - one with change to a file
391 - one deleting and recreating the file
391 - one deleting and recreating the file
392
392
393 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
393 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
394 consider history and rename on both branch of the merge.
394 consider history and rename on both branch of the merge.
395
395
396 $ hg up 'desc("i-2")'
396 $ hg up 'desc("i-2")'
397 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
397 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
398 $ echo "some update" >> d
398 $ echo "some update" >> d
399 $ hg commit -m "g-1: update d"
399 $ hg commit -m "g-1: update d"
400 created new head
400 created new head
401 $ hg up 'desc("d-2")'
401 $ hg up 'desc("d-2")'
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 $ hg merge 'desc("g-1")' --tool :union
403 $ hg merge 'desc("g-1")' --tool :union
404 merging d
404 merging d
405 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
405 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 (branch merge, don't forget to commit)
406 (branch merge, don't forget to commit)
407 $ hg ci -m 'mDGm-0 simple merge - one way'
407 $ hg ci -m 'mDGm-0 simple merge - one way'
408 $ hg up 'desc("g-1")'
408 $ hg up 'desc("g-1")'
409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 $ hg merge 'desc("d-2")' --tool :union
410 $ hg merge 'desc("d-2")' --tool :union
411 merging d
411 merging d
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 (branch merge, don't forget to commit)
413 (branch merge, don't forget to commit)
414 $ hg ci -m 'mGDm-0 simple merge - the other way'
414 $ hg ci -m 'mGDm-0 simple merge - the other way'
415 created new head
415 created new head
416 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
416 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
417 @ 27 mGDm-0 simple merge - the other way
417 @ 27 mGDm-0 simple merge - the other way
418 |\
418 |\
419 +---o 26 mDGm-0 simple merge - one way
419 +---o 26 mDGm-0 simple merge - one way
420 | |/
420 | |/
421 | o 25 g-1: update d
421 | o 25 g-1: update d
422 | |
422 | |
423 o | 8 d-2 re-add d
423 o | 8 d-2 re-add d
424 | |
424 | |
425 o | 7 d-1 delete d
425 o | 7 d-1 delete d
426 |/
426 |/
427 o 2 i-2: c -move-> d
427 o 2 i-2: c -move-> d
428 |
428 |
429 o 1 i-1: a -move-> c
429 o 1 i-1: a -move-> c
430 |
430 |
431 o 0 i-0 initial commit: a b h
431 o 0 i-0 initial commit: a b h
432
432
433
433
434
434
435 Merge:
435 Merge:
436 - one with change to a file (d)
436 - one with change to a file (d)
437 - one overwriting that file with a rename (from h to i, to d)
437 - one overwriting that file with a rename (from h to i, to d)
438
438
439 This case is similar to BF/FB, but an actual merge happens, so both side of the
439 This case is similar to BF/FB, but an actual merge happens, so both side of the
440 history are relevant.
440 history are relevant.
441
441
442 Note:
442 Note:
443 | In this case, the merge get conflicting information since on one side we have
443 | In this case, the merge get conflicting information since on one side we have
444 | "a -> c -> d". and one the other one we have "h -> i -> d".
444 | "a -> c -> d". and one the other one we have "h -> i -> d".
445 |
445 |
446 | The current code arbitrarily pick one side
446 | The current code arbitrarily pick one side
447
447
448 $ hg up 'desc("f-2")'
448 $ hg up 'desc("f-2")'
449 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
449 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
450 $ hg merge 'desc("g-1")' --tool :union
450 $ hg merge 'desc("g-1")' --tool :union
451 merging d
451 merging d
452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 (branch merge, don't forget to commit)
453 (branch merge, don't forget to commit)
454 $ hg ci -m 'mFGm-0 simple merge - one way'
454 $ hg ci -m 'mFGm-0 simple merge - one way'
455 created new head
455 created new head
456 $ hg up 'desc("g-1")'
456 $ hg up 'desc("g-1")'
457 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
458 $ hg merge 'desc("f-2")' --tool :union
458 $ hg merge 'desc("f-2")' --tool :union
459 merging d
459 merging d
460 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
460 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
461 (branch merge, don't forget to commit)
461 (branch merge, don't forget to commit)
462 $ hg ci -m 'mGFm-0 simple merge - the other way'
462 $ hg ci -m 'mGFm-0 simple merge - the other way'
463 created new head
463 created new head
464 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
464 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
465 @ 29 mGFm-0 simple merge - the other way
465 @ 29 mGFm-0 simple merge - the other way
466 |\
466 |\
467 +---o 28 mFGm-0 simple merge - one way
467 +---o 28 mFGm-0 simple merge - one way
468 | |/
468 | |/
469 | o 25 g-1: update d
469 | o 25 g-1: update d
470 | |
470 | |
471 o | 22 f-2: rename i -> d
471 o | 22 f-2: rename i -> d
472 | |
472 | |
473 o | 21 f-1: rename h -> i
473 o | 21 f-1: rename h -> i
474 |/
474 |/
475 o 2 i-2: c -move-> d
475 o 2 i-2: c -move-> d
476 |
476 |
477 o 1 i-1: a -move-> c
477 o 1 i-1: a -move-> c
478 |
478 |
479 o 0 i-0 initial commit: a b h
479 o 0 i-0 initial commit: a b h
480
480
481
481
482
482
483 Comparing with merging with a deletion (and keeping the file)
483 Comparing with merging with a deletion (and keeping the file)
484 -------------------------------------------------------------
484 -------------------------------------------------------------
485
485
486 Merge:
486 Merge:
487 - one removing a file (d)
487 - one removing a file (d)
488 - one updating that file
488 - one updating that file
489 - the merge keep the modified version of the file (canceling the delete)
489 - the merge keep the modified version of the file (canceling the delete)
490
490
491 In this case, the file keep on living after the merge. So we should not drop its
491 In this case, the file keep on living after the merge. So we should not drop its
492 copy tracing chain.
492 copy tracing chain.
493
493
494 $ hg up 'desc("c-1")'
494 $ hg up 'desc("c-1")'
495 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
495 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
496 $ hg merge 'desc("g-1")'
496 $ hg merge 'desc("g-1")'
497 file 'd' was deleted in local [working copy] but was modified in other [merge rev].
497 file 'd' was deleted in local [working copy] but was modified in other [merge rev].
498 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
498 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
499 What do you want to do? u
499 What do you want to do? u
500 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
500 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
501 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
501 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
502 [1]
502 [1]
503 $ hg resolve -t :other d
503 $ hg resolve -t :other d
504 (no more unresolved files)
504 (no more unresolved files)
505 $ hg ci -m "mCGm-0"
505 $ hg ci -m "mCGm-0"
506 created new head
506 created new head
507
507
508 $ hg up 'desc("g-1")'
508 $ hg up 'desc("g-1")'
509 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
509 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 $ hg merge 'desc("c-1")'
510 $ hg merge 'desc("c-1")'
511 file 'd' was deleted in other [merge rev] but was modified in local [working copy].
511 file 'd' was deleted in other [merge rev] but was modified in local [working copy].
512 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
512 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
513 What do you want to do? u
513 What do you want to do? u
514 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
514 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
515 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
515 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
516 [1]
516 [1]
517 $ hg resolve -t :local d
517 $ hg resolve -t :local d
518 (no more unresolved files)
518 (no more unresolved files)
519 $ hg ci -m "mGCm-0"
519 $ hg ci -m "mGCm-0"
520 created new head
520 created new head
521
521
522 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
522 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
523 @ 31 mGCm-0
523 @ 31 mGCm-0
524 |\
524 |\
525 +---o 30 mCGm-0
525 +---o 30 mCGm-0
526 | |/
526 | |/
527 | o 25 g-1: update d
527 | o 25 g-1: update d
528 | |
528 | |
529 o | 6 c-1 delete d
529 o | 6 c-1 delete d
530 |/
530 |/
531 o 2 i-2: c -move-> d
531 o 2 i-2: c -move-> d
532 |
532 |
533 o 1 i-1: a -move-> c
533 o 1 i-1: a -move-> c
534 |
534 |
535 o 0 i-0 initial commit: a b h
535 o 0 i-0 initial commit: a b h
536
536
537
537
538
538
539
539
540 Comparing with merge restoring an untouched deleted file
540 Comparing with merge restoring an untouched deleted file
541 --------------------------------------------------------
541 --------------------------------------------------------
542
542
543 Merge:
543 Merge:
544 - one removing a file (d)
544 - one removing a file (d)
545 - one leaving the file untouched
545 - one leaving the file untouched
546 - the merge actively restore the file to the same content.
546 - the merge actively restore the file to the same content.
547
547
548 In this case, the file keep on living after the merge. So we should not drop its
548 In this case, the file keep on living after the merge. So we should not drop its
549 copy tracing chain.
549 copy tracing chain.
550
550
551 $ hg up 'desc("c-1")'
551 $ hg up 'desc("c-1")'
552 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
552 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
553 $ hg merge 'desc("b-1")'
553 $ hg merge 'desc("b-1")'
554 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
554 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
555 (branch merge, don't forget to commit)
555 (branch merge, don't forget to commit)
556 $ hg revert --rev 'desc("b-1")' d
556 $ hg revert --rev 'desc("b-1")' d
557 $ hg ci -m "mCB-revert-m-0"
557 $ hg ci -m "mCB-revert-m-0"
558 created new head
558 created new head
559
559
560 $ hg up 'desc("b-1")'
560 $ hg up 'desc("b-1")'
561 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
561 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
562 $ hg merge 'desc("c-1")'
562 $ hg merge 'desc("c-1")'
563 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
563 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
564 (branch merge, don't forget to commit)
564 (branch merge, don't forget to commit)
565 $ hg revert --rev 'desc("b-1")' d
565 $ hg revert --rev 'desc("b-1")' d
566 $ hg ci -m "mBC-revert-m-0"
566 $ hg ci -m "mBC-revert-m-0"
567 created new head
567 created new head
568
568
569 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
569 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
570 @ 33 mBC-revert-m-0
570 @ 33 mBC-revert-m-0
571 |\
571 |\
572 +---o 32 mCB-revert-m-0
572 +---o 32 mCB-revert-m-0
573 | |/
573 | |/
574 | o 6 c-1 delete d
574 | o 6 c-1 delete d
575 | |
575 | |
576 o | 5 b-1: b update
576 o | 5 b-1: b update
577 |/
577 |/
578 o 2 i-2: c -move-> d
578 o 2 i-2: c -move-> d
579 |
579 |
580 o 1 i-1: a -move-> c
580 o 1 i-1: a -move-> c
581 |
581 |
582 o 0 i-0 initial commit: a b h
582 o 0 i-0 initial commit: a b h
583
583
584
584
585
585
586 $ hg up null --quiet
586 $ hg up null --quiet
587
587
588 Merging a branch where a rename was deleted with a branch where the same file was renamed
589 ------------------------------------------------------------------------------------------
590
591 Create a "conflicting" merge where `d` get removed on one branch before its
592 rename information actually conflict with the other branch.
593
594 (the copy information from the branch that was not deleted should win).
595
596 $ hg up 'desc("i-0")'
597 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
598 $ hg mv b d
599 $ hg ci -m "h-1: b -(move)-> d"
600 created new head
601
602 $ hg up 'desc("c-1")'
603 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
604 $ hg merge 'desc("h-1")'
605 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
606 (branch merge, don't forget to commit)
607 $ hg ci -m "mCH-delete-before-conflict-m-0"
608
609 $ hg up 'desc("h-1")'
610 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
611 $ hg merge 'desc("c-1")'
612 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
613 (branch merge, don't forget to commit)
614 $ hg ci -m "mHC-delete-before-conflict-m-0"
615 created new head
616 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
617 @ 36 mHC-delete-before-conflict-m-0
618 |\
619 +---o 35 mCH-delete-before-conflict-m-0
620 | |/
621 | o 34 h-1: b -(move)-> d
622 | |
623 o | 6 c-1 delete d
624 | |
625 o | 2 i-2: c -move-> d
626 | |
627 o | 1 i-1: a -move-> c
628 |/
629 o 0 i-0 initial commit: a b h
630
631
588
632
589 Test that sidedata computations during upgrades are correct
633 Test that sidedata computations during upgrades are correct
590 ===========================================================
634 ===========================================================
591
635
592 We upgrade a repository that is not using sidedata (the filelog case) and
636 We upgrade a repository that is not using sidedata (the filelog case) and
593 check that the same side data have been generated as if they were computed at
637 check that the same side data have been generated as if they were computed at
594 commit time.
638 commit time.
595
639
596
640
597 #if upgraded
641 #if upgraded
598 $ cat >> $HGRCPATH << EOF
642 $ cat >> $HGRCPATH << EOF
599 > [format]
643 > [format]
600 > exp-use-side-data = yes
644 > exp-use-side-data = yes
601 > exp-use-copies-side-data-changeset = yes
645 > exp-use-copies-side-data-changeset = yes
602 > EOF
646 > EOF
603 $ hg debugformat -v
647 $ hg debugformat -v
604 format-variant repo config default
648 format-variant repo config default
605 fncache: yes yes yes
649 fncache: yes yes yes
606 dotencode: yes yes yes
650 dotencode: yes yes yes
607 generaldelta: yes yes yes
651 generaldelta: yes yes yes
608 sparserevlog: yes yes yes
652 sparserevlog: yes yes yes
609 sidedata: no yes no
653 sidedata: no yes no
610 persistent-nodemap: no no no
654 persistent-nodemap: no no no
611 copies-sdc: no yes no
655 copies-sdc: no yes no
612 plain-cl-delta: yes yes yes
656 plain-cl-delta: yes yes yes
613 compression: * (glob)
657 compression: * (glob)
614 compression-level: default default default
658 compression-level: default default default
615 $ hg debugupgraderepo --run --quiet
659 $ hg debugupgraderepo --run --quiet
616 upgrade will perform the following actions:
660 upgrade will perform the following actions:
617
661
618 requirements
662 requirements
619 preserved: * (glob)
663 preserved: * (glob)
620 added: exp-copies-sidedata-changeset, exp-sidedata-flag
664 added: exp-copies-sidedata-changeset, exp-sidedata-flag
621
665
622 #endif
666 #endif
623
667
624
668
625 #if no-compatibility no-filelog no-changeset
669 #if no-compatibility no-filelog no-changeset
626
670
627 $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do
671 $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do
628 > echo "##### revision $rev #####"
672 > echo "##### revision $rev #####"
629 > hg debugsidedata -c -v -- $rev
673 > hg debugsidedata -c -v -- $rev
630 > hg debugchangedfiles $rev
674 > hg debugchangedfiles $rev
631 > done
675 > done
632 ##### revision 0 #####
676 ##### revision 0 #####
633 1 sidedata entries
677 1 sidedata entries
634 entry-0014 size 34
678 entry-0014 size 34
635 '\x00\x00\x00\x03\x04\x00\x00\x00\x01\x00\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00abh'
679 '\x00\x00\x00\x03\x04\x00\x00\x00\x01\x00\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00abh'
636 added : a, ;
680 added : a, ;
637 added : b, ;
681 added : b, ;
638 added : h, ;
682 added : h, ;
639 ##### revision 1 #####
683 ##### revision 1 #####
640 1 sidedata entries
684 1 sidedata entries
641 entry-0014 size 24
685 entry-0014 size 24
642 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ac'
686 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ac'
643 removed : a, ;
687 removed : a, ;
644 added p1: c, a;
688 added p1: c, a;
645 ##### revision 2 #####
689 ##### revision 2 #####
646 1 sidedata entries
690 1 sidedata entries
647 entry-0014 size 24
691 entry-0014 size 24
648 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00cd'
692 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00cd'
649 removed : c, ;
693 removed : c, ;
650 added p1: d, c;
694 added p1: d, c;
651 ##### revision 3 #####
695 ##### revision 3 #####
652 1 sidedata entries
696 1 sidedata entries
653 entry-0014 size 24
697 entry-0014 size 24
654 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de'
698 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de'
655 removed : d, ;
699 removed : d, ;
656 added p1: e, d;
700 added p1: e, d;
657 ##### revision 4 #####
701 ##### revision 4 #####
658 1 sidedata entries
702 1 sidedata entries
659 entry-0014 size 24
703 entry-0014 size 24
660 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef'
704 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef'
661 removed : e, ;
705 removed : e, ;
662 added p1: f, e;
706 added p1: f, e;
663 ##### revision 5 #####
707 ##### revision 5 #####
664 1 sidedata entries
708 1 sidedata entries
665 entry-0014 size 14
709 entry-0014 size 14
666 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b'
710 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b'
667 touched : b, ;
711 touched : b, ;
668 ##### revision 6 #####
712 ##### revision 6 #####
669 1 sidedata entries
713 1 sidedata entries
670 entry-0014 size 14
714 entry-0014 size 14
671 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
715 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
672 removed : d, ;
716 removed : d, ;
673 ##### revision 7 #####
717 ##### revision 7 #####
674 1 sidedata entries
718 1 sidedata entries
675 entry-0014 size 14
719 entry-0014 size 14
676 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
720 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
677 removed : d, ;
721 removed : d, ;
678 ##### revision 8 #####
722 ##### revision 8 #####
679 1 sidedata entries
723 1 sidedata entries
680 entry-0014 size 14
724 entry-0014 size 14
681 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
725 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
682 added : d, ;
726 added : d, ;
683 ##### revision 9 #####
727 ##### revision 9 #####
684 1 sidedata entries
728 1 sidedata entries
685 entry-0014 size 24
729 entry-0014 size 24
686 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg'
730 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg'
687 removed : b, ;
731 removed : b, ;
688 added p1: g, b;
732 added p1: g, b;
689 ##### revision 10 #####
733 ##### revision 10 #####
690 1 sidedata entries
734 1 sidedata entries
691 entry-0014 size 24
735 entry-0014 size 24
692 '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg'
736 '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg'
693 added p1: f, g;
737 added p1: f, g;
694 removed : g, ;
738 removed : g, ;
695 ##### revision 11 #####
739 ##### revision 11 #####
696 1 sidedata entries
740 1 sidedata entries
697 entry-0014 size 4
741 entry-0014 size 4
698 '\x00\x00\x00\x00'
742 '\x00\x00\x00\x00'
699 ##### revision 12 #####
743 ##### revision 12 #####
700 1 sidedata entries
744 1 sidedata entries
701 entry-0014 size 4
745 entry-0014 size 4
702 '\x00\x00\x00\x00'
746 '\x00\x00\x00\x00'
703 ##### revision 13 #####
747 ##### revision 13 #####
704 1 sidedata entries
748 1 sidedata entries
705 entry-0014 size 4
749 entry-0014 size 4
706 '\x00\x00\x00\x00'
750 '\x00\x00\x00\x00'
707 ##### revision 14 #####
751 ##### revision 14 #####
708 1 sidedata entries
752 1 sidedata entries
709 entry-0014 size 14
753 entry-0014 size 14
710 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
754 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
711 added : d, ;
755 added : d, ;
712 ##### revision 15 #####
756 ##### revision 15 #####
713 1 sidedata entries
757 1 sidedata entries
714 entry-0014 size 4
758 entry-0014 size 4
715 '\x00\x00\x00\x00'
759 '\x00\x00\x00\x00'
716 ##### revision 16 #####
760 ##### revision 16 #####
717 1 sidedata entries
761 1 sidedata entries
718 entry-0014 size 14
762 entry-0014 size 14
719 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
763 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
720 added : d, ;
764 added : d, ;
721 ##### revision 17 #####
765 ##### revision 17 #####
722 1 sidedata entries
766 1 sidedata entries
723 entry-0014 size 4
767 entry-0014 size 4
724 '\x00\x00\x00\x00'
768 '\x00\x00\x00\x00'
725 ##### revision 18 #####
769 ##### revision 18 #####
726 1 sidedata entries
770 1 sidedata entries
727 entry-0014 size 4
771 entry-0014 size 4
728 '\x00\x00\x00\x00'
772 '\x00\x00\x00\x00'
729 ##### revision 19 #####
773 ##### revision 19 #####
730 1 sidedata entries
774 1 sidedata entries
731 entry-0014 size 14
775 entry-0014 size 14
732 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
776 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
733 merged : f, ;
777 merged : f, ;
734 ##### revision 20 #####
778 ##### revision 20 #####
735 1 sidedata entries
779 1 sidedata entries
736 entry-0014 size 14
780 entry-0014 size 14
737 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
781 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
738 merged : f, ;
782 merged : f, ;
739 ##### revision 21 #####
783 ##### revision 21 #####
740 1 sidedata entries
784 1 sidedata entries
741 entry-0014 size 24
785 entry-0014 size 24
742 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi'
786 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi'
743 removed : h, ;
787 removed : h, ;
744 added p1: i, h;
788 added p1: i, h;
745 ##### revision 22 #####
789 ##### revision 22 #####
746 1 sidedata entries
790 1 sidedata entries
747 entry-0014 size 24
791 entry-0014 size 24
748 '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di'
792 '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di'
749 touched p1: d, i;
793 touched p1: d, i;
750 removed : i, ;
794 removed : i, ;
751 ##### revision 23 #####
795 ##### revision 23 #####
752 1 sidedata entries
796 1 sidedata entries
753 entry-0014 size 4
797 entry-0014 size 4
754 '\x00\x00\x00\x00'
798 '\x00\x00\x00\x00'
755 ##### revision 24 #####
799 ##### revision 24 #####
756 1 sidedata entries
800 1 sidedata entries
757 entry-0014 size 4
801 entry-0014 size 4
758 '\x00\x00\x00\x00'
802 '\x00\x00\x00\x00'
759 ##### revision 25 #####
803 ##### revision 25 #####
760 1 sidedata entries
804 1 sidedata entries
761 entry-0014 size 14
805 entry-0014 size 14
762 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
806 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
763 touched : d, ;
807 touched : d, ;
764 ##### revision 26 #####
808 ##### revision 26 #####
765 1 sidedata entries
809 1 sidedata entries
766 entry-0014 size 14
810 entry-0014 size 14
767 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
811 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
768 merged : d, ;
812 merged : d, ;
769 ##### revision 27 #####
813 ##### revision 27 #####
770 1 sidedata entries
814 1 sidedata entries
771 entry-0014 size 14
815 entry-0014 size 14
772 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
816 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
773 merged : d, ;
817 merged : d, ;
774 ##### revision 28 #####
818 ##### revision 28 #####
775 1 sidedata entries
819 1 sidedata entries
776 entry-0014 size 14
820 entry-0014 size 14
777 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
821 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
778 merged : d, ;
822 merged : d, ;
779 ##### revision 29 #####
823 ##### revision 29 #####
780 1 sidedata entries
824 1 sidedata entries
781 entry-0014 size 14
825 entry-0014 size 14
782 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
826 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
783 merged : d, ;
827 merged : d, ;
784 ##### revision 30 #####
828 ##### revision 30 #####
785 1 sidedata entries
829 1 sidedata entries
786 entry-0014 size 14
830 entry-0014 size 14
787 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
831 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
788 salvaged : d, ;
832 salvaged : d, ;
789 ##### revision 31 #####
833 ##### revision 31 #####
790 1 sidedata entries
834 1 sidedata entries
791 entry-0014 size 14
835 entry-0014 size 14
792 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
836 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
793 salvaged : d, ;
837 salvaged : d, ;
794 ##### revision 32 #####
838 ##### revision 32 #####
795 1 sidedata entries
839 1 sidedata entries
796 entry-0014 size 14
840 entry-0014 size 14
797 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
841 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
798 salvaged : d, ;
842 salvaged : d, ;
799 ##### revision 33 #####
843 ##### revision 33 #####
800 1 sidedata entries
844 1 sidedata entries
801 entry-0014 size 14
845 entry-0014 size 14
802 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
846 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
803 salvaged : d, ;
847 salvaged : d, ;
848 ##### revision 34 #####
849 1 sidedata entries
850 entry-0014 size 24
851 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bd'
852 removed : b, ;
853 added p1: d, b;
854 ##### revision 35 #####
855 1 sidedata entries
856 entry-0014 size 4
857 '\x00\x00\x00\x00'
858 ##### revision 36 #####
859 1 sidedata entries
860 entry-0014 size 4
861 '\x00\x00\x00\x00'
804
862
805 #endif
863 #endif
806
864
807
865
808 Test copy information chaining
866 Test copy information chaining
809 ==============================
867 ==============================
810
868
811 merging with unrelated change does not interfere with the renames
869 merging with unrelated change does not interfere with the renames
812 ---------------------------------------------------------------
870 ---------------------------------------------------------------
813
871
814 - rename on one side
872 - rename on one side
815 - unrelated change on the other side
873 - unrelated change on the other side
816
874
817 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
875 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
818 o 12 mABm-0 simple merge - the other way
876 o 12 mABm-0 simple merge - the other way
819 |\
877 |\
820 +---o 11 mBAm-0 simple merge - one way
878 +---o 11 mBAm-0 simple merge - one way
821 | |/
879 | |/
822 | o 5 b-1: b update
880 | o 5 b-1: b update
823 | |
881 | |
824 o | 4 a-2: e -move-> f
882 o | 4 a-2: e -move-> f
825 | |
883 | |
826 o | 3 a-1: d -move-> e
884 o | 3 a-1: d -move-> e
827 |/
885 |/
828 o 2 i-2: c -move-> d
886 o 2 i-2: c -move-> d
829 |
887 |
830 o 1 i-1: a -move-> c
888 o 1 i-1: a -move-> c
831 |
889 |
832 o 0 i-0 initial commit: a b h
890 o 0 i-0 initial commit: a b h
833
891
834
892
835 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")'
893 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")'
836 A f
894 A f
837 d
895 d
838 R d
896 R d
839 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")'
897 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")'
840 A f
898 A f
841 d
899 d
842 R d
900 R d
843 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")'
901 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")'
844 M b
902 M b
845 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")'
903 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")'
846 M b
904 M b
847 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")'
905 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")'
848 M b
906 M b
849 A f
907 A f
850 d
908 d
851 R d
909 R d
852 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")'
910 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")'
853 M b
911 M b
854 A f
912 A f
855 d
913 d
856 R d
914 R d
857 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")'
915 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")'
858 M b
916 M b
859 A f
917 A f
860 a
918 a
861 R a
919 R a
862 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")'
920 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")'
863 M b
921 M b
864 A f
922 A f
865 a
923 a
866 R a
924 R a
867
925
868 merging with the side having a delete
926 merging with the side having a delete
869 -------------------------------------
927 -------------------------------------
870
928
871 case summary:
929 case summary:
872 - one with change to an unrelated file
930 - one with change to an unrelated file
873 - one deleting the change
931 - one deleting the change
874 and recreate an unrelated file after the merge
932 and recreate an unrelated file after the merge
875
933
876 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
934 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
877 o 16 mCBm-1 re-add d
935 o 16 mCBm-1 re-add d
878 |
936 |
879 o 15 mCBm-0 simple merge - the other way
937 o 15 mCBm-0 simple merge - the other way
880 |\
938 |\
881 | | o 14 mBCm-1 re-add d
939 | | o 14 mBCm-1 re-add d
882 | | |
940 | | |
883 +---o 13 mBCm-0 simple merge - one way
941 +---o 13 mBCm-0 simple merge - one way
884 | |/
942 | |/
885 | o 6 c-1 delete d
943 | o 6 c-1 delete d
886 | |
944 | |
887 o | 5 b-1: b update
945 o | 5 b-1: b update
888 |/
946 |/
889 o 2 i-2: c -move-> d
947 o 2 i-2: c -move-> d
890 |
948 |
891 o 1 i-1: a -move-> c
949 o 1 i-1: a -move-> c
892 |
950 |
893 o 0 i-0 initial commit: a b h
951 o 0 i-0 initial commit: a b h
894
952
895 - comparing from the merge
953 - comparing from the merge
896
954
897 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")'
955 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")'
898 R d
956 R d
899 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")'
957 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")'
900 R d
958 R d
901 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")'
959 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")'
902 M b
960 M b
903 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")'
961 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")'
904 M b
962 M b
905 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")'
963 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")'
906 M b
964 M b
907 R d
965 R d
908 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")'
966 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")'
909 M b
967 M b
910 R d
968 R d
911 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")'
969 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")'
912 M b
970 M b
913 R a
971 R a
914 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")'
972 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")'
915 M b
973 M b
916 R a
974 R a
917
975
918 - comparing with the merge children re-adding the file
976 - comparing with the merge children re-adding the file
919
977
920 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")'
978 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")'
921 M d
979 M d
922 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")'
980 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")'
923 M d
981 M d
924 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")'
982 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")'
925 M b
983 M b
926 A d
984 A d
927 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")'
985 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")'
928 M b
986 M b
929 A d
987 A d
930 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")'
988 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")'
931 M b
989 M b
932 M d
990 M d
933 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")'
991 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")'
934 M b
992 M b
935 M d
993 M d
936 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")'
994 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")'
937 M b
995 M b
938 A d
996 A d
939 R a
997 R a
940 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")'
998 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")'
941 M b
999 M b
942 A d
1000 A d
943 R a
1001 R a
944
1002
945 Comparing with a merge re-adding the file afterward
1003 Comparing with a merge re-adding the file afterward
946 ---------------------------------------------------
1004 ---------------------------------------------------
947
1005
948 Merge:
1006 Merge:
949 - one with change to an unrelated file
1007 - one with change to an unrelated file
950 - one deleting and recreating the change
1008 - one deleting and recreating the change
951
1009
952 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
1010 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
953 o 18 mDBm-0 simple merge - the other way
1011 o 18 mDBm-0 simple merge - the other way
954 |\
1012 |\
955 +---o 17 mBDm-0 simple merge - one way
1013 +---o 17 mBDm-0 simple merge - one way
956 | |/
1014 | |/
957 | o 8 d-2 re-add d
1015 | o 8 d-2 re-add d
958 | |
1016 | |
959 | o 7 d-1 delete d
1017 | o 7 d-1 delete d
960 | |
1018 | |
961 o | 5 b-1: b update
1019 o | 5 b-1: b update
962 |/
1020 |/
963 o 2 i-2: c -move-> d
1021 o 2 i-2: c -move-> d
964 |
1022 |
965 o 1 i-1: a -move-> c
1023 o 1 i-1: a -move-> c
966 |
1024 |
967 o 0 i-0 initial commit: a b h
1025 o 0 i-0 initial commit: a b h
968
1026
969 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")'
1027 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")'
970 M d
1028 M d
971 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")'
1029 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")'
972 M d
1030 M d
973 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")'
1031 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")'
974 M b
1032 M b
975 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")'
1033 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")'
976 M b
1034 M b
977 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")'
1035 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")'
978 M b
1036 M b
979 M d
1037 M d
980 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")'
1038 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")'
981 M b
1039 M b
982 M d
1040 M d
983
1041
984 The bugs makes recorded copy is different depending of where we started the merge from since
1042 The bugs makes recorded copy is different depending of where we started the merge from since
985
1043
986 $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d'
1044 $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d'
987 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1045 b004912a8510032a0350a74daa2803dadfb00e12 644 d
988 $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d'
1046 $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d'
989 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1047 b004912a8510032a0350a74daa2803dadfb00e12 644 d
990
1048
991 $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d'
1049 $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d'
992 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1050 b004912a8510032a0350a74daa2803dadfb00e12 644 d
993 $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d'
1051 $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d'
994 169be882533bc917905d46c0c951aa9a1e288dcf 644 d (no-changeset !)
1052 169be882533bc917905d46c0c951aa9a1e288dcf 644 d (no-changeset !)
995 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 d (changeset !)
1053 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 d (changeset !)
996 $ hg debugindex d | head -n 4
1054 $ hg debugindex d | head -n 4
997 rev linkrev nodeid p1 p2
1055 rev linkrev nodeid p1 p2
998 0 2 169be882533b 000000000000 000000000000 (no-changeset !)
1056 0 2 169be882533b 000000000000 000000000000 (no-changeset !)
999 0 2 b789fdd96dc2 000000000000 000000000000 (changeset !)
1057 0 2 b789fdd96dc2 000000000000 000000000000 (changeset !)
1000 1 8 b004912a8510 000000000000 000000000000
1058 1 8 b004912a8510 000000000000 000000000000
1001 2 22 4a067cf8965d 000000000000 000000000000 (no-changeset !)
1059 2 22 4a067cf8965d 000000000000 000000000000 (no-changeset !)
1002 2 22 fe6f8b4f507f 000000000000 000000000000 (changeset !)
1060 2 22 fe6f8b4f507f 000000000000 000000000000 (changeset !)
1003
1061
1004 Log output should not include a merge commit as it did not happen
1062 Log output should not include a merge commit as it did not happen
1005
1063
1006 $ hg log -Gfr 'desc("mBDm-0")' d
1064 $ hg log -Gfr 'desc("mBDm-0")' d
1007 o 8 d-2 re-add d
1065 o 8 d-2 re-add d
1008 |
1066 |
1009 ~
1067 ~
1010
1068
1011 $ hg log -Gfr 'desc("mDBm-0")' d
1069 $ hg log -Gfr 'desc("mDBm-0")' d
1012 o 8 d-2 re-add d
1070 o 8 d-2 re-add d
1013 |
1071 |
1014 ~
1072 ~
1015
1073
1016 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")'
1074 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")'
1017 M b
1075 M b
1018 A d
1076 A d
1019 R a
1077 R a
1020 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")'
1078 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")'
1021 M b
1079 M b
1022 A d
1080 A d
1023 R a
1081 R a
1024
1082
1025
1083
1026 Comparing with a merge with colliding rename
1084 Comparing with a merge with colliding rename
1027 --------------------------------------------
1085 --------------------------------------------
1028
1086
1029 - the "e-" branch renaming b to f (through 'g')
1087 - the "e-" branch renaming b to f (through 'g')
1030 - the "a-" branch renaming d to f (through e)
1088 - the "a-" branch renaming d to f (through e)
1031
1089
1032 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
1090 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
1033 o 20 mEAm-0 simple merge - the other way
1091 o 20 mEAm-0 simple merge - the other way
1034 |\
1092 |\
1035 +---o 19 mAEm-0 simple merge - one way
1093 +---o 19 mAEm-0 simple merge - one way
1036 | |/
1094 | |/
1037 | o 10 e-2 g -move-> f
1095 | o 10 e-2 g -move-> f
1038 | |
1096 | |
1039 | o 9 e-1 b -move-> g
1097 | o 9 e-1 b -move-> g
1040 | |
1098 | |
1041 o | 4 a-2: e -move-> f
1099 o | 4 a-2: e -move-> f
1042 | |
1100 | |
1043 o | 3 a-1: d -move-> e
1101 o | 3 a-1: d -move-> e
1044 |/
1102 |/
1045 o 2 i-2: c -move-> d
1103 o 2 i-2: c -move-> d
1046 |
1104 |
1047 o 1 i-1: a -move-> c
1105 o 1 i-1: a -move-> c
1048 |
1106 |
1049 o 0 i-0 initial commit: a b h
1107 o 0 i-0 initial commit: a b h
1050
1108
1051 #if no-changeset
1109 #if no-changeset
1052 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
1110 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
1053 c39c6083dad048d5138618a46f123e2f397f4f18 644 f
1111 c39c6083dad048d5138618a46f123e2f397f4f18 644 f
1054 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
1112 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
1055 a9a8bc3860c9d8fa5f2f7e6ea8d40498322737fd 644 f
1113 a9a8bc3860c9d8fa5f2f7e6ea8d40498322737fd 644 f
1056 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
1114 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
1057 263ea25e220aaeb7b9bac551c702037849aa75e8 644 f
1115 263ea25e220aaeb7b9bac551c702037849aa75e8 644 f
1058 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
1116 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
1059 71b9b7e73d973572ade6dd765477fcee6890e8b1 644 f
1117 71b9b7e73d973572ade6dd765477fcee6890e8b1 644 f
1060 $ hg debugindex f
1118 $ hg debugindex f
1061 rev linkrev nodeid p1 p2
1119 rev linkrev nodeid p1 p2
1062 0 4 263ea25e220a 000000000000 000000000000
1120 0 4 263ea25e220a 000000000000 000000000000
1063 1 10 71b9b7e73d97 000000000000 000000000000
1121 1 10 71b9b7e73d97 000000000000 000000000000
1064 2 19 c39c6083dad0 263ea25e220a 71b9b7e73d97
1122 2 19 c39c6083dad0 263ea25e220a 71b9b7e73d97
1065 3 20 a9a8bc3860c9 71b9b7e73d97 263ea25e220a
1123 3 20 a9a8bc3860c9 71b9b7e73d97 263ea25e220a
1066 #else
1124 #else
1067 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
1125 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
1068 498e8799f49f9da1ca06bb2d6d4accf165c5b572 644 f
1126 498e8799f49f9da1ca06bb2d6d4accf165c5b572 644 f
1069 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
1127 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
1070 c5b506a7118667a38a9c9348a1f63b679e382f57 644 f
1128 c5b506a7118667a38a9c9348a1f63b679e382f57 644 f
1071 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
1129 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
1072 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 f
1130 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 f
1073 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
1131 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
1074 1e88685f5ddec574a34c70af492f95b6debc8741 644 f
1132 1e88685f5ddec574a34c70af492f95b6debc8741 644 f
1075 $ hg debugindex f
1133 $ hg debugindex f
1076 rev linkrev nodeid p1 p2
1134 rev linkrev nodeid p1 p2
1077 0 4 b789fdd96dc2 000000000000 000000000000
1135 0 4 b789fdd96dc2 000000000000 000000000000
1078 1 10 1e88685f5dde 000000000000 000000000000
1136 1 10 1e88685f5dde 000000000000 000000000000
1079 2 19 498e8799f49f b789fdd96dc2 1e88685f5dde
1137 2 19 498e8799f49f b789fdd96dc2 1e88685f5dde
1080 3 20 c5b506a71186 1e88685f5dde b789fdd96dc2
1138 3 20 c5b506a71186 1e88685f5dde b789fdd96dc2
1081 #endif
1139 #endif
1082
1140
1083 # Here the filelog based implementation is not looking at the rename
1141 # Here the filelog based implementation is not looking at the rename
1084 # information (because the file exist on both side). However the changelog
1142 # information (because the file exist on both side). However the changelog
1085 # based on works fine. We have different output.
1143 # based on works fine. We have different output.
1086
1144
1087 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")'
1145 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")'
1088 M f
1146 M f
1089 b (no-filelog !)
1147 b (no-filelog !)
1090 R b
1148 R b
1091 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")'
1149 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")'
1092 M f
1150 M f
1093 b (no-filelog !)
1151 b (no-filelog !)
1094 R b
1152 R b
1095 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")'
1153 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")'
1096 M f
1154 M f
1097 d (no-filelog !)
1155 d (no-filelog !)
1098 R d
1156 R d
1099 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")'
1157 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")'
1100 M f
1158 M f
1101 d (no-filelog !)
1159 d (no-filelog !)
1102 R d
1160 R d
1103 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")'
1161 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")'
1104 A f
1162 A f
1105 d
1163 d
1106 R d
1164 R d
1107 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")'
1165 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")'
1108 A f
1166 A f
1109 b
1167 b
1110 R b
1168 R b
1111
1169
1112 # From here, we run status against revision where both source file exists.
1170 # From here, we run status against revision where both source file exists.
1113 #
1171 #
1114 # The filelog based implementation picks an arbitrary side based on revision
1172 # The filelog based implementation picks an arbitrary side based on revision
1115 # numbers. So the same side "wins" whatever the parents order is. This is
1173 # numbers. So the same side "wins" whatever the parents order is. This is
1116 # sub-optimal because depending on revision numbers means the result can be
1174 # sub-optimal because depending on revision numbers means the result can be
1117 # different from one repository to the next.
1175 # different from one repository to the next.
1118 #
1176 #
1119 # The changeset based algorithm use the parent order to break tie on conflicting
1177 # The changeset based algorithm use the parent order to break tie on conflicting
1120 # information and will have a different order depending on who is p1 and p2.
1178 # information and will have a different order depending on who is p1 and p2.
1121 # That order is stable accross repositories. (data from p1 prevails)
1179 # That order is stable accross repositories. (data from p1 prevails)
1122
1180
1123 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")'
1181 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")'
1124 A f
1182 A f
1125 d
1183 d
1126 R b
1184 R b
1127 R d
1185 R d
1128 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")'
1186 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")'
1129 A f
1187 A f
1130 d (filelog !)
1188 d (filelog !)
1131 b (no-filelog !)
1189 b (no-filelog !)
1132 R b
1190 R b
1133 R d
1191 R d
1134 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")'
1192 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")'
1135 A f
1193 A f
1136 a
1194 a
1137 R a
1195 R a
1138 R b
1196 R b
1139 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")'
1197 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")'
1140 A f
1198 A f
1141 a (filelog !)
1199 a (filelog !)
1142 b (no-filelog !)
1200 b (no-filelog !)
1143 R a
1201 R a
1144 R b
1202 R b
1145
1203
1146
1204
1147 Note:
1205 Note:
1148 | In this case, one of the merge wrongly record a merge while there is none.
1206 | In this case, one of the merge wrongly record a merge while there is none.
1149 | This lead to bad copy tracing information to be dug up.
1207 | This lead to bad copy tracing information to be dug up.
1150
1208
1151
1209
1152 Merge:
1210 Merge:
1153 - one with change to an unrelated file (b)
1211 - one with change to an unrelated file (b)
1154 - one overwriting a file (d) with a rename (from h to i to d)
1212 - one overwriting a file (d) with a rename (from h to i to d)
1155
1213
1156 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
1214 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
1157 o 24 mFBm-0 simple merge - the other way
1215 o 24 mFBm-0 simple merge - the other way
1158 |\
1216 |\
1159 +---o 23 mBFm-0 simple merge - one way
1217 +---o 23 mBFm-0 simple merge - one way
1160 | |/
1218 | |/
1161 | o 22 f-2: rename i -> d
1219 | o 22 f-2: rename i -> d
1162 | |
1220 | |
1163 | o 21 f-1: rename h -> i
1221 | o 21 f-1: rename h -> i
1164 | |
1222 | |
1165 o | 5 b-1: b update
1223 o | 5 b-1: b update
1166 |/
1224 |/
1167 o 2 i-2: c -move-> d
1225 o 2 i-2: c -move-> d
1168 |
1226 |
1169 o 1 i-1: a -move-> c
1227 o 1 i-1: a -move-> c
1170 |
1228 |
1171 o 0 i-0 initial commit: a b h
1229 o 0 i-0 initial commit: a b h
1172
1230
1173 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")'
1231 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")'
1174 M b
1232 M b
1175 A d
1233 A d
1176 h
1234 h
1177 R a
1235 R a
1178 R h
1236 R h
1179 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")'
1237 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")'
1180 M b
1238 M b
1181 A d
1239 A d
1182 h
1240 h
1183 R a
1241 R a
1184 R h
1242 R h
1185 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")'
1243 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")'
1186 M d
1244 M d
1187 h (no-filelog !)
1245 h (no-filelog !)
1188 R h
1246 R h
1189 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")'
1247 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")'
1190 M b
1248 M b
1191 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")'
1249 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")'
1192 M b
1250 M b
1193 M d
1251 M d
1194 i (no-filelog !)
1252 i (no-filelog !)
1195 R i
1253 R i
1196 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")'
1254 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")'
1197 M d
1255 M d
1198 h (no-filelog !)
1256 h (no-filelog !)
1199 R h
1257 R h
1200 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")'
1258 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")'
1201 M b
1259 M b
1202 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")'
1260 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")'
1203 M b
1261 M b
1204 M d
1262 M d
1205 i (no-filelog !)
1263 i (no-filelog !)
1206 R i
1264 R i
1207
1265
1208 #if no-changeset
1266 #if no-changeset
1209 $ hg log -Gfr 'desc("mBFm-0")' d
1267 $ hg log -Gfr 'desc("mBFm-0")' d
1210 o 22 f-2: rename i -> d
1268 o 22 f-2: rename i -> d
1211 |
1269 |
1212 o 21 f-1: rename h -> i
1270 o 21 f-1: rename h -> i
1213 :
1271 :
1214 o 0 i-0 initial commit: a b h
1272 o 0 i-0 initial commit: a b h
1215
1273
1216 #else
1274 #else
1217 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1275 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1218 $ hg log -Gfr 'desc("mBFm-0")' d
1276 $ hg log -Gfr 'desc("mBFm-0")' d
1219 o 22 f-2: rename i -> d
1277 o 22 f-2: rename i -> d
1220 |
1278 |
1221 ~
1279 ~
1222 #endif
1280 #endif
1223
1281
1224 #if no-changeset
1282 #if no-changeset
1225 $ hg log -Gfr 'desc("mFBm-0")' d
1283 $ hg log -Gfr 'desc("mFBm-0")' d
1226 o 22 f-2: rename i -> d
1284 o 22 f-2: rename i -> d
1227 |
1285 |
1228 o 21 f-1: rename h -> i
1286 o 21 f-1: rename h -> i
1229 :
1287 :
1230 o 0 i-0 initial commit: a b h
1288 o 0 i-0 initial commit: a b h
1231
1289
1232 #else
1290 #else
1233 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1291 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1234 $ hg log -Gfr 'desc("mFBm-0")' d
1292 $ hg log -Gfr 'desc("mFBm-0")' d
1235 o 22 f-2: rename i -> d
1293 o 22 f-2: rename i -> d
1236 |
1294 |
1237 ~
1295 ~
1238 #endif
1296 #endif
1239
1297
1240
1298
1241 Merge:
1299 Merge:
1242 - one with change to a file
1300 - one with change to a file
1243 - one deleting and recreating the file
1301 - one deleting and recreating the file
1244
1302
1245 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
1303 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
1246 consider history and rename on both branch of the merge.
1304 consider history and rename on both branch of the merge.
1247
1305
1248 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
1306 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
1249 o 27 mGDm-0 simple merge - the other way
1307 o 27 mGDm-0 simple merge - the other way
1250 |\
1308 |\
1251 +---o 26 mDGm-0 simple merge - one way
1309 +---o 26 mDGm-0 simple merge - one way
1252 | |/
1310 | |/
1253 | o 25 g-1: update d
1311 | o 25 g-1: update d
1254 | |
1312 | |
1255 o | 8 d-2 re-add d
1313 o | 8 d-2 re-add d
1256 | |
1314 | |
1257 o | 7 d-1 delete d
1315 o | 7 d-1 delete d
1258 |/
1316 |/
1259 o 2 i-2: c -move-> d
1317 o 2 i-2: c -move-> d
1260 |
1318 |
1261 o 1 i-1: a -move-> c
1319 o 1 i-1: a -move-> c
1262 |
1320 |
1263 o 0 i-0 initial commit: a b h
1321 o 0 i-0 initial commit: a b h
1264
1322
1265 One side of the merge have a long history with rename. The other side of the
1323 One side of the merge have a long history with rename. The other side of the
1266 merge point to a new file with a smaller history. Each side is "valid".
1324 merge point to a new file with a smaller history. Each side is "valid".
1267
1325
1268 (and again the filelog based algorithm only explore one, with a pick based on
1326 (and again the filelog based algorithm only explore one, with a pick based on
1269 revision numbers)
1327 revision numbers)
1270
1328
1271 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")'
1329 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")'
1272 A d
1330 A d
1273 a (filelog !)
1331 a (filelog !)
1274 R a
1332 R a
1275 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")'
1333 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")'
1276 A d
1334 A d
1277 a
1335 a
1278 R a
1336 R a
1279 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")'
1337 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")'
1280 M d
1338 M d
1281 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")'
1339 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")'
1282 M d
1340 M d
1283 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")'
1341 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")'
1284 M d
1342 M d
1285 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")'
1343 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")'
1286 M d
1344 M d
1287
1345
1288 #if no-changeset
1346 #if no-changeset
1289 $ hg log -Gfr 'desc("mDGm-0")' d
1347 $ hg log -Gfr 'desc("mDGm-0")' d
1290 o 26 mDGm-0 simple merge - one way
1348 o 26 mDGm-0 simple merge - one way
1291 |\
1349 |\
1292 | o 25 g-1: update d
1350 | o 25 g-1: update d
1293 | |
1351 | |
1294 o | 8 d-2 re-add d
1352 o | 8 d-2 re-add d
1295 |/
1353 |/
1296 o 2 i-2: c -move-> d
1354 o 2 i-2: c -move-> d
1297 |
1355 |
1298 o 1 i-1: a -move-> c
1356 o 1 i-1: a -move-> c
1299 |
1357 |
1300 o 0 i-0 initial commit: a b h
1358 o 0 i-0 initial commit: a b h
1301
1359
1302 #else
1360 #else
1303 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1361 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1304 $ hg log -Gfr 'desc("mDGm-0")' d
1362 $ hg log -Gfr 'desc("mDGm-0")' d
1305 o 26 mDGm-0 simple merge - one way
1363 o 26 mDGm-0 simple merge - one way
1306 |\
1364 |\
1307 | o 25 g-1: update d
1365 | o 25 g-1: update d
1308 | |
1366 | |
1309 o | 8 d-2 re-add d
1367 o | 8 d-2 re-add d
1310 |/
1368 |/
1311 o 2 i-2: c -move-> d
1369 o 2 i-2: c -move-> d
1312 |
1370 |
1313 ~
1371 ~
1314 #endif
1372 #endif
1315
1373
1316
1374
1317 #if no-changeset
1375 #if no-changeset
1318 $ hg log -Gfr 'desc("mDGm-0")' d
1376 $ hg log -Gfr 'desc("mDGm-0")' d
1319 o 26 mDGm-0 simple merge - one way
1377 o 26 mDGm-0 simple merge - one way
1320 |\
1378 |\
1321 | o 25 g-1: update d
1379 | o 25 g-1: update d
1322 | |
1380 | |
1323 o | 8 d-2 re-add d
1381 o | 8 d-2 re-add d
1324 |/
1382 |/
1325 o 2 i-2: c -move-> d
1383 o 2 i-2: c -move-> d
1326 |
1384 |
1327 o 1 i-1: a -move-> c
1385 o 1 i-1: a -move-> c
1328 |
1386 |
1329 o 0 i-0 initial commit: a b h
1387 o 0 i-0 initial commit: a b h
1330
1388
1331 #else
1389 #else
1332 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1390 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1333 $ hg log -Gfr 'desc("mDGm-0")' d
1391 $ hg log -Gfr 'desc("mDGm-0")' d
1334 o 26 mDGm-0 simple merge - one way
1392 o 26 mDGm-0 simple merge - one way
1335 |\
1393 |\
1336 | o 25 g-1: update d
1394 | o 25 g-1: update d
1337 | |
1395 | |
1338 o | 8 d-2 re-add d
1396 o | 8 d-2 re-add d
1339 |/
1397 |/
1340 o 2 i-2: c -move-> d
1398 o 2 i-2: c -move-> d
1341 |
1399 |
1342 ~
1400 ~
1343 #endif
1401 #endif
1344
1402
1345
1403
1346 Merge:
1404 Merge:
1347 - one with change to a file (d)
1405 - one with change to a file (d)
1348 - one overwriting that file with a rename (from h to i, to d)
1406 - one overwriting that file with a rename (from h to i, to d)
1349
1407
1350 This case is similar to BF/FB, but an actual merge happens, so both side of the
1408 This case is similar to BF/FB, but an actual merge happens, so both side of the
1351 history are relevant.
1409 history are relevant.
1352
1410
1353 Note:
1411 Note:
1354 | In this case, the merge get conflicting information since on one side we have
1412 | In this case, the merge get conflicting information since on one side we have
1355 | "a -> c -> d". and one the other one we have "h -> i -> d".
1413 | "a -> c -> d". and one the other one we have "h -> i -> d".
1356 |
1414 |
1357 | The current code arbitrarily pick one side
1415 | The current code arbitrarily pick one side
1358
1416
1359 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
1417 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
1360 o 29 mGFm-0 simple merge - the other way
1418 o 29 mGFm-0 simple merge - the other way
1361 |\
1419 |\
1362 +---o 28 mFGm-0 simple merge - one way
1420 +---o 28 mFGm-0 simple merge - one way
1363 | |/
1421 | |/
1364 | o 25 g-1: update d
1422 | o 25 g-1: update d
1365 | |
1423 | |
1366 o | 22 f-2: rename i -> d
1424 o | 22 f-2: rename i -> d
1367 | |
1425 | |
1368 o | 21 f-1: rename h -> i
1426 o | 21 f-1: rename h -> i
1369 |/
1427 |/
1370 o 2 i-2: c -move-> d
1428 o 2 i-2: c -move-> d
1371 |
1429 |
1372 o 1 i-1: a -move-> c
1430 o 1 i-1: a -move-> c
1373 |
1431 |
1374 o 0 i-0 initial commit: a b h
1432 o 0 i-0 initial commit: a b h
1375
1433
1376 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")'
1434 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")'
1377 A d
1435 A d
1378 h
1436 h
1379 R a
1437 R a
1380 R h
1438 R h
1381 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")'
1439 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")'
1382 A d
1440 A d
1383 a (no-filelog !)
1441 a (no-filelog !)
1384 h (filelog !)
1442 h (filelog !)
1385 R a
1443 R a
1386 R h
1444 R h
1387 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")'
1445 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")'
1388 M d
1446 M d
1389 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")'
1447 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")'
1390 M d
1448 M d
1391 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")'
1449 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")'
1392 M d
1450 M d
1393 i (no-filelog !)
1451 i (no-filelog !)
1394 R i
1452 R i
1395 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")'
1453 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")'
1396 M d
1454 M d
1397 i (no-filelog !)
1455 i (no-filelog !)
1398 R i
1456 R i
1399 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")'
1457 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")'
1400 M d
1458 M d
1401 h (no-filelog !)
1459 h (no-filelog !)
1402 R h
1460 R h
1403 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")'
1461 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")'
1404 M d
1462 M d
1405 h (no-filelog !)
1463 h (no-filelog !)
1406 R h
1464 R h
1407
1465
1408 #if no-changeset
1466 #if no-changeset
1409 $ hg log -Gfr 'desc("mFGm-0")' d
1467 $ hg log -Gfr 'desc("mFGm-0")' d
1410 o 28 mFGm-0 simple merge - one way
1468 o 28 mFGm-0 simple merge - one way
1411 |\
1469 |\
1412 | o 25 g-1: update d
1470 | o 25 g-1: update d
1413 | |
1471 | |
1414 o | 22 f-2: rename i -> d
1472 o | 22 f-2: rename i -> d
1415 | |
1473 | |
1416 o | 21 f-1: rename h -> i
1474 o | 21 f-1: rename h -> i
1417 |/
1475 |/
1418 o 2 i-2: c -move-> d
1476 o 2 i-2: c -move-> d
1419 |
1477 |
1420 o 1 i-1: a -move-> c
1478 o 1 i-1: a -move-> c
1421 |
1479 |
1422 o 0 i-0 initial commit: a b h
1480 o 0 i-0 initial commit: a b h
1423
1481
1424 #else
1482 #else
1425 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1483 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1426 $ hg log -Gfr 'desc("mFGm-0")' d
1484 $ hg log -Gfr 'desc("mFGm-0")' d
1427 o 28 mFGm-0 simple merge - one way
1485 o 28 mFGm-0 simple merge - one way
1428 |\
1486 |\
1429 | o 25 g-1: update d
1487 | o 25 g-1: update d
1430 | |
1488 | |
1431 o | 22 f-2: rename i -> d
1489 o | 22 f-2: rename i -> d
1432 |/
1490 |/
1433 o 2 i-2: c -move-> d
1491 o 2 i-2: c -move-> d
1434 |
1492 |
1435 ~
1493 ~
1436 #endif
1494 #endif
1437
1495
1438 #if no-changeset
1496 #if no-changeset
1439 $ hg log -Gfr 'desc("mGFm-0")' d
1497 $ hg log -Gfr 'desc("mGFm-0")' d
1440 o 29 mGFm-0 simple merge - the other way
1498 o 29 mGFm-0 simple merge - the other way
1441 |\
1499 |\
1442 | o 25 g-1: update d
1500 | o 25 g-1: update d
1443 | |
1501 | |
1444 o | 22 f-2: rename i -> d
1502 o | 22 f-2: rename i -> d
1445 | |
1503 | |
1446 o | 21 f-1: rename h -> i
1504 o | 21 f-1: rename h -> i
1447 |/
1505 |/
1448 o 2 i-2: c -move-> d
1506 o 2 i-2: c -move-> d
1449 |
1507 |
1450 o 1 i-1: a -move-> c
1508 o 1 i-1: a -move-> c
1451 |
1509 |
1452 o 0 i-0 initial commit: a b h
1510 o 0 i-0 initial commit: a b h
1453
1511
1454 #else
1512 #else
1455 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1513 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1456 $ hg log -Gfr 'desc("mGFm-0")' d
1514 $ hg log -Gfr 'desc("mGFm-0")' d
1457 o 29 mGFm-0 simple merge - the other way
1515 o 29 mGFm-0 simple merge - the other way
1458 |\
1516 |\
1459 | o 25 g-1: update d
1517 | o 25 g-1: update d
1460 | |
1518 | |
1461 o | 22 f-2: rename i -> d
1519 o | 22 f-2: rename i -> d
1462 |/
1520 |/
1463 o 2 i-2: c -move-> d
1521 o 2 i-2: c -move-> d
1464 |
1522 |
1465 ~
1523 ~
1466 #endif
1524 #endif
1467
1525
1468
1526
1469 Comparing with merging with a deletion (and keeping the file)
1527 Comparing with merging with a deletion (and keeping the file)
1470 -------------------------------------------------------------
1528 -------------------------------------------------------------
1471
1529
1472 Merge:
1530 Merge:
1473 - one removing a file (d)
1531 - one removing a file (d)
1474 - one updating that file
1532 - one updating that file
1475 - the merge keep the modified version of the file (canceling the delete)
1533 - the merge keep the modified version of the file (canceling the delete)
1476
1534
1477 In this case, the file keep on living after the merge. So we should not drop its
1535 In this case, the file keep on living after the merge. So we should not drop its
1478 copy tracing chain.
1536 copy tracing chain.
1479
1537
1480 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
1538 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
1481 o 31 mGCm-0
1539 o 31 mGCm-0
1482 |\
1540 |\
1483 +---o 30 mCGm-0
1541 +---o 30 mCGm-0
1484 | |/
1542 | |/
1485 | o 25 g-1: update d
1543 | o 25 g-1: update d
1486 | |
1544 | |
1487 o | 6 c-1 delete d
1545 o | 6 c-1 delete d
1488 |/
1546 |/
1489 o 2 i-2: c -move-> d
1547 o 2 i-2: c -move-> d
1490 |
1548 |
1491 o 1 i-1: a -move-> c
1549 o 1 i-1: a -move-> c
1492 |
1550 |
1493 o 0 i-0 initial commit: a b h
1551 o 0 i-0 initial commit: a b h
1494
1552
1495
1553
1496 'a' is the copy source of 'd'
1554 'a' is the copy source of 'd'
1497
1555
1498 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")'
1556 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")'
1499 A d
1557 A d
1500 a (no-compatibility no-changeset !)
1558 a (no-compatibility no-changeset !)
1501 R a
1559 R a
1502 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")'
1560 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")'
1503 A d
1561 A d
1504 a (no-compatibility no-changeset !)
1562 a (no-compatibility no-changeset !)
1505 R a
1563 R a
1506 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")'
1564 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")'
1507 A d
1565 A d
1508 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")'
1566 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")'
1509 A d
1567 A d
1510 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")'
1568 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")'
1511 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")'
1569 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")'
1512
1570
1513
1571
1514 Comparing with merge restoring an untouched deleted file
1572 Comparing with merge restoring an untouched deleted file
1515 --------------------------------------------------------
1573 --------------------------------------------------------
1516
1574
1517 Merge:
1575 Merge:
1518 - one removing a file (d)
1576 - one removing a file (d)
1519 - one leaving the file untouched
1577 - one leaving the file untouched
1520 - the merge actively restore the file to the same content.
1578 - the merge actively restore the file to the same content.
1521
1579
1522 In this case, the file keep on living after the merge. So we should not drop its
1580 In this case, the file keep on living after the merge. So we should not drop its
1523 copy tracing chain.
1581 copy tracing chain.
1524
1582
1525 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
1583 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
1526 o 33 mBC-revert-m-0
1584 o 33 mBC-revert-m-0
1527 |\
1585 |\
1528 +---o 32 mCB-revert-m-0
1586 +---o 32 mCB-revert-m-0
1529 | |/
1587 | |/
1530 | o 6 c-1 delete d
1588 | o 6 c-1 delete d
1531 | |
1589 | |
1532 o | 5 b-1: b update
1590 o | 5 b-1: b update
1533 |/
1591 |/
1534 o 2 i-2: c -move-> d
1592 o 2 i-2: c -move-> d
1535 |
1593 |
1536 o 1 i-1: a -move-> c
1594 o 1 i-1: a -move-> c
1537 |
1595 |
1538 o 0 i-0 initial commit: a b h
1596 o 0 i-0 initial commit: a b h
1539
1597
1540
1598
1541 'a' is the the copy source of 'd'
1599 'a' is the the copy source of 'd'
1542
1600
1543 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")'
1601 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")'
1544 M b
1602 M b
1545 A d
1603 A d
1546 a (no-compatibility no-changeset !)
1604 a (no-compatibility no-changeset !)
1547 R a
1605 R a
1548 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")'
1606 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")'
1549 M b
1607 M b
1550 A d
1608 A d
1551 a (no-compatibility no-changeset !)
1609 a (no-compatibility no-changeset !)
1552 R a
1610 R a
1553 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")'
1611 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")'
1554 M b
1612 M b
1555 A d
1613 A d
1556 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")'
1614 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")'
1557 M b
1615 M b
1558 A d
1616 A d
1559 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")'
1617 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")'
1560 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")'
1618 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")'
1619
1620
1621 Merging a branch where a rename was deleted with a branch where the same file was renamed
1622 ------------------------------------------------------------------------------------------
1623
1624 Create a "conflicting" merge where `d` get removed on one branch before its
1625 rename information actually conflict with the other branch.
1626
1627 (the copy information from the branch that was not deleted should win).
1628
1629 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
1630 @ 36 mHC-delete-before-conflict-m-0
1631 |\
1632 +---o 35 mCH-delete-before-conflict-m-0
1633 | |/
1634 | o 34 h-1: b -(move)-> d
1635 | |
1636 o | 6 c-1 delete d
1637 | |
1638 o | 2 i-2: c -move-> d
1639 | |
1640 o | 1 i-1: a -move-> c
1641 |/
1642 o 0 i-0 initial commit: a b h
1643
1644
1645 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCH-delete-before-conflict-m")'
1646 A d
1647 b (no-compatibility no-changeset !)
1648 R a
1649 R b
1650 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mHC-delete-before-conflict-m")'
1651 A d
1652 b
1653 R a
1654 R b
1655 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCH-delete-before-conflict-m")'
1656 A d
1657 b
1658 R b
1659 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mHC-delete-before-conflict-m")'
1660 A d
1661 b
1662 R b
1663 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mCH-delete-before-conflict-m")'
1664 R a
1665 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mHC-delete-before-conflict-m")'
1666 R a
@@ -1,653 +1,653 b''
1 #testcases filelog compatibility changeset sidedata
1 #testcases filelog compatibility changeset sidedata
2
2
3 $ cat >> $HGRCPATH << EOF
3 $ cat >> $HGRCPATH << EOF
4 > [extensions]
4 > [extensions]
5 > rebase=
5 > rebase=
6 > [alias]
6 > [alias]
7 > l = log -G -T '{rev} {desc}\n{files}\n'
7 > l = log -G -T '{rev} {desc}\n{files}\n'
8 > EOF
8 > EOF
9
9
10 #if compatibility
10 #if compatibility
11 $ cat >> $HGRCPATH << EOF
11 $ cat >> $HGRCPATH << EOF
12 > [experimental]
12 > [experimental]
13 > copies.read-from = compatibility
13 > copies.read-from = compatibility
14 > EOF
14 > EOF
15 #endif
15 #endif
16
16
17 #if changeset
17 #if changeset
18 $ cat >> $HGRCPATH << EOF
18 $ cat >> $HGRCPATH << EOF
19 > [experimental]
19 > [experimental]
20 > copies.read-from = changeset-only
20 > copies.read-from = changeset-only
21 > copies.write-to = changeset-only
21 > copies.write-to = changeset-only
22 > EOF
22 > EOF
23 #endif
23 #endif
24
24
25 #if sidedata
25 #if sidedata
26 $ cat >> $HGRCPATH << EOF
26 $ cat >> $HGRCPATH << EOF
27 > [format]
27 > [format]
28 > exp-use-copies-side-data-changeset = yes
28 > exp-use-copies-side-data-changeset = yes
29 > EOF
29 > EOF
30 #endif
30 #endif
31
31
32 $ REPONUM=0
32 $ REPONUM=0
33 $ newrepo() {
33 $ newrepo() {
34 > cd $TESTTMP
34 > cd $TESTTMP
35 > REPONUM=`expr $REPONUM + 1`
35 > REPONUM=`expr $REPONUM + 1`
36 > hg init repo-$REPONUM
36 > hg init repo-$REPONUM
37 > cd repo-$REPONUM
37 > cd repo-$REPONUM
38 > }
38 > }
39
39
40 Simple rename case
40 Simple rename case
41 $ newrepo
41 $ newrepo
42 $ echo x > x
42 $ echo x > x
43 $ hg ci -Aqm 'add x'
43 $ hg ci -Aqm 'add x'
44 $ hg mv x y
44 $ hg mv x y
45 $ hg debugp1copies
45 $ hg debugp1copies
46 x -> y
46 x -> y
47 $ hg debugp2copies
47 $ hg debugp2copies
48 $ hg ci -m 'rename x to y'
48 $ hg ci -m 'rename x to y'
49 $ hg l
49 $ hg l
50 @ 1 rename x to y
50 @ 1 rename x to y
51 | x y
51 | x y
52 o 0 add x
52 o 0 add x
53 x
53 x
54 $ hg debugp1copies -r 1
54 $ hg debugp1copies -r 1
55 x -> y
55 x -> y
56 $ hg debugpathcopies 0 1
56 $ hg debugpathcopies 0 1
57 x -> y
57 x -> y
58 $ hg debugpathcopies 1 0
58 $ hg debugpathcopies 1 0
59 y -> x
59 y -> x
60 Test filtering copies by path. We do filtering by destination.
60 Test filtering copies by path. We do filtering by destination.
61 $ hg debugpathcopies 0 1 x
61 $ hg debugpathcopies 0 1 x
62 $ hg debugpathcopies 1 0 x
62 $ hg debugpathcopies 1 0 x
63 y -> x
63 y -> x
64 $ hg debugpathcopies 0 1 y
64 $ hg debugpathcopies 0 1 y
65 x -> y
65 x -> y
66 $ hg debugpathcopies 1 0 y
66 $ hg debugpathcopies 1 0 y
67
67
68 Copies not including commit changes
68 Copies not including commit changes
69 $ newrepo
69 $ newrepo
70 $ echo x > x
70 $ echo x > x
71 $ hg ci -Aqm 'add x'
71 $ hg ci -Aqm 'add x'
72 $ hg mv x y
72 $ hg mv x y
73 $ hg debugpathcopies . .
73 $ hg debugpathcopies . .
74 $ hg debugpathcopies . 'wdir()'
74 $ hg debugpathcopies . 'wdir()'
75 x -> y
75 x -> y
76 $ hg debugpathcopies 'wdir()' .
76 $ hg debugpathcopies 'wdir()' .
77 y -> x
77 y -> x
78
78
79 Copy a file onto another file
79 Copy a file onto another file
80 $ newrepo
80 $ newrepo
81 $ echo x > x
81 $ echo x > x
82 $ echo y > y
82 $ echo y > y
83 $ hg ci -Aqm 'add x and y'
83 $ hg ci -Aqm 'add x and y'
84 $ hg cp -f x y
84 $ hg cp -f x y
85 $ hg debugp1copies
85 $ hg debugp1copies
86 x -> y
86 x -> y
87 $ hg debugp2copies
87 $ hg debugp2copies
88 $ hg ci -m 'copy x onto y'
88 $ hg ci -m 'copy x onto y'
89 $ hg l
89 $ hg l
90 @ 1 copy x onto y
90 @ 1 copy x onto y
91 | y
91 | y
92 o 0 add x and y
92 o 0 add x and y
93 x y
93 x y
94 $ hg debugp1copies -r 1
94 $ hg debugp1copies -r 1
95 x -> y
95 x -> y
96 Incorrectly doesn't show the rename
96 Incorrectly doesn't show the rename
97 $ hg debugpathcopies 0 1
97 $ hg debugpathcopies 0 1
98
98
99 Copy a file onto another file with same content. If metadata is stored in changeset, this does not
99 Copy a file onto another file with same content. If metadata is stored in changeset, this does not
100 produce a new filelog entry. The changeset's "files" entry should still list the file.
100 produce a new filelog entry. The changeset's "files" entry should still list the file.
101 $ newrepo
101 $ newrepo
102 $ echo x > x
102 $ echo x > x
103 $ echo x > x2
103 $ echo x > x2
104 $ hg ci -Aqm 'add x and x2 with same content'
104 $ hg ci -Aqm 'add x and x2 with same content'
105 $ hg cp -f x x2
105 $ hg cp -f x x2
106 $ hg ci -m 'copy x onto x2'
106 $ hg ci -m 'copy x onto x2'
107 $ hg l
107 $ hg l
108 @ 1 copy x onto x2
108 @ 1 copy x onto x2
109 | x2
109 | x2
110 o 0 add x and x2 with same content
110 o 0 add x and x2 with same content
111 x x2
111 x x2
112 $ hg debugp1copies -r 1
112 $ hg debugp1copies -r 1
113 x -> x2
113 x -> x2
114 Incorrectly doesn't show the rename
114 Incorrectly doesn't show the rename
115 $ hg debugpathcopies 0 1
115 $ hg debugpathcopies 0 1
116
116
117 Rename file in a loop: x->y->z->x
117 Rename file in a loop: x->y->z->x
118 $ newrepo
118 $ newrepo
119 $ echo x > x
119 $ echo x > x
120 $ hg ci -Aqm 'add x'
120 $ hg ci -Aqm 'add x'
121 $ hg mv x y
121 $ hg mv x y
122 $ hg debugp1copies
122 $ hg debugp1copies
123 x -> y
123 x -> y
124 $ hg debugp2copies
124 $ hg debugp2copies
125 $ hg ci -m 'rename x to y'
125 $ hg ci -m 'rename x to y'
126 $ hg mv y z
126 $ hg mv y z
127 $ hg ci -m 'rename y to z'
127 $ hg ci -m 'rename y to z'
128 $ hg mv z x
128 $ hg mv z x
129 $ hg ci -m 'rename z to x'
129 $ hg ci -m 'rename z to x'
130 $ hg l
130 $ hg l
131 @ 3 rename z to x
131 @ 3 rename z to x
132 | x z
132 | x z
133 o 2 rename y to z
133 o 2 rename y to z
134 | y z
134 | y z
135 o 1 rename x to y
135 o 1 rename x to y
136 | x y
136 | x y
137 o 0 add x
137 o 0 add x
138 x
138 x
139 $ hg debugpathcopies 0 3
139 $ hg debugpathcopies 0 3
140
140
141 Copy x to z, then remove z, then copy x2 (same content as x) to z. With copy metadata in the
141 Copy x to z, then remove z, then copy x2 (same content as x) to z. With copy metadata in the
142 changeset, the two copies here will have the same filelog entry, so ctx['z'].introrev() might point
142 changeset, the two copies here will have the same filelog entry, so ctx['z'].introrev() might point
143 to the first commit that added the file. We should still report the copy as being from x2.
143 to the first commit that added the file. We should still report the copy as being from x2.
144 $ newrepo
144 $ newrepo
145 $ echo x > x
145 $ echo x > x
146 $ echo x > x2
146 $ echo x > x2
147 $ hg ci -Aqm 'add x and x2 with same content'
147 $ hg ci -Aqm 'add x and x2 with same content'
148 $ hg cp x z
148 $ hg cp x z
149 $ hg ci -qm 'copy x to z'
149 $ hg ci -qm 'copy x to z'
150 $ hg rm z
150 $ hg rm z
151 $ hg ci -m 'remove z'
151 $ hg ci -m 'remove z'
152 $ hg cp x2 z
152 $ hg cp x2 z
153 $ hg ci -m 'copy x2 to z'
153 $ hg ci -m 'copy x2 to z'
154 $ hg l
154 $ hg l
155 @ 3 copy x2 to z
155 @ 3 copy x2 to z
156 | z
156 | z
157 o 2 remove z
157 o 2 remove z
158 | z
158 | z
159 o 1 copy x to z
159 o 1 copy x to z
160 | z
160 | z
161 o 0 add x and x2 with same content
161 o 0 add x and x2 with same content
162 x x2
162 x x2
163 $ hg debugp1copies -r 3
163 $ hg debugp1copies -r 3
164 x2 -> z
164 x2 -> z
165 $ hg debugpathcopies 0 3
165 $ hg debugpathcopies 0 3
166 x2 -> z
166 x2 -> z
167
167
168 Create x and y, then rename them both to the same name, but on different sides of a fork
168 Create x and y, then rename them both to the same name, but on different sides of a fork
169 $ newrepo
169 $ newrepo
170 $ echo x > x
170 $ echo x > x
171 $ echo y > y
171 $ echo y > y
172 $ hg ci -Aqm 'add x and y'
172 $ hg ci -Aqm 'add x and y'
173 $ hg mv x z
173 $ hg mv x z
174 $ hg ci -qm 'rename x to z'
174 $ hg ci -qm 'rename x to z'
175 $ hg co -q 0
175 $ hg co -q 0
176 $ hg mv y z
176 $ hg mv y z
177 $ hg ci -qm 'rename y to z'
177 $ hg ci -qm 'rename y to z'
178 $ hg l
178 $ hg l
179 @ 2 rename y to z
179 @ 2 rename y to z
180 | y z
180 | y z
181 | o 1 rename x to z
181 | o 1 rename x to z
182 |/ x z
182 |/ x z
183 o 0 add x and y
183 o 0 add x and y
184 x y
184 x y
185 $ hg debugpathcopies 1 2
185 $ hg debugpathcopies 1 2
186 z -> x
186 z -> x
187 y -> z
187 y -> z
188
188
189 Fork renames x to y on one side and removes x on the other
189 Fork renames x to y on one side and removes x on the other
190 $ newrepo
190 $ newrepo
191 $ echo x > x
191 $ echo x > x
192 $ hg ci -Aqm 'add x'
192 $ hg ci -Aqm 'add x'
193 $ hg mv x y
193 $ hg mv x y
194 $ hg ci -m 'rename x to y'
194 $ hg ci -m 'rename x to y'
195 $ hg co -q 0
195 $ hg co -q 0
196 $ hg rm x
196 $ hg rm x
197 $ hg ci -m 'remove x'
197 $ hg ci -m 'remove x'
198 created new head
198 created new head
199 $ hg l
199 $ hg l
200 @ 2 remove x
200 @ 2 remove x
201 | x
201 | x
202 | o 1 rename x to y
202 | o 1 rename x to y
203 |/ x y
203 |/ x y
204 o 0 add x
204 o 0 add x
205 x
205 x
206 $ hg debugpathcopies 1 2
206 $ hg debugpathcopies 1 2
207
207
208 Merge rename from other branch
208 Merge rename from other branch
209 $ newrepo
209 $ newrepo
210 $ echo x > x
210 $ echo x > x
211 $ hg ci -Aqm 'add x'
211 $ hg ci -Aqm 'add x'
212 $ hg mv x y
212 $ hg mv x y
213 $ hg ci -m 'rename x to y'
213 $ hg ci -m 'rename x to y'
214 $ hg co -q 0
214 $ hg co -q 0
215 $ echo z > z
215 $ echo z > z
216 $ hg ci -Aqm 'add z'
216 $ hg ci -Aqm 'add z'
217 $ hg merge -q 1
217 $ hg merge -q 1
218 $ hg debugp1copies
218 $ hg debugp1copies
219 $ hg debugp2copies
219 $ hg debugp2copies
220 $ hg ci -m 'merge rename from p2'
220 $ hg ci -m 'merge rename from p2'
221 $ hg l
221 $ hg l
222 @ 3 merge rename from p2
222 @ 3 merge rename from p2
223 |\
223 |\
224 | o 2 add z
224 | o 2 add z
225 | | z
225 | | z
226 o | 1 rename x to y
226 o | 1 rename x to y
227 |/ x y
227 |/ x y
228 o 0 add x
228 o 0 add x
229 x
229 x
230 Perhaps we should indicate the rename here, but `hg status` is documented to be weird during
230 Perhaps we should indicate the rename here, but `hg status` is documented to be weird during
231 merges, so...
231 merges, so...
232 $ hg debugp1copies -r 3
232 $ hg debugp1copies -r 3
233 $ hg debugp2copies -r 3
233 $ hg debugp2copies -r 3
234 $ hg debugpathcopies 0 3
234 $ hg debugpathcopies 0 3
235 x -> y
235 x -> y
236 $ hg debugpathcopies 1 2
236 $ hg debugpathcopies 1 2
237 y -> x
237 y -> x
238 $ hg debugpathcopies 1 3
238 $ hg debugpathcopies 1 3
239 $ hg debugpathcopies 2 3
239 $ hg debugpathcopies 2 3
240 x -> y
240 x -> y
241
241
242 Copy file from either side in a merge
242 Copy file from either side in a merge
243 $ newrepo
243 $ newrepo
244 $ echo x > x
244 $ echo x > x
245 $ hg ci -Aqm 'add x'
245 $ hg ci -Aqm 'add x'
246 $ hg co -q null
246 $ hg co -q null
247 $ echo y > y
247 $ echo y > y
248 $ hg ci -Aqm 'add y'
248 $ hg ci -Aqm 'add y'
249 $ hg merge -q 0
249 $ hg merge -q 0
250 $ hg cp y z
250 $ hg cp y z
251 $ hg debugp1copies
251 $ hg debugp1copies
252 y -> z
252 y -> z
253 $ hg debugp2copies
253 $ hg debugp2copies
254 $ hg ci -m 'copy file from p1 in merge'
254 $ hg ci -m 'copy file from p1 in merge'
255 $ hg co -q 1
255 $ hg co -q 1
256 $ hg merge -q 0
256 $ hg merge -q 0
257 $ hg cp x z
257 $ hg cp x z
258 $ hg debugp1copies
258 $ hg debugp1copies
259 $ hg debugp2copies
259 $ hg debugp2copies
260 x -> z
260 x -> z
261 $ hg ci -qm 'copy file from p2 in merge'
261 $ hg ci -qm 'copy file from p2 in merge'
262 $ hg l
262 $ hg l
263 @ 3 copy file from p2 in merge
263 @ 3 copy file from p2 in merge
264 |\ z
264 |\ z
265 +---o 2 copy file from p1 in merge
265 +---o 2 copy file from p1 in merge
266 | |/ z
266 | |/ z
267 | o 1 add y
267 | o 1 add y
268 | y
268 | y
269 o 0 add x
269 o 0 add x
270 x
270 x
271 $ hg debugp1copies -r 2
271 $ hg debugp1copies -r 2
272 y -> z
272 y -> z
273 $ hg debugp2copies -r 2
273 $ hg debugp2copies -r 2
274 $ hg debugpathcopies 1 2
274 $ hg debugpathcopies 1 2
275 y -> z
275 y -> z
276 $ hg debugpathcopies 0 2
276 $ hg debugpathcopies 0 2
277 $ hg debugp1copies -r 3
277 $ hg debugp1copies -r 3
278 $ hg debugp2copies -r 3
278 $ hg debugp2copies -r 3
279 x -> z
279 x -> z
280 $ hg debugpathcopies 1 3
280 $ hg debugpathcopies 1 3
281 $ hg debugpathcopies 0 3
281 $ hg debugpathcopies 0 3
282 x -> z
282 x -> z
283
283
284 Copy file that exists on both sides of the merge, same content on both sides
284 Copy file that exists on both sides of the merge, same content on both sides
285 $ newrepo
285 $ newrepo
286 $ echo x > x
286 $ echo x > x
287 $ hg ci -Aqm 'add x on branch 1'
287 $ hg ci -Aqm 'add x on branch 1'
288 $ hg co -q null
288 $ hg co -q null
289 $ echo x > x
289 $ echo x > x
290 $ hg ci -Aqm 'add x on branch 2'
290 $ hg ci -Aqm 'add x on branch 2'
291 $ hg merge -q 0
291 $ hg merge -q 0
292 $ hg cp x z
292 $ hg cp x z
293 $ hg debugp1copies
293 $ hg debugp1copies
294 x -> z
294 x -> z
295 $ hg debugp2copies
295 $ hg debugp2copies
296 $ hg ci -qm 'merge'
296 $ hg ci -qm 'merge'
297 $ hg l
297 $ hg l
298 @ 2 merge
298 @ 2 merge
299 |\ z
299 |\ z
300 | o 1 add x on branch 2
300 | o 1 add x on branch 2
301 | x
301 | x
302 o 0 add x on branch 1
302 o 0 add x on branch 1
303 x
303 x
304 $ hg debugp1copies -r 2
304 $ hg debugp1copies -r 2
305 x -> z
305 x -> z
306 $ hg debugp2copies -r 2
306 $ hg debugp2copies -r 2
307 It's a little weird that it shows up on both sides
307 It's a little weird that it shows up on both sides
308 $ hg debugpathcopies 1 2
308 $ hg debugpathcopies 1 2
309 x -> z
309 x -> z
310 $ hg debugpathcopies 0 2
310 $ hg debugpathcopies 0 2
311 x -> z (filelog !)
311 x -> z (filelog !)
312
312
313 Copy file that exists on both sides of the merge, different content
313 Copy file that exists on both sides of the merge, different content
314 $ newrepo
314 $ newrepo
315 $ echo branch1 > x
315 $ echo branch1 > x
316 $ hg ci -Aqm 'add x on branch 1'
316 $ hg ci -Aqm 'add x on branch 1'
317 $ hg co -q null
317 $ hg co -q null
318 $ echo branch2 > x
318 $ echo branch2 > x
319 $ hg ci -Aqm 'add x on branch 2'
319 $ hg ci -Aqm 'add x on branch 2'
320 $ hg merge -q 0
320 $ hg merge -q 0
321 warning: conflicts while merging x! (edit, then use 'hg resolve --mark')
321 warning: conflicts while merging x! (edit, then use 'hg resolve --mark')
322 [1]
322 [1]
323 $ echo resolved > x
323 $ echo resolved > x
324 $ hg resolve -m x
324 $ hg resolve -m x
325 (no more unresolved files)
325 (no more unresolved files)
326 $ hg cp x z
326 $ hg cp x z
327 $ hg debugp1copies
327 $ hg debugp1copies
328 x -> z
328 x -> z
329 $ hg debugp2copies
329 $ hg debugp2copies
330 $ hg ci -qm 'merge'
330 $ hg ci -qm 'merge'
331 $ hg l
331 $ hg l
332 @ 2 merge
332 @ 2 merge
333 |\ x z
333 |\ x z
334 | o 1 add x on branch 2
334 | o 1 add x on branch 2
335 | x
335 | x
336 o 0 add x on branch 1
336 o 0 add x on branch 1
337 x
337 x
338 $ hg debugp1copies -r 2
338 $ hg debugp1copies -r 2
339 x -> z (changeset !)
339 x -> z (changeset !)
340 x -> z (sidedata !)
340 x -> z (sidedata !)
341 $ hg debugp2copies -r 2
341 $ hg debugp2copies -r 2
342 x -> z (no-changeset no-sidedata !)
342 x -> z (no-changeset no-sidedata !)
343 $ hg debugpathcopies 1 2
343 $ hg debugpathcopies 1 2
344 x -> z (changeset !)
344 x -> z (changeset !)
345 x -> z (sidedata !)
345 x -> z (sidedata !)
346 $ hg debugpathcopies 0 2
346 $ hg debugpathcopies 0 2
347 x -> z (no-changeset no-sidedata !)
347 x -> z (no-changeset no-sidedata !)
348
348
349 Copy x->y on one side of merge and copy x->z on the other side. Pathcopies from one parent
349 Copy x->y on one side of merge and copy x->z on the other side. Pathcopies from one parent
350 of the merge to the merge should include the copy from the other side.
350 of the merge to the merge should include the copy from the other side.
351 $ newrepo
351 $ newrepo
352 $ echo x > x
352 $ echo x > x
353 $ hg ci -Aqm 'add x'
353 $ hg ci -Aqm 'add x'
354 $ hg cp x y
354 $ hg cp x y
355 $ hg ci -qm 'copy x to y'
355 $ hg ci -qm 'copy x to y'
356 $ hg co -q 0
356 $ hg co -q 0
357 $ hg cp x z
357 $ hg cp x z
358 $ hg ci -qm 'copy x to z'
358 $ hg ci -qm 'copy x to z'
359 $ hg merge -q 1
359 $ hg merge -q 1
360 $ hg ci -m 'merge copy x->y and copy x->z'
360 $ hg ci -m 'merge copy x->y and copy x->z'
361 $ hg l
361 $ hg l
362 @ 3 merge copy x->y and copy x->z
362 @ 3 merge copy x->y and copy x->z
363 |\
363 |\
364 | o 2 copy x to z
364 | o 2 copy x to z
365 | | z
365 | | z
366 o | 1 copy x to y
366 o | 1 copy x to y
367 |/ y
367 |/ y
368 o 0 add x
368 o 0 add x
369 x
369 x
370 $ hg debugp1copies -r 3
370 $ hg debugp1copies -r 3
371 $ hg debugp2copies -r 3
371 $ hg debugp2copies -r 3
372 $ hg debugpathcopies 2 3
372 $ hg debugpathcopies 2 3
373 x -> y
373 x -> y
374 $ hg debugpathcopies 1 3
374 $ hg debugpathcopies 1 3
375 x -> z
375 x -> z
376
376
377 Copy x to y on one side of merge, create y and rename to z on the other side.
377 Copy x to y on one side of merge, create y and rename to z on the other side.
378 $ newrepo
378 $ newrepo
379 $ echo x > x
379 $ echo x > x
380 $ hg ci -Aqm 'add x'
380 $ hg ci -Aqm 'add x'
381 $ hg cp x y
381 $ hg cp x y
382 $ hg ci -qm 'copy x to y'
382 $ hg ci -qm 'copy x to y'
383 $ hg co -q 0
383 $ hg co -q 0
384 $ echo y > y
384 $ echo y > y
385 $ hg ci -Aqm 'add y'
385 $ hg ci -Aqm 'add y'
386 $ hg mv y z
386 $ hg mv y z
387 $ hg ci -m 'rename y to z'
387 $ hg ci -m 'rename y to z'
388 $ hg merge -q 1
388 $ hg merge -q 1
389 $ hg ci -m 'merge'
389 $ hg ci -m 'merge'
390 $ hg l
390 $ hg l
391 @ 4 merge
391 @ 4 merge
392 |\
392 |\
393 | o 3 rename y to z
393 | o 3 rename y to z
394 | | y z
394 | | y z
395 | o 2 add y
395 | o 2 add y
396 | | y
396 | | y
397 o | 1 copy x to y
397 o | 1 copy x to y
398 |/ y
398 |/ y
399 o 0 add x
399 o 0 add x
400 x
400 x
401 $ hg debugp1copies -r 3
401 $ hg debugp1copies -r 3
402 y -> z
402 y -> z
403 $ hg debugp2copies -r 3
403 $ hg debugp2copies -r 3
404 $ hg debugpathcopies 2 3
404 $ hg debugpathcopies 2 3
405 y -> z
405 y -> z
406 $ hg debugpathcopies 1 3
406 $ hg debugpathcopies 1 3
407 y -> z (no-filelog !)
407 y -> z (no-filelog !)
408
408
409 Create x and y, then rename x to z on one side of merge, and rename y to z and
409 Create x and y, then rename x to z on one side of merge, and rename y to z and
410 modify z on the other side. When storing copies in the changeset, we don't
410 modify z on the other side. When storing copies in the changeset, we don't
411 filter out copies whose target was created on the other side of the merge.
411 filter out copies whose target was created on the other side of the merge.
412 $ newrepo
412 $ newrepo
413 $ echo x > x
413 $ echo x > x
414 $ echo y > y
414 $ echo y > y
415 $ hg ci -Aqm 'add x and y'
415 $ hg ci -Aqm 'add x and y'
416 $ hg mv x z
416 $ hg mv x z
417 $ hg ci -qm 'rename x to z'
417 $ hg ci -qm 'rename x to z'
418 $ hg co -q 0
418 $ hg co -q 0
419 $ hg mv y z
419 $ hg mv y z
420 $ hg ci -qm 'rename y to z'
420 $ hg ci -qm 'rename y to z'
421 $ echo z >> z
421 $ echo z >> z
422 $ hg ci -m 'modify z'
422 $ hg ci -m 'modify z'
423 $ hg merge -q 1
423 $ hg merge -q 1
424 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
424 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
425 [1]
425 [1]
426 $ echo z > z
426 $ echo z > z
427 $ hg resolve -qm z
427 $ hg resolve -qm z
428 $ hg ci -m 'merge 1 into 3'
428 $ hg ci -m 'merge 1 into 3'
429 Try merging the other direction too
429 Try merging the other direction too
430 $ hg co -q 1
430 $ hg co -q 1
431 $ hg merge -q 3
431 $ hg merge -q 3
432 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
432 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
433 [1]
433 [1]
434 $ echo z > z
434 $ echo z > z
435 $ hg resolve -qm z
435 $ hg resolve -qm z
436 $ hg ci -m 'merge 3 into 1'
436 $ hg ci -m 'merge 3 into 1'
437 created new head
437 created new head
438 $ hg l
438 $ hg l
439 @ 5 merge 3 into 1
439 @ 5 merge 3 into 1
440 |\ z
440 |\ z
441 +---o 4 merge 1 into 3
441 +---o 4 merge 1 into 3
442 | |/ z
442 | |/ z
443 | o 3 modify z
443 | o 3 modify z
444 | | z
444 | | z
445 | o 2 rename y to z
445 | o 2 rename y to z
446 | | y z
446 | | y z
447 o | 1 rename x to z
447 o | 1 rename x to z
448 |/ x z
448 |/ x z
449 o 0 add x and y
449 o 0 add x and y
450 x y
450 x y
451 $ hg debugpathcopies 1 4
451 $ hg debugpathcopies 1 4
452 y -> z (no-filelog !)
452 y -> z (no-filelog !)
453 $ hg debugpathcopies 2 4
453 $ hg debugpathcopies 2 4
454 x -> z (no-filelog !)
454 x -> z (no-filelog !)
455 $ hg debugpathcopies 0 4
455 $ hg debugpathcopies 0 4
456 x -> z (filelog !)
456 x -> z (filelog !)
457 y -> z (no-filelog !)
457 y -> z (no-filelog !)
458 $ hg debugpathcopies 1 5
458 $ hg debugpathcopies 1 5
459 y -> z (no-filelog !)
459 y -> z (no-filelog !)
460 $ hg debugpathcopies 2 5
460 $ hg debugpathcopies 2 5
461 x -> z (no-filelog !)
461 x -> z (no-filelog !)
462 $ hg debugpathcopies 0 5
462 $ hg debugpathcopies 0 5
463 x -> z
463 x -> z
464
464
465
465
466 Create x and y, then rename x to z on one side of merge, and rename y to z and
466 Create x and y, then rename x to z on one side of merge, and rename y to z and
467 then delete z on the other side.
467 then delete z on the other side.
468 $ newrepo
468 $ newrepo
469 $ echo x > x
469 $ echo x > x
470 $ echo y > y
470 $ echo y > y
471 $ hg ci -Aqm 'add x and y'
471 $ hg ci -Aqm 'add x and y'
472 $ hg mv x z
472 $ hg mv x z
473 $ hg ci -qm 'rename x to z'
473 $ hg ci -qm 'rename x to z'
474 $ hg co -q 0
474 $ hg co -q 0
475 $ hg mv y z
475 $ hg mv y z
476 $ hg ci -qm 'rename y to z'
476 $ hg ci -qm 'rename y to z'
477 $ hg rm z
477 $ hg rm z
478 $ hg ci -m 'delete z'
478 $ hg ci -m 'delete z'
479 $ hg merge -q 1
479 $ hg merge -q 1
480 $ echo z > z
480 $ echo z > z
481 $ hg ci -m 'merge 1 into 3'
481 $ hg ci -m 'merge 1 into 3'
482 Try merging the other direction too
482 Try merging the other direction too
483 $ hg co -q 1
483 $ hg co -q 1
484 $ hg merge -q 3
484 $ hg merge -q 3
485 $ echo z > z
485 $ echo z > z
486 $ hg ci -m 'merge 3 into 1'
486 $ hg ci -m 'merge 3 into 1'
487 created new head
487 created new head
488 $ hg l
488 $ hg l
489 @ 5 merge 3 into 1
489 @ 5 merge 3 into 1
490 |\ z
490 |\ z
491 +---o 4 merge 1 into 3
491 +---o 4 merge 1 into 3
492 | |/ z
492 | |/ z
493 | o 3 delete z
493 | o 3 delete z
494 | | z
494 | | z
495 | o 2 rename y to z
495 | o 2 rename y to z
496 | | y z
496 | | y z
497 o | 1 rename x to z
497 o | 1 rename x to z
498 |/ x z
498 |/ x z
499 o 0 add x and y
499 o 0 add x and y
500 x y
500 x y
501 $ hg debugpathcopies 1 4
501 $ hg debugpathcopies 1 4
502 $ hg debugpathcopies 2 4
502 $ hg debugpathcopies 2 4
503 x -> z (no-filelog !)
503 x -> z (no-filelog !)
504 $ hg debugpathcopies 0 4
504 $ hg debugpathcopies 0 4
505 x -> z (filelog !)
505 x -> z (no-changeset no-compatibility !)
506 $ hg debugpathcopies 1 5
506 $ hg debugpathcopies 1 5
507 $ hg debugpathcopies 2 5
507 $ hg debugpathcopies 2 5
508 x -> z (no-filelog !)
508 x -> z (no-filelog !)
509 $ hg debugpathcopies 0 5
509 $ hg debugpathcopies 0 5
510 x -> z
510 x -> z
511
511
512
512
513 Test for a case in fullcopytracing algorithm where neither of the merging csets
513 Test for a case in fullcopytracing algorithm where neither of the merging csets
514 is a descendant of the merge base. This test reflects that the algorithm
514 is a descendant of the merge base. This test reflects that the algorithm
515 correctly finds the copies:
515 correctly finds the copies:
516
516
517 $ cat >> $HGRCPATH << EOF
517 $ cat >> $HGRCPATH << EOF
518 > [experimental]
518 > [experimental]
519 > evolution.createmarkers=True
519 > evolution.createmarkers=True
520 > evolution.allowunstable=True
520 > evolution.allowunstable=True
521 > EOF
521 > EOF
522
522
523 $ newrepo
523 $ newrepo
524 $ echo a > a
524 $ echo a > a
525 $ hg add a
525 $ hg add a
526 $ hg ci -m "added a"
526 $ hg ci -m "added a"
527 $ echo b > b
527 $ echo b > b
528 $ hg add b
528 $ hg add b
529 $ hg ci -m "added b"
529 $ hg ci -m "added b"
530
530
531 $ hg mv b b1
531 $ hg mv b b1
532 $ hg ci -m "rename b to b1"
532 $ hg ci -m "rename b to b1"
533
533
534 $ hg up ".^"
534 $ hg up ".^"
535 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
535 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
536 $ echo d > d
536 $ echo d > d
537 $ hg add d
537 $ hg add d
538 $ hg ci -m "added d"
538 $ hg ci -m "added d"
539 created new head
539 created new head
540
540
541 $ echo baba >> b
541 $ echo baba >> b
542 $ hg ci --amend -m "added d, modified b"
542 $ hg ci --amend -m "added d, modified b"
543
543
544 $ hg l --hidden
544 $ hg l --hidden
545 @ 4 added d, modified b
545 @ 4 added d, modified b
546 | b d
546 | b d
547 | x 3 added d
547 | x 3 added d
548 |/ d
548 |/ d
549 | o 2 rename b to b1
549 | o 2 rename b to b1
550 |/ b b1
550 |/ b b1
551 o 1 added b
551 o 1 added b
552 | b
552 | b
553 o 0 added a
553 o 0 added a
554 a
554 a
555
555
556 Grafting revision 4 on top of revision 2, showing that it respect the rename:
556 Grafting revision 4 on top of revision 2, showing that it respect the rename:
557
557
558 $ hg up 2 -q
558 $ hg up 2 -q
559 $ hg graft -r 4 --base 3 --hidden
559 $ hg graft -r 4 --base 3 --hidden
560 grafting 4:af28412ec03c "added d, modified b" (tip) (no-changeset !)
560 grafting 4:af28412ec03c "added d, modified b" (tip) (no-changeset !)
561 grafting 4:6325ca0b7a1c "added d, modified b" (tip) (changeset !)
561 grafting 4:6325ca0b7a1c "added d, modified b" (tip) (changeset !)
562 merging b1 and b to b1
562 merging b1 and b to b1
563
563
564 $ hg l -l1 -p
564 $ hg l -l1 -p
565 @ 5 added d, modified b
565 @ 5 added d, modified b
566 | b1
566 | b1
567 ~ diff -r 5a4825cc2926 -r 94a2f1a0e8e2 b1 (no-changeset !)
567 ~ diff -r 5a4825cc2926 -r 94a2f1a0e8e2 b1 (no-changeset !)
568 ~ diff -r 0a0ed3b3251c -r d544fb655520 b1 (changeset !)
568 ~ diff -r 0a0ed3b3251c -r d544fb655520 b1 (changeset !)
569 --- a/b1 Thu Jan 01 00:00:00 1970 +0000
569 --- a/b1 Thu Jan 01 00:00:00 1970 +0000
570 +++ b/b1 Thu Jan 01 00:00:00 1970 +0000
570 +++ b/b1 Thu Jan 01 00:00:00 1970 +0000
571 @@ -1,1 +1,2 @@
571 @@ -1,1 +1,2 @@
572 b
572 b
573 +baba
573 +baba
574
574
575 Test to make sure that fullcopytracing algorithm doesn't fail when neither of the
575 Test to make sure that fullcopytracing algorithm doesn't fail when neither of the
576 merging csets is a descendant of the base.
576 merging csets is a descendant of the base.
577 -------------------------------------------------------------------------------------------------
577 -------------------------------------------------------------------------------------------------
578
578
579 $ newrepo
579 $ newrepo
580 $ echo a > a
580 $ echo a > a
581 $ hg add a
581 $ hg add a
582 $ hg ci -m "added a"
582 $ hg ci -m "added a"
583 $ echo b > b
583 $ echo b > b
584 $ hg add b
584 $ hg add b
585 $ hg ci -m "added b"
585 $ hg ci -m "added b"
586
586
587 $ echo foobar > willconflict
587 $ echo foobar > willconflict
588 $ hg add willconflict
588 $ hg add willconflict
589 $ hg ci -m "added willconflict"
589 $ hg ci -m "added willconflict"
590 $ echo c > c
590 $ echo c > c
591 $ hg add c
591 $ hg add c
592 $ hg ci -m "added c"
592 $ hg ci -m "added c"
593
593
594 $ hg l
594 $ hg l
595 @ 3 added c
595 @ 3 added c
596 | c
596 | c
597 o 2 added willconflict
597 o 2 added willconflict
598 | willconflict
598 | willconflict
599 o 1 added b
599 o 1 added b
600 | b
600 | b
601 o 0 added a
601 o 0 added a
602 a
602 a
603
603
604 $ hg up ".^^"
604 $ hg up ".^^"
605 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
605 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
606 $ echo d > d
606 $ echo d > d
607 $ hg add d
607 $ hg add d
608 $ hg ci -m "added d"
608 $ hg ci -m "added d"
609 created new head
609 created new head
610
610
611 $ echo barfoo > willconflict
611 $ echo barfoo > willconflict
612 $ hg add willconflict
612 $ hg add willconflict
613 $ hg ci --amend -m "added willconflict and d"
613 $ hg ci --amend -m "added willconflict and d"
614
614
615 $ hg l
615 $ hg l
616 @ 5 added willconflict and d
616 @ 5 added willconflict and d
617 | d willconflict
617 | d willconflict
618 | o 3 added c
618 | o 3 added c
619 | | c
619 | | c
620 | o 2 added willconflict
620 | o 2 added willconflict
621 |/ willconflict
621 |/ willconflict
622 o 1 added b
622 o 1 added b
623 | b
623 | b
624 o 0 added a
624 o 0 added a
625 a
625 a
626
626
627 $ hg rebase -r . -d 2 -t :other
627 $ hg rebase -r . -d 2 -t :other
628 rebasing 5:5018b1509e94 tip "added willconflict and d" (no-changeset !)
628 rebasing 5:5018b1509e94 tip "added willconflict and d" (no-changeset !)
629 rebasing 5:af8d273bf580 tip "added willconflict and d" (changeset !)
629 rebasing 5:af8d273bf580 tip "added willconflict and d" (changeset !)
630
630
631 $ hg up 3 -q
631 $ hg up 3 -q
632 $ hg l --hidden
632 $ hg l --hidden
633 o 6 added willconflict and d
633 o 6 added willconflict and d
634 | d willconflict
634 | d willconflict
635 | x 5 added willconflict and d
635 | x 5 added willconflict and d
636 | | d willconflict
636 | | d willconflict
637 | | x 4 added d
637 | | x 4 added d
638 | |/ d
638 | |/ d
639 +---@ 3 added c
639 +---@ 3 added c
640 | | c
640 | | c
641 o | 2 added willconflict
641 o | 2 added willconflict
642 |/ willconflict
642 |/ willconflict
643 o 1 added b
643 o 1 added b
644 | b
644 | b
645 o 0 added a
645 o 0 added a
646 a
646 a
647
647
648 Now if we trigger a merge between revision 3 and 6 using base revision 4,
648 Now if we trigger a merge between revision 3 and 6 using base revision 4,
649 neither of the merging csets will be a descendant of the base revision:
649 neither of the merging csets will be a descendant of the base revision:
650
650
651 $ hg graft -r 6 --base 4 --hidden -t :other
651 $ hg graft -r 6 --base 4 --hidden -t :other
652 grafting 6:99802e4f1e46 "added willconflict and d" (tip) (no-changeset !)
652 grafting 6:99802e4f1e46 "added willconflict and d" (tip) (no-changeset !)
653 grafting 6:b19f0df72728 "added willconflict and d" (tip) (changeset !)
653 grafting 6:b19f0df72728 "added willconflict and d" (tip) (changeset !)
General Comments 0
You need to be logged in to leave comments. Login now