Show More
@@ -1,1269 +1,1281 b'' | |||||
1 | # coding: utf8 |
|
1 | # coding: utf8 | |
2 | # copies.py - copy detection for Mercurial |
|
2 | # copies.py - copy detection for Mercurial | |
3 | # |
|
3 | # | |
4 | # Copyright 2008 Matt Mackall <mpm@selenic.com> |
|
4 | # Copyright 2008 Matt Mackall <mpm@selenic.com> | |
5 | # |
|
5 | # | |
6 | # This software may be used and distributed according to the terms of the |
|
6 | # This software may be used and distributed according to the terms of the | |
7 | # GNU General Public License version 2 or any later version. |
|
7 | # GNU General Public License version 2 or any later version. | |
8 |
|
8 | |||
9 | from __future__ import absolute_import |
|
9 | from __future__ import absolute_import | |
10 |
|
10 | |||
11 | import collections |
|
11 | import collections | |
12 | import os |
|
12 | import os | |
13 |
|
13 | |||
14 | from .i18n import _ |
|
14 | from .i18n import _ | |
15 | from .node import ( |
|
15 | from .node import ( | |
16 | nullid, |
|
16 | nullid, | |
17 | nullrev, |
|
17 | nullrev, | |
18 | ) |
|
18 | ) | |
19 |
|
19 | |||
20 | from . import ( |
|
20 | from . import ( | |
21 | match as matchmod, |
|
21 | match as matchmod, | |
22 | pathutil, |
|
22 | pathutil, | |
23 | policy, |
|
23 | policy, | |
24 | pycompat, |
|
24 | pycompat, | |
25 | util, |
|
25 | util, | |
26 | ) |
|
26 | ) | |
27 |
|
27 | |||
28 |
|
28 | |||
29 | from .utils import stringutil |
|
29 | from .utils import stringutil | |
30 |
|
30 | |||
31 | from .revlogutils import ( |
|
31 | from .revlogutils import ( | |
32 | flagutil, |
|
32 | flagutil, | |
33 | sidedata as sidedatamod, |
|
33 | sidedata as sidedatamod, | |
34 | ) |
|
34 | ) | |
35 |
|
35 | |||
36 | rustmod = policy.importrust("copy_tracing") |
|
36 | rustmod = policy.importrust("copy_tracing") | |
37 |
|
37 | |||
38 |
|
38 | |||
39 | def _filter(src, dst, t): |
|
39 | def _filter(src, dst, t): | |
40 | """filters out invalid copies after chaining""" |
|
40 | """filters out invalid copies after chaining""" | |
41 |
|
41 | |||
42 | # When _chain()'ing copies in 'a' (from 'src' via some other commit 'mid') |
|
42 | # When _chain()'ing copies in 'a' (from 'src' via some other commit 'mid') | |
43 | # with copies in 'b' (from 'mid' to 'dst'), we can get the different cases |
|
43 | # with copies in 'b' (from 'mid' to 'dst'), we can get the different cases | |
44 | # in the following table (not including trivial cases). For example, case 6 |
|
44 | # in the following table (not including trivial cases). For example, case 6 | |
45 | # is where a file existed in 'src' and remained under that name in 'mid' and |
|
45 | # is where a file existed in 'src' and remained under that name in 'mid' and | |
46 | # then was renamed between 'mid' and 'dst'. |
|
46 | # then was renamed between 'mid' and 'dst'. | |
47 | # |
|
47 | # | |
48 | # case src mid dst result |
|
48 | # case src mid dst result | |
49 | # 1 x y - - |
|
49 | # 1 x y - - | |
50 | # 2 x y y x->y |
|
50 | # 2 x y y x->y | |
51 | # 3 x y x - |
|
51 | # 3 x y x - | |
52 | # 4 x y z x->z |
|
52 | # 4 x y z x->z | |
53 | # 5 - x y - |
|
53 | # 5 - x y - | |
54 | # 6 x x y x->y |
|
54 | # 6 x x y x->y | |
55 | # |
|
55 | # | |
56 | # _chain() takes care of chaining the copies in 'a' and 'b', but it |
|
56 | # _chain() takes care of chaining the copies in 'a' and 'b', but it | |
57 | # cannot tell the difference between cases 1 and 2, between 3 and 4, or |
|
57 | # cannot tell the difference between cases 1 and 2, between 3 and 4, or | |
58 | # between 5 and 6, so it includes all cases in its result. |
|
58 | # between 5 and 6, so it includes all cases in its result. | |
59 | # Cases 1, 3, and 5 are then removed by _filter(). |
|
59 | # Cases 1, 3, and 5 are then removed by _filter(). | |
60 |
|
60 | |||
61 | for k, v in list(t.items()): |
|
61 | for k, v in list(t.items()): | |
62 | if k == v: # case 3 |
|
62 | if k == v: # case 3 | |
63 | del t[k] |
|
63 | del t[k] | |
64 | elif v not in src: # case 5 |
|
64 | elif v not in src: # case 5 | |
65 | # remove copies from files that didn't exist |
|
65 | # remove copies from files that didn't exist | |
66 | del t[k] |
|
66 | del t[k] | |
67 | elif k not in dst: # case 1 |
|
67 | elif k not in dst: # case 1 | |
68 | # remove copies to files that were then removed |
|
68 | # remove copies to files that were then removed | |
69 | del t[k] |
|
69 | del t[k] | |
70 |
|
70 | |||
71 |
|
71 | |||
72 | def _chain(prefix, suffix): |
|
72 | def _chain(prefix, suffix): | |
73 | """chain two sets of copies 'prefix' and 'suffix'""" |
|
73 | """chain two sets of copies 'prefix' and 'suffix'""" | |
74 | result = prefix.copy() |
|
74 | result = prefix.copy() | |
75 | for key, value in pycompat.iteritems(suffix): |
|
75 | for key, value in pycompat.iteritems(suffix): | |
76 | result[key] = prefix.get(value, value) |
|
76 | result[key] = prefix.get(value, value) | |
77 | return result |
|
77 | return result | |
78 |
|
78 | |||
79 |
|
79 | |||
80 | def _tracefile(fctx, am, basemf): |
|
80 | def _tracefile(fctx, am, basemf): | |
81 | """return file context that is the ancestor of fctx present in ancestor |
|
81 | """return file context that is the ancestor of fctx present in ancestor | |
82 | manifest am |
|
82 | manifest am | |
83 |
|
83 | |||
84 | Note: we used to try and stop after a given limit, however checking if that |
|
84 | Note: we used to try and stop after a given limit, however checking if that | |
85 | limit is reached turned out to be very expensive. we are better off |
|
85 | limit is reached turned out to be very expensive. we are better off | |
86 | disabling that feature.""" |
|
86 | disabling that feature.""" | |
87 |
|
87 | |||
88 | for f in fctx.ancestors(): |
|
88 | for f in fctx.ancestors(): | |
89 | path = f.path() |
|
89 | path = f.path() | |
90 | if am.get(path, None) == f.filenode(): |
|
90 | if am.get(path, None) == f.filenode(): | |
91 | return path |
|
91 | return path | |
92 | if basemf and basemf.get(path, None) == f.filenode(): |
|
92 | if basemf and basemf.get(path, None) == f.filenode(): | |
93 | return path |
|
93 | return path | |
94 |
|
94 | |||
95 |
|
95 | |||
96 | def _dirstatecopies(repo, match=None): |
|
96 | def _dirstatecopies(repo, match=None): | |
97 | ds = repo.dirstate |
|
97 | ds = repo.dirstate | |
98 | c = ds.copies().copy() |
|
98 | c = ds.copies().copy() | |
99 | for k in list(c): |
|
99 | for k in list(c): | |
100 | if ds[k] not in b'anm' or (match and not match(k)): |
|
100 | if ds[k] not in b'anm' or (match and not match(k)): | |
101 | del c[k] |
|
101 | del c[k] | |
102 | return c |
|
102 | return c | |
103 |
|
103 | |||
104 |
|
104 | |||
105 | def _computeforwardmissing(a, b, match=None): |
|
105 | def _computeforwardmissing(a, b, match=None): | |
106 | """Computes which files are in b but not a. |
|
106 | """Computes which files are in b but not a. | |
107 | This is its own function so extensions can easily wrap this call to see what |
|
107 | This is its own function so extensions can easily wrap this call to see what | |
108 | files _forwardcopies is about to process. |
|
108 | files _forwardcopies is about to process. | |
109 | """ |
|
109 | """ | |
110 | ma = a.manifest() |
|
110 | ma = a.manifest() | |
111 | mb = b.manifest() |
|
111 | mb = b.manifest() | |
112 | return mb.filesnotin(ma, match=match) |
|
112 | return mb.filesnotin(ma, match=match) | |
113 |
|
113 | |||
114 |
|
114 | |||
115 | def usechangesetcentricalgo(repo): |
|
115 | def usechangesetcentricalgo(repo): | |
116 | """Checks if we should use changeset-centric copy algorithms""" |
|
116 | """Checks if we should use changeset-centric copy algorithms""" | |
117 | if repo.filecopiesmode == b'changeset-sidedata': |
|
117 | if repo.filecopiesmode == b'changeset-sidedata': | |
118 | return True |
|
118 | return True | |
119 | readfrom = repo.ui.config(b'experimental', b'copies.read-from') |
|
119 | readfrom = repo.ui.config(b'experimental', b'copies.read-from') | |
120 | changesetsource = (b'changeset-only', b'compatibility') |
|
120 | changesetsource = (b'changeset-only', b'compatibility') | |
121 | return readfrom in changesetsource |
|
121 | return readfrom in changesetsource | |
122 |
|
122 | |||
123 |
|
123 | |||
124 | def _committedforwardcopies(a, b, base, match): |
|
124 | def _committedforwardcopies(a, b, base, match): | |
125 | """Like _forwardcopies(), but b.rev() cannot be None (working copy)""" |
|
125 | """Like _forwardcopies(), but b.rev() cannot be None (working copy)""" | |
126 | # files might have to be traced back to the fctx parent of the last |
|
126 | # files might have to be traced back to the fctx parent of the last | |
127 | # one-side-only changeset, but not further back than that |
|
127 | # one-side-only changeset, but not further back than that | |
128 | repo = a._repo |
|
128 | repo = a._repo | |
129 |
|
129 | |||
130 | if usechangesetcentricalgo(repo): |
|
130 | if usechangesetcentricalgo(repo): | |
131 | return _changesetforwardcopies(a, b, match) |
|
131 | return _changesetforwardcopies(a, b, match) | |
132 |
|
132 | |||
133 | debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies') |
|
133 | debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies') | |
134 | dbg = repo.ui.debug |
|
134 | dbg = repo.ui.debug | |
135 | if debug: |
|
135 | if debug: | |
136 | dbg(b'debug.copies: looking into rename from %s to %s\n' % (a, b)) |
|
136 | dbg(b'debug.copies: looking into rename from %s to %s\n' % (a, b)) | |
137 | am = a.manifest() |
|
137 | am = a.manifest() | |
138 | basemf = None if base is None else base.manifest() |
|
138 | basemf = None if base is None else base.manifest() | |
139 |
|
139 | |||
140 | # find where new files came from |
|
140 | # find where new files came from | |
141 | # we currently don't try to find where old files went, too expensive |
|
141 | # we currently don't try to find where old files went, too expensive | |
142 | # this means we can miss a case like 'hg rm b; hg cp a b' |
|
142 | # this means we can miss a case like 'hg rm b; hg cp a b' | |
143 | cm = {} |
|
143 | cm = {} | |
144 |
|
144 | |||
145 | # Computing the forward missing is quite expensive on large manifests, since |
|
145 | # Computing the forward missing is quite expensive on large manifests, since | |
146 | # it compares the entire manifests. We can optimize it in the common use |
|
146 | # it compares the entire manifests. We can optimize it in the common use | |
147 | # case of computing what copies are in a commit versus its parent (like |
|
147 | # case of computing what copies are in a commit versus its parent (like | |
148 | # during a rebase or histedit). Note, we exclude merge commits from this |
|
148 | # during a rebase or histedit). Note, we exclude merge commits from this | |
149 | # optimization, since the ctx.files() for a merge commit is not correct for |
|
149 | # optimization, since the ctx.files() for a merge commit is not correct for | |
150 | # this comparison. |
|
150 | # this comparison. | |
151 | forwardmissingmatch = match |
|
151 | forwardmissingmatch = match | |
152 | if b.p1() == a and b.p2().node() == nullid: |
|
152 | if b.p1() == a and b.p2().node() == nullid: | |
153 | filesmatcher = matchmod.exact(b.files()) |
|
153 | filesmatcher = matchmod.exact(b.files()) | |
154 | forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher) |
|
154 | forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher) | |
155 | if repo.ui.configbool(b'devel', b'copy-tracing.trace-all-files'): |
|
155 | if repo.ui.configbool(b'devel', b'copy-tracing.trace-all-files'): | |
156 | missing = list(b.walk(match)) |
|
156 | missing = list(b.walk(match)) | |
157 | # _computeforwardmissing(a, b, match=forwardmissingmatch) |
|
157 | # _computeforwardmissing(a, b, match=forwardmissingmatch) | |
158 | if debug: |
|
158 | if debug: | |
159 | dbg(b'debug.copies: searching all files: %d\n' % len(missing)) |
|
159 | dbg(b'debug.copies: searching all files: %d\n' % len(missing)) | |
160 | else: |
|
160 | else: | |
161 | missing = _computeforwardmissing(a, b, match=forwardmissingmatch) |
|
161 | missing = _computeforwardmissing(a, b, match=forwardmissingmatch) | |
162 | if debug: |
|
162 | if debug: | |
163 | dbg( |
|
163 | dbg( | |
164 | b'debug.copies: missing files to search: %d\n' |
|
164 | b'debug.copies: missing files to search: %d\n' | |
165 | % len(missing) |
|
165 | % len(missing) | |
166 | ) |
|
166 | ) | |
167 |
|
167 | |||
168 | ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True) |
|
168 | ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True) | |
169 |
|
169 | |||
170 | for f in sorted(missing): |
|
170 | for f in sorted(missing): | |
171 | if debug: |
|
171 | if debug: | |
172 | dbg(b'debug.copies: tracing file: %s\n' % f) |
|
172 | dbg(b'debug.copies: tracing file: %s\n' % f) | |
173 | fctx = b[f] |
|
173 | fctx = b[f] | |
174 | fctx._ancestrycontext = ancestrycontext |
|
174 | fctx._ancestrycontext = ancestrycontext | |
175 |
|
175 | |||
176 | if debug: |
|
176 | if debug: | |
177 | start = util.timer() |
|
177 | start = util.timer() | |
178 | opath = _tracefile(fctx, am, basemf) |
|
178 | opath = _tracefile(fctx, am, basemf) | |
179 | if opath: |
|
179 | if opath: | |
180 | if debug: |
|
180 | if debug: | |
181 | dbg(b'debug.copies: rename of: %s\n' % opath) |
|
181 | dbg(b'debug.copies: rename of: %s\n' % opath) | |
182 | cm[f] = opath |
|
182 | cm[f] = opath | |
183 | if debug: |
|
183 | if debug: | |
184 | dbg( |
|
184 | dbg( | |
185 | b'debug.copies: time: %f seconds\n' |
|
185 | b'debug.copies: time: %f seconds\n' | |
186 | % (util.timer() - start) |
|
186 | % (util.timer() - start) | |
187 | ) |
|
187 | ) | |
188 | return cm |
|
188 | return cm | |
189 |
|
189 | |||
190 |
|
190 | |||
191 | def _revinfo_getter(repo, match): |
|
191 | def _revinfo_getter(repo, match): | |
192 | """returns a function that returns the following data given a <rev>" |
|
192 | """returns a function that returns the following data given a <rev>" | |
193 |
|
193 | |||
194 | * p1: revision number of first parent |
|
194 | * p1: revision number of first parent | |
195 | * p2: revision number of first parent |
|
195 | * p2: revision number of first parent | |
196 | * changes: a ChangingFiles object |
|
196 | * changes: a ChangingFiles object | |
197 | """ |
|
197 | """ | |
198 | cl = repo.changelog |
|
198 | cl = repo.changelog | |
199 | parents = cl.parentrevs |
|
199 | parents = cl.parentrevs | |
200 | flags = cl.flags |
|
200 | flags = cl.flags | |
201 |
|
201 | |||
202 | HASCOPIESINFO = flagutil.REVIDX_HASCOPIESINFO |
|
202 | HASCOPIESINFO = flagutil.REVIDX_HASCOPIESINFO | |
203 |
|
203 | |||
204 | changelogrevision = cl.changelogrevision |
|
204 | changelogrevision = cl.changelogrevision | |
205 |
|
205 | |||
206 | if rustmod is not None: |
|
206 | if rustmod is not None: | |
207 |
|
207 | |||
208 | def revinfo(rev): |
|
208 | def revinfo(rev): | |
209 | p1, p2 = parents(rev) |
|
209 | p1, p2 = parents(rev) | |
210 | if flags(rev) & HASCOPIESINFO: |
|
210 | if flags(rev) & HASCOPIESINFO: | |
211 | raw = changelogrevision(rev)._sidedata.get(sidedatamod.SD_FILES) |
|
211 | raw = changelogrevision(rev)._sidedata.get(sidedatamod.SD_FILES) | |
212 | else: |
|
212 | else: | |
213 | raw = None |
|
213 | raw = None | |
214 | return (p1, p2, raw) |
|
214 | return (p1, p2, raw) | |
215 |
|
215 | |||
216 | else: |
|
216 | else: | |
217 |
|
217 | |||
218 | def revinfo(rev): |
|
218 | def revinfo(rev): | |
219 | p1, p2 = parents(rev) |
|
219 | p1, p2 = parents(rev) | |
220 | if flags(rev) & HASCOPIESINFO: |
|
220 | if flags(rev) & HASCOPIESINFO: | |
221 | changes = changelogrevision(rev).changes |
|
221 | changes = changelogrevision(rev).changes | |
222 | else: |
|
222 | else: | |
223 | changes = None |
|
223 | changes = None | |
224 | return (p1, p2, changes) |
|
224 | return (p1, p2, changes) | |
225 |
|
225 | |||
226 | return revinfo |
|
226 | return revinfo | |
227 |
|
227 | |||
228 |
|
228 | |||
229 | def cached_is_ancestor(is_ancestor): |
|
229 | def cached_is_ancestor(is_ancestor): | |
230 | """return a cached version of is_ancestor""" |
|
230 | """return a cached version of is_ancestor""" | |
231 | cache = {} |
|
231 | cache = {} | |
232 |
|
232 | |||
233 | def _is_ancestor(anc, desc): |
|
233 | def _is_ancestor(anc, desc): | |
234 | if anc > desc: |
|
234 | if anc > desc: | |
235 | return False |
|
235 | return False | |
236 | elif anc == desc: |
|
236 | elif anc == desc: | |
237 | return True |
|
237 | return True | |
238 | key = (anc, desc) |
|
238 | key = (anc, desc) | |
239 | ret = cache.get(key) |
|
239 | ret = cache.get(key) | |
240 | if ret is None: |
|
240 | if ret is None: | |
241 | ret = cache[key] = is_ancestor(anc, desc) |
|
241 | ret = cache[key] = is_ancestor(anc, desc) | |
242 | return ret |
|
242 | return ret | |
243 |
|
243 | |||
244 | return _is_ancestor |
|
244 | return _is_ancestor | |
245 |
|
245 | |||
246 |
|
246 | |||
247 | def _changesetforwardcopies(a, b, match): |
|
247 | def _changesetforwardcopies(a, b, match): | |
248 | if a.rev() in (nullrev, b.rev()): |
|
248 | if a.rev() in (nullrev, b.rev()): | |
249 | return {} |
|
249 | return {} | |
250 |
|
250 | |||
251 | repo = a.repo().unfiltered() |
|
251 | repo = a.repo().unfiltered() | |
252 | children = {} |
|
252 | children = {} | |
253 |
|
253 | |||
254 | cl = repo.changelog |
|
254 | cl = repo.changelog | |
255 | isancestor = cl.isancestorrev |
|
255 | isancestor = cl.isancestorrev | |
256 |
|
256 | |||
257 | # To track rename from "A" to B, we need to gather all parent β children |
|
257 | # To track rename from "A" to B, we need to gather all parent β children | |
258 | # edges that are contains in `::B` but not in `::A`. |
|
258 | # edges that are contains in `::B` but not in `::A`. | |
259 | # |
|
259 | # | |
260 | # |
|
260 | # | |
261 | # To do so, we need to gather all revisions exclusiveΒΉ to "B" (ieΒΉ: `::b - |
|
261 | # To do so, we need to gather all revisions exclusiveΒΉ to "B" (ieΒΉ: `::b - | |
262 | # ::a`) and also all the "roots point", ie the parents of the exclusive set |
|
262 | # ::a`) and also all the "roots point", ie the parents of the exclusive set | |
263 | # that belong to ::a. These are exactly all the revisions needed to express |
|
263 | # that belong to ::a. These are exactly all the revisions needed to express | |
264 | # the parent β children we need to combine. |
|
264 | # the parent β children we need to combine. | |
265 | # |
|
265 | # | |
266 | # [1] actually, we need to gather all the edges within `(::a)::b`, ie: |
|
266 | # [1] actually, we need to gather all the edges within `(::a)::b`, ie: | |
267 | # excluding paths that leads to roots that are not ancestors of `a`. We |
|
267 | # excluding paths that leads to roots that are not ancestors of `a`. We | |
268 | # keep this out of the explanation because it is hard enough without this special case.. |
|
268 | # keep this out of the explanation because it is hard enough without this special case.. | |
269 |
|
269 | |||
270 | parents = cl._uncheckedparentrevs |
|
270 | parents = cl._uncheckedparentrevs | |
271 | graph_roots = (nullrev, nullrev) |
|
271 | graph_roots = (nullrev, nullrev) | |
272 |
|
272 | |||
273 | ancestors = cl.ancestors([a.rev()], inclusive=True) |
|
273 | ancestors = cl.ancestors([a.rev()], inclusive=True) | |
274 | revs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()]) |
|
274 | revs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()]) | |
275 | roots = set() |
|
275 | roots = set() | |
276 | has_graph_roots = False |
|
276 | has_graph_roots = False | |
277 |
|
277 | |||
278 | # iterate over `only(B, A)` |
|
278 | # iterate over `only(B, A)` | |
279 | for r in revs: |
|
279 | for r in revs: | |
280 | ps = parents(r) |
|
280 | ps = parents(r) | |
281 | if ps == graph_roots: |
|
281 | if ps == graph_roots: | |
282 | has_graph_roots = True |
|
282 | has_graph_roots = True | |
283 | else: |
|
283 | else: | |
284 | p1, p2 = ps |
|
284 | p1, p2 = ps | |
285 |
|
285 | |||
286 | # find all the "root points" (see larger comment above) |
|
286 | # find all the "root points" (see larger comment above) | |
287 | if p1 != nullrev and p1 in ancestors: |
|
287 | if p1 != nullrev and p1 in ancestors: | |
288 | roots.add(p1) |
|
288 | roots.add(p1) | |
289 | if p2 != nullrev and p2 in ancestors: |
|
289 | if p2 != nullrev and p2 in ancestors: | |
290 | roots.add(p2) |
|
290 | roots.add(p2) | |
291 | if not roots: |
|
291 | if not roots: | |
292 | # no common revision to track copies from |
|
292 | # no common revision to track copies from | |
293 | return {} |
|
293 | return {} | |
294 | if has_graph_roots: |
|
294 | if has_graph_roots: | |
295 | # this deal with the special case mentionned in the [1] footnotes. We |
|
295 | # this deal with the special case mentionned in the [1] footnotes. We | |
296 | # must filter out revisions that leads to non-common graphroots. |
|
296 | # must filter out revisions that leads to non-common graphroots. | |
297 | roots = list(roots) |
|
297 | roots = list(roots) | |
298 | m = min(roots) |
|
298 | m = min(roots) | |
299 | h = [b.rev()] |
|
299 | h = [b.rev()] | |
300 | roots_to_head = cl.reachableroots(m, h, roots, includepath=True) |
|
300 | roots_to_head = cl.reachableroots(m, h, roots, includepath=True) | |
301 | roots_to_head = set(roots_to_head) |
|
301 | roots_to_head = set(roots_to_head) | |
302 | revs = [r for r in revs if r in roots_to_head] |
|
302 | revs = [r for r in revs if r in roots_to_head] | |
303 |
|
303 | |||
304 | if repo.filecopiesmode == b'changeset-sidedata': |
|
304 | if repo.filecopiesmode == b'changeset-sidedata': | |
305 | # When using side-data, we will process the edges "from" the children. |
|
305 | # When using side-data, we will process the edges "from" the children. | |
306 | # We iterate over the childre, gathering previous collected data for |
|
306 | # We iterate over the childre, gathering previous collected data for | |
307 | # the parents. Do know when the parents data is no longer necessary, we |
|
307 | # the parents. Do know when the parents data is no longer necessary, we | |
308 | # keep a counter of how many children each revision has. |
|
308 | # keep a counter of how many children each revision has. | |
309 | # |
|
309 | # | |
310 | # An interresting property of `children_count` is that it only contains |
|
310 | # An interresting property of `children_count` is that it only contains | |
311 | # revision that will be relevant for a edge of the graph. So if a |
|
311 | # revision that will be relevant for a edge of the graph. So if a | |
312 | # children has parent not in `children_count`, that edges should not be |
|
312 | # children has parent not in `children_count`, that edges should not be | |
313 | # processed. |
|
313 | # processed. | |
314 | children_count = dict((r, 0) for r in roots) |
|
314 | children_count = dict((r, 0) for r in roots) | |
315 | for r in revs: |
|
315 | for r in revs: | |
316 | for p in cl.parentrevs(r): |
|
316 | for p in cl.parentrevs(r): | |
317 | if p == nullrev: |
|
317 | if p == nullrev: | |
318 | continue |
|
318 | continue | |
319 | children_count[r] = 0 |
|
319 | children_count[r] = 0 | |
320 | if p in children_count: |
|
320 | if p in children_count: | |
321 | children_count[p] += 1 |
|
321 | children_count[p] += 1 | |
322 | revinfo = _revinfo_getter(repo, match) |
|
322 | revinfo = _revinfo_getter(repo, match) | |
323 | return _combine_changeset_copies( |
|
323 | return _combine_changeset_copies( | |
324 | revs, children_count, b.rev(), revinfo, match, isancestor |
|
324 | revs, children_count, b.rev(), revinfo, match, isancestor | |
325 | ) |
|
325 | ) | |
326 | else: |
|
326 | else: | |
327 | # When not using side-data, we will process the edges "from" the parent. |
|
327 | # When not using side-data, we will process the edges "from" the parent. | |
328 | # so we need a full mapping of the parent -> children relation. |
|
328 | # so we need a full mapping of the parent -> children relation. | |
329 | children = dict((r, []) for r in roots) |
|
329 | children = dict((r, []) for r in roots) | |
330 | for r in revs: |
|
330 | for r in revs: | |
331 | for p in cl.parentrevs(r): |
|
331 | for p in cl.parentrevs(r): | |
332 | if p == nullrev: |
|
332 | if p == nullrev: | |
333 | continue |
|
333 | continue | |
334 | children[r] = [] |
|
334 | children[r] = [] | |
335 | if p in children: |
|
335 | if p in children: | |
336 | children[p].append(r) |
|
336 | children[p].append(r) | |
337 | x = revs.pop() |
|
337 | x = revs.pop() | |
338 | assert x == b.rev() |
|
338 | assert x == b.rev() | |
339 | revs.extend(roots) |
|
339 | revs.extend(roots) | |
340 | revs.sort() |
|
340 | revs.sort() | |
341 |
|
341 | |||
342 | revinfo = _revinfo_getter_extra(repo) |
|
342 | revinfo = _revinfo_getter_extra(repo) | |
343 | return _combine_changeset_copies_extra( |
|
343 | return _combine_changeset_copies_extra( | |
344 | revs, children, b.rev(), revinfo, match, isancestor |
|
344 | revs, children, b.rev(), revinfo, match, isancestor | |
345 | ) |
|
345 | ) | |
346 |
|
346 | |||
347 |
|
347 | |||
348 | def _combine_changeset_copies( |
|
348 | def _combine_changeset_copies( | |
349 | revs, children_count, targetrev, revinfo, match, isancestor |
|
349 | revs, children_count, targetrev, revinfo, match, isancestor | |
350 | ): |
|
350 | ): | |
351 | """combine the copies information for each item of iterrevs |
|
351 | """combine the copies information for each item of iterrevs | |
352 |
|
352 | |||
353 | revs: sorted iterable of revision to visit |
|
353 | revs: sorted iterable of revision to visit | |
354 | children_count: a {parent: <number-of-relevant-children>} mapping. |
|
354 | children_count: a {parent: <number-of-relevant-children>} mapping. | |
355 | targetrev: the final copies destination revision (not in iterrevs) |
|
355 | targetrev: the final copies destination revision (not in iterrevs) | |
356 | revinfo(rev): a function that return (p1, p2, p1copies, p2copies, removed) |
|
356 | revinfo(rev): a function that return (p1, p2, p1copies, p2copies, removed) | |
357 | match: a matcher |
|
357 | match: a matcher | |
358 |
|
358 | |||
359 | It returns the aggregated copies information for `targetrev`. |
|
359 | It returns the aggregated copies information for `targetrev`. | |
360 | """ |
|
360 | """ | |
361 |
|
361 | |||
362 | alwaysmatch = match.always() |
|
362 | alwaysmatch = match.always() | |
363 |
|
363 | |||
364 | if rustmod is not None: |
|
364 | if rustmod is not None: | |
365 | final_copies = rustmod.combine_changeset_copies( |
|
365 | final_copies = rustmod.combine_changeset_copies( | |
366 | list(revs), children_count, targetrev, revinfo, isancestor |
|
366 | list(revs), children_count, targetrev, revinfo, isancestor | |
367 | ) |
|
367 | ) | |
368 | else: |
|
368 | else: | |
369 | isancestor = cached_is_ancestor(isancestor) |
|
369 | isancestor = cached_is_ancestor(isancestor) | |
370 |
|
370 | |||
371 | all_copies = {} |
|
371 | all_copies = {} | |
372 | # iterate over all the "children" side of copy tracing "edge" |
|
372 | # iterate over all the "children" side of copy tracing "edge" | |
373 | for current_rev in revs: |
|
373 | for current_rev in revs: | |
374 | p1, p2, changes = revinfo(current_rev) |
|
374 | p1, p2, changes = revinfo(current_rev) | |
375 | current_copies = None |
|
375 | current_copies = None | |
376 | # iterate over all parents to chain the existing data with the |
|
376 | # iterate over all parents to chain the existing data with the | |
377 | # data from the parent β child edge. |
|
377 | # data from the parent β child edge. | |
378 | for parent, parent_rev in ((1, p1), (2, p2)): |
|
378 | for parent, parent_rev in ((1, p1), (2, p2)): | |
379 | if parent_rev == nullrev: |
|
379 | if parent_rev == nullrev: | |
380 | continue |
|
380 | continue | |
381 | remaining_children = children_count.get(parent_rev) |
|
381 | remaining_children = children_count.get(parent_rev) | |
382 | if remaining_children is None: |
|
382 | if remaining_children is None: | |
383 | continue |
|
383 | continue | |
384 | remaining_children -= 1 |
|
384 | remaining_children -= 1 | |
385 | children_count[parent_rev] = remaining_children |
|
385 | children_count[parent_rev] = remaining_children | |
386 | if remaining_children: |
|
386 | if remaining_children: | |
387 | copies = all_copies.get(parent_rev, None) |
|
387 | copies = all_copies.get(parent_rev, None) | |
388 | else: |
|
388 | else: | |
389 | copies = all_copies.pop(parent_rev, None) |
|
389 | copies = all_copies.pop(parent_rev, None) | |
390 |
|
390 | |||
391 | if copies is None: |
|
391 | if copies is None: | |
392 | # this is a root |
|
392 | # this is a root | |
393 | newcopies = copies = {} |
|
393 | newcopies = copies = {} | |
394 | elif remaining_children: |
|
394 | elif remaining_children: | |
395 | newcopies = copies.copy() |
|
395 | newcopies = copies.copy() | |
396 | else: |
|
396 | else: | |
397 | newcopies = copies |
|
397 | newcopies = copies | |
398 | # chain the data in the edge with the existing data |
|
398 | # chain the data in the edge with the existing data | |
399 | if changes is not None: |
|
399 | if changes is not None: | |
400 | childcopies = {} |
|
400 | childcopies = {} | |
401 | if parent == 1: |
|
401 | if parent == 1: | |
402 | childcopies = changes.copied_from_p1 |
|
402 | childcopies = changes.copied_from_p1 | |
403 | elif parent == 2: |
|
403 | elif parent == 2: | |
404 | childcopies = changes.copied_from_p2 |
|
404 | childcopies = changes.copied_from_p2 | |
405 |
|
405 | |||
406 | if childcopies: |
|
406 | if childcopies: | |
407 | newcopies = copies.copy() |
|
407 | newcopies = copies.copy() | |
408 | for dest, source in pycompat.iteritems(childcopies): |
|
408 | for dest, source in pycompat.iteritems(childcopies): | |
409 | prev = copies.get(source) |
|
409 | prev = copies.get(source) | |
410 | if prev is not None and prev[1] is not None: |
|
410 | if prev is not None and prev[1] is not None: | |
411 | source = prev[1] |
|
411 | source = prev[1] | |
412 | newcopies[dest] = (current_rev, source) |
|
412 | newcopies[dest] = (current_rev, source) | |
413 | assert newcopies is not copies |
|
413 | assert newcopies is not copies | |
414 | if changes.removed: |
|
414 | if changes.removed: | |
415 | for f in changes.removed: |
|
415 | for f in changes.removed: | |
416 | if f in newcopies: |
|
416 | if f in newcopies: | |
417 | if newcopies is copies: |
|
417 | if newcopies is copies: | |
418 | # copy on write to avoid affecting potential other |
|
418 | # copy on write to avoid affecting potential other | |
419 | # branches. when there are no other branches, this |
|
419 | # branches. when there are no other branches, this | |
420 | # could be avoided. |
|
420 | # could be avoided. | |
421 | newcopies = copies.copy() |
|
421 | newcopies = copies.copy() | |
422 | newcopies[f] = (current_rev, None) |
|
422 | newcopies[f] = (current_rev, None) | |
423 | # check potential need to combine the data from another parent (for |
|
423 | # check potential need to combine the data from another parent (for | |
424 | # that child). See comment below for details. |
|
424 | # that child). See comment below for details. | |
425 | if current_copies is None: |
|
425 | if current_copies is None: | |
426 | current_copies = newcopies |
|
426 | current_copies = newcopies | |
427 | else: |
|
427 | else: | |
428 | # we are the second parent to work on c, we need to merge our |
|
428 | # we are the second parent to work on c, we need to merge our | |
429 | # work with the other. |
|
429 | # work with the other. | |
430 | # |
|
430 | # | |
431 | # In case of conflict, parent 1 take precedence over parent 2. |
|
431 | # In case of conflict, parent 1 take precedence over parent 2. | |
432 | # This is an arbitrary choice made anew when implementing |
|
432 | # This is an arbitrary choice made anew when implementing | |
433 | # changeset based copies. It was made without regards with |
|
433 | # changeset based copies. It was made without regards with | |
434 | # potential filelog related behavior. |
|
434 | # potential filelog related behavior. | |
435 | assert parent == 2 |
|
435 | assert parent == 2 | |
436 | current_copies = _merge_copies_dict( |
|
436 | current_copies = _merge_copies_dict( | |
437 |
newcopies, |
|
437 | newcopies, | |
|
438 | current_copies, | |||
|
439 | isancestor, | |||
|
440 | changes, | |||
|
441 | current_rev, | |||
438 | ) |
|
442 | ) | |
439 | all_copies[current_rev] = current_copies |
|
443 | all_copies[current_rev] = current_copies | |
440 |
|
444 | |||
441 | # filter out internal details and return a {dest: source mapping} |
|
445 | # filter out internal details and return a {dest: source mapping} | |
442 | final_copies = {} |
|
446 | final_copies = {} | |
443 | for dest, (tt, source) in all_copies[targetrev].items(): |
|
447 | for dest, (tt, source) in all_copies[targetrev].items(): | |
444 | if source is not None: |
|
448 | if source is not None: | |
445 | final_copies[dest] = source |
|
449 | final_copies[dest] = source | |
446 | if not alwaysmatch: |
|
450 | if not alwaysmatch: | |
447 | for filename in list(final_copies.keys()): |
|
451 | for filename in list(final_copies.keys()): | |
448 | if not match(filename): |
|
452 | if not match(filename): | |
449 | del final_copies[filename] |
|
453 | del final_copies[filename] | |
450 | return final_copies |
|
454 | return final_copies | |
451 |
|
455 | |||
452 |
|
456 | |||
453 | # constant to decide which side to pick with _merge_copies_dict |
|
457 | # constant to decide which side to pick with _merge_copies_dict | |
454 | PICK_MINOR = 0 |
|
458 | PICK_MINOR = 0 | |
455 | PICK_MAJOR = 1 |
|
459 | PICK_MAJOR = 1 | |
456 | PICK_EITHER = 2 |
|
460 | PICK_EITHER = 2 | |
457 |
|
461 | |||
458 |
|
462 | |||
459 | def _merge_copies_dict(minor, major, isancestor, changes): |
|
463 | def _merge_copies_dict(minor, major, isancestor, changes, current_merge): | |
460 | """merge two copies-mapping together, minor and major |
|
464 | """merge two copies-mapping together, minor and major | |
461 |
|
465 | |||
462 | In case of conflict, value from "major" will be picked. |
|
466 | In case of conflict, value from "major" will be picked. | |
463 |
|
467 | |||
464 | - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an |
|
468 | - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an | |
465 | ancestors of `high_rev`, |
|
469 | ancestors of `high_rev`, | |
466 |
|
470 | |||
467 | - `ismerged(path)`: callable return True if `path` have been merged in the |
|
471 | - `ismerged(path)`: callable return True if `path` have been merged in the | |
468 | current revision, |
|
472 | current revision, | |
469 |
|
473 | |||
470 | return the resulting dict (in practice, the "minor" object, updated) |
|
474 | return the resulting dict (in practice, the "minor" object, updated) | |
471 | """ |
|
475 | """ | |
472 | for dest, value in major.items(): |
|
476 | for dest, value in major.items(): | |
473 | other = minor.get(dest) |
|
477 | other = minor.get(dest) | |
474 | if other is None: |
|
478 | if other is None: | |
475 | minor[dest] = value |
|
479 | minor[dest] = value | |
476 | else: |
|
480 | else: | |
477 | pick = _compare_values(changes, isancestor, dest, other, value) |
|
481 | pick, overwrite = _compare_values( | |
478 | if pick == PICK_MAJOR: |
|
482 | changes, isancestor, dest, other, value | |
|
483 | ) | |||
|
484 | if overwrite: | |||
|
485 | if pick == PICK_MAJOR: | |||
|
486 | minor[dest] = (current_merge, value[1]) | |||
|
487 | else: | |||
|
488 | minor[dest] = (current_merge, other[1]) | |||
|
489 | elif pick == PICK_MAJOR: | |||
479 | minor[dest] = value |
|
490 | minor[dest] = value | |
480 | return minor |
|
491 | return minor | |
481 |
|
492 | |||
482 |
|
493 | |||
483 | def _compare_values(changes, isancestor, dest, minor, major): |
|
494 | def _compare_values(changes, isancestor, dest, minor, major): | |
484 | """compare two value within a _merge_copies_dict loop iteration |
|
495 | """compare two value within a _merge_copies_dict loop iteration | |
485 |
|
496 | |||
486 | return pick |
|
497 | return (pick, overwrite). | |
487 |
|
498 | |||
488 | - pick is one of PICK_MINOR, PICK_MAJOR or PICK_EITHER |
|
499 | - pick is one of PICK_MINOR, PICK_MAJOR or PICK_EITHER | |
|
500 | - overwrite is True if pick is a return of an ambiguity that needs resolution. | |||
489 | """ |
|
501 | """ | |
490 | major_tt, major_value = major |
|
502 | major_tt, major_value = major | |
491 | minor_tt, minor_value = minor |
|
503 | minor_tt, minor_value = minor | |
492 |
|
504 | |||
493 | if major_tt == minor_tt: |
|
505 | if major_tt == minor_tt: | |
494 | # if it comes from the same revision it must be the same value |
|
506 | # if it comes from the same revision it must be the same value | |
495 | assert major_value == minor_value |
|
507 | assert major_value == minor_value | |
496 | return PICK_EITHER |
|
508 | return PICK_EITHER, False | |
497 | elif ( |
|
509 | elif ( | |
498 | changes is not None |
|
510 | changes is not None | |
499 | and minor_value is not None |
|
511 | and minor_value is not None | |
500 | and major_value is None |
|
512 | and major_value is None | |
501 | and dest in changes.salvaged |
|
513 | and dest in changes.salvaged | |
502 | ): |
|
514 | ): | |
503 | # In this case, a deletion was reverted, the "alive" value overwrite |
|
515 | # In this case, a deletion was reverted, the "alive" value overwrite | |
504 | # the deleted one. |
|
516 | # the deleted one. | |
505 | return PICK_MINOR |
|
517 | return PICK_MINOR, True | |
506 | elif ( |
|
518 | elif ( | |
507 | changes is not None |
|
519 | changes is not None | |
508 | and major_value is not None |
|
520 | and major_value is not None | |
509 | and minor_value is None |
|
521 | and minor_value is None | |
510 | and dest in changes.salvaged |
|
522 | and dest in changes.salvaged | |
511 | ): |
|
523 | ): | |
512 | # In this case, a deletion was reverted, the "alive" value overwrite |
|
524 | # In this case, a deletion was reverted, the "alive" value overwrite | |
513 | # the deleted one. |
|
525 | # the deleted one. | |
514 | return PICK_MAJOR |
|
526 | return PICK_MAJOR, True | |
515 | elif isancestor(minor_tt, major_tt): |
|
527 | elif isancestor(minor_tt, major_tt): | |
516 | if changes is not None and dest in changes.merged: |
|
528 | if changes is not None and dest in changes.merged: | |
517 | # change to dest happened on the branch without copy-source change, |
|
529 | # change to dest happened on the branch without copy-source change, | |
518 | # so both source are valid and "major" wins. |
|
530 | # so both source are valid and "major" wins. | |
519 | return PICK_MAJOR |
|
531 | return PICK_MAJOR, True | |
520 | else: |
|
532 | else: | |
521 | return PICK_MAJOR |
|
533 | return PICK_MAJOR, False | |
522 | elif isancestor(major_tt, minor_tt): |
|
534 | elif isancestor(major_tt, minor_tt): | |
523 | if changes is not None and dest in changes.merged: |
|
535 | if changes is not None and dest in changes.merged: | |
524 | # change to dest happened on the branch without copy-source change, |
|
536 | # change to dest happened on the branch without copy-source change, | |
525 | # so both source are valid and "major" wins. |
|
537 | # so both source are valid and "major" wins. | |
526 | return PICK_MAJOR |
|
538 | return PICK_MAJOR, True | |
527 | else: |
|
539 | else: | |
528 | return PICK_MINOR |
|
540 | return PICK_MINOR, False | |
529 | elif minor_value is None: |
|
541 | elif minor_value is None: | |
530 | # in case of conflict, the "alive" side wins. |
|
542 | # in case of conflict, the "alive" side wins. | |
531 | return PICK_MAJOR |
|
543 | return PICK_MAJOR, True | |
532 | elif major_value is None: |
|
544 | elif major_value is None: | |
533 | # in case of conflict, the "alive" side wins. |
|
545 | # in case of conflict, the "alive" side wins. | |
534 | return PICK_MINOR |
|
546 | return PICK_MINOR, True | |
535 | else: |
|
547 | else: | |
536 | # in case of conflict where both side are alive, major wins. |
|
548 | # in case of conflict where both side are alive, major wins. | |
537 | return PICK_MAJOR |
|
549 | return PICK_MAJOR, True | |
538 |
|
550 | |||
539 |
|
551 | |||
540 | def _revinfo_getter_extra(repo): |
|
552 | def _revinfo_getter_extra(repo): | |
541 | """return a function that return multiple data given a <rev>"i |
|
553 | """return a function that return multiple data given a <rev>"i | |
542 |
|
554 | |||
543 | * p1: revision number of first parent |
|
555 | * p1: revision number of first parent | |
544 | * p2: revision number of first parent |
|
556 | * p2: revision number of first parent | |
545 | * p1copies: mapping of copies from p1 |
|
557 | * p1copies: mapping of copies from p1 | |
546 | * p2copies: mapping of copies from p2 |
|
558 | * p2copies: mapping of copies from p2 | |
547 | * removed: a list of removed files |
|
559 | * removed: a list of removed files | |
548 | * ismerged: a callback to know if file was merged in that revision |
|
560 | * ismerged: a callback to know if file was merged in that revision | |
549 | """ |
|
561 | """ | |
550 | cl = repo.changelog |
|
562 | cl = repo.changelog | |
551 | parents = cl.parentrevs |
|
563 | parents = cl.parentrevs | |
552 |
|
564 | |||
553 | def get_ismerged(rev): |
|
565 | def get_ismerged(rev): | |
554 | ctx = repo[rev] |
|
566 | ctx = repo[rev] | |
555 |
|
567 | |||
556 | def ismerged(path): |
|
568 | def ismerged(path): | |
557 | if path not in ctx.files(): |
|
569 | if path not in ctx.files(): | |
558 | return False |
|
570 | return False | |
559 | fctx = ctx[path] |
|
571 | fctx = ctx[path] | |
560 | parents = fctx._filelog.parents(fctx._filenode) |
|
572 | parents = fctx._filelog.parents(fctx._filenode) | |
561 | nb_parents = 0 |
|
573 | nb_parents = 0 | |
562 | for n in parents: |
|
574 | for n in parents: | |
563 | if n != nullid: |
|
575 | if n != nullid: | |
564 | nb_parents += 1 |
|
576 | nb_parents += 1 | |
565 | return nb_parents >= 2 |
|
577 | return nb_parents >= 2 | |
566 |
|
578 | |||
567 | return ismerged |
|
579 | return ismerged | |
568 |
|
580 | |||
569 | def revinfo(rev): |
|
581 | def revinfo(rev): | |
570 | p1, p2 = parents(rev) |
|
582 | p1, p2 = parents(rev) | |
571 | ctx = repo[rev] |
|
583 | ctx = repo[rev] | |
572 | p1copies, p2copies = ctx._copies |
|
584 | p1copies, p2copies = ctx._copies | |
573 | removed = ctx.filesremoved() |
|
585 | removed = ctx.filesremoved() | |
574 | return p1, p2, p1copies, p2copies, removed, get_ismerged(rev) |
|
586 | return p1, p2, p1copies, p2copies, removed, get_ismerged(rev) | |
575 |
|
587 | |||
576 | return revinfo |
|
588 | return revinfo | |
577 |
|
589 | |||
578 |
|
590 | |||
579 | def _combine_changeset_copies_extra( |
|
591 | def _combine_changeset_copies_extra( | |
580 | revs, children, targetrev, revinfo, match, isancestor |
|
592 | revs, children, targetrev, revinfo, match, isancestor | |
581 | ): |
|
593 | ): | |
582 | """version of `_combine_changeset_copies` that works with the Google |
|
594 | """version of `_combine_changeset_copies` that works with the Google | |
583 | specific "extra" based storage for copy information""" |
|
595 | specific "extra" based storage for copy information""" | |
584 | all_copies = {} |
|
596 | all_copies = {} | |
585 | alwaysmatch = match.always() |
|
597 | alwaysmatch = match.always() | |
586 | for r in revs: |
|
598 | for r in revs: | |
587 | copies = all_copies.pop(r, None) |
|
599 | copies = all_copies.pop(r, None) | |
588 | if copies is None: |
|
600 | if copies is None: | |
589 | # this is a root |
|
601 | # this is a root | |
590 | copies = {} |
|
602 | copies = {} | |
591 | for i, c in enumerate(children[r]): |
|
603 | for i, c in enumerate(children[r]): | |
592 | p1, p2, p1copies, p2copies, removed, ismerged = revinfo(c) |
|
604 | p1, p2, p1copies, p2copies, removed, ismerged = revinfo(c) | |
593 | if r == p1: |
|
605 | if r == p1: | |
594 | parent = 1 |
|
606 | parent = 1 | |
595 | childcopies = p1copies |
|
607 | childcopies = p1copies | |
596 | else: |
|
608 | else: | |
597 | assert r == p2 |
|
609 | assert r == p2 | |
598 | parent = 2 |
|
610 | parent = 2 | |
599 | childcopies = p2copies |
|
611 | childcopies = p2copies | |
600 | if not alwaysmatch: |
|
612 | if not alwaysmatch: | |
601 | childcopies = { |
|
613 | childcopies = { | |
602 | dst: src for dst, src in childcopies.items() if match(dst) |
|
614 | dst: src for dst, src in childcopies.items() if match(dst) | |
603 | } |
|
615 | } | |
604 | newcopies = copies |
|
616 | newcopies = copies | |
605 | if childcopies: |
|
617 | if childcopies: | |
606 | newcopies = copies.copy() |
|
618 | newcopies = copies.copy() | |
607 | for dest, source in pycompat.iteritems(childcopies): |
|
619 | for dest, source in pycompat.iteritems(childcopies): | |
608 | prev = copies.get(source) |
|
620 | prev = copies.get(source) | |
609 | if prev is not None and prev[1] is not None: |
|
621 | if prev is not None and prev[1] is not None: | |
610 | source = prev[1] |
|
622 | source = prev[1] | |
611 | newcopies[dest] = (c, source) |
|
623 | newcopies[dest] = (c, source) | |
612 | assert newcopies is not copies |
|
624 | assert newcopies is not copies | |
613 | for f in removed: |
|
625 | for f in removed: | |
614 | if f in newcopies: |
|
626 | if f in newcopies: | |
615 | if newcopies is copies: |
|
627 | if newcopies is copies: | |
616 | # copy on write to avoid affecting potential other |
|
628 | # copy on write to avoid affecting potential other | |
617 | # branches. when there are no other branches, this |
|
629 | # branches. when there are no other branches, this | |
618 | # could be avoided. |
|
630 | # could be avoided. | |
619 | newcopies = copies.copy() |
|
631 | newcopies = copies.copy() | |
620 | newcopies[f] = (c, None) |
|
632 | newcopies[f] = (c, None) | |
621 | othercopies = all_copies.get(c) |
|
633 | othercopies = all_copies.get(c) | |
622 | if othercopies is None: |
|
634 | if othercopies is None: | |
623 | all_copies[c] = newcopies |
|
635 | all_copies[c] = newcopies | |
624 | else: |
|
636 | else: | |
625 | # we are the second parent to work on c, we need to merge our |
|
637 | # we are the second parent to work on c, we need to merge our | |
626 | # work with the other. |
|
638 | # work with the other. | |
627 | # |
|
639 | # | |
628 | # In case of conflict, parent 1 take precedence over parent 2. |
|
640 | # In case of conflict, parent 1 take precedence over parent 2. | |
629 | # This is an arbitrary choice made anew when implementing |
|
641 | # This is an arbitrary choice made anew when implementing | |
630 | # changeset based copies. It was made without regards with |
|
642 | # changeset based copies. It was made without regards with | |
631 | # potential filelog related behavior. |
|
643 | # potential filelog related behavior. | |
632 | if parent == 1: |
|
644 | if parent == 1: | |
633 | _merge_copies_dict_extra( |
|
645 | _merge_copies_dict_extra( | |
634 | othercopies, newcopies, isancestor, ismerged |
|
646 | othercopies, newcopies, isancestor, ismerged | |
635 | ) |
|
647 | ) | |
636 | else: |
|
648 | else: | |
637 | _merge_copies_dict_extra( |
|
649 | _merge_copies_dict_extra( | |
638 | newcopies, othercopies, isancestor, ismerged |
|
650 | newcopies, othercopies, isancestor, ismerged | |
639 | ) |
|
651 | ) | |
640 | all_copies[c] = newcopies |
|
652 | all_copies[c] = newcopies | |
641 |
|
653 | |||
642 | final_copies = {} |
|
654 | final_copies = {} | |
643 | for dest, (tt, source) in all_copies[targetrev].items(): |
|
655 | for dest, (tt, source) in all_copies[targetrev].items(): | |
644 | if source is not None: |
|
656 | if source is not None: | |
645 | final_copies[dest] = source |
|
657 | final_copies[dest] = source | |
646 | return final_copies |
|
658 | return final_copies | |
647 |
|
659 | |||
648 |
|
660 | |||
649 | def _merge_copies_dict_extra(minor, major, isancestor, ismerged): |
|
661 | def _merge_copies_dict_extra(minor, major, isancestor, ismerged): | |
650 | """version of `_merge_copies_dict` that works with the Google |
|
662 | """version of `_merge_copies_dict` that works with the Google | |
651 | specific "extra" based storage for copy information""" |
|
663 | specific "extra" based storage for copy information""" | |
652 | for dest, value in major.items(): |
|
664 | for dest, value in major.items(): | |
653 | other = minor.get(dest) |
|
665 | other = minor.get(dest) | |
654 | if other is None: |
|
666 | if other is None: | |
655 | minor[dest] = value |
|
667 | minor[dest] = value | |
656 | else: |
|
668 | else: | |
657 | new_tt = value[0] |
|
669 | new_tt = value[0] | |
658 | other_tt = other[0] |
|
670 | other_tt = other[0] | |
659 | if value[1] == other[1]: |
|
671 | if value[1] == other[1]: | |
660 | continue |
|
672 | continue | |
661 | # content from "major" wins, unless it is older |
|
673 | # content from "major" wins, unless it is older | |
662 | # than the branch point or there is a merge |
|
674 | # than the branch point or there is a merge | |
663 | if ( |
|
675 | if ( | |
664 | new_tt == other_tt |
|
676 | new_tt == other_tt | |
665 | or not isancestor(new_tt, other_tt) |
|
677 | or not isancestor(new_tt, other_tt) | |
666 | or ismerged(dest) |
|
678 | or ismerged(dest) | |
667 | ): |
|
679 | ): | |
668 | minor[dest] = value |
|
680 | minor[dest] = value | |
669 |
|
681 | |||
670 |
|
682 | |||
671 | def _forwardcopies(a, b, base=None, match=None): |
|
683 | def _forwardcopies(a, b, base=None, match=None): | |
672 | """find {dst@b: src@a} copy mapping where a is an ancestor of b""" |
|
684 | """find {dst@b: src@a} copy mapping where a is an ancestor of b""" | |
673 |
|
685 | |||
674 | if base is None: |
|
686 | if base is None: | |
675 | base = a |
|
687 | base = a | |
676 | match = a.repo().narrowmatch(match) |
|
688 | match = a.repo().narrowmatch(match) | |
677 | # check for working copy |
|
689 | # check for working copy | |
678 | if b.rev() is None: |
|
690 | if b.rev() is None: | |
679 | cm = _committedforwardcopies(a, b.p1(), base, match) |
|
691 | cm = _committedforwardcopies(a, b.p1(), base, match) | |
680 | # combine copies from dirstate if necessary |
|
692 | # combine copies from dirstate if necessary | |
681 | copies = _chain(cm, _dirstatecopies(b._repo, match)) |
|
693 | copies = _chain(cm, _dirstatecopies(b._repo, match)) | |
682 | else: |
|
694 | else: | |
683 | copies = _committedforwardcopies(a, b, base, match) |
|
695 | copies = _committedforwardcopies(a, b, base, match) | |
684 | return copies |
|
696 | return copies | |
685 |
|
697 | |||
686 |
|
698 | |||
687 | def _backwardrenames(a, b, match): |
|
699 | def _backwardrenames(a, b, match): | |
688 | if a._repo.ui.config(b'experimental', b'copytrace') == b'off': |
|
700 | if a._repo.ui.config(b'experimental', b'copytrace') == b'off': | |
689 | return {} |
|
701 | return {} | |
690 |
|
702 | |||
691 | # Even though we're not taking copies into account, 1:n rename situations |
|
703 | # Even though we're not taking copies into account, 1:n rename situations | |
692 | # can still exist (e.g. hg cp a b; hg mv a c). In those cases we |
|
704 | # can still exist (e.g. hg cp a b; hg mv a c). In those cases we | |
693 | # arbitrarily pick one of the renames. |
|
705 | # arbitrarily pick one of the renames. | |
694 | # We don't want to pass in "match" here, since that would filter |
|
706 | # We don't want to pass in "match" here, since that would filter | |
695 | # the destination by it. Since we're reversing the copies, we want |
|
707 | # the destination by it. Since we're reversing the copies, we want | |
696 | # to filter the source instead. |
|
708 | # to filter the source instead. | |
697 | f = _forwardcopies(b, a) |
|
709 | f = _forwardcopies(b, a) | |
698 | r = {} |
|
710 | r = {} | |
699 | for k, v in sorted(pycompat.iteritems(f)): |
|
711 | for k, v in sorted(pycompat.iteritems(f)): | |
700 | if match and not match(v): |
|
712 | if match and not match(v): | |
701 | continue |
|
713 | continue | |
702 | # remove copies |
|
714 | # remove copies | |
703 | if v in a: |
|
715 | if v in a: | |
704 | continue |
|
716 | continue | |
705 | r[v] = k |
|
717 | r[v] = k | |
706 | return r |
|
718 | return r | |
707 |
|
719 | |||
708 |
|
720 | |||
709 | def pathcopies(x, y, match=None): |
|
721 | def pathcopies(x, y, match=None): | |
710 | """find {dst@y: src@x} copy mapping for directed compare""" |
|
722 | """find {dst@y: src@x} copy mapping for directed compare""" | |
711 | repo = x._repo |
|
723 | repo = x._repo | |
712 | debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies') |
|
724 | debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies') | |
713 | if debug: |
|
725 | if debug: | |
714 | repo.ui.debug( |
|
726 | repo.ui.debug( | |
715 | b'debug.copies: searching copies from %s to %s\n' % (x, y) |
|
727 | b'debug.copies: searching copies from %s to %s\n' % (x, y) | |
716 | ) |
|
728 | ) | |
717 | if x == y or not x or not y: |
|
729 | if x == y or not x or not y: | |
718 | return {} |
|
730 | return {} | |
719 | if y.rev() is None and x == y.p1(): |
|
731 | if y.rev() is None and x == y.p1(): | |
720 | if debug: |
|
732 | if debug: | |
721 | repo.ui.debug(b'debug.copies: search mode: dirstate\n') |
|
733 | repo.ui.debug(b'debug.copies: search mode: dirstate\n') | |
722 | # short-circuit to avoid issues with merge states |
|
734 | # short-circuit to avoid issues with merge states | |
723 | return _dirstatecopies(repo, match) |
|
735 | return _dirstatecopies(repo, match) | |
724 | a = y.ancestor(x) |
|
736 | a = y.ancestor(x) | |
725 | if a == x: |
|
737 | if a == x: | |
726 | if debug: |
|
738 | if debug: | |
727 | repo.ui.debug(b'debug.copies: search mode: forward\n') |
|
739 | repo.ui.debug(b'debug.copies: search mode: forward\n') | |
728 | copies = _forwardcopies(x, y, match=match) |
|
740 | copies = _forwardcopies(x, y, match=match) | |
729 | elif a == y: |
|
741 | elif a == y: | |
730 | if debug: |
|
742 | if debug: | |
731 | repo.ui.debug(b'debug.copies: search mode: backward\n') |
|
743 | repo.ui.debug(b'debug.copies: search mode: backward\n') | |
732 | copies = _backwardrenames(x, y, match=match) |
|
744 | copies = _backwardrenames(x, y, match=match) | |
733 | else: |
|
745 | else: | |
734 | if debug: |
|
746 | if debug: | |
735 | repo.ui.debug(b'debug.copies: search mode: combined\n') |
|
747 | repo.ui.debug(b'debug.copies: search mode: combined\n') | |
736 | base = None |
|
748 | base = None | |
737 | if a.rev() != nullrev: |
|
749 | if a.rev() != nullrev: | |
738 | base = x |
|
750 | base = x | |
739 | copies = _chain( |
|
751 | copies = _chain( | |
740 | _backwardrenames(x, a, match=match), |
|
752 | _backwardrenames(x, a, match=match), | |
741 | _forwardcopies(a, y, base, match=match), |
|
753 | _forwardcopies(a, y, base, match=match), | |
742 | ) |
|
754 | ) | |
743 | _filter(x, y, copies) |
|
755 | _filter(x, y, copies) | |
744 | return copies |
|
756 | return copies | |
745 |
|
757 | |||
746 |
|
758 | |||
747 | def mergecopies(repo, c1, c2, base): |
|
759 | def mergecopies(repo, c1, c2, base): | |
748 | """ |
|
760 | """ | |
749 | Finds moves and copies between context c1 and c2 that are relevant for |
|
761 | Finds moves and copies between context c1 and c2 that are relevant for | |
750 | merging. 'base' will be used as the merge base. |
|
762 | merging. 'base' will be used as the merge base. | |
751 |
|
763 | |||
752 | Copytracing is used in commands like rebase, merge, unshelve, etc to merge |
|
764 | Copytracing is used in commands like rebase, merge, unshelve, etc to merge | |
753 | files that were moved/ copied in one merge parent and modified in another. |
|
765 | files that were moved/ copied in one merge parent and modified in another. | |
754 | For example: |
|
766 | For example: | |
755 |
|
767 | |||
756 | o ---> 4 another commit |
|
768 | o ---> 4 another commit | |
757 | | |
|
769 | | | |
758 | | o ---> 3 commit that modifies a.txt |
|
770 | | o ---> 3 commit that modifies a.txt | |
759 | | / |
|
771 | | / | |
760 | o / ---> 2 commit that moves a.txt to b.txt |
|
772 | o / ---> 2 commit that moves a.txt to b.txt | |
761 | |/ |
|
773 | |/ | |
762 | o ---> 1 merge base |
|
774 | o ---> 1 merge base | |
763 |
|
775 | |||
764 | If we try to rebase revision 3 on revision 4, since there is no a.txt in |
|
776 | If we try to rebase revision 3 on revision 4, since there is no a.txt in | |
765 | revision 4, and if user have copytrace disabled, we prints the following |
|
777 | revision 4, and if user have copytrace disabled, we prints the following | |
766 | message: |
|
778 | message: | |
767 |
|
779 | |||
768 | ```other changed <file> which local deleted``` |
|
780 | ```other changed <file> which local deleted``` | |
769 |
|
781 | |||
770 | Returns a tuple where: |
|
782 | Returns a tuple where: | |
771 |
|
783 | |||
772 | "branch_copies" an instance of branch_copies. |
|
784 | "branch_copies" an instance of branch_copies. | |
773 |
|
785 | |||
774 | "diverge" is a mapping of source name -> list of destination names |
|
786 | "diverge" is a mapping of source name -> list of destination names | |
775 | for divergent renames. |
|
787 | for divergent renames. | |
776 |
|
788 | |||
777 | This function calls different copytracing algorithms based on config. |
|
789 | This function calls different copytracing algorithms based on config. | |
778 | """ |
|
790 | """ | |
779 | # avoid silly behavior for update from empty dir |
|
791 | # avoid silly behavior for update from empty dir | |
780 | if not c1 or not c2 or c1 == c2: |
|
792 | if not c1 or not c2 or c1 == c2: | |
781 | return branch_copies(), branch_copies(), {} |
|
793 | return branch_copies(), branch_copies(), {} | |
782 |
|
794 | |||
783 | narrowmatch = c1.repo().narrowmatch() |
|
795 | narrowmatch = c1.repo().narrowmatch() | |
784 |
|
796 | |||
785 | # avoid silly behavior for parent -> working dir |
|
797 | # avoid silly behavior for parent -> working dir | |
786 | if c2.node() is None and c1.node() == repo.dirstate.p1(): |
|
798 | if c2.node() is None and c1.node() == repo.dirstate.p1(): | |
787 | return ( |
|
799 | return ( | |
788 | branch_copies(_dirstatecopies(repo, narrowmatch)), |
|
800 | branch_copies(_dirstatecopies(repo, narrowmatch)), | |
789 | branch_copies(), |
|
801 | branch_copies(), | |
790 | {}, |
|
802 | {}, | |
791 | ) |
|
803 | ) | |
792 |
|
804 | |||
793 | copytracing = repo.ui.config(b'experimental', b'copytrace') |
|
805 | copytracing = repo.ui.config(b'experimental', b'copytrace') | |
794 | if stringutil.parsebool(copytracing) is False: |
|
806 | if stringutil.parsebool(copytracing) is False: | |
795 | # stringutil.parsebool() returns None when it is unable to parse the |
|
807 | # stringutil.parsebool() returns None when it is unable to parse the | |
796 | # value, so we should rely on making sure copytracing is on such cases |
|
808 | # value, so we should rely on making sure copytracing is on such cases | |
797 | return branch_copies(), branch_copies(), {} |
|
809 | return branch_copies(), branch_copies(), {} | |
798 |
|
810 | |||
799 | if usechangesetcentricalgo(repo): |
|
811 | if usechangesetcentricalgo(repo): | |
800 | # The heuristics don't make sense when we need changeset-centric algos |
|
812 | # The heuristics don't make sense when we need changeset-centric algos | |
801 | return _fullcopytracing(repo, c1, c2, base) |
|
813 | return _fullcopytracing(repo, c1, c2, base) | |
802 |
|
814 | |||
803 | # Copy trace disabling is explicitly below the node == p1 logic above |
|
815 | # Copy trace disabling is explicitly below the node == p1 logic above | |
804 | # because the logic above is required for a simple copy to be kept across a |
|
816 | # because the logic above is required for a simple copy to be kept across a | |
805 | # rebase. |
|
817 | # rebase. | |
806 | if copytracing == b'heuristics': |
|
818 | if copytracing == b'heuristics': | |
807 | # Do full copytracing if only non-public revisions are involved as |
|
819 | # Do full copytracing if only non-public revisions are involved as | |
808 | # that will be fast enough and will also cover the copies which could |
|
820 | # that will be fast enough and will also cover the copies which could | |
809 | # be missed by heuristics |
|
821 | # be missed by heuristics | |
810 | if _isfullcopytraceable(repo, c1, base): |
|
822 | if _isfullcopytraceable(repo, c1, base): | |
811 | return _fullcopytracing(repo, c1, c2, base) |
|
823 | return _fullcopytracing(repo, c1, c2, base) | |
812 | return _heuristicscopytracing(repo, c1, c2, base) |
|
824 | return _heuristicscopytracing(repo, c1, c2, base) | |
813 | else: |
|
825 | else: | |
814 | return _fullcopytracing(repo, c1, c2, base) |
|
826 | return _fullcopytracing(repo, c1, c2, base) | |
815 |
|
827 | |||
816 |
|
828 | |||
817 | def _isfullcopytraceable(repo, c1, base): |
|
829 | def _isfullcopytraceable(repo, c1, base): | |
818 | """Checks that if base, source and destination are all no-public branches, |
|
830 | """Checks that if base, source and destination are all no-public branches, | |
819 | if yes let's use the full copytrace algorithm for increased capabilities |
|
831 | if yes let's use the full copytrace algorithm for increased capabilities | |
820 | since it will be fast enough. |
|
832 | since it will be fast enough. | |
821 |
|
833 | |||
822 | `experimental.copytrace.sourcecommitlimit` can be used to set a limit for |
|
834 | `experimental.copytrace.sourcecommitlimit` can be used to set a limit for | |
823 | number of changesets from c1 to base such that if number of changesets are |
|
835 | number of changesets from c1 to base such that if number of changesets are | |
824 | more than the limit, full copytracing algorithm won't be used. |
|
836 | more than the limit, full copytracing algorithm won't be used. | |
825 | """ |
|
837 | """ | |
826 | if c1.rev() is None: |
|
838 | if c1.rev() is None: | |
827 | c1 = c1.p1() |
|
839 | c1 = c1.p1() | |
828 | if c1.mutable() and base.mutable(): |
|
840 | if c1.mutable() and base.mutable(): | |
829 | sourcecommitlimit = repo.ui.configint( |
|
841 | sourcecommitlimit = repo.ui.configint( | |
830 | b'experimental', b'copytrace.sourcecommitlimit' |
|
842 | b'experimental', b'copytrace.sourcecommitlimit' | |
831 | ) |
|
843 | ) | |
832 | commits = len(repo.revs(b'%d::%d', base.rev(), c1.rev())) |
|
844 | commits = len(repo.revs(b'%d::%d', base.rev(), c1.rev())) | |
833 | return commits < sourcecommitlimit |
|
845 | return commits < sourcecommitlimit | |
834 | return False |
|
846 | return False | |
835 |
|
847 | |||
836 |
|
848 | |||
837 | def _checksinglesidecopies( |
|
849 | def _checksinglesidecopies( | |
838 | src, dsts1, m1, m2, mb, c2, base, copy, renamedelete |
|
850 | src, dsts1, m1, m2, mb, c2, base, copy, renamedelete | |
839 | ): |
|
851 | ): | |
840 | if src not in m2: |
|
852 | if src not in m2: | |
841 | # deleted on side 2 |
|
853 | # deleted on side 2 | |
842 | if src not in m1: |
|
854 | if src not in m1: | |
843 | # renamed on side 1, deleted on side 2 |
|
855 | # renamed on side 1, deleted on side 2 | |
844 | renamedelete[src] = dsts1 |
|
856 | renamedelete[src] = dsts1 | |
845 | elif src not in mb: |
|
857 | elif src not in mb: | |
846 | # Work around the "short-circuit to avoid issues with merge states" |
|
858 | # Work around the "short-circuit to avoid issues with merge states" | |
847 | # thing in pathcopies(): pathcopies(x, y) can return a copy where the |
|
859 | # thing in pathcopies(): pathcopies(x, y) can return a copy where the | |
848 | # destination doesn't exist in y. |
|
860 | # destination doesn't exist in y. | |
849 | pass |
|
861 | pass | |
850 | elif mb[src] != m2[src] and not _related(c2[src], base[src]): |
|
862 | elif mb[src] != m2[src] and not _related(c2[src], base[src]): | |
851 | return |
|
863 | return | |
852 | elif mb[src] != m2[src] or mb.flags(src) != m2.flags(src): |
|
864 | elif mb[src] != m2[src] or mb.flags(src) != m2.flags(src): | |
853 | # modified on side 2 |
|
865 | # modified on side 2 | |
854 | for dst in dsts1: |
|
866 | for dst in dsts1: | |
855 | copy[dst] = src |
|
867 | copy[dst] = src | |
856 |
|
868 | |||
857 |
|
869 | |||
858 | class branch_copies(object): |
|
870 | class branch_copies(object): | |
859 | """Information about copies made on one side of a merge/graft. |
|
871 | """Information about copies made on one side of a merge/graft. | |
860 |
|
872 | |||
861 | "copy" is a mapping from destination name -> source name, |
|
873 | "copy" is a mapping from destination name -> source name, | |
862 | where source is in c1 and destination is in c2 or vice-versa. |
|
874 | where source is in c1 and destination is in c2 or vice-versa. | |
863 |
|
875 | |||
864 | "movewithdir" is a mapping from source name -> destination name, |
|
876 | "movewithdir" is a mapping from source name -> destination name, | |
865 | where the file at source present in one context but not the other |
|
877 | where the file at source present in one context but not the other | |
866 | needs to be moved to destination by the merge process, because the |
|
878 | needs to be moved to destination by the merge process, because the | |
867 | other context moved the directory it is in. |
|
879 | other context moved the directory it is in. | |
868 |
|
880 | |||
869 | "renamedelete" is a mapping of source name -> list of destination |
|
881 | "renamedelete" is a mapping of source name -> list of destination | |
870 | names for files deleted in c1 that were renamed in c2 or vice-versa. |
|
882 | names for files deleted in c1 that were renamed in c2 or vice-versa. | |
871 |
|
883 | |||
872 | "dirmove" is a mapping of detected source dir -> destination dir renames. |
|
884 | "dirmove" is a mapping of detected source dir -> destination dir renames. | |
873 | This is needed for handling changes to new files previously grafted into |
|
885 | This is needed for handling changes to new files previously grafted into | |
874 | renamed directories. |
|
886 | renamed directories. | |
875 | """ |
|
887 | """ | |
876 |
|
888 | |||
877 | def __init__( |
|
889 | def __init__( | |
878 | self, copy=None, renamedelete=None, dirmove=None, movewithdir=None |
|
890 | self, copy=None, renamedelete=None, dirmove=None, movewithdir=None | |
879 | ): |
|
891 | ): | |
880 | self.copy = {} if copy is None else copy |
|
892 | self.copy = {} if copy is None else copy | |
881 | self.renamedelete = {} if renamedelete is None else renamedelete |
|
893 | self.renamedelete = {} if renamedelete is None else renamedelete | |
882 | self.dirmove = {} if dirmove is None else dirmove |
|
894 | self.dirmove = {} if dirmove is None else dirmove | |
883 | self.movewithdir = {} if movewithdir is None else movewithdir |
|
895 | self.movewithdir = {} if movewithdir is None else movewithdir | |
884 |
|
896 | |||
885 | def __repr__(self): |
|
897 | def __repr__(self): | |
886 | return '<branch_copies\n copy=%r\n renamedelete=%r\n dirmove=%r\n movewithdir=%r\n>' % ( |
|
898 | return '<branch_copies\n copy=%r\n renamedelete=%r\n dirmove=%r\n movewithdir=%r\n>' % ( | |
887 | self.copy, |
|
899 | self.copy, | |
888 | self.renamedelete, |
|
900 | self.renamedelete, | |
889 | self.dirmove, |
|
901 | self.dirmove, | |
890 | self.movewithdir, |
|
902 | self.movewithdir, | |
891 | ) |
|
903 | ) | |
892 |
|
904 | |||
893 |
|
905 | |||
894 | def _fullcopytracing(repo, c1, c2, base): |
|
906 | def _fullcopytracing(repo, c1, c2, base): | |
895 | """The full copytracing algorithm which finds all the new files that were |
|
907 | """The full copytracing algorithm which finds all the new files that were | |
896 | added from merge base up to the top commit and for each file it checks if |
|
908 | added from merge base up to the top commit and for each file it checks if | |
897 | this file was copied from another file. |
|
909 | this file was copied from another file. | |
898 |
|
910 | |||
899 | This is pretty slow when a lot of changesets are involved but will track all |
|
911 | This is pretty slow when a lot of changesets are involved but will track all | |
900 | the copies. |
|
912 | the copies. | |
901 | """ |
|
913 | """ | |
902 | m1 = c1.manifest() |
|
914 | m1 = c1.manifest() | |
903 | m2 = c2.manifest() |
|
915 | m2 = c2.manifest() | |
904 | mb = base.manifest() |
|
916 | mb = base.manifest() | |
905 |
|
917 | |||
906 | copies1 = pathcopies(base, c1) |
|
918 | copies1 = pathcopies(base, c1) | |
907 | copies2 = pathcopies(base, c2) |
|
919 | copies2 = pathcopies(base, c2) | |
908 |
|
920 | |||
909 | if not (copies1 or copies2): |
|
921 | if not (copies1 or copies2): | |
910 | return branch_copies(), branch_copies(), {} |
|
922 | return branch_copies(), branch_copies(), {} | |
911 |
|
923 | |||
912 | inversecopies1 = {} |
|
924 | inversecopies1 = {} | |
913 | inversecopies2 = {} |
|
925 | inversecopies2 = {} | |
914 | for dst, src in copies1.items(): |
|
926 | for dst, src in copies1.items(): | |
915 | inversecopies1.setdefault(src, []).append(dst) |
|
927 | inversecopies1.setdefault(src, []).append(dst) | |
916 | for dst, src in copies2.items(): |
|
928 | for dst, src in copies2.items(): | |
917 | inversecopies2.setdefault(src, []).append(dst) |
|
929 | inversecopies2.setdefault(src, []).append(dst) | |
918 |
|
930 | |||
919 | copy1 = {} |
|
931 | copy1 = {} | |
920 | copy2 = {} |
|
932 | copy2 = {} | |
921 | diverge = {} |
|
933 | diverge = {} | |
922 | renamedelete1 = {} |
|
934 | renamedelete1 = {} | |
923 | renamedelete2 = {} |
|
935 | renamedelete2 = {} | |
924 | allsources = set(inversecopies1) | set(inversecopies2) |
|
936 | allsources = set(inversecopies1) | set(inversecopies2) | |
925 | for src in allsources: |
|
937 | for src in allsources: | |
926 | dsts1 = inversecopies1.get(src) |
|
938 | dsts1 = inversecopies1.get(src) | |
927 | dsts2 = inversecopies2.get(src) |
|
939 | dsts2 = inversecopies2.get(src) | |
928 | if dsts1 and dsts2: |
|
940 | if dsts1 and dsts2: | |
929 | # copied/renamed on both sides |
|
941 | # copied/renamed on both sides | |
930 | if src not in m1 and src not in m2: |
|
942 | if src not in m1 and src not in m2: | |
931 | # renamed on both sides |
|
943 | # renamed on both sides | |
932 | dsts1 = set(dsts1) |
|
944 | dsts1 = set(dsts1) | |
933 | dsts2 = set(dsts2) |
|
945 | dsts2 = set(dsts2) | |
934 | # If there's some overlap in the rename destinations, we |
|
946 | # If there's some overlap in the rename destinations, we | |
935 | # consider it not divergent. For example, if side 1 copies 'a' |
|
947 | # consider it not divergent. For example, if side 1 copies 'a' | |
936 | # to 'b' and 'c' and deletes 'a', and side 2 copies 'a' to 'c' |
|
948 | # to 'b' and 'c' and deletes 'a', and side 2 copies 'a' to 'c' | |
937 | # and 'd' and deletes 'a'. |
|
949 | # and 'd' and deletes 'a'. | |
938 | if dsts1 & dsts2: |
|
950 | if dsts1 & dsts2: | |
939 | for dst in dsts1 & dsts2: |
|
951 | for dst in dsts1 & dsts2: | |
940 | copy1[dst] = src |
|
952 | copy1[dst] = src | |
941 | copy2[dst] = src |
|
953 | copy2[dst] = src | |
942 | else: |
|
954 | else: | |
943 | diverge[src] = sorted(dsts1 | dsts2) |
|
955 | diverge[src] = sorted(dsts1 | dsts2) | |
944 | elif src in m1 and src in m2: |
|
956 | elif src in m1 and src in m2: | |
945 | # copied on both sides |
|
957 | # copied on both sides | |
946 | dsts1 = set(dsts1) |
|
958 | dsts1 = set(dsts1) | |
947 | dsts2 = set(dsts2) |
|
959 | dsts2 = set(dsts2) | |
948 | for dst in dsts1 & dsts2: |
|
960 | for dst in dsts1 & dsts2: | |
949 | copy1[dst] = src |
|
961 | copy1[dst] = src | |
950 | copy2[dst] = src |
|
962 | copy2[dst] = src | |
951 | # TODO: Handle cases where it was renamed on one side and copied |
|
963 | # TODO: Handle cases where it was renamed on one side and copied | |
952 | # on the other side |
|
964 | # on the other side | |
953 | elif dsts1: |
|
965 | elif dsts1: | |
954 | # copied/renamed only on side 1 |
|
966 | # copied/renamed only on side 1 | |
955 | _checksinglesidecopies( |
|
967 | _checksinglesidecopies( | |
956 | src, dsts1, m1, m2, mb, c2, base, copy1, renamedelete1 |
|
968 | src, dsts1, m1, m2, mb, c2, base, copy1, renamedelete1 | |
957 | ) |
|
969 | ) | |
958 | elif dsts2: |
|
970 | elif dsts2: | |
959 | # copied/renamed only on side 2 |
|
971 | # copied/renamed only on side 2 | |
960 | _checksinglesidecopies( |
|
972 | _checksinglesidecopies( | |
961 | src, dsts2, m2, m1, mb, c1, base, copy2, renamedelete2 |
|
973 | src, dsts2, m2, m1, mb, c1, base, copy2, renamedelete2 | |
962 | ) |
|
974 | ) | |
963 |
|
975 | |||
964 | # find interesting file sets from manifests |
|
976 | # find interesting file sets from manifests | |
965 | cache = [] |
|
977 | cache = [] | |
966 |
|
978 | |||
967 | def _get_addedfiles(idx): |
|
979 | def _get_addedfiles(idx): | |
968 | if not cache: |
|
980 | if not cache: | |
969 | addedinm1 = m1.filesnotin(mb, repo.narrowmatch()) |
|
981 | addedinm1 = m1.filesnotin(mb, repo.narrowmatch()) | |
970 | addedinm2 = m2.filesnotin(mb, repo.narrowmatch()) |
|
982 | addedinm2 = m2.filesnotin(mb, repo.narrowmatch()) | |
971 | u1 = sorted(addedinm1 - addedinm2) |
|
983 | u1 = sorted(addedinm1 - addedinm2) | |
972 | u2 = sorted(addedinm2 - addedinm1) |
|
984 | u2 = sorted(addedinm2 - addedinm1) | |
973 | cache.extend((u1, u2)) |
|
985 | cache.extend((u1, u2)) | |
974 | return cache[idx] |
|
986 | return cache[idx] | |
975 |
|
987 | |||
976 | u1fn = lambda: _get_addedfiles(0) |
|
988 | u1fn = lambda: _get_addedfiles(0) | |
977 | u2fn = lambda: _get_addedfiles(1) |
|
989 | u2fn = lambda: _get_addedfiles(1) | |
978 | if repo.ui.debugflag: |
|
990 | if repo.ui.debugflag: | |
979 | u1 = u1fn() |
|
991 | u1 = u1fn() | |
980 | u2 = u2fn() |
|
992 | u2 = u2fn() | |
981 |
|
993 | |||
982 | header = b" unmatched files in %s" |
|
994 | header = b" unmatched files in %s" | |
983 | if u1: |
|
995 | if u1: | |
984 | repo.ui.debug( |
|
996 | repo.ui.debug( | |
985 | b"%s:\n %s\n" % (header % b'local', b"\n ".join(u1)) |
|
997 | b"%s:\n %s\n" % (header % b'local', b"\n ".join(u1)) | |
986 | ) |
|
998 | ) | |
987 | if u2: |
|
999 | if u2: | |
988 | repo.ui.debug( |
|
1000 | repo.ui.debug( | |
989 | b"%s:\n %s\n" % (header % b'other', b"\n ".join(u2)) |
|
1001 | b"%s:\n %s\n" % (header % b'other', b"\n ".join(u2)) | |
990 | ) |
|
1002 | ) | |
991 |
|
1003 | |||
992 | renamedeleteset = set() |
|
1004 | renamedeleteset = set() | |
993 | divergeset = set() |
|
1005 | divergeset = set() | |
994 | for dsts in diverge.values(): |
|
1006 | for dsts in diverge.values(): | |
995 | divergeset.update(dsts) |
|
1007 | divergeset.update(dsts) | |
996 | for dsts in renamedelete1.values(): |
|
1008 | for dsts in renamedelete1.values(): | |
997 | renamedeleteset.update(dsts) |
|
1009 | renamedeleteset.update(dsts) | |
998 | for dsts in renamedelete2.values(): |
|
1010 | for dsts in renamedelete2.values(): | |
999 | renamedeleteset.update(dsts) |
|
1011 | renamedeleteset.update(dsts) | |
1000 |
|
1012 | |||
1001 | repo.ui.debug( |
|
1013 | repo.ui.debug( | |
1002 | b" all copies found (* = to merge, ! = divergent, " |
|
1014 | b" all copies found (* = to merge, ! = divergent, " | |
1003 | b"% = renamed and deleted):\n" |
|
1015 | b"% = renamed and deleted):\n" | |
1004 | ) |
|
1016 | ) | |
1005 | for side, copies in ((b"local", copies1), (b"remote", copies2)): |
|
1017 | for side, copies in ((b"local", copies1), (b"remote", copies2)): | |
1006 | if not copies: |
|
1018 | if not copies: | |
1007 | continue |
|
1019 | continue | |
1008 | repo.ui.debug(b" on %s side:\n" % side) |
|
1020 | repo.ui.debug(b" on %s side:\n" % side) | |
1009 | for f in sorted(copies): |
|
1021 | for f in sorted(copies): | |
1010 | note = b"" |
|
1022 | note = b"" | |
1011 | if f in copy1 or f in copy2: |
|
1023 | if f in copy1 or f in copy2: | |
1012 | note += b"*" |
|
1024 | note += b"*" | |
1013 | if f in divergeset: |
|
1025 | if f in divergeset: | |
1014 | note += b"!" |
|
1026 | note += b"!" | |
1015 | if f in renamedeleteset: |
|
1027 | if f in renamedeleteset: | |
1016 | note += b"%" |
|
1028 | note += b"%" | |
1017 | repo.ui.debug( |
|
1029 | repo.ui.debug( | |
1018 | b" src: '%s' -> dst: '%s' %s\n" % (copies[f], f, note) |
|
1030 | b" src: '%s' -> dst: '%s' %s\n" % (copies[f], f, note) | |
1019 | ) |
|
1031 | ) | |
1020 | del renamedeleteset |
|
1032 | del renamedeleteset | |
1021 | del divergeset |
|
1033 | del divergeset | |
1022 |
|
1034 | |||
1023 | repo.ui.debug(b" checking for directory renames\n") |
|
1035 | repo.ui.debug(b" checking for directory renames\n") | |
1024 |
|
1036 | |||
1025 | dirmove1, movewithdir2 = _dir_renames(repo, c1, copy1, copies1, u2fn) |
|
1037 | dirmove1, movewithdir2 = _dir_renames(repo, c1, copy1, copies1, u2fn) | |
1026 | dirmove2, movewithdir1 = _dir_renames(repo, c2, copy2, copies2, u1fn) |
|
1038 | dirmove2, movewithdir1 = _dir_renames(repo, c2, copy2, copies2, u1fn) | |
1027 |
|
1039 | |||
1028 | branch_copies1 = branch_copies(copy1, renamedelete1, dirmove1, movewithdir1) |
|
1040 | branch_copies1 = branch_copies(copy1, renamedelete1, dirmove1, movewithdir1) | |
1029 | branch_copies2 = branch_copies(copy2, renamedelete2, dirmove2, movewithdir2) |
|
1041 | branch_copies2 = branch_copies(copy2, renamedelete2, dirmove2, movewithdir2) | |
1030 |
|
1042 | |||
1031 | return branch_copies1, branch_copies2, diverge |
|
1043 | return branch_copies1, branch_copies2, diverge | |
1032 |
|
1044 | |||
1033 |
|
1045 | |||
1034 | def _dir_renames(repo, ctx, copy, fullcopy, addedfilesfn): |
|
1046 | def _dir_renames(repo, ctx, copy, fullcopy, addedfilesfn): | |
1035 | """Finds moved directories and files that should move with them. |
|
1047 | """Finds moved directories and files that should move with them. | |
1036 |
|
1048 | |||
1037 | ctx: the context for one of the sides |
|
1049 | ctx: the context for one of the sides | |
1038 | copy: files copied on the same side (as ctx) |
|
1050 | copy: files copied on the same side (as ctx) | |
1039 | fullcopy: files copied on the same side (as ctx), including those that |
|
1051 | fullcopy: files copied on the same side (as ctx), including those that | |
1040 | merge.manifestmerge() won't care about |
|
1052 | merge.manifestmerge() won't care about | |
1041 | addedfilesfn: function returning added files on the other side (compared to |
|
1053 | addedfilesfn: function returning added files on the other side (compared to | |
1042 | ctx) |
|
1054 | ctx) | |
1043 | """ |
|
1055 | """ | |
1044 | # generate a directory move map |
|
1056 | # generate a directory move map | |
1045 | invalid = set() |
|
1057 | invalid = set() | |
1046 | dirmove = {} |
|
1058 | dirmove = {} | |
1047 |
|
1059 | |||
1048 | # examine each file copy for a potential directory move, which is |
|
1060 | # examine each file copy for a potential directory move, which is | |
1049 | # when all the files in a directory are moved to a new directory |
|
1061 | # when all the files in a directory are moved to a new directory | |
1050 | for dst, src in pycompat.iteritems(fullcopy): |
|
1062 | for dst, src in pycompat.iteritems(fullcopy): | |
1051 | dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst) |
|
1063 | dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst) | |
1052 | if dsrc in invalid: |
|
1064 | if dsrc in invalid: | |
1053 | # already seen to be uninteresting |
|
1065 | # already seen to be uninteresting | |
1054 | continue |
|
1066 | continue | |
1055 | elif ctx.hasdir(dsrc) and ctx.hasdir(ddst): |
|
1067 | elif ctx.hasdir(dsrc) and ctx.hasdir(ddst): | |
1056 | # directory wasn't entirely moved locally |
|
1068 | # directory wasn't entirely moved locally | |
1057 | invalid.add(dsrc) |
|
1069 | invalid.add(dsrc) | |
1058 | elif dsrc in dirmove and dirmove[dsrc] != ddst: |
|
1070 | elif dsrc in dirmove and dirmove[dsrc] != ddst: | |
1059 | # files from the same directory moved to two different places |
|
1071 | # files from the same directory moved to two different places | |
1060 | invalid.add(dsrc) |
|
1072 | invalid.add(dsrc) | |
1061 | else: |
|
1073 | else: | |
1062 | # looks good so far |
|
1074 | # looks good so far | |
1063 | dirmove[dsrc] = ddst |
|
1075 | dirmove[dsrc] = ddst | |
1064 |
|
1076 | |||
1065 | for i in invalid: |
|
1077 | for i in invalid: | |
1066 | if i in dirmove: |
|
1078 | if i in dirmove: | |
1067 | del dirmove[i] |
|
1079 | del dirmove[i] | |
1068 | del invalid |
|
1080 | del invalid | |
1069 |
|
1081 | |||
1070 | if not dirmove: |
|
1082 | if not dirmove: | |
1071 | return {}, {} |
|
1083 | return {}, {} | |
1072 |
|
1084 | |||
1073 | dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)} |
|
1085 | dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)} | |
1074 |
|
1086 | |||
1075 | for d in dirmove: |
|
1087 | for d in dirmove: | |
1076 | repo.ui.debug( |
|
1088 | repo.ui.debug( | |
1077 | b" discovered dir src: '%s' -> dst: '%s'\n" % (d, dirmove[d]) |
|
1089 | b" discovered dir src: '%s' -> dst: '%s'\n" % (d, dirmove[d]) | |
1078 | ) |
|
1090 | ) | |
1079 |
|
1091 | |||
1080 | movewithdir = {} |
|
1092 | movewithdir = {} | |
1081 | # check unaccounted nonoverlapping files against directory moves |
|
1093 | # check unaccounted nonoverlapping files against directory moves | |
1082 | for f in addedfilesfn(): |
|
1094 | for f in addedfilesfn(): | |
1083 | if f not in fullcopy: |
|
1095 | if f not in fullcopy: | |
1084 | for d in dirmove: |
|
1096 | for d in dirmove: | |
1085 | if f.startswith(d): |
|
1097 | if f.startswith(d): | |
1086 | # new file added in a directory that was moved, move it |
|
1098 | # new file added in a directory that was moved, move it | |
1087 | df = dirmove[d] + f[len(d) :] |
|
1099 | df = dirmove[d] + f[len(d) :] | |
1088 | if df not in copy: |
|
1100 | if df not in copy: | |
1089 | movewithdir[f] = df |
|
1101 | movewithdir[f] = df | |
1090 | repo.ui.debug( |
|
1102 | repo.ui.debug( | |
1091 | b" pending file src: '%s' -> dst: '%s'\n" |
|
1103 | b" pending file src: '%s' -> dst: '%s'\n" | |
1092 | % (f, df) |
|
1104 | % (f, df) | |
1093 | ) |
|
1105 | ) | |
1094 | break |
|
1106 | break | |
1095 |
|
1107 | |||
1096 | return dirmove, movewithdir |
|
1108 | return dirmove, movewithdir | |
1097 |
|
1109 | |||
1098 |
|
1110 | |||
1099 | def _heuristicscopytracing(repo, c1, c2, base): |
|
1111 | def _heuristicscopytracing(repo, c1, c2, base): | |
1100 | """Fast copytracing using filename heuristics |
|
1112 | """Fast copytracing using filename heuristics | |
1101 |
|
1113 | |||
1102 | Assumes that moves or renames are of following two types: |
|
1114 | Assumes that moves or renames are of following two types: | |
1103 |
|
1115 | |||
1104 | 1) Inside a directory only (same directory name but different filenames) |
|
1116 | 1) Inside a directory only (same directory name but different filenames) | |
1105 | 2) Move from one directory to another |
|
1117 | 2) Move from one directory to another | |
1106 | (same filenames but different directory names) |
|
1118 | (same filenames but different directory names) | |
1107 |
|
1119 | |||
1108 | Works only when there are no merge commits in the "source branch". |
|
1120 | Works only when there are no merge commits in the "source branch". | |
1109 | Source branch is commits from base up to c2 not including base. |
|
1121 | Source branch is commits from base up to c2 not including base. | |
1110 |
|
1122 | |||
1111 | If merge is involved it fallbacks to _fullcopytracing(). |
|
1123 | If merge is involved it fallbacks to _fullcopytracing(). | |
1112 |
|
1124 | |||
1113 | Can be used by setting the following config: |
|
1125 | Can be used by setting the following config: | |
1114 |
|
1126 | |||
1115 | [experimental] |
|
1127 | [experimental] | |
1116 | copytrace = heuristics |
|
1128 | copytrace = heuristics | |
1117 |
|
1129 | |||
1118 | In some cases the copy/move candidates found by heuristics can be very large |
|
1130 | In some cases the copy/move candidates found by heuristics can be very large | |
1119 | in number and that will make the algorithm slow. The number of possible |
|
1131 | in number and that will make the algorithm slow. The number of possible | |
1120 | candidates to check can be limited by using the config |
|
1132 | candidates to check can be limited by using the config | |
1121 | `experimental.copytrace.movecandidateslimit` which defaults to 100. |
|
1133 | `experimental.copytrace.movecandidateslimit` which defaults to 100. | |
1122 | """ |
|
1134 | """ | |
1123 |
|
1135 | |||
1124 | if c1.rev() is None: |
|
1136 | if c1.rev() is None: | |
1125 | c1 = c1.p1() |
|
1137 | c1 = c1.p1() | |
1126 | if c2.rev() is None: |
|
1138 | if c2.rev() is None: | |
1127 | c2 = c2.p1() |
|
1139 | c2 = c2.p1() | |
1128 |
|
1140 | |||
1129 | changedfiles = set() |
|
1141 | changedfiles = set() | |
1130 | m1 = c1.manifest() |
|
1142 | m1 = c1.manifest() | |
1131 | if not repo.revs(b'%d::%d', base.rev(), c2.rev()): |
|
1143 | if not repo.revs(b'%d::%d', base.rev(), c2.rev()): | |
1132 | # If base is not in c2 branch, we switch to fullcopytracing |
|
1144 | # If base is not in c2 branch, we switch to fullcopytracing | |
1133 | repo.ui.debug( |
|
1145 | repo.ui.debug( | |
1134 | b"switching to full copytracing as base is not " |
|
1146 | b"switching to full copytracing as base is not " | |
1135 | b"an ancestor of c2\n" |
|
1147 | b"an ancestor of c2\n" | |
1136 | ) |
|
1148 | ) | |
1137 | return _fullcopytracing(repo, c1, c2, base) |
|
1149 | return _fullcopytracing(repo, c1, c2, base) | |
1138 |
|
1150 | |||
1139 | ctx = c2 |
|
1151 | ctx = c2 | |
1140 | while ctx != base: |
|
1152 | while ctx != base: | |
1141 | if len(ctx.parents()) == 2: |
|
1153 | if len(ctx.parents()) == 2: | |
1142 | # To keep things simple let's not handle merges |
|
1154 | # To keep things simple let's not handle merges | |
1143 | repo.ui.debug(b"switching to full copytracing because of merges\n") |
|
1155 | repo.ui.debug(b"switching to full copytracing because of merges\n") | |
1144 | return _fullcopytracing(repo, c1, c2, base) |
|
1156 | return _fullcopytracing(repo, c1, c2, base) | |
1145 | changedfiles.update(ctx.files()) |
|
1157 | changedfiles.update(ctx.files()) | |
1146 | ctx = ctx.p1() |
|
1158 | ctx = ctx.p1() | |
1147 |
|
1159 | |||
1148 | copies2 = {} |
|
1160 | copies2 = {} | |
1149 | cp = _forwardcopies(base, c2) |
|
1161 | cp = _forwardcopies(base, c2) | |
1150 | for dst, src in pycompat.iteritems(cp): |
|
1162 | for dst, src in pycompat.iteritems(cp): | |
1151 | if src in m1: |
|
1163 | if src in m1: | |
1152 | copies2[dst] = src |
|
1164 | copies2[dst] = src | |
1153 |
|
1165 | |||
1154 | # file is missing if it isn't present in the destination, but is present in |
|
1166 | # file is missing if it isn't present in the destination, but is present in | |
1155 | # the base and present in the source. |
|
1167 | # the base and present in the source. | |
1156 | # Presence in the base is important to exclude added files, presence in the |
|
1168 | # Presence in the base is important to exclude added files, presence in the | |
1157 | # source is important to exclude removed files. |
|
1169 | # source is important to exclude removed files. | |
1158 | filt = lambda f: f not in m1 and f in base and f in c2 |
|
1170 | filt = lambda f: f not in m1 and f in base and f in c2 | |
1159 | missingfiles = [f for f in changedfiles if filt(f)] |
|
1171 | missingfiles = [f for f in changedfiles if filt(f)] | |
1160 |
|
1172 | |||
1161 | copies1 = {} |
|
1173 | copies1 = {} | |
1162 | if missingfiles: |
|
1174 | if missingfiles: | |
1163 | basenametofilename = collections.defaultdict(list) |
|
1175 | basenametofilename = collections.defaultdict(list) | |
1164 | dirnametofilename = collections.defaultdict(list) |
|
1176 | dirnametofilename = collections.defaultdict(list) | |
1165 |
|
1177 | |||
1166 | for f in m1.filesnotin(base.manifest()): |
|
1178 | for f in m1.filesnotin(base.manifest()): | |
1167 | basename = os.path.basename(f) |
|
1179 | basename = os.path.basename(f) | |
1168 | dirname = os.path.dirname(f) |
|
1180 | dirname = os.path.dirname(f) | |
1169 | basenametofilename[basename].append(f) |
|
1181 | basenametofilename[basename].append(f) | |
1170 | dirnametofilename[dirname].append(f) |
|
1182 | dirnametofilename[dirname].append(f) | |
1171 |
|
1183 | |||
1172 | for f in missingfiles: |
|
1184 | for f in missingfiles: | |
1173 | basename = os.path.basename(f) |
|
1185 | basename = os.path.basename(f) | |
1174 | dirname = os.path.dirname(f) |
|
1186 | dirname = os.path.dirname(f) | |
1175 | samebasename = basenametofilename[basename] |
|
1187 | samebasename = basenametofilename[basename] | |
1176 | samedirname = dirnametofilename[dirname] |
|
1188 | samedirname = dirnametofilename[dirname] | |
1177 | movecandidates = samebasename + samedirname |
|
1189 | movecandidates = samebasename + samedirname | |
1178 | # f is guaranteed to be present in c2, that's why |
|
1190 | # f is guaranteed to be present in c2, that's why | |
1179 | # c2.filectx(f) won't fail |
|
1191 | # c2.filectx(f) won't fail | |
1180 | f2 = c2.filectx(f) |
|
1192 | f2 = c2.filectx(f) | |
1181 | # we can have a lot of candidates which can slow down the heuristics |
|
1193 | # we can have a lot of candidates which can slow down the heuristics | |
1182 | # config value to limit the number of candidates moves to check |
|
1194 | # config value to limit the number of candidates moves to check | |
1183 | maxcandidates = repo.ui.configint( |
|
1195 | maxcandidates = repo.ui.configint( | |
1184 | b'experimental', b'copytrace.movecandidateslimit' |
|
1196 | b'experimental', b'copytrace.movecandidateslimit' | |
1185 | ) |
|
1197 | ) | |
1186 |
|
1198 | |||
1187 | if len(movecandidates) > maxcandidates: |
|
1199 | if len(movecandidates) > maxcandidates: | |
1188 | repo.ui.status( |
|
1200 | repo.ui.status( | |
1189 | _( |
|
1201 | _( | |
1190 | b"skipping copytracing for '%s', more " |
|
1202 | b"skipping copytracing for '%s', more " | |
1191 | b"candidates than the limit: %d\n" |
|
1203 | b"candidates than the limit: %d\n" | |
1192 | ) |
|
1204 | ) | |
1193 | % (f, len(movecandidates)) |
|
1205 | % (f, len(movecandidates)) | |
1194 | ) |
|
1206 | ) | |
1195 | continue |
|
1207 | continue | |
1196 |
|
1208 | |||
1197 | for candidate in movecandidates: |
|
1209 | for candidate in movecandidates: | |
1198 | f1 = c1.filectx(candidate) |
|
1210 | f1 = c1.filectx(candidate) | |
1199 | if _related(f1, f2): |
|
1211 | if _related(f1, f2): | |
1200 | # if there are a few related copies then we'll merge |
|
1212 | # if there are a few related copies then we'll merge | |
1201 | # changes into all of them. This matches the behaviour |
|
1213 | # changes into all of them. This matches the behaviour | |
1202 | # of upstream copytracing |
|
1214 | # of upstream copytracing | |
1203 | copies1[candidate] = f |
|
1215 | copies1[candidate] = f | |
1204 |
|
1216 | |||
1205 | return branch_copies(copies1), branch_copies(copies2), {} |
|
1217 | return branch_copies(copies1), branch_copies(copies2), {} | |
1206 |
|
1218 | |||
1207 |
|
1219 | |||
1208 | def _related(f1, f2): |
|
1220 | def _related(f1, f2): | |
1209 | """return True if f1 and f2 filectx have a common ancestor |
|
1221 | """return True if f1 and f2 filectx have a common ancestor | |
1210 |
|
1222 | |||
1211 | Walk back to common ancestor to see if the two files originate |
|
1223 | Walk back to common ancestor to see if the two files originate | |
1212 | from the same file. Since workingfilectx's rev() is None it messes |
|
1224 | from the same file. Since workingfilectx's rev() is None it messes | |
1213 | up the integer comparison logic, hence the pre-step check for |
|
1225 | up the integer comparison logic, hence the pre-step check for | |
1214 | None (f1 and f2 can only be workingfilectx's initially). |
|
1226 | None (f1 and f2 can only be workingfilectx's initially). | |
1215 | """ |
|
1227 | """ | |
1216 |
|
1228 | |||
1217 | if f1 == f2: |
|
1229 | if f1 == f2: | |
1218 | return True # a match |
|
1230 | return True # a match | |
1219 |
|
1231 | |||
1220 | g1, g2 = f1.ancestors(), f2.ancestors() |
|
1232 | g1, g2 = f1.ancestors(), f2.ancestors() | |
1221 | try: |
|
1233 | try: | |
1222 | f1r, f2r = f1.linkrev(), f2.linkrev() |
|
1234 | f1r, f2r = f1.linkrev(), f2.linkrev() | |
1223 |
|
1235 | |||
1224 | if f1r is None: |
|
1236 | if f1r is None: | |
1225 | f1 = next(g1) |
|
1237 | f1 = next(g1) | |
1226 | if f2r is None: |
|
1238 | if f2r is None: | |
1227 | f2 = next(g2) |
|
1239 | f2 = next(g2) | |
1228 |
|
1240 | |||
1229 | while True: |
|
1241 | while True: | |
1230 | f1r, f2r = f1.linkrev(), f2.linkrev() |
|
1242 | f1r, f2r = f1.linkrev(), f2.linkrev() | |
1231 | if f1r > f2r: |
|
1243 | if f1r > f2r: | |
1232 | f1 = next(g1) |
|
1244 | f1 = next(g1) | |
1233 | elif f2r > f1r: |
|
1245 | elif f2r > f1r: | |
1234 | f2 = next(g2) |
|
1246 | f2 = next(g2) | |
1235 | else: # f1 and f2 point to files in the same linkrev |
|
1247 | else: # f1 and f2 point to files in the same linkrev | |
1236 | return f1 == f2 # true if they point to the same file |
|
1248 | return f1 == f2 # true if they point to the same file | |
1237 | except StopIteration: |
|
1249 | except StopIteration: | |
1238 | return False |
|
1250 | return False | |
1239 |
|
1251 | |||
1240 |
|
1252 | |||
1241 | def graftcopies(wctx, ctx, base): |
|
1253 | def graftcopies(wctx, ctx, base): | |
1242 | """reproduce copies between base and ctx in the wctx |
|
1254 | """reproduce copies between base and ctx in the wctx | |
1243 |
|
1255 | |||
1244 | Unlike mergecopies(), this function will only consider copies between base |
|
1256 | Unlike mergecopies(), this function will only consider copies between base | |
1245 | and ctx; it will ignore copies between base and wctx. Also unlike |
|
1257 | and ctx; it will ignore copies between base and wctx. Also unlike | |
1246 | mergecopies(), this function will apply copies to the working copy (instead |
|
1258 | mergecopies(), this function will apply copies to the working copy (instead | |
1247 | of just returning information about the copies). That makes it cheaper |
|
1259 | of just returning information about the copies). That makes it cheaper | |
1248 | (especially in the common case of base==ctx.p1()) and useful also when |
|
1260 | (especially in the common case of base==ctx.p1()) and useful also when | |
1249 | experimental.copytrace=off. |
|
1261 | experimental.copytrace=off. | |
1250 |
|
1262 | |||
1251 | merge.update() will have already marked most copies, but it will only |
|
1263 | merge.update() will have already marked most copies, but it will only | |
1252 | mark copies if it thinks the source files are related (see |
|
1264 | mark copies if it thinks the source files are related (see | |
1253 | merge._related()). It will also not mark copies if the file wasn't modified |
|
1265 | merge._related()). It will also not mark copies if the file wasn't modified | |
1254 | on the local side. This function adds the copies that were "missed" |
|
1266 | on the local side. This function adds the copies that were "missed" | |
1255 | by merge.update(). |
|
1267 | by merge.update(). | |
1256 | """ |
|
1268 | """ | |
1257 | new_copies = pathcopies(base, ctx) |
|
1269 | new_copies = pathcopies(base, ctx) | |
1258 | parent = wctx.p1() |
|
1270 | parent = wctx.p1() | |
1259 | _filter(parent, wctx, new_copies) |
|
1271 | _filter(parent, wctx, new_copies) | |
1260 | # Extra filtering to drop copy information for files that existed before |
|
1272 | # Extra filtering to drop copy information for files that existed before | |
1261 | # the graft. This is to handle the case of grafting a rename onto a commit |
|
1273 | # the graft. This is to handle the case of grafting a rename onto a commit | |
1262 | # that already has the rename. Otherwise the presence of copy information |
|
1274 | # that already has the rename. Otherwise the presence of copy information | |
1263 | # would result in the creation of an empty commit where we would prefer to |
|
1275 | # would result in the creation of an empty commit where we would prefer to | |
1264 | # not create one. |
|
1276 | # not create one. | |
1265 | for dest, __ in list(new_copies.items()): |
|
1277 | for dest, __ in list(new_copies.items()): | |
1266 | if dest in parent: |
|
1278 | if dest in parent: | |
1267 | del new_copies[dest] |
|
1279 | del new_copies[dest] | |
1268 | for dst, src in pycompat.iteritems(new_copies): |
|
1280 | for dst, src in pycompat.iteritems(new_copies): | |
1269 | wctx[dst].markcopied(src) |
|
1281 | wctx[dst].markcopied(src) |
@@ -1,815 +1,871 b'' | |||||
1 | use crate::utils::hg_path::HgPath; |
|
1 | use crate::utils::hg_path::HgPath; | |
2 | use crate::utils::hg_path::HgPathBuf; |
|
2 | use crate::utils::hg_path::HgPathBuf; | |
3 | use crate::Revision; |
|
3 | use crate::Revision; | |
4 | use crate::NULL_REVISION; |
|
4 | use crate::NULL_REVISION; | |
5 |
|
5 | |||
6 | use im_rc::ordmap::DiffItem; |
|
6 | use im_rc::ordmap::DiffItem; | |
7 | use im_rc::ordmap::Entry; |
|
7 | use im_rc::ordmap::Entry; | |
8 | use im_rc::ordmap::OrdMap; |
|
8 | use im_rc::ordmap::OrdMap; | |
9 |
|
9 | |||
10 | use std::cmp::Ordering; |
|
10 | use std::cmp::Ordering; | |
11 | use std::collections::HashMap; |
|
11 | use std::collections::HashMap; | |
12 | use std::convert::TryInto; |
|
12 | use std::convert::TryInto; | |
13 |
|
13 | |||
14 | pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>; |
|
14 | pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>; | |
15 |
|
15 | |||
16 | type PathToken = usize; |
|
16 | type PathToken = usize; | |
17 |
|
17 | |||
18 | #[derive(Clone, Debug, PartialEq, Copy)] |
|
18 | #[derive(Clone, Debug, PartialEq, Copy)] | |
19 | struct TimeStampedPathCopy { |
|
19 | struct TimeStampedPathCopy { | |
20 | /// revision at which the copy information was added |
|
20 | /// revision at which the copy information was added | |
21 | rev: Revision, |
|
21 | rev: Revision, | |
22 | /// the copy source, (Set to None in case of deletion of the associated |
|
22 | /// the copy source, (Set to None in case of deletion of the associated | |
23 | /// key) |
|
23 | /// key) | |
24 | path: Option<PathToken>, |
|
24 | path: Option<PathToken>, | |
25 | } |
|
25 | } | |
26 |
|
26 | |||
27 | /// maps CopyDestination to Copy Source (+ a "timestamp" for the operation) |
|
27 | /// maps CopyDestination to Copy Source (+ a "timestamp" for the operation) | |
28 | type TimeStampedPathCopies = OrdMap<PathToken, TimeStampedPathCopy>; |
|
28 | type TimeStampedPathCopies = OrdMap<PathToken, TimeStampedPathCopy>; | |
29 |
|
29 | |||
30 | /// hold parent 1, parent 2 and relevant files actions. |
|
30 | /// hold parent 1, parent 2 and relevant files actions. | |
31 | pub type RevInfo<'a> = (Revision, Revision, ChangedFiles<'a>); |
|
31 | pub type RevInfo<'a> = (Revision, Revision, ChangedFiles<'a>); | |
32 |
|
32 | |||
33 | /// represent the files affected by a changesets |
|
33 | /// represent the files affected by a changesets | |
34 | /// |
|
34 | /// | |
35 | /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need |
|
35 | /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need | |
36 | /// all the data categories tracked by it. |
|
36 | /// all the data categories tracked by it. | |
37 | /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need |
|
37 | /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need | |
38 | /// all the data categories tracked by it. |
|
38 | /// all the data categories tracked by it. | |
39 | pub struct ChangedFiles<'a> { |
|
39 | pub struct ChangedFiles<'a> { | |
40 | nb_items: u32, |
|
40 | nb_items: u32, | |
41 | index: &'a [u8], |
|
41 | index: &'a [u8], | |
42 | data: &'a [u8], |
|
42 | data: &'a [u8], | |
43 | } |
|
43 | } | |
44 |
|
44 | |||
45 | /// Represent active changes that affect the copy tracing. |
|
45 | /// Represent active changes that affect the copy tracing. | |
46 | enum Action<'a> { |
|
46 | enum Action<'a> { | |
47 | /// The parent ? children edge is removing a file |
|
47 | /// The parent ? children edge is removing a file | |
48 | /// |
|
48 | /// | |
49 | /// (actually, this could be the edge from the other parent, but it does |
|
49 | /// (actually, this could be the edge from the other parent, but it does | |
50 | /// not matters) |
|
50 | /// not matters) | |
51 | Removed(&'a HgPath), |
|
51 | Removed(&'a HgPath), | |
52 | /// The parent ? children edge introduce copy information between (dest, |
|
52 | /// The parent ? children edge introduce copy information between (dest, | |
53 | /// source) |
|
53 | /// source) | |
54 | Copied(&'a HgPath, &'a HgPath), |
|
54 | Copied(&'a HgPath, &'a HgPath), | |
55 | } |
|
55 | } | |
56 |
|
56 | |||
57 | /// This express the possible "special" case we can get in a merge |
|
57 | /// This express the possible "special" case we can get in a merge | |
58 | /// |
|
58 | /// | |
59 | /// See mercurial/metadata.py for details on these values. |
|
59 | /// See mercurial/metadata.py for details on these values. | |
60 | #[derive(PartialEq)] |
|
60 | #[derive(PartialEq)] | |
61 | enum MergeCase { |
|
61 | enum MergeCase { | |
62 | /// Merged: file had history on both side that needed to be merged |
|
62 | /// Merged: file had history on both side that needed to be merged | |
63 | Merged, |
|
63 | Merged, | |
64 | /// Salvaged: file was candidate for deletion, but survived the merge |
|
64 | /// Salvaged: file was candidate for deletion, but survived the merge | |
65 | Salvaged, |
|
65 | Salvaged, | |
66 | /// Normal: Not one of the two cases above |
|
66 | /// Normal: Not one of the two cases above | |
67 | Normal, |
|
67 | Normal, | |
68 | } |
|
68 | } | |
69 |
|
69 | |||
70 | type FileChange<'a> = (u8, &'a HgPath, &'a HgPath); |
|
70 | type FileChange<'a> = (u8, &'a HgPath, &'a HgPath); | |
71 |
|
71 | |||
72 | const EMPTY: &[u8] = b""; |
|
72 | const EMPTY: &[u8] = b""; | |
73 | const COPY_MASK: u8 = 3; |
|
73 | const COPY_MASK: u8 = 3; | |
74 | const P1_COPY: u8 = 2; |
|
74 | const P1_COPY: u8 = 2; | |
75 | const P2_COPY: u8 = 3; |
|
75 | const P2_COPY: u8 = 3; | |
76 | const ACTION_MASK: u8 = 28; |
|
76 | const ACTION_MASK: u8 = 28; | |
77 | const REMOVED: u8 = 12; |
|
77 | const REMOVED: u8 = 12; | |
78 | const MERGED: u8 = 8; |
|
78 | const MERGED: u8 = 8; | |
79 | const SALVAGED: u8 = 16; |
|
79 | const SALVAGED: u8 = 16; | |
80 |
|
80 | |||
81 | impl<'a> ChangedFiles<'a> { |
|
81 | impl<'a> ChangedFiles<'a> { | |
82 | const INDEX_START: usize = 4; |
|
82 | const INDEX_START: usize = 4; | |
83 | const ENTRY_SIZE: u32 = 9; |
|
83 | const ENTRY_SIZE: u32 = 9; | |
84 | const FILENAME_START: u32 = 1; |
|
84 | const FILENAME_START: u32 = 1; | |
85 | const COPY_SOURCE_START: u32 = 5; |
|
85 | const COPY_SOURCE_START: u32 = 5; | |
86 |
|
86 | |||
87 | pub fn new(data: &'a [u8]) -> Self { |
|
87 | pub fn new(data: &'a [u8]) -> Self { | |
88 | assert!( |
|
88 | assert!( | |
89 | data.len() >= 4, |
|
89 | data.len() >= 4, | |
90 | "data size ({}) is too small to contain the header (4)", |
|
90 | "data size ({}) is too small to contain the header (4)", | |
91 | data.len() |
|
91 | data.len() | |
92 | ); |
|
92 | ); | |
93 | let nb_items_raw: [u8; 4] = (&data[0..=3]) |
|
93 | let nb_items_raw: [u8; 4] = (&data[0..=3]) | |
94 | .try_into() |
|
94 | .try_into() | |
95 | .expect("failed to turn 4 bytes into 4 bytes"); |
|
95 | .expect("failed to turn 4 bytes into 4 bytes"); | |
96 | let nb_items = u32::from_be_bytes(nb_items_raw); |
|
96 | let nb_items = u32::from_be_bytes(nb_items_raw); | |
97 |
|
97 | |||
98 | let index_size = (nb_items * Self::ENTRY_SIZE) as usize; |
|
98 | let index_size = (nb_items * Self::ENTRY_SIZE) as usize; | |
99 | let index_end = Self::INDEX_START + index_size; |
|
99 | let index_end = Self::INDEX_START + index_size; | |
100 |
|
100 | |||
101 | assert!( |
|
101 | assert!( | |
102 | data.len() >= index_end, |
|
102 | data.len() >= index_end, | |
103 | "data size ({}) is too small to fit the index_data ({})", |
|
103 | "data size ({}) is too small to fit the index_data ({})", | |
104 | data.len(), |
|
104 | data.len(), | |
105 | index_end |
|
105 | index_end | |
106 | ); |
|
106 | ); | |
107 |
|
107 | |||
108 | let ret = ChangedFiles { |
|
108 | let ret = ChangedFiles { | |
109 | nb_items, |
|
109 | nb_items, | |
110 | index: &data[Self::INDEX_START..index_end], |
|
110 | index: &data[Self::INDEX_START..index_end], | |
111 | data: &data[index_end..], |
|
111 | data: &data[index_end..], | |
112 | }; |
|
112 | }; | |
113 | let max_data = ret.filename_end(nb_items - 1) as usize; |
|
113 | let max_data = ret.filename_end(nb_items - 1) as usize; | |
114 | assert!( |
|
114 | assert!( | |
115 | ret.data.len() >= max_data, |
|
115 | ret.data.len() >= max_data, | |
116 | "data size ({}) is too small to fit all data ({})", |
|
116 | "data size ({}) is too small to fit all data ({})", | |
117 | data.len(), |
|
117 | data.len(), | |
118 | index_end + max_data |
|
118 | index_end + max_data | |
119 | ); |
|
119 | ); | |
120 | ret |
|
120 | ret | |
121 | } |
|
121 | } | |
122 |
|
122 | |||
123 | pub fn new_empty() -> Self { |
|
123 | pub fn new_empty() -> Self { | |
124 | ChangedFiles { |
|
124 | ChangedFiles { | |
125 | nb_items: 0, |
|
125 | nb_items: 0, | |
126 | index: EMPTY, |
|
126 | index: EMPTY, | |
127 | data: EMPTY, |
|
127 | data: EMPTY, | |
128 | } |
|
128 | } | |
129 | } |
|
129 | } | |
130 |
|
130 | |||
131 | /// internal function to return an individual entry at a given index |
|
131 | /// internal function to return an individual entry at a given index | |
132 | fn entry(&'a self, idx: u32) -> FileChange<'a> { |
|
132 | fn entry(&'a self, idx: u32) -> FileChange<'a> { | |
133 | if idx >= self.nb_items { |
|
133 | if idx >= self.nb_items { | |
134 | panic!( |
|
134 | panic!( | |
135 | "index for entry is higher that the number of file {} >= {}", |
|
135 | "index for entry is higher that the number of file {} >= {}", | |
136 | idx, self.nb_items |
|
136 | idx, self.nb_items | |
137 | ) |
|
137 | ) | |
138 | } |
|
138 | } | |
139 | let flags = self.flags(idx); |
|
139 | let flags = self.flags(idx); | |
140 | let filename = self.filename(idx); |
|
140 | let filename = self.filename(idx); | |
141 | let copy_idx = self.copy_idx(idx); |
|
141 | let copy_idx = self.copy_idx(idx); | |
142 | let copy_source = self.filename(copy_idx); |
|
142 | let copy_source = self.filename(copy_idx); | |
143 | (flags, filename, copy_source) |
|
143 | (flags, filename, copy_source) | |
144 | } |
|
144 | } | |
145 |
|
145 | |||
146 | /// internal function to return the filename of the entry at a given index |
|
146 | /// internal function to return the filename of the entry at a given index | |
147 | fn filename(&self, idx: u32) -> &HgPath { |
|
147 | fn filename(&self, idx: u32) -> &HgPath { | |
148 | let filename_start; |
|
148 | let filename_start; | |
149 | if idx == 0 { |
|
149 | if idx == 0 { | |
150 | filename_start = 0; |
|
150 | filename_start = 0; | |
151 | } else { |
|
151 | } else { | |
152 | filename_start = self.filename_end(idx - 1) |
|
152 | filename_start = self.filename_end(idx - 1) | |
153 | } |
|
153 | } | |
154 | let filename_end = self.filename_end(idx); |
|
154 | let filename_end = self.filename_end(idx); | |
155 | let filename_start = filename_start as usize; |
|
155 | let filename_start = filename_start as usize; | |
156 | let filename_end = filename_end as usize; |
|
156 | let filename_end = filename_end as usize; | |
157 | HgPath::new(&self.data[filename_start..filename_end]) |
|
157 | HgPath::new(&self.data[filename_start..filename_end]) | |
158 | } |
|
158 | } | |
159 |
|
159 | |||
160 | /// internal function to return the flag field of the entry at a given |
|
160 | /// internal function to return the flag field of the entry at a given | |
161 | /// index |
|
161 | /// index | |
162 | fn flags(&self, idx: u32) -> u8 { |
|
162 | fn flags(&self, idx: u32) -> u8 { | |
163 | let idx = idx as usize; |
|
163 | let idx = idx as usize; | |
164 | self.index[idx * (Self::ENTRY_SIZE as usize)] |
|
164 | self.index[idx * (Self::ENTRY_SIZE as usize)] | |
165 | } |
|
165 | } | |
166 |
|
166 | |||
167 | /// internal function to return the end of a filename part at a given index |
|
167 | /// internal function to return the end of a filename part at a given index | |
168 | fn filename_end(&self, idx: u32) -> u32 { |
|
168 | fn filename_end(&self, idx: u32) -> u32 { | |
169 | let start = (idx * Self::ENTRY_SIZE) + Self::FILENAME_START; |
|
169 | let start = (idx * Self::ENTRY_SIZE) + Self::FILENAME_START; | |
170 | let end = (idx * Self::ENTRY_SIZE) + Self::COPY_SOURCE_START; |
|
170 | let end = (idx * Self::ENTRY_SIZE) + Self::COPY_SOURCE_START; | |
171 | let start = start as usize; |
|
171 | let start = start as usize; | |
172 | let end = end as usize; |
|
172 | let end = end as usize; | |
173 | let raw = (&self.index[start..end]) |
|
173 | let raw = (&self.index[start..end]) | |
174 | .try_into() |
|
174 | .try_into() | |
175 | .expect("failed to turn 4 bytes into 4 bytes"); |
|
175 | .expect("failed to turn 4 bytes into 4 bytes"); | |
176 | u32::from_be_bytes(raw) |
|
176 | u32::from_be_bytes(raw) | |
177 | } |
|
177 | } | |
178 |
|
178 | |||
179 | /// internal function to return index of the copy source of the entry at a |
|
179 | /// internal function to return index of the copy source of the entry at a | |
180 | /// given index |
|
180 | /// given index | |
181 | fn copy_idx(&self, idx: u32) -> u32 { |
|
181 | fn copy_idx(&self, idx: u32) -> u32 { | |
182 | let start = (idx * Self::ENTRY_SIZE) + Self::COPY_SOURCE_START; |
|
182 | let start = (idx * Self::ENTRY_SIZE) + Self::COPY_SOURCE_START; | |
183 | let end = (idx + 1) * Self::ENTRY_SIZE; |
|
183 | let end = (idx + 1) * Self::ENTRY_SIZE; | |
184 | let start = start as usize; |
|
184 | let start = start as usize; | |
185 | let end = end as usize; |
|
185 | let end = end as usize; | |
186 | let raw = (&self.index[start..end]) |
|
186 | let raw = (&self.index[start..end]) | |
187 | .try_into() |
|
187 | .try_into() | |
188 | .expect("failed to turn 4 bytes into 4 bytes"); |
|
188 | .expect("failed to turn 4 bytes into 4 bytes"); | |
189 | u32::from_be_bytes(raw) |
|
189 | u32::from_be_bytes(raw) | |
190 | } |
|
190 | } | |
191 |
|
191 | |||
192 | /// Return an iterator over all the `Action` in this instance. |
|
192 | /// Return an iterator over all the `Action` in this instance. | |
193 | fn iter_actions(&self, parent: Parent) -> ActionsIterator { |
|
193 | fn iter_actions(&self, parent: Parent) -> ActionsIterator { | |
194 | ActionsIterator { |
|
194 | ActionsIterator { | |
195 | changes: &self, |
|
195 | changes: &self, | |
196 | parent: parent, |
|
196 | parent: parent, | |
197 | current: 0, |
|
197 | current: 0, | |
198 | } |
|
198 | } | |
199 | } |
|
199 | } | |
200 |
|
200 | |||
201 | /// return the MergeCase value associated with a filename |
|
201 | /// return the MergeCase value associated with a filename | |
202 | fn get_merge_case(&self, path: &HgPath) -> MergeCase { |
|
202 | fn get_merge_case(&self, path: &HgPath) -> MergeCase { | |
203 | if self.nb_items == 0 { |
|
203 | if self.nb_items == 0 { | |
204 | return MergeCase::Normal; |
|
204 | return MergeCase::Normal; | |
205 | } |
|
205 | } | |
206 | let mut low_part = 0; |
|
206 | let mut low_part = 0; | |
207 | let mut high_part = self.nb_items; |
|
207 | let mut high_part = self.nb_items; | |
208 |
|
208 | |||
209 | while low_part < high_part { |
|
209 | while low_part < high_part { | |
210 | let cursor = (low_part + high_part - 1) / 2; |
|
210 | let cursor = (low_part + high_part - 1) / 2; | |
211 | let (flags, filename, _source) = self.entry(cursor); |
|
211 | let (flags, filename, _source) = self.entry(cursor); | |
212 | match path.cmp(filename) { |
|
212 | match path.cmp(filename) { | |
213 | Ordering::Less => low_part = cursor + 1, |
|
213 | Ordering::Less => low_part = cursor + 1, | |
214 | Ordering::Greater => high_part = cursor, |
|
214 | Ordering::Greater => high_part = cursor, | |
215 | Ordering::Equal => { |
|
215 | Ordering::Equal => { | |
216 | return match flags & ACTION_MASK { |
|
216 | return match flags & ACTION_MASK { | |
217 | MERGED => MergeCase::Merged, |
|
217 | MERGED => MergeCase::Merged, | |
218 | SALVAGED => MergeCase::Salvaged, |
|
218 | SALVAGED => MergeCase::Salvaged, | |
219 | _ => MergeCase::Normal, |
|
219 | _ => MergeCase::Normal, | |
220 | }; |
|
220 | }; | |
221 | } |
|
221 | } | |
222 | } |
|
222 | } | |
223 | } |
|
223 | } | |
224 | MergeCase::Normal |
|
224 | MergeCase::Normal | |
225 | } |
|
225 | } | |
226 | } |
|
226 | } | |
227 |
|
227 | |||
228 | /// A struct responsible for answering "is X ancestors of Y" quickly |
|
228 | /// A struct responsible for answering "is X ancestors of Y" quickly | |
229 | /// |
|
229 | /// | |
230 | /// The structure will delegate ancestors call to a callback, and cache the |
|
230 | /// The structure will delegate ancestors call to a callback, and cache the | |
231 | /// result. |
|
231 | /// result. | |
232 | #[derive(Debug)] |
|
232 | #[derive(Debug)] | |
233 | struct AncestorOracle<'a, A: Fn(Revision, Revision) -> bool> { |
|
233 | struct AncestorOracle<'a, A: Fn(Revision, Revision) -> bool> { | |
234 | inner: &'a A, |
|
234 | inner: &'a A, | |
235 | pairs: HashMap<(Revision, Revision), bool>, |
|
235 | pairs: HashMap<(Revision, Revision), bool>, | |
236 | } |
|
236 | } | |
237 |
|
237 | |||
238 | impl<'a, A: Fn(Revision, Revision) -> bool> AncestorOracle<'a, A> { |
|
238 | impl<'a, A: Fn(Revision, Revision) -> bool> AncestorOracle<'a, A> { | |
239 | fn new(func: &'a A) -> Self { |
|
239 | fn new(func: &'a A) -> Self { | |
240 | Self { |
|
240 | Self { | |
241 | inner: func, |
|
241 | inner: func, | |
242 | pairs: HashMap::default(), |
|
242 | pairs: HashMap::default(), | |
243 | } |
|
243 | } | |
244 | } |
|
244 | } | |
245 |
|
245 | |||
246 | fn record_overwrite(&mut self, anc: Revision, desc: Revision) { |
|
246 | fn record_overwrite(&mut self, anc: Revision, desc: Revision) { | |
247 | self.pairs.insert((anc, desc), true); |
|
247 | self.pairs.insert((anc, desc), true); | |
248 | } |
|
248 | } | |
249 |
|
249 | |||
250 | /// returns `true` if `anc` is an ancestors of `desc`, `false` otherwise |
|
250 | /// returns `true` if `anc` is an ancestors of `desc`, `false` otherwise | |
251 | fn is_overwrite(&mut self, anc: Revision, desc: Revision) -> bool { |
|
251 | fn is_overwrite(&mut self, anc: Revision, desc: Revision) -> bool { | |
252 | if anc > desc { |
|
252 | if anc > desc { | |
253 | false |
|
253 | false | |
254 | } else if anc == desc { |
|
254 | } else if anc == desc { | |
255 | true |
|
255 | true | |
256 | } else { |
|
256 | } else { | |
257 | if let Some(b) = self.pairs.get(&(anc, desc)) { |
|
257 | if let Some(b) = self.pairs.get(&(anc, desc)) { | |
258 | *b |
|
258 | *b | |
259 | } else { |
|
259 | } else { | |
260 | let b = (self.inner)(anc, desc); |
|
260 | let b = (self.inner)(anc, desc); | |
261 | self.pairs.insert((anc, desc), b); |
|
261 | self.pairs.insert((anc, desc), b); | |
262 | b |
|
262 | b | |
263 | } |
|
263 | } | |
264 | } |
|
264 | } | |
265 | } |
|
265 | } | |
266 | } |
|
266 | } | |
267 |
|
267 | |||
268 | struct ActionsIterator<'a> { |
|
268 | struct ActionsIterator<'a> { | |
269 | changes: &'a ChangedFiles<'a>, |
|
269 | changes: &'a ChangedFiles<'a>, | |
270 | parent: Parent, |
|
270 | parent: Parent, | |
271 | current: u32, |
|
271 | current: u32, | |
272 | } |
|
272 | } | |
273 |
|
273 | |||
274 | impl<'a> Iterator for ActionsIterator<'a> { |
|
274 | impl<'a> Iterator for ActionsIterator<'a> { | |
275 | type Item = Action<'a>; |
|
275 | type Item = Action<'a>; | |
276 |
|
276 | |||
277 | fn next(&mut self) -> Option<Action<'a>> { |
|
277 | fn next(&mut self) -> Option<Action<'a>> { | |
278 | let copy_flag = match self.parent { |
|
278 | let copy_flag = match self.parent { | |
279 | Parent::FirstParent => P1_COPY, |
|
279 | Parent::FirstParent => P1_COPY, | |
280 | Parent::SecondParent => P2_COPY, |
|
280 | Parent::SecondParent => P2_COPY, | |
281 | }; |
|
281 | }; | |
282 | while self.current < self.changes.nb_items { |
|
282 | while self.current < self.changes.nb_items { | |
283 | let (flags, file, source) = self.changes.entry(self.current); |
|
283 | let (flags, file, source) = self.changes.entry(self.current); | |
284 | self.current += 1; |
|
284 | self.current += 1; | |
285 | if (flags & ACTION_MASK) == REMOVED { |
|
285 | if (flags & ACTION_MASK) == REMOVED { | |
286 | return Some(Action::Removed(file)); |
|
286 | return Some(Action::Removed(file)); | |
287 | } |
|
287 | } | |
288 | let copy = flags & COPY_MASK; |
|
288 | let copy = flags & COPY_MASK; | |
289 | if copy == copy_flag { |
|
289 | if copy == copy_flag { | |
290 | return Some(Action::Copied(file, source)); |
|
290 | return Some(Action::Copied(file, source)); | |
291 | } |
|
291 | } | |
292 | } |
|
292 | } | |
293 | return None; |
|
293 | return None; | |
294 | } |
|
294 | } | |
295 | } |
|
295 | } | |
296 |
|
296 | |||
297 | /// A small struct whose purpose is to ensure lifetime of bytes referenced in |
|
297 | /// A small struct whose purpose is to ensure lifetime of bytes referenced in | |
298 | /// ChangedFiles |
|
298 | /// ChangedFiles | |
299 | /// |
|
299 | /// | |
300 | /// It is passed to the RevInfoMaker callback who can assign any necessary |
|
300 | /// It is passed to the RevInfoMaker callback who can assign any necessary | |
301 | /// content to the `data` attribute. The copy tracing code is responsible for |
|
301 | /// content to the `data` attribute. The copy tracing code is responsible for | |
302 | /// keeping the DataHolder alive at least as long as the ChangedFiles object. |
|
302 | /// keeping the DataHolder alive at least as long as the ChangedFiles object. | |
303 | pub struct DataHolder<D> { |
|
303 | pub struct DataHolder<D> { | |
304 | /// RevInfoMaker callback should assign data referenced by the |
|
304 | /// RevInfoMaker callback should assign data referenced by the | |
305 | /// ChangedFiles struct it return to this attribute. The DataHolder |
|
305 | /// ChangedFiles struct it return to this attribute. The DataHolder | |
306 | /// lifetime will be at least as long as the ChangedFiles one. |
|
306 | /// lifetime will be at least as long as the ChangedFiles one. | |
307 | pub data: Option<D>, |
|
307 | pub data: Option<D>, | |
308 | } |
|
308 | } | |
309 |
|
309 | |||
310 | pub type RevInfoMaker<'a, D> = |
|
310 | pub type RevInfoMaker<'a, D> = | |
311 | Box<dyn for<'r> Fn(Revision, &'r mut DataHolder<D>) -> RevInfo<'r> + 'a>; |
|
311 | Box<dyn for<'r> Fn(Revision, &'r mut DataHolder<D>) -> RevInfo<'r> + 'a>; | |
312 |
|
312 | |||
313 | /// enum used to carry information about the parent β child currently processed |
|
313 | /// enum used to carry information about the parent β child currently processed | |
314 | #[derive(Copy, Clone, Debug)] |
|
314 | #[derive(Copy, Clone, Debug)] | |
315 | enum Parent { |
|
315 | enum Parent { | |
316 | /// The `p1(x) β x` edge |
|
316 | /// The `p1(x) β x` edge | |
317 | FirstParent, |
|
317 | FirstParent, | |
318 | /// The `p2(x) β x` edge |
|
318 | /// The `p2(x) β x` edge | |
319 | SecondParent, |
|
319 | SecondParent, | |
320 | } |
|
320 | } | |
321 |
|
321 | |||
322 | /// A small "tokenizer" responsible of turning full HgPath into lighter |
|
322 | /// A small "tokenizer" responsible of turning full HgPath into lighter | |
323 | /// PathToken |
|
323 | /// PathToken | |
324 | /// |
|
324 | /// | |
325 | /// Dealing with small object, like integer is much faster, so HgPath input are |
|
325 | /// Dealing with small object, like integer is much faster, so HgPath input are | |
326 | /// turned into integer "PathToken" and converted back in the end. |
|
326 | /// turned into integer "PathToken" and converted back in the end. | |
327 | #[derive(Clone, Debug, Default)] |
|
327 | #[derive(Clone, Debug, Default)] | |
328 | struct TwoWayPathMap { |
|
328 | struct TwoWayPathMap { | |
329 | token: HashMap<HgPathBuf, PathToken>, |
|
329 | token: HashMap<HgPathBuf, PathToken>, | |
330 | path: Vec<HgPathBuf>, |
|
330 | path: Vec<HgPathBuf>, | |
331 | } |
|
331 | } | |
332 |
|
332 | |||
333 | impl TwoWayPathMap { |
|
333 | impl TwoWayPathMap { | |
334 | fn tokenize(&mut self, path: &HgPath) -> PathToken { |
|
334 | fn tokenize(&mut self, path: &HgPath) -> PathToken { | |
335 | match self.token.get(path) { |
|
335 | match self.token.get(path) { | |
336 | Some(a) => *a, |
|
336 | Some(a) => *a, | |
337 | None => { |
|
337 | None => { | |
338 | let a = self.token.len(); |
|
338 | let a = self.token.len(); | |
339 | let buf = path.to_owned(); |
|
339 | let buf = path.to_owned(); | |
340 | self.path.push(buf.clone()); |
|
340 | self.path.push(buf.clone()); | |
341 | self.token.insert(buf, a); |
|
341 | self.token.insert(buf, a); | |
342 | a |
|
342 | a | |
343 | } |
|
343 | } | |
344 | } |
|
344 | } | |
345 | } |
|
345 | } | |
346 |
|
346 | |||
347 | fn untokenize(&self, token: PathToken) -> &HgPathBuf { |
|
347 | fn untokenize(&self, token: PathToken) -> &HgPathBuf { | |
348 | assert!(token < self.path.len(), format!("Unknown token: {}", token)); |
|
348 | assert!(token < self.path.len(), format!("Unknown token: {}", token)); | |
349 | &self.path[token] |
|
349 | &self.path[token] | |
350 | } |
|
350 | } | |
351 | } |
|
351 | } | |
352 |
|
352 | |||
353 | /// Same as mercurial.copies._combine_changeset_copies, but in Rust. |
|
353 | /// Same as mercurial.copies._combine_changeset_copies, but in Rust. | |
354 | /// |
|
354 | /// | |
355 | /// Arguments are: |
|
355 | /// Arguments are: | |
356 | /// |
|
356 | /// | |
357 | /// revs: all revisions to be considered |
|
357 | /// revs: all revisions to be considered | |
358 | /// children: a {parent ? [childrens]} mapping |
|
358 | /// children: a {parent ? [childrens]} mapping | |
359 | /// target_rev: the final revision we are combining copies to |
|
359 | /// target_rev: the final revision we are combining copies to | |
360 | /// rev_info(rev): callback to get revision information: |
|
360 | /// rev_info(rev): callback to get revision information: | |
361 | /// * first parent |
|
361 | /// * first parent | |
362 | /// * second parent |
|
362 | /// * second parent | |
363 | /// * ChangedFiles |
|
363 | /// * ChangedFiles | |
364 | /// isancestors(low_rev, high_rev): callback to check if a revision is an |
|
364 | /// isancestors(low_rev, high_rev): callback to check if a revision is an | |
365 | /// ancestor of another |
|
365 | /// ancestor of another | |
366 | pub fn combine_changeset_copies<A: Fn(Revision, Revision) -> bool, D>( |
|
366 | pub fn combine_changeset_copies<A: Fn(Revision, Revision) -> bool, D>( | |
367 | revs: Vec<Revision>, |
|
367 | revs: Vec<Revision>, | |
368 | mut children_count: HashMap<Revision, usize>, |
|
368 | mut children_count: HashMap<Revision, usize>, | |
369 | target_rev: Revision, |
|
369 | target_rev: Revision, | |
370 | rev_info: RevInfoMaker<D>, |
|
370 | rev_info: RevInfoMaker<D>, | |
371 | is_ancestor: &A, |
|
371 | is_ancestor: &A, | |
372 | ) -> PathCopies { |
|
372 | ) -> PathCopies { | |
373 | let mut all_copies = HashMap::new(); |
|
373 | let mut all_copies = HashMap::new(); | |
374 | let mut oracle = AncestorOracle::new(is_ancestor); |
|
374 | let mut oracle = AncestorOracle::new(is_ancestor); | |
375 |
|
375 | |||
376 | let mut path_map = TwoWayPathMap::default(); |
|
376 | let mut path_map = TwoWayPathMap::default(); | |
377 |
|
377 | |||
378 | for rev in revs { |
|
378 | for rev in revs { | |
379 | let mut d: DataHolder<D> = DataHolder { data: None }; |
|
379 | let mut d: DataHolder<D> = DataHolder { data: None }; | |
380 | let (p1, p2, changes) = rev_info(rev, &mut d); |
|
380 | let (p1, p2, changes) = rev_info(rev, &mut d); | |
381 |
|
381 | |||
382 | // We will chain the copies information accumulated for the parent with |
|
382 | // We will chain the copies information accumulated for the parent with | |
383 | // the individual copies information the curent revision. Creating a |
|
383 | // the individual copies information the curent revision. Creating a | |
384 | // new TimeStampedPath for each `rev` β `children` vertex. |
|
384 | // new TimeStampedPath for each `rev` β `children` vertex. | |
385 | let mut copies: Option<TimeStampedPathCopies> = None; |
|
385 | let mut copies: Option<TimeStampedPathCopies> = None; | |
386 | if p1 != NULL_REVISION { |
|
386 | if p1 != NULL_REVISION { | |
387 | // Retrieve data computed in a previous iteration |
|
387 | // Retrieve data computed in a previous iteration | |
388 | let parent_copies = get_and_clean_parent_copies( |
|
388 | let parent_copies = get_and_clean_parent_copies( | |
389 | &mut all_copies, |
|
389 | &mut all_copies, | |
390 | &mut children_count, |
|
390 | &mut children_count, | |
391 | p1, |
|
391 | p1, | |
392 | ); |
|
392 | ); | |
393 | if let Some(parent_copies) = parent_copies { |
|
393 | if let Some(parent_copies) = parent_copies { | |
394 | // combine it with data for that revision |
|
394 | // combine it with data for that revision | |
395 | let vertex_copies = add_from_changes( |
|
395 | let vertex_copies = add_from_changes( | |
396 | &mut path_map, |
|
396 | &mut path_map, | |
397 | &mut oracle, |
|
397 | &mut oracle, | |
398 | &parent_copies, |
|
398 | &parent_copies, | |
399 | &changes, |
|
399 | &changes, | |
400 | Parent::FirstParent, |
|
400 | Parent::FirstParent, | |
401 | rev, |
|
401 | rev, | |
402 | ); |
|
402 | ); | |
403 | // keep that data around for potential later combination |
|
403 | // keep that data around for potential later combination | |
404 | copies = Some(vertex_copies); |
|
404 | copies = Some(vertex_copies); | |
405 | } |
|
405 | } | |
406 | } |
|
406 | } | |
407 | if p2 != NULL_REVISION { |
|
407 | if p2 != NULL_REVISION { | |
408 | // Retrieve data computed in a previous iteration |
|
408 | // Retrieve data computed in a previous iteration | |
409 | let parent_copies = get_and_clean_parent_copies( |
|
409 | let parent_copies = get_and_clean_parent_copies( | |
410 | &mut all_copies, |
|
410 | &mut all_copies, | |
411 | &mut children_count, |
|
411 | &mut children_count, | |
412 | p2, |
|
412 | p2, | |
413 | ); |
|
413 | ); | |
414 | if let Some(parent_copies) = parent_copies { |
|
414 | if let Some(parent_copies) = parent_copies { | |
415 | // combine it with data for that revision |
|
415 | // combine it with data for that revision | |
416 | let vertex_copies = add_from_changes( |
|
416 | let vertex_copies = add_from_changes( | |
417 | &mut path_map, |
|
417 | &mut path_map, | |
418 | &mut oracle, |
|
418 | &mut oracle, | |
419 | &parent_copies, |
|
419 | &parent_copies, | |
420 | &changes, |
|
420 | &changes, | |
421 | Parent::SecondParent, |
|
421 | Parent::SecondParent, | |
422 | rev, |
|
422 | rev, | |
423 | ); |
|
423 | ); | |
424 |
|
424 | |||
425 | copies = match copies { |
|
425 | copies = match copies { | |
426 | None => Some(vertex_copies), |
|
426 | None => Some(vertex_copies), | |
427 | // Merge has two parents needs to combines their copy |
|
427 | // Merge has two parents needs to combines their copy | |
428 | // information. |
|
428 | // information. | |
429 | // |
|
429 | // | |
430 | // If we got data from both parents, We need to combine |
|
430 | // If we got data from both parents, We need to combine | |
431 | // them. |
|
431 | // them. | |
432 | Some(copies) => Some(merge_copies_dict( |
|
432 | Some(copies) => Some(merge_copies_dict( | |
433 | &path_map, |
|
433 | &path_map, | |
434 | rev, |
|
434 | rev, | |
435 | vertex_copies, |
|
435 | vertex_copies, | |
436 | copies, |
|
436 | copies, | |
437 | &changes, |
|
437 | &changes, | |
438 | &mut oracle, |
|
438 | &mut oracle, | |
439 | )), |
|
439 | )), | |
440 | }; |
|
440 | }; | |
441 | } |
|
441 | } | |
442 | } |
|
442 | } | |
443 | match copies { |
|
443 | match copies { | |
444 | Some(copies) => { |
|
444 | Some(copies) => { | |
445 | all_copies.insert(rev, copies); |
|
445 | all_copies.insert(rev, copies); | |
446 | } |
|
446 | } | |
447 | _ => {} |
|
447 | _ => {} | |
448 | } |
|
448 | } | |
449 | } |
|
449 | } | |
450 |
|
450 | |||
451 | // Drop internal information (like the timestamp) and return the final |
|
451 | // Drop internal information (like the timestamp) and return the final | |
452 | // mapping. |
|
452 | // mapping. | |
453 | let tt_result = all_copies |
|
453 | let tt_result = all_copies | |
454 | .remove(&target_rev) |
|
454 | .remove(&target_rev) | |
455 | .expect("target revision was not processed"); |
|
455 | .expect("target revision was not processed"); | |
456 | let mut result = PathCopies::default(); |
|
456 | let mut result = PathCopies::default(); | |
457 | for (dest, tt_source) in tt_result { |
|
457 | for (dest, tt_source) in tt_result { | |
458 | if let Some(path) = tt_source.path { |
|
458 | if let Some(path) = tt_source.path { | |
459 | let path_dest = path_map.untokenize(dest).to_owned(); |
|
459 | let path_dest = path_map.untokenize(dest).to_owned(); | |
460 | let path_path = path_map.untokenize(path).to_owned(); |
|
460 | let path_path = path_map.untokenize(path).to_owned(); | |
461 | result.insert(path_dest, path_path); |
|
461 | result.insert(path_dest, path_path); | |
462 | } |
|
462 | } | |
463 | } |
|
463 | } | |
464 | result |
|
464 | result | |
465 | } |
|
465 | } | |
466 |
|
466 | |||
467 | /// fetch previous computed information |
|
467 | /// fetch previous computed information | |
468 | /// |
|
468 | /// | |
469 | /// If no other children are expected to need this information, we drop it from |
|
469 | /// If no other children are expected to need this information, we drop it from | |
470 | /// the cache. |
|
470 | /// the cache. | |
471 | /// |
|
471 | /// | |
472 | /// If parent is not part of the set we are expected to walk, return None. |
|
472 | /// If parent is not part of the set we are expected to walk, return None. | |
473 | fn get_and_clean_parent_copies( |
|
473 | fn get_and_clean_parent_copies( | |
474 | all_copies: &mut HashMap<Revision, TimeStampedPathCopies>, |
|
474 | all_copies: &mut HashMap<Revision, TimeStampedPathCopies>, | |
475 | children_count: &mut HashMap<Revision, usize>, |
|
475 | children_count: &mut HashMap<Revision, usize>, | |
476 | parent_rev: Revision, |
|
476 | parent_rev: Revision, | |
477 | ) -> Option<TimeStampedPathCopies> { |
|
477 | ) -> Option<TimeStampedPathCopies> { | |
478 | let count = children_count.get_mut(&parent_rev)?; |
|
478 | let count = children_count.get_mut(&parent_rev)?; | |
479 | *count -= 1; |
|
479 | *count -= 1; | |
480 | if *count == 0 { |
|
480 | if *count == 0 { | |
481 | match all_copies.remove(&parent_rev) { |
|
481 | match all_copies.remove(&parent_rev) { | |
482 | Some(c) => Some(c), |
|
482 | Some(c) => Some(c), | |
483 | None => Some(TimeStampedPathCopies::default()), |
|
483 | None => Some(TimeStampedPathCopies::default()), | |
484 | } |
|
484 | } | |
485 | } else { |
|
485 | } else { | |
486 | match all_copies.get(&parent_rev) { |
|
486 | match all_copies.get(&parent_rev) { | |
487 | Some(c) => Some(c.clone()), |
|
487 | Some(c) => Some(c.clone()), | |
488 | None => Some(TimeStampedPathCopies::default()), |
|
488 | None => Some(TimeStampedPathCopies::default()), | |
489 | } |
|
489 | } | |
490 | } |
|
490 | } | |
491 | } |
|
491 | } | |
492 |
|
492 | |||
493 | /// Combine ChangedFiles with some existing PathCopies information and return |
|
493 | /// Combine ChangedFiles with some existing PathCopies information and return | |
494 | /// the result |
|
494 | /// the result | |
495 | fn add_from_changes<A: Fn(Revision, Revision) -> bool>( |
|
495 | fn add_from_changes<A: Fn(Revision, Revision) -> bool>( | |
496 | path_map: &mut TwoWayPathMap, |
|
496 | path_map: &mut TwoWayPathMap, | |
497 | oracle: &mut AncestorOracle<A>, |
|
497 | oracle: &mut AncestorOracle<A>, | |
498 | base_copies: &TimeStampedPathCopies, |
|
498 | base_copies: &TimeStampedPathCopies, | |
499 | changes: &ChangedFiles, |
|
499 | changes: &ChangedFiles, | |
500 | parent: Parent, |
|
500 | parent: Parent, | |
501 | current_rev: Revision, |
|
501 | current_rev: Revision, | |
502 | ) -> TimeStampedPathCopies { |
|
502 | ) -> TimeStampedPathCopies { | |
503 | let mut copies = base_copies.clone(); |
|
503 | let mut copies = base_copies.clone(); | |
504 | for action in changes.iter_actions(parent) { |
|
504 | for action in changes.iter_actions(parent) { | |
505 | match action { |
|
505 | match action { | |
506 | Action::Copied(path_dest, path_source) => { |
|
506 | Action::Copied(path_dest, path_source) => { | |
507 | let dest = path_map.tokenize(path_dest); |
|
507 | let dest = path_map.tokenize(path_dest); | |
508 | let source = path_map.tokenize(path_source); |
|
508 | let source = path_map.tokenize(path_source); | |
509 | let entry; |
|
509 | let entry; | |
510 | if let Some(v) = base_copies.get(&source) { |
|
510 | if let Some(v) = base_copies.get(&source) { | |
511 | entry = match &v.path { |
|
511 | entry = match &v.path { | |
512 | Some(path) => Some((*(path)).to_owned()), |
|
512 | Some(path) => Some((*(path)).to_owned()), | |
513 | None => Some(source.to_owned()), |
|
513 | None => Some(source.to_owned()), | |
514 | } |
|
514 | } | |
515 | } else { |
|
515 | } else { | |
516 | entry = Some(source.to_owned()); |
|
516 | entry = Some(source.to_owned()); | |
517 | } |
|
517 | } | |
518 | // Each new entry is introduced by the children, we |
|
518 | // Each new entry is introduced by the children, we | |
519 | // record this information as we will need it to take |
|
519 | // record this information as we will need it to take | |
520 | // the right decision when merging conflicting copy |
|
520 | // the right decision when merging conflicting copy | |
521 | // information. See merge_copies_dict for details. |
|
521 | // information. See merge_copies_dict for details. | |
522 | match copies.entry(dest) { |
|
522 | match copies.entry(dest) { | |
523 | Entry::Vacant(slot) => { |
|
523 | Entry::Vacant(slot) => { | |
524 | let ttpc = TimeStampedPathCopy { |
|
524 | let ttpc = TimeStampedPathCopy { | |
525 | rev: current_rev, |
|
525 | rev: current_rev, | |
526 | path: entry, |
|
526 | path: entry, | |
527 | }; |
|
527 | }; | |
528 | slot.insert(ttpc); |
|
528 | slot.insert(ttpc); | |
529 | } |
|
529 | } | |
530 | Entry::Occupied(mut slot) => { |
|
530 | Entry::Occupied(mut slot) => { | |
531 | let mut ttpc = slot.get_mut(); |
|
531 | let mut ttpc = slot.get_mut(); | |
532 | oracle.record_overwrite(ttpc.rev, current_rev); |
|
532 | oracle.record_overwrite(ttpc.rev, current_rev); | |
533 | ttpc.rev = current_rev; |
|
533 | ttpc.rev = current_rev; | |
534 | ttpc.path = entry; |
|
534 | ttpc.path = entry; | |
535 | } |
|
535 | } | |
536 | } |
|
536 | } | |
537 | } |
|
537 | } | |
538 | Action::Removed(deleted_path) => { |
|
538 | Action::Removed(deleted_path) => { | |
539 | // We must drop copy information for removed file. |
|
539 | // We must drop copy information for removed file. | |
540 | // |
|
540 | // | |
541 | // We need to explicitly record them as dropped to |
|
541 | // We need to explicitly record them as dropped to | |
542 | // propagate this information when merging two |
|
542 | // propagate this information when merging two | |
543 | // TimeStampedPathCopies object. |
|
543 | // TimeStampedPathCopies object. | |
544 | let deleted = path_map.tokenize(deleted_path); |
|
544 | let deleted = path_map.tokenize(deleted_path); | |
545 | copies.entry(deleted).and_modify(|old| { |
|
545 | copies.entry(deleted).and_modify(|old| { | |
546 | oracle.record_overwrite(old.rev, current_rev); |
|
546 | oracle.record_overwrite(old.rev, current_rev); | |
547 | old.rev = current_rev; |
|
547 | old.rev = current_rev; | |
548 | old.path = None; |
|
548 | old.path = None; | |
549 | }); |
|
549 | }); | |
550 | } |
|
550 | } | |
551 | } |
|
551 | } | |
552 | } |
|
552 | } | |
553 | copies |
|
553 | copies | |
554 | } |
|
554 | } | |
555 |
|
555 | |||
556 | /// merge two copies-mapping together, minor and major |
|
556 | /// merge two copies-mapping together, minor and major | |
557 | /// |
|
557 | /// | |
558 | /// In case of conflict, value from "major" will be picked, unless in some |
|
558 | /// In case of conflict, value from "major" will be picked, unless in some | |
559 | /// cases. See inline documentation for details. |
|
559 | /// cases. See inline documentation for details. | |
560 | fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>( |
|
560 | fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>( | |
561 | path_map: &TwoWayPathMap, |
|
561 | path_map: &TwoWayPathMap, | |
562 | current_merge: Revision, |
|
562 | current_merge: Revision, | |
563 | mut minor: TimeStampedPathCopies, |
|
563 | mut minor: TimeStampedPathCopies, | |
564 | mut major: TimeStampedPathCopies, |
|
564 | mut major: TimeStampedPathCopies, | |
565 | changes: &ChangedFiles, |
|
565 | changes: &ChangedFiles, | |
566 | oracle: &mut AncestorOracle<A>, |
|
566 | oracle: &mut AncestorOracle<A>, | |
567 | ) -> TimeStampedPathCopies { |
|
567 | ) -> TimeStampedPathCopies { | |
568 | // This closure exist as temporary help while multiple developper are |
|
568 | // This closure exist as temporary help while multiple developper are | |
569 | // actively working on this code. Feel free to re-inline it once this |
|
569 | // actively working on this code. Feel free to re-inline it once this | |
570 | // code is more settled. |
|
570 | // code is more settled. | |
571 | let mut cmp_value = |
|
571 | let cmp_value = |oracle: &mut AncestorOracle<A>, | |
572 |
|
|
572 | dest: &PathToken, | |
573 | src_minor: &TimeStampedPathCopy, |
|
573 | src_minor: &TimeStampedPathCopy, | |
574 | src_major: &TimeStampedPathCopy| { |
|
574 | src_major: &TimeStampedPathCopy| { | |
575 |
|
|
575 | compare_value( | |
576 |
|
|
576 | path_map, | |
577 |
|
|
577 | current_merge, | |
578 |
|
|
578 | changes, | |
579 |
|
|
579 | oracle, | |
580 |
|
|
580 | dest, | |
581 |
|
|
581 | src_minor, | |
582 |
|
|
582 | src_major, | |
583 |
|
|
583 | ) | |
584 |
|
|
584 | }; | |
585 | if minor.is_empty() { |
|
585 | if minor.is_empty() { | |
586 | major |
|
586 | major | |
587 | } else if major.is_empty() { |
|
587 | } else if major.is_empty() { | |
588 | minor |
|
588 | minor | |
589 | } else if minor.len() * 2 < major.len() { |
|
589 | } else if minor.len() * 2 < major.len() { | |
590 | // Lets says we are merging two TimeStampedPathCopies instance A and B. |
|
590 | // Lets says we are merging two TimeStampedPathCopies instance A and B. | |
591 | // |
|
591 | // | |
592 | // If A contains N items, the merge result will never contains more |
|
592 | // If A contains N items, the merge result will never contains more | |
593 | // than N values differents than the one in A |
|
593 | // than N values differents than the one in A | |
594 | // |
|
594 | // | |
595 | // If B contains M items, with M > N, the merge result will always |
|
595 | // If B contains M items, with M > N, the merge result will always | |
596 | // result in a minimum of M - N value differents than the on in |
|
596 | // result in a minimum of M - N value differents than the on in | |
597 | // A |
|
597 | // A | |
598 | // |
|
598 | // | |
599 | // As a result, if N < (M-N), we know that simply iterating over A will |
|
599 | // As a result, if N < (M-N), we know that simply iterating over A will | |
600 | // yield less difference than iterating over the difference |
|
600 | // yield less difference than iterating over the difference | |
601 | // between A and B. |
|
601 | // between A and B. | |
602 | // |
|
602 | // | |
603 | // This help performance a lot in case were a tiny |
|
603 | // This help performance a lot in case were a tiny | |
604 | // TimeStampedPathCopies is merged with a much larger one. |
|
604 | // TimeStampedPathCopies is merged with a much larger one. | |
605 | for (dest, src_minor) in minor { |
|
605 | for (dest, src_minor) in minor { | |
606 | let src_major = major.get(&dest); |
|
606 | let src_major = major.get(&dest); | |
607 | match src_major { |
|
607 | match src_major { | |
608 |
None => |
|
608 | None => { | |
|
609 | major.insert(dest, src_minor); | |||
|
610 | } | |||
609 | Some(src_major) => { |
|
611 | Some(src_major) => { | |
610 | match cmp_value(&dest, &src_minor, src_major) { |
|
612 | let (pick, overwrite) = | |
611 | MergePick::Any | MergePick::Major => None, |
|
613 | cmp_value(oracle, &dest, &src_minor, src_major); | |
612 | MergePick::Minor => major.insert(dest, src_minor), |
|
614 | if overwrite { | |
|
615 | oracle.record_overwrite(src_minor.rev, current_merge); | |||
|
616 | oracle.record_overwrite(src_major.rev, current_merge); | |||
|
617 | let path = match pick { | |||
|
618 | MergePick::Major => src_major.path, | |||
|
619 | MergePick::Minor => src_minor.path, | |||
|
620 | MergePick::Any => src_major.path, | |||
|
621 | }; | |||
|
622 | let src = TimeStampedPathCopy { | |||
|
623 | rev: current_merge, | |||
|
624 | path, | |||
|
625 | }; | |||
|
626 | major.insert(dest, src); | |||
|
627 | } else { | |||
|
628 | match pick { | |||
|
629 | MergePick::Any | MergePick::Major => None, | |||
|
630 | MergePick::Minor => major.insert(dest, src_minor), | |||
|
631 | }; | |||
613 | } |
|
632 | } | |
614 | } |
|
633 | } | |
615 | }; |
|
634 | }; | |
616 | } |
|
635 | } | |
617 | major |
|
636 | major | |
618 | } else if major.len() * 2 < minor.len() { |
|
637 | } else if major.len() * 2 < minor.len() { | |
619 | // This use the same rational than the previous block. |
|
638 | // This use the same rational than the previous block. | |
620 | // (Check previous block documentation for details.) |
|
639 | // (Check previous block documentation for details.) | |
621 | for (dest, src_major) in major { |
|
640 | for (dest, src_major) in major { | |
622 | let src_minor = minor.get(&dest); |
|
641 | let src_minor = minor.get(&dest); | |
623 | match src_minor { |
|
642 | match src_minor { | |
624 |
None => |
|
643 | None => { | |
|
644 | minor.insert(dest, src_major); | |||
|
645 | } | |||
625 | Some(src_minor) => { |
|
646 | Some(src_minor) => { | |
626 | match cmp_value(&dest, src_minor, &src_major) { |
|
647 | let (pick, overwrite) = | |
627 | MergePick::Any | MergePick::Minor => None, |
|
648 | cmp_value(oracle, &dest, &src_major, src_minor); | |
628 | MergePick::Major => minor.insert(dest, src_major), |
|
649 | if overwrite { | |
|
650 | oracle.record_overwrite(src_minor.rev, current_merge); | |||
|
651 | oracle.record_overwrite(src_major.rev, current_merge); | |||
|
652 | let path = match pick { | |||
|
653 | MergePick::Major => src_minor.path, | |||
|
654 | MergePick::Minor => src_major.path, | |||
|
655 | MergePick::Any => src_major.path, | |||
|
656 | }; | |||
|
657 | let src = TimeStampedPathCopy { | |||
|
658 | rev: current_merge, | |||
|
659 | path, | |||
|
660 | }; | |||
|
661 | minor.insert(dest, src); | |||
|
662 | } else { | |||
|
663 | match pick { | |||
|
664 | MergePick::Any | MergePick::Major => None, | |||
|
665 | MergePick::Minor => minor.insert(dest, src_major), | |||
|
666 | }; | |||
629 | } |
|
667 | } | |
630 | } |
|
668 | } | |
631 | }; |
|
669 | }; | |
632 | } |
|
670 | } | |
633 | minor |
|
671 | minor | |
634 | } else { |
|
672 | } else { | |
635 | let mut override_minor = Vec::new(); |
|
673 | let mut override_minor = Vec::new(); | |
636 | let mut override_major = Vec::new(); |
|
674 | let mut override_major = Vec::new(); | |
637 |
|
675 | |||
638 | let mut to_major = |k: &PathToken, v: &TimeStampedPathCopy| { |
|
676 | let mut to_major = |k: &PathToken, v: &TimeStampedPathCopy| { | |
639 | override_major.push((k.clone(), v.clone())) |
|
677 | override_major.push((k.clone(), v.clone())) | |
640 | }; |
|
678 | }; | |
641 | let mut to_minor = |k: &PathToken, v: &TimeStampedPathCopy| { |
|
679 | let mut to_minor = |k: &PathToken, v: &TimeStampedPathCopy| { | |
642 | override_minor.push((k.clone(), v.clone())) |
|
680 | override_minor.push((k.clone(), v.clone())) | |
643 | }; |
|
681 | }; | |
644 |
|
682 | |||
645 | // The diff function leverage detection of the identical subpart if |
|
683 | // The diff function leverage detection of the identical subpart if | |
646 | // minor and major has some common ancestors. This make it very |
|
684 | // minor and major has some common ancestors. This make it very | |
647 | // fast is most case. |
|
685 | // fast is most case. | |
648 | // |
|
686 | // | |
649 | // In case where the two map are vastly different in size, the current |
|
687 | // In case where the two map are vastly different in size, the current | |
650 | // approach is still slowish because the iteration will iterate over |
|
688 | // approach is still slowish because the iteration will iterate over | |
651 | // all the "exclusive" content of the larger on. This situation can be |
|
689 | // all the "exclusive" content of the larger on. This situation can be | |
652 | // frequent when the subgraph of revision we are processing has a lot |
|
690 | // frequent when the subgraph of revision we are processing has a lot | |
653 | // of roots. Each roots adding they own fully new map to the mix (and |
|
691 | // of roots. Each roots adding they own fully new map to the mix (and | |
654 | // likely a small map, if the path from the root to the "main path" is |
|
692 | // likely a small map, if the path from the root to the "main path" is | |
655 | // small. |
|
693 | // small. | |
656 | // |
|
694 | // | |
657 | // We could do better by detecting such situation and processing them |
|
695 | // We could do better by detecting such situation and processing them | |
658 | // differently. |
|
696 | // differently. | |
659 | for d in minor.diff(&major) { |
|
697 | for d in minor.diff(&major) { | |
660 | match d { |
|
698 | match d { | |
661 | DiffItem::Add(k, v) => to_minor(k, v), |
|
699 | DiffItem::Add(k, v) => to_minor(k, v), | |
662 | DiffItem::Remove(k, v) => to_major(k, v), |
|
700 | DiffItem::Remove(k, v) => to_major(k, v), | |
663 | DiffItem::Update { old, new } => { |
|
701 | DiffItem::Update { old, new } => { | |
664 | let (dest, src_major) = new; |
|
702 | let (dest, src_major) = new; | |
665 | let (_, src_minor) = old; |
|
703 | let (_, src_minor) = old; | |
666 | match cmp_value(dest, src_minor, src_major) { |
|
704 | let (pick, overwrite) = | |
667 |
|
|
705 | cmp_value(oracle, dest, src_minor, src_major); | |
668 | MergePick::Minor => to_major(dest, src_minor), |
|
706 | if overwrite { | |
669 | // If the two entry are identical, no need to do |
|
707 | oracle.record_overwrite(src_minor.rev, current_merge); | |
670 | // anything (but diff should not have yield them) |
|
708 | oracle.record_overwrite(src_major.rev, current_merge); | |
671 | MergePick::Any => unreachable!(), |
|
709 | let path = match pick { | |
|
710 | MergePick::Major => src_major.path, | |||
|
711 | MergePick::Minor => src_minor.path, | |||
|
712 | // If the two entry are identical, no need to do | |||
|
713 | // anything (but diff should not have yield them) | |||
|
714 | MergePick::Any => src_major.path, | |||
|
715 | }; | |||
|
716 | let src = TimeStampedPathCopy { | |||
|
717 | rev: current_merge, | |||
|
718 | path, | |||
|
719 | }; | |||
|
720 | to_minor(dest, &src); | |||
|
721 | to_major(dest, &src); | |||
|
722 | } else { | |||
|
723 | match pick { | |||
|
724 | MergePick::Major => to_minor(dest, src_major), | |||
|
725 | MergePick::Minor => to_major(dest, src_minor), | |||
|
726 | // If the two entry are identical, no need to do | |||
|
727 | // anything (but diff should not have yield them) | |||
|
728 | MergePick::Any => unreachable!(), | |||
|
729 | } | |||
672 | } |
|
730 | } | |
673 | } |
|
731 | } | |
674 | }; |
|
732 | }; | |
675 | } |
|
733 | } | |
676 |
|
734 | |||
677 | let updates; |
|
735 | let updates; | |
678 | let mut result; |
|
736 | let mut result; | |
679 | if override_major.is_empty() { |
|
737 | if override_major.is_empty() { | |
680 | result = major |
|
738 | result = major | |
681 | } else if override_minor.is_empty() { |
|
739 | } else if override_minor.is_empty() { | |
682 | result = minor |
|
740 | result = minor | |
683 | } else { |
|
741 | } else { | |
684 | if override_minor.len() < override_major.len() { |
|
742 | if override_minor.len() < override_major.len() { | |
685 | updates = override_minor; |
|
743 | updates = override_minor; | |
686 | result = minor; |
|
744 | result = minor; | |
687 | } else { |
|
745 | } else { | |
688 | updates = override_major; |
|
746 | updates = override_major; | |
689 | result = major; |
|
747 | result = major; | |
690 | } |
|
748 | } | |
691 | for (k, v) in updates { |
|
749 | for (k, v) in updates { | |
692 | result.insert(k, v); |
|
750 | result.insert(k, v); | |
693 | } |
|
751 | } | |
694 | } |
|
752 | } | |
695 | result |
|
753 | result | |
696 | } |
|
754 | } | |
697 | } |
|
755 | } | |
698 |
|
756 | |||
699 | /// represent the side that should prevail when merging two |
|
757 | /// represent the side that should prevail when merging two | |
700 | /// TimeStampedPathCopies |
|
758 | /// TimeStampedPathCopies | |
701 | enum MergePick { |
|
759 | enum MergePick { | |
702 | /// The "major" (p1) side prevails |
|
760 | /// The "major" (p1) side prevails | |
703 | Major, |
|
761 | Major, | |
704 | /// The "minor" (p2) side prevails |
|
762 | /// The "minor" (p2) side prevails | |
705 | Minor, |
|
763 | Minor, | |
706 | /// Any side could be used (because they are the same) |
|
764 | /// Any side could be used (because they are the same) | |
707 | Any, |
|
765 | Any, | |
708 | } |
|
766 | } | |
709 |
|
767 | |||
710 | /// decide which side prevails in case of conflicting values |
|
768 | /// decide which side prevails in case of conflicting values | |
711 | #[allow(clippy::if_same_then_else)] |
|
769 | #[allow(clippy::if_same_then_else)] | |
712 | fn compare_value<A: Fn(Revision, Revision) -> bool>( |
|
770 | fn compare_value<A: Fn(Revision, Revision) -> bool>( | |
713 | path_map: &TwoWayPathMap, |
|
771 | path_map: &TwoWayPathMap, | |
714 | current_merge: Revision, |
|
772 | current_merge: Revision, | |
715 | changes: &ChangedFiles, |
|
773 | changes: &ChangedFiles, | |
716 | oracle: &mut AncestorOracle<A>, |
|
774 | oracle: &mut AncestorOracle<A>, | |
717 | dest: &PathToken, |
|
775 | dest: &PathToken, | |
718 | src_minor: &TimeStampedPathCopy, |
|
776 | src_minor: &TimeStampedPathCopy, | |
719 | src_major: &TimeStampedPathCopy, |
|
777 | src_major: &TimeStampedPathCopy, | |
720 | ) -> MergePick { |
|
778 | ) -> (MergePick, bool) { | |
721 | if src_major.rev == current_merge { |
|
779 | if src_major.rev == current_merge { | |
722 | if src_minor.rev == current_merge { |
|
780 | if src_minor.rev == current_merge { | |
723 | if src_major.path.is_none() { |
|
781 | if src_major.path.is_none() { | |
724 | // We cannot get different copy information for both p1 and p2 |
|
782 | // We cannot get different copy information for both p1 and p2 | |
725 | // from the same revision. Unless this was a |
|
783 | // from the same revision. Unless this was a | |
726 | // deletion |
|
784 | // deletion | |
727 | MergePick::Any |
|
785 | (MergePick::Any, false) | |
728 | } else { |
|
786 | } else { | |
729 | unreachable!(); |
|
787 | unreachable!(); | |
730 | } |
|
788 | } | |
731 | } else { |
|
789 | } else { | |
732 | // The last value comes the current merge, this value -will- win |
|
790 | // The last value comes the current merge, this value -will- win | |
733 | // eventually. |
|
791 | // eventually. | |
734 | oracle.record_overwrite(src_minor.rev, src_major.rev); |
|
792 | (MergePick::Major, true) | |
735 | MergePick::Major |
|
|||
736 | } |
|
793 | } | |
737 | } else if src_minor.rev == current_merge { |
|
794 | } else if src_minor.rev == current_merge { | |
738 | // The last value comes the current merge, this value -will- win |
|
795 | // The last value comes the current merge, this value -will- win | |
739 | // eventually. |
|
796 | // eventually. | |
740 | oracle.record_overwrite(src_major.rev, src_minor.rev); |
|
797 | (MergePick::Minor, true) | |
741 | MergePick::Minor |
|
|||
742 | } else if src_major.path == src_minor.path { |
|
798 | } else if src_major.path == src_minor.path { | |
743 | // we have the same value, but from other source; |
|
799 | // we have the same value, but from other source; | |
744 | if src_major.rev == src_minor.rev { |
|
800 | if src_major.rev == src_minor.rev { | |
745 | // If the two entry are identical, they are both valid |
|
801 | // If the two entry are identical, they are both valid | |
746 | MergePick::Any |
|
802 | (MergePick::Any, false) | |
747 | } else if oracle.is_overwrite(src_major.rev, src_minor.rev) { |
|
803 | } else if oracle.is_overwrite(src_major.rev, src_minor.rev) { | |
748 | MergePick::Minor |
|
804 | (MergePick::Minor, false) | |
749 | } else if oracle.is_overwrite(src_minor.rev, src_major.rev) { |
|
805 | } else if oracle.is_overwrite(src_minor.rev, src_major.rev) { | |
750 | MergePick::Major |
|
806 | (MergePick::Major, false) | |
751 | } else { |
|
807 | } else { | |
752 |
MergePick:: |
|
808 | (MergePick::Any, true) | |
753 | } |
|
809 | } | |
754 | } else if src_major.rev == src_minor.rev { |
|
810 | } else if src_major.rev == src_minor.rev { | |
755 | // We cannot get copy information for both p1 and p2 in the |
|
811 | // We cannot get copy information for both p1 and p2 in the | |
756 | // same rev. So this is the same value. |
|
812 | // same rev. So this is the same value. | |
757 | unreachable!( |
|
813 | unreachable!( | |
758 | "conflicting information from p1 and p2 in the same revision" |
|
814 | "conflicting information from p1 and p2 in the same revision" | |
759 | ); |
|
815 | ); | |
760 | } else { |
|
816 | } else { | |
761 | let dest_path = path_map.untokenize(*dest); |
|
817 | let dest_path = path_map.untokenize(*dest); | |
762 | let action = changes.get_merge_case(dest_path); |
|
818 | let action = changes.get_merge_case(dest_path); | |
763 | if src_minor.path.is_some() |
|
819 | if src_minor.path.is_some() | |
764 | && src_major.path.is_none() |
|
820 | && src_major.path.is_none() | |
765 | && action == MergeCase::Salvaged |
|
821 | && action == MergeCase::Salvaged | |
766 | { |
|
822 | { | |
767 | // If the file is "deleted" in the major side but was |
|
823 | // If the file is "deleted" in the major side but was | |
768 | // salvaged by the merge, we keep the minor side alive |
|
824 | // salvaged by the merge, we keep the minor side alive | |
769 | MergePick::Minor |
|
825 | (MergePick::Minor, true) | |
770 | } else if src_major.path.is_some() |
|
826 | } else if src_major.path.is_some() | |
771 | && src_minor.path.is_none() |
|
827 | && src_minor.path.is_none() | |
772 | && action == MergeCase::Salvaged |
|
828 | && action == MergeCase::Salvaged | |
773 | { |
|
829 | { | |
774 | // If the file is "deleted" in the minor side but was |
|
830 | // If the file is "deleted" in the minor side but was | |
775 | // salvaged by the merge, unconditionnaly preserve the |
|
831 | // salvaged by the merge, unconditionnaly preserve the | |
776 | // major side. |
|
832 | // major side. | |
777 | MergePick::Major |
|
833 | (MergePick::Major, true) | |
778 | } else if oracle.is_overwrite(src_minor.rev, src_major.rev) { |
|
834 | } else if oracle.is_overwrite(src_minor.rev, src_major.rev) { | |
779 | // The information from the minor version are strictly older than |
|
835 | // The information from the minor version are strictly older than | |
780 | // the major version |
|
836 | // the major version | |
781 | if action == MergeCase::Merged { |
|
837 | if action == MergeCase::Merged { | |
782 | // If the file was actively merged, its means some non-copy |
|
838 | // If the file was actively merged, its means some non-copy | |
783 | // activity happened on the other branch. It |
|
839 | // activity happened on the other branch. It | |
784 | // mean the older copy information are still relevant. |
|
840 | // mean the older copy information are still relevant. | |
785 | // |
|
841 | // | |
786 | // The major side wins such conflict. |
|
842 | // The major side wins such conflict. | |
787 | MergePick::Major |
|
843 | (MergePick::Major, true) | |
788 | } else { |
|
844 | } else { | |
789 | // No activity on the minor branch, pick the newer one. |
|
845 | // No activity on the minor branch, pick the newer one. | |
790 | MergePick::Major |
|
846 | (MergePick::Major, false) | |
791 | } |
|
847 | } | |
792 | } else if oracle.is_overwrite(src_major.rev, src_minor.rev) { |
|
848 | } else if oracle.is_overwrite(src_major.rev, src_minor.rev) { | |
793 | if action == MergeCase::Merged { |
|
849 | if action == MergeCase::Merged { | |
794 | // If the file was actively merged, its means some non-copy |
|
850 | // If the file was actively merged, its means some non-copy | |
795 | // activity happened on the other branch. It |
|
851 | // activity happened on the other branch. It | |
796 | // mean the older copy information are still relevant. |
|
852 | // mean the older copy information are still relevant. | |
797 | // |
|
853 | // | |
798 | // The major side wins such conflict. |
|
854 | // The major side wins such conflict. | |
799 | MergePick::Major |
|
855 | (MergePick::Major, true) | |
800 | } else { |
|
856 | } else { | |
801 | // No activity on the minor branch, pick the newer one. |
|
857 | // No activity on the minor branch, pick the newer one. | |
802 | MergePick::Minor |
|
858 | (MergePick::Minor, false) | |
803 | } |
|
859 | } | |
804 | } else if src_minor.path.is_none() { |
|
860 | } else if src_minor.path.is_none() { | |
805 | // the minor side has no relevant information, pick the alive one |
|
861 | // the minor side has no relevant information, pick the alive one | |
806 | MergePick::Major |
|
862 | (MergePick::Major, true) | |
807 | } else if src_major.path.is_none() { |
|
863 | } else if src_major.path.is_none() { | |
808 | // the major side has no relevant information, pick the alive one |
|
864 | // the major side has no relevant information, pick the alive one | |
809 | MergePick::Minor |
|
865 | (MergePick::Minor, true) | |
810 | } else { |
|
866 | } else { | |
811 | // by default the major side wins |
|
867 | // by default the major side wins | |
812 | MergePick::Major |
|
868 | (MergePick::Major, true) | |
813 | } |
|
869 | } | |
814 | } |
|
870 | } | |
815 | } |
|
871 | } |
@@ -1,3441 +1,3406 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 >> ./no-linkrev |
|
17 | $ cat << EOF >> ./no-linkrev | |
18 | > #!$PYTHON |
|
18 | > #!$PYTHON | |
19 | > # filter out linkrev part of the debugindex command |
|
19 | > # filter out linkrev part of the debugindex command | |
20 | > import sys |
|
20 | > import sys | |
21 | > for line in sys.stdin: |
|
21 | > for line in sys.stdin: | |
22 | > if " linkrev " in line: |
|
22 | > if " linkrev " in line: | |
23 | > print(line.rstrip()) |
|
23 | > print(line.rstrip()) | |
24 | > else: |
|
24 | > else: | |
25 | > l = "%s *%s" % (line[:6], line[14:].rstrip()) |
|
25 | > l = "%s *%s" % (line[:6], line[14:].rstrip()) | |
26 | > print(l) |
|
26 | > print(l) | |
27 | > EOF |
|
27 | > EOF | |
28 | $ chmod +x no-linkrev |
|
28 | $ chmod +x no-linkrev | |
29 |
|
29 | |||
30 | $ cat << EOF >> $HGRCPATH |
|
30 | $ cat << EOF >> $HGRCPATH | |
31 | > [diff] |
|
31 | > [diff] | |
32 | > git=yes |
|
32 | > git=yes | |
33 | > [command-templates] |
|
33 | > [command-templates] | |
34 | > log={desc}\n |
|
34 | > log={desc}\n | |
35 | > EOF |
|
35 | > EOF | |
36 |
|
36 | |||
37 | #if compatibility |
|
37 | #if compatibility | |
38 | $ cat >> $HGRCPATH << EOF |
|
38 | $ cat >> $HGRCPATH << EOF | |
39 | > [experimental] |
|
39 | > [experimental] | |
40 | > copies.read-from = compatibility |
|
40 | > copies.read-from = compatibility | |
41 | > EOF |
|
41 | > EOF | |
42 | #endif |
|
42 | #endif | |
43 |
|
43 | |||
44 | #if changeset |
|
44 | #if changeset | |
45 | $ cat >> $HGRCPATH << EOF |
|
45 | $ cat >> $HGRCPATH << EOF | |
46 | > [experimental] |
|
46 | > [experimental] | |
47 | > copies.read-from = changeset-only |
|
47 | > copies.read-from = changeset-only | |
48 | > copies.write-to = changeset-only |
|
48 | > copies.write-to = changeset-only | |
49 | > EOF |
|
49 | > EOF | |
50 | #endif |
|
50 | #endif | |
51 |
|
51 | |||
52 | #if sidedata |
|
52 | #if sidedata | |
53 | $ cat >> $HGRCPATH << EOF |
|
53 | $ cat >> $HGRCPATH << EOF | |
54 | > [format] |
|
54 | > [format] | |
55 | > exp-use-side-data = yes |
|
55 | > exp-use-side-data = yes | |
56 | > exp-use-copies-side-data-changeset = yes |
|
56 | > exp-use-copies-side-data-changeset = yes | |
57 | > EOF |
|
57 | > EOF | |
58 | #endif |
|
58 | #endif | |
59 |
|
59 | |||
60 |
|
60 | |||
61 | $ cat > same-content.txt << EOF |
|
61 | $ cat > same-content.txt << EOF | |
62 | > Here is some content that will be the same accros multiple file. |
|
62 | > Here is some content that will be the same accros multiple file. | |
63 | > |
|
63 | > | |
64 | > This is done on purpose so that we end up in some merge situation, were the |
|
64 | > This is done on purpose so that we end up in some merge situation, were the | |
65 | > resulting content is the same as in the parent(s), but a new filenodes still |
|
65 | > resulting content is the same as in the parent(s), but a new filenodes still | |
66 | > need to be created to record some file history information (especially |
|
66 | > need to be created to record some file history information (especially | |
67 | > about copies). |
|
67 | > about copies). | |
68 | > EOF |
|
68 | > EOF | |
69 |
|
69 | |||
70 | $ hg init repo-chain |
|
70 | $ hg init repo-chain | |
71 | $ cd repo-chain |
|
71 | $ cd repo-chain | |
72 |
|
72 | |||
73 | Add some linear rename initialy |
|
73 | Add some linear rename initialy | |
74 |
|
74 | |||
75 | $ cp ../same-content.txt a |
|
75 | $ cp ../same-content.txt a | |
76 | $ cp ../same-content.txt b |
|
76 | $ cp ../same-content.txt b | |
77 | $ cp ../same-content.txt h |
|
77 | $ cp ../same-content.txt h | |
78 | $ echo "original content for P" > p |
|
78 | $ echo "original content for P" > p | |
79 | $ echo "original content for Q" > q |
|
79 | $ echo "original content for Q" > q | |
80 | $ echo "original content for R" > r |
|
80 | $ echo "original content for R" > r | |
81 | $ hg ci -Am 'i-0 initial commit: a b h' |
|
81 | $ hg ci -Am 'i-0 initial commit: a b h' | |
82 | adding a |
|
82 | adding a | |
83 | adding b |
|
83 | adding b | |
84 | adding h |
|
84 | adding h | |
85 | adding p |
|
85 | adding p | |
86 | adding q |
|
86 | adding q | |
87 | adding r |
|
87 | adding r | |
88 | $ hg mv a c |
|
88 | $ hg mv a c | |
89 | $ hg mv p s |
|
89 | $ hg mv p s | |
90 | $ hg ci -Am 'i-1: a -move-> c, p -move-> s' |
|
90 | $ hg ci -Am 'i-1: a -move-> c, p -move-> s' | |
91 | $ hg mv c d |
|
91 | $ hg mv c d | |
92 | $ hg mv s t |
|
92 | $ hg mv s t | |
93 | $ hg ci -Am 'i-2: c -move-> d, s -move-> t' |
|
93 | $ hg ci -Am 'i-2: c -move-> d, s -move-> t' | |
94 | $ hg log -G |
|
94 | $ hg log -G | |
95 | @ i-2: c -move-> d, s -move-> t |
|
95 | @ i-2: c -move-> d, s -move-> t | |
96 | | |
|
96 | | | |
97 | o i-1: a -move-> c, p -move-> s |
|
97 | o i-1: a -move-> c, p -move-> s | |
98 | | |
|
98 | | | |
99 | o i-0 initial commit: a b h |
|
99 | o i-0 initial commit: a b h | |
100 |
|
100 | |||
101 |
|
101 | |||
102 | And having another branch with renames on the other side |
|
102 | And having another branch with renames on the other side | |
103 |
|
103 | |||
104 | $ hg mv d e |
|
104 | $ hg mv d e | |
105 | $ hg ci -Am 'a-1: d -move-> e' |
|
105 | $ hg ci -Am 'a-1: d -move-> e' | |
106 | $ hg mv e f |
|
106 | $ hg mv e f | |
107 | $ hg ci -Am 'a-2: e -move-> f' |
|
107 | $ hg ci -Am 'a-2: e -move-> f' | |
108 | $ hg log -G --rev '::.' |
|
108 | $ hg log -G --rev '::.' | |
109 | @ a-2: e -move-> f |
|
109 | @ a-2: e -move-> f | |
110 | | |
|
110 | | | |
111 | o a-1: d -move-> e |
|
111 | o a-1: d -move-> e | |
112 | | |
|
112 | | | |
113 | o i-2: c -move-> d, s -move-> t |
|
113 | o i-2: c -move-> d, s -move-> t | |
114 | | |
|
114 | | | |
115 | o i-1: a -move-> c, p -move-> s |
|
115 | o i-1: a -move-> c, p -move-> s | |
116 | | |
|
116 | | | |
117 | o i-0 initial commit: a b h |
|
117 | o i-0 initial commit: a b h | |
118 |
|
118 | |||
119 |
|
119 | |||
120 | Have a branching with nothing on one side |
|
120 | Have a branching with nothing on one side | |
121 |
|
121 | |||
122 | $ hg up 'desc("i-2")' |
|
122 | $ hg up 'desc("i-2")' | |
123 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
123 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
124 | $ echo foo > b |
|
124 | $ echo foo > b | |
125 | $ hg ci -m 'b-1: b update' |
|
125 | $ hg ci -m 'b-1: b update' | |
126 | created new head |
|
126 | created new head | |
127 | $ hg log -G --rev '::.' |
|
127 | $ hg log -G --rev '::.' | |
128 | @ b-1: b update |
|
128 | @ b-1: b update | |
129 | | |
|
129 | | | |
130 | o i-2: c -move-> d, s -move-> t |
|
130 | o i-2: c -move-> d, s -move-> t | |
131 | | |
|
131 | | | |
132 | o i-1: a -move-> c, p -move-> s |
|
132 | o i-1: a -move-> c, p -move-> s | |
133 | | |
|
133 | | | |
134 | o i-0 initial commit: a b h |
|
134 | o i-0 initial commit: a b h | |
135 |
|
135 | |||
136 |
|
136 | |||
137 | Create a branch that delete a file previous renamed |
|
137 | Create a branch that delete a file previous renamed | |
138 |
|
138 | |||
139 | $ hg up 'desc("i-2")' |
|
139 | $ hg up 'desc("i-2")' | |
140 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
140 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
141 | $ hg rm d |
|
141 | $ hg rm d | |
142 | $ hg ci -m 'c-1 delete d' |
|
142 | $ hg ci -m 'c-1 delete d' | |
143 | created new head |
|
143 | created new head | |
144 | $ hg log -G --rev '::.' |
|
144 | $ hg log -G --rev '::.' | |
145 | @ c-1 delete d |
|
145 | @ c-1 delete d | |
146 | | |
|
146 | | | |
147 | o i-2: c -move-> d, s -move-> t |
|
147 | o i-2: c -move-> d, s -move-> t | |
148 | | |
|
148 | | | |
149 | o i-1: a -move-> c, p -move-> s |
|
149 | o i-1: a -move-> c, p -move-> s | |
150 | | |
|
150 | | | |
151 | o i-0 initial commit: a b h |
|
151 | o i-0 initial commit: a b h | |
152 |
|
152 | |||
153 |
|
153 | |||
154 | Create a branch that delete a file previous renamed and recreate it |
|
154 | Create a branch that delete a file previous renamed and recreate it | |
155 |
|
155 | |||
156 | $ hg up 'desc("i-2")' |
|
156 | $ hg up 'desc("i-2")' | |
157 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
157 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
158 | $ hg rm d |
|
158 | $ hg rm d | |
159 | $ hg ci -m 'd-1 delete d' |
|
159 | $ hg ci -m 'd-1 delete d' | |
160 | created new head |
|
160 | created new head | |
161 | $ echo bar > d |
|
161 | $ echo bar > d | |
162 | $ hg add d |
|
162 | $ hg add d | |
163 | $ hg ci -m 'd-2 re-add d' |
|
163 | $ hg ci -m 'd-2 re-add d' | |
164 | $ hg log -G --rev '::.' |
|
164 | $ hg log -G --rev '::.' | |
165 | @ d-2 re-add d |
|
165 | @ d-2 re-add d | |
166 | | |
|
166 | | | |
167 | o d-1 delete d |
|
167 | o d-1 delete d | |
168 | | |
|
168 | | | |
169 | o i-2: c -move-> d, s -move-> t |
|
169 | o i-2: c -move-> d, s -move-> t | |
170 | | |
|
170 | | | |
171 | o i-1: a -move-> c, p -move-> s |
|
171 | o i-1: a -move-> c, p -move-> s | |
172 | | |
|
172 | | | |
173 | o i-0 initial commit: a b h |
|
173 | o i-0 initial commit: a b h | |
174 |
|
174 | |||
175 |
|
175 | |||
176 | Having another branch renaming a different file to the same filename as another |
|
176 | Having another branch renaming a different file to the same filename as another | |
177 |
|
177 | |||
178 | $ hg up 'desc("i-2")' |
|
178 | $ hg up 'desc("i-2")' | |
179 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
179 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
180 | $ hg mv b g |
|
180 | $ hg mv b g | |
181 | $ hg ci -m 'e-1 b -move-> g' |
|
181 | $ hg ci -m 'e-1 b -move-> g' | |
182 | created new head |
|
182 | created new head | |
183 | $ hg mv g f |
|
183 | $ hg mv g f | |
184 | $ hg ci -m 'e-2 g -move-> f' |
|
184 | $ hg ci -m 'e-2 g -move-> f' | |
185 | $ hg log -G --rev '::.' |
|
185 | $ hg log -G --rev '::.' | |
186 | @ e-2 g -move-> f |
|
186 | @ e-2 g -move-> f | |
187 | | |
|
187 | | | |
188 | o e-1 b -move-> g |
|
188 | o e-1 b -move-> g | |
189 | | |
|
189 | | | |
190 | o i-2: c -move-> d, s -move-> t |
|
190 | o i-2: c -move-> d, s -move-> t | |
191 | | |
|
191 | | | |
192 | o i-1: a -move-> c, p -move-> s |
|
192 | o i-1: a -move-> c, p -move-> s | |
193 | | |
|
193 | | | |
194 | o i-0 initial commit: a b h |
|
194 | o i-0 initial commit: a b h | |
195 |
|
195 | |||
196 | $ hg up -q null |
|
196 | $ hg up -q null | |
197 |
|
197 | |||
198 | Having a branch similar to the 'a' one, but moving the 'p' file around. |
|
198 | Having a branch similar to the 'a' one, but moving the 'p' file around. | |
199 |
|
199 | |||
200 | $ hg up 'desc("i-2")' |
|
200 | $ hg up 'desc("i-2")' | |
201 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
201 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
202 | $ hg mv t u |
|
202 | $ hg mv t u | |
203 | $ hg ci -Am 'p-1: t -move-> u' |
|
203 | $ hg ci -Am 'p-1: t -move-> u' | |
204 | created new head |
|
204 | created new head | |
205 | $ hg mv u v |
|
205 | $ hg mv u v | |
206 | $ hg ci -Am 'p-2: u -move-> v' |
|
206 | $ hg ci -Am 'p-2: u -move-> v' | |
207 | $ hg log -G --rev '::.' |
|
207 | $ hg log -G --rev '::.' | |
208 | @ p-2: u -move-> v |
|
208 | @ p-2: u -move-> v | |
209 | | |
|
209 | | | |
210 | o p-1: t -move-> u |
|
210 | o p-1: t -move-> u | |
211 | | |
|
211 | | | |
212 | o i-2: c -move-> d, s -move-> t |
|
212 | o i-2: c -move-> d, s -move-> t | |
213 | | |
|
213 | | | |
214 | o i-1: a -move-> c, p -move-> s |
|
214 | o i-1: a -move-> c, p -move-> s | |
215 | | |
|
215 | | | |
216 | o i-0 initial commit: a b h |
|
216 | o i-0 initial commit: a b h | |
217 |
|
217 | |||
218 | $ hg up -q null |
|
218 | $ hg up -q null | |
219 |
|
219 | |||
220 | Having another branch renaming a different file to the same filename as another |
|
220 | Having another branch renaming a different file to the same filename as another | |
221 |
|
221 | |||
222 | $ hg up 'desc("i-2")' |
|
222 | $ hg up 'desc("i-2")' | |
223 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
223 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
224 | $ hg mv r w |
|
224 | $ hg mv r w | |
225 | $ hg ci -m 'q-1 r -move-> w' |
|
225 | $ hg ci -m 'q-1 r -move-> w' | |
226 | created new head |
|
226 | created new head | |
227 | $ hg mv w v |
|
227 | $ hg mv w v | |
228 | $ hg ci -m 'q-2 w -move-> v' |
|
228 | $ hg ci -m 'q-2 w -move-> v' | |
229 | $ hg log -G --rev '::.' |
|
229 | $ hg log -G --rev '::.' | |
230 | @ q-2 w -move-> v |
|
230 | @ q-2 w -move-> v | |
231 | | |
|
231 | | | |
232 | o q-1 r -move-> w |
|
232 | o q-1 r -move-> w | |
233 | | |
|
233 | | | |
234 | o i-2: c -move-> d, s -move-> t |
|
234 | o i-2: c -move-> d, s -move-> t | |
235 | | |
|
235 | | | |
236 | o i-1: a -move-> c, p -move-> s |
|
236 | o i-1: a -move-> c, p -move-> s | |
237 | | |
|
237 | | | |
238 | o i-0 initial commit: a b h |
|
238 | o i-0 initial commit: a b h | |
239 |
|
239 | |||
240 | $ hg up -q null |
|
240 | $ hg up -q null | |
241 |
|
241 | |||
242 | Setup all merge |
|
242 | Setup all merge | |
243 | =============== |
|
243 | =============== | |
244 |
|
244 | |||
245 | This is done beforehand to validate that the upgrade process creates valid copy |
|
245 | This is done beforehand to validate that the upgrade process creates valid copy | |
246 | information. |
|
246 | information. | |
247 |
|
247 | |||
248 | merging with unrelated change does not interfere with the renames |
|
248 | merging with unrelated change does not interfere with the renames | |
249 | --------------------------------------------------------------- |
|
249 | --------------------------------------------------------------- | |
250 |
|
250 | |||
251 | - rename on one side |
|
251 | - rename on one side | |
252 | - unrelated change on the other side |
|
252 | - unrelated change on the other side | |
253 |
|
253 | |||
254 | $ case_desc="simple merge - A side: multiple renames, B side: unrelated update" |
|
254 | $ case_desc="simple merge - A side: multiple renames, B side: unrelated update" | |
255 |
|
255 | |||
256 | $ hg up 'desc("b-1")' |
|
256 | $ hg up 'desc("b-1")' | |
257 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
257 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
258 | $ hg merge 'desc("a-2")' |
|
258 | $ hg merge 'desc("a-2")' | |
259 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
259 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
260 | (branch merge, don't forget to commit) |
|
260 | (branch merge, don't forget to commit) | |
261 | $ hg ci -m "mBAm-0 $case_desc - one way" |
|
261 | $ hg ci -m "mBAm-0 $case_desc - one way" | |
262 | $ hg up 'desc("a-2")' |
|
262 | $ hg up 'desc("a-2")' | |
263 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
263 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
264 | $ hg merge 'desc("b-1")' |
|
264 | $ hg merge 'desc("b-1")' | |
265 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
265 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
266 | (branch merge, don't forget to commit) |
|
266 | (branch merge, don't forget to commit) | |
267 | $ hg ci -m "mABm-0 $case_desc - the other way" |
|
267 | $ hg ci -m "mABm-0 $case_desc - the other way" | |
268 | created new head |
|
268 | created new head | |
269 | $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))' |
|
269 | $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))' | |
270 | @ mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way |
|
270 | @ mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way | |
271 | |\ |
|
271 | |\ | |
272 | +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way |
|
272 | +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way | |
273 | | |/ |
|
273 | | |/ | |
274 | | o b-1: b update |
|
274 | | o b-1: b update | |
275 | | | |
|
275 | | | | |
276 | o | a-2: e -move-> f |
|
276 | o | a-2: e -move-> f | |
277 | | | |
|
277 | | | | |
278 | o | a-1: d -move-> e |
|
278 | o | a-1: d -move-> e | |
279 | |/ |
|
279 | |/ | |
280 | o i-2: c -move-> d, s -move-> t |
|
280 | o i-2: c -move-> d, s -move-> t | |
281 | | |
|
281 | | | |
282 | o i-1: a -move-> c, p -move-> s |
|
282 | o i-1: a -move-> c, p -move-> s | |
283 | | |
|
283 | | | |
284 | o i-0 initial commit: a b h |
|
284 | o i-0 initial commit: a b h | |
285 |
|
285 | |||
286 |
|
286 | |||
287 |
|
287 | |||
288 | merging with the side having a delete |
|
288 | merging with the side having a delete | |
289 | ------------------------------------- |
|
289 | ------------------------------------- | |
290 |
|
290 | |||
291 | case summary: |
|
291 | case summary: | |
292 | - one with change to an unrelated file |
|
292 | - one with change to an unrelated file | |
293 | - one deleting the change |
|
293 | - one deleting the change | |
294 | and recreate an unrelated file after the merge |
|
294 | and recreate an unrelated file after the merge | |
295 |
|
295 | |||
296 | $ case_desc="simple merge - C side: delete a file with copies history , B side: unrelated update" |
|
296 | $ case_desc="simple merge - C side: delete a file with copies history , B side: unrelated update" | |
297 |
|
297 | |||
298 | $ hg up 'desc("b-1")' |
|
298 | $ hg up 'desc("b-1")' | |
299 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
299 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
300 | $ hg merge 'desc("c-1")' |
|
300 | $ hg merge 'desc("c-1")' | |
301 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
301 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
302 | (branch merge, don't forget to commit) |
|
302 | (branch merge, don't forget to commit) | |
303 | $ hg ci -m "mBCm-0 $case_desc - one way" |
|
303 | $ hg ci -m "mBCm-0 $case_desc - one way" | |
304 | $ echo bar > d |
|
304 | $ echo bar > d | |
305 | $ hg add d |
|
305 | $ hg add d | |
306 | $ hg ci -m 'mBCm-1 re-add d' |
|
306 | $ hg ci -m 'mBCm-1 re-add d' | |
307 | $ hg up 'desc("c-1")' |
|
307 | $ hg up 'desc("c-1")' | |
308 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
308 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
309 | $ hg merge 'desc("b-1")' |
|
309 | $ hg merge 'desc("b-1")' | |
310 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
310 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
311 | (branch merge, don't forget to commit) |
|
311 | (branch merge, don't forget to commit) | |
312 | $ hg ci -m "mCBm-0 $case_desc - the other way" |
|
312 | $ hg ci -m "mCBm-0 $case_desc - the other way" | |
313 | created new head |
|
313 | created new head | |
314 | $ echo bar > d |
|
314 | $ echo bar > d | |
315 | $ hg add d |
|
315 | $ hg add d | |
316 | $ hg ci -m 'mCBm-1 re-add d' |
|
316 | $ hg ci -m 'mCBm-1 re-add d' | |
317 | $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))' |
|
317 | $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))' | |
318 | @ mCBm-1 re-add d |
|
318 | @ mCBm-1 re-add d | |
319 | | |
|
319 | | | |
320 | o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way |
|
320 | o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way | |
321 | |\ |
|
321 | |\ | |
322 | | | o mBCm-1 re-add d |
|
322 | | | o mBCm-1 re-add d | |
323 | | | | |
|
323 | | | | | |
324 | +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way |
|
324 | +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way | |
325 | | |/ |
|
325 | | |/ | |
326 | | o c-1 delete d |
|
326 | | o c-1 delete d | |
327 | | | |
|
327 | | | | |
328 | o | b-1: b update |
|
328 | o | b-1: b update | |
329 | |/ |
|
329 | |/ | |
330 | o i-2: c -move-> d, s -move-> t |
|
330 | o i-2: c -move-> d, s -move-> t | |
331 | | |
|
331 | | | |
332 | o i-1: a -move-> c, p -move-> s |
|
332 | o i-1: a -move-> c, p -move-> s | |
333 | | |
|
333 | | | |
334 | o i-0 initial commit: a b h |
|
334 | o i-0 initial commit: a b h | |
335 |
|
335 | |||
336 |
|
336 | |||
337 | Comparing with a merge re-adding the file afterward |
|
337 | Comparing with a merge re-adding the file afterward | |
338 | --------------------------------------------------- |
|
338 | --------------------------------------------------- | |
339 |
|
339 | |||
340 | Merge: |
|
340 | Merge: | |
341 | - one with change to an unrelated file |
|
341 | - one with change to an unrelated file | |
342 | - one deleting and recreating the change |
|
342 | - one deleting and recreating the change | |
343 |
|
343 | |||
344 | $ case_desc="simple merge - B side: unrelated update, D side: delete and recreate a file (with different content)" |
|
344 | $ case_desc="simple merge - B side: unrelated update, D side: delete and recreate a file (with different content)" | |
345 |
|
345 | |||
346 | $ hg up 'desc("b-1")' |
|
346 | $ hg up 'desc("b-1")' | |
347 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
347 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
348 | $ hg merge 'desc("d-2")' |
|
348 | $ hg merge 'desc("d-2")' | |
349 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
349 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
350 | (branch merge, don't forget to commit) |
|
350 | (branch merge, don't forget to commit) | |
351 | $ hg ci -m "mBDm-0 $case_desc - one way" |
|
351 | $ hg ci -m "mBDm-0 $case_desc - one way" | |
352 | $ hg up 'desc("d-2")' |
|
352 | $ hg up 'desc("d-2")' | |
353 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
353 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
354 | $ hg merge 'desc("b-1")' |
|
354 | $ hg merge 'desc("b-1")' | |
355 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
355 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
356 | (branch merge, don't forget to commit) |
|
356 | (branch merge, don't forget to commit) | |
357 | $ hg ci -m "mDBm-0 $case_desc - the other way" |
|
357 | $ hg ci -m "mDBm-0 $case_desc - the other way" | |
358 | created new head |
|
358 | created new head | |
359 | $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))' |
|
359 | $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))' | |
360 | @ mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way |
|
360 | @ mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way | |
361 | |\ |
|
361 | |\ | |
362 | +---o mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way |
|
362 | +---o mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way | |
363 | | |/ |
|
363 | | |/ | |
364 | | o d-2 re-add d |
|
364 | | o d-2 re-add d | |
365 | | | |
|
365 | | | | |
366 | | o d-1 delete d |
|
366 | | o d-1 delete d | |
367 | | | |
|
367 | | | | |
368 | o | b-1: b update |
|
368 | o | b-1: b update | |
369 | |/ |
|
369 | |/ | |
370 | o i-2: c -move-> d, s -move-> t |
|
370 | o i-2: c -move-> d, s -move-> t | |
371 | | |
|
371 | | | |
372 | o i-1: a -move-> c, p -move-> s |
|
372 | o i-1: a -move-> c, p -move-> s | |
373 | | |
|
373 | | | |
374 | o i-0 initial commit: a b h |
|
374 | o i-0 initial commit: a b h | |
375 |
|
375 | |||
376 |
|
376 | |||
377 |
|
377 | |||
378 | Comparing with a merge with colliding rename |
|
378 | Comparing with a merge with colliding rename | |
379 | -------------------------------------------- |
|
379 | -------------------------------------------- | |
380 |
|
380 | |||
381 | Subcase: new copy information on both side |
|
381 | Subcase: new copy information on both side | |
382 | `````````````````````````````````````````` |
|
382 | `````````````````````````````````````````` | |
383 |
|
383 | |||
384 | - the "e-" branch renaming b to f (through 'g') |
|
384 | - the "e-" branch renaming b to f (through 'g') | |
385 | - the "a-" branch renaming d to f (through e) |
|
385 | - the "a-" branch renaming d to f (through e) | |
386 |
|
386 | |||
387 | $ case_desc="merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f)" |
|
387 | $ case_desc="merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f)" | |
388 |
|
388 | |||
389 | $ hg up 'desc("a-2")' |
|
389 | $ hg up 'desc("a-2")' | |
390 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
390 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
391 | $ hg merge 'desc("e-2")' |
|
391 | $ hg merge 'desc("e-2")' | |
392 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
392 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
393 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
393 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
394 | (branch merge, don't forget to commit) |
|
394 | (branch merge, don't forget to commit) | |
395 | $ hg ci -m "mAEm-0 $case_desc - one way" |
|
395 | $ hg ci -m "mAEm-0 $case_desc - one way" | |
396 | $ hg up 'desc("e-2")' |
|
396 | $ hg up 'desc("e-2")' | |
397 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
397 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) | |
398 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
398 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) | |
399 | $ hg merge 'desc("a-2")' |
|
399 | $ hg merge 'desc("a-2")' | |
400 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
400 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
401 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
401 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
402 | (branch merge, don't forget to commit) |
|
402 | (branch merge, don't forget to commit) | |
403 | $ hg ci -m "mEAm-0 $case_desc - the other way" |
|
403 | $ hg ci -m "mEAm-0 $case_desc - the other way" | |
404 | created new head |
|
404 | created new head | |
405 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' |
|
405 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' | |
406 | @ mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way |
|
406 | @ mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way | |
407 | |\ |
|
407 | |\ | |
408 | +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way |
|
408 | +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way | |
409 | | |/ |
|
409 | | |/ | |
410 | | o e-2 g -move-> f |
|
410 | | o e-2 g -move-> f | |
411 | | | |
|
411 | | | | |
412 | | o e-1 b -move-> g |
|
412 | | o e-1 b -move-> g | |
413 | | | |
|
413 | | | | |
414 | o | a-2: e -move-> f |
|
414 | o | a-2: e -move-> f | |
415 | | | |
|
415 | | | | |
416 | o | a-1: d -move-> e |
|
416 | o | a-1: d -move-> e | |
417 | |/ |
|
417 | |/ | |
418 | o i-2: c -move-> d, s -move-> t |
|
418 | o i-2: c -move-> d, s -move-> t | |
419 | | |
|
419 | | | |
420 | o i-1: a -move-> c, p -move-> s |
|
420 | o i-1: a -move-> c, p -move-> s | |
421 | | |
|
421 | | | |
422 | o i-0 initial commit: a b h |
|
422 | o i-0 initial commit: a b h | |
423 |
|
423 | |||
424 |
|
424 | |||
425 | Subcase: new copy information on both side with an actual merge happening |
|
425 | Subcase: new copy information on both side with an actual merge happening | |
426 | ````````````````````````````````````````````````````````````````````````` |
|
426 | ````````````````````````````````````````````````````````````````````````` | |
427 |
|
427 | |||
428 | - the "p-" branch renaming 't' to 'v' (through 'u') |
|
428 | - the "p-" branch renaming 't' to 'v' (through 'u') | |
429 | - the "q-" branch renaming 'r' to 'v' (through 'w') |
|
429 | - the "q-" branch renaming 'r' to 'v' (through 'w') | |
430 |
|
430 | |||
431 | $ case_desc="merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content)" |
|
431 | $ case_desc="merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content)" | |
432 |
|
432 | |||
433 | $ hg up 'desc("p-2")' |
|
433 | $ hg up 'desc("p-2")' | |
434 | 3 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
434 | 3 files updated, 0 files merged, 2 files removed, 0 files unresolved | |
435 | $ hg merge 'desc("q-2")' --tool ':union' |
|
435 | $ hg merge 'desc("q-2")' --tool ':union' | |
436 | merging v |
|
436 | merging v | |
437 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
437 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
438 | (branch merge, don't forget to commit) |
|
438 | (branch merge, don't forget to commit) | |
439 | $ hg ci -m "mPQm-0 $case_desc - one way" |
|
439 | $ hg ci -m "mPQm-0 $case_desc - one way" | |
440 | $ hg up 'desc("q-2")' |
|
440 | $ hg up 'desc("q-2")' | |
441 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
441 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
442 | $ hg merge 'desc("p-2")' --tool ':union' |
|
442 | $ hg merge 'desc("p-2")' --tool ':union' | |
443 | merging v |
|
443 | merging v | |
444 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
444 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
445 | (branch merge, don't forget to commit) |
|
445 | (branch merge, don't forget to commit) | |
446 | $ hg ci -m "mQPm-0 $case_desc - the other way" |
|
446 | $ hg ci -m "mQPm-0 $case_desc - the other way" | |
447 | created new head |
|
447 | created new head | |
448 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' |
|
448 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' | |
449 | o mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way |
|
449 | o mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way | |
450 | |\ |
|
450 | |\ | |
451 | +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way |
|
451 | +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way | |
452 | | |/ |
|
452 | | |/ | |
453 | | o e-2 g -move-> f |
|
453 | | o e-2 g -move-> f | |
454 | | | |
|
454 | | | | |
455 | | o e-1 b -move-> g |
|
455 | | o e-1 b -move-> g | |
456 | | | |
|
456 | | | | |
457 | o | a-2: e -move-> f |
|
457 | o | a-2: e -move-> f | |
458 | | | |
|
458 | | | | |
459 | o | a-1: d -move-> e |
|
459 | o | a-1: d -move-> e | |
460 | |/ |
|
460 | |/ | |
461 | o i-2: c -move-> d, s -move-> t |
|
461 | o i-2: c -move-> d, s -move-> t | |
462 | | |
|
462 | | | |
463 | o i-1: a -move-> c, p -move-> s |
|
463 | o i-1: a -move-> c, p -move-> s | |
464 | | |
|
464 | | | |
465 | o i-0 initial commit: a b h |
|
465 | o i-0 initial commit: a b h | |
466 |
|
466 | |||
467 |
|
467 | |||
468 | Subcase: existing copy information overwritten on one branch |
|
468 | Subcase: existing copy information overwritten on one branch | |
469 | ```````````````````````````````````````````````````````````` |
|
469 | ```````````````````````````````````````````````````````````` | |
470 |
|
470 | |||
471 | Merge: |
|
471 | Merge: | |
472 | - one with change to an unrelated file (b) |
|
472 | - one with change to an unrelated file (b) | |
473 | - one overwriting a file (d) with a rename (from h to i to d) |
|
473 | - one overwriting a file (d) with a rename (from h to i to d) | |
474 |
|
474 | |||
475 | $ case_desc="simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d)" |
|
475 | $ case_desc="simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d)" | |
476 |
|
476 | |||
477 | $ hg up 'desc("i-2")' |
|
477 | $ hg up 'desc("i-2")' | |
478 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
478 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
479 | $ hg mv h i |
|
479 | $ hg mv h i | |
480 | $ hg commit -m "f-1: rename h -> i" |
|
480 | $ hg commit -m "f-1: rename h -> i" | |
481 | created new head |
|
481 | created new head | |
482 | $ hg mv --force i d |
|
482 | $ hg mv --force i d | |
483 | $ hg commit -m "f-2: rename i -> d" |
|
483 | $ hg commit -m "f-2: rename i -> d" | |
484 | $ hg debugindex d | ../no-linkrev |
|
484 | $ hg debugindex d | ../no-linkrev | |
485 | rev linkrev nodeid p1 p2 |
|
485 | rev linkrev nodeid p1 p2 | |
486 | 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !) |
|
486 | 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !) | |
487 | 0 * ae258f702dfe 000000000000 000000000000 (changeset !) |
|
487 | 0 * ae258f702dfe 000000000000 000000000000 (changeset !) | |
488 | 1 * b004912a8510 000000000000 000000000000 |
|
488 | 1 * b004912a8510 000000000000 000000000000 | |
489 | 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !) |
|
489 | 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !) | |
490 | $ hg up 'desc("b-1")' |
|
490 | $ hg up 'desc("b-1")' | |
491 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
491 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) | |
492 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
492 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) | |
493 | $ hg merge 'desc("f-2")' |
|
493 | $ hg merge 'desc("f-2")' | |
494 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
494 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
495 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
495 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
496 | (branch merge, don't forget to commit) |
|
496 | (branch merge, don't forget to commit) | |
497 | $ hg ci -m "mBFm-0 $case_desc - one way" |
|
497 | $ hg ci -m "mBFm-0 $case_desc - one way" | |
498 | $ hg up 'desc("f-2")' |
|
498 | $ hg up 'desc("f-2")' | |
499 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
499 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
500 | $ hg merge 'desc("b-1")' |
|
500 | $ hg merge 'desc("b-1")' | |
501 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
501 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
502 | (branch merge, don't forget to commit) |
|
502 | (branch merge, don't forget to commit) | |
503 | $ hg ci -m "mFBm-0 $case_desc - the other way" |
|
503 | $ hg ci -m "mFBm-0 $case_desc - the other way" | |
504 | created new head |
|
504 | created new head | |
505 | $ hg up null --quiet |
|
505 | $ hg up null --quiet | |
506 | $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))' |
|
506 | $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))' | |
507 | o mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way |
|
507 | o mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way | |
508 | |\ |
|
508 | |\ | |
509 | +---o mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way |
|
509 | +---o mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way | |
510 | | |/ |
|
510 | | |/ | |
511 | | o f-2: rename i -> d |
|
511 | | o f-2: rename i -> d | |
512 | | | |
|
512 | | | | |
513 | | o f-1: rename h -> i |
|
513 | | o f-1: rename h -> i | |
514 | | | |
|
514 | | | | |
515 | o | b-1: b update |
|
515 | o | b-1: b update | |
516 | |/ |
|
516 | |/ | |
517 | o i-2: c -move-> d, s -move-> t |
|
517 | o i-2: c -move-> d, s -move-> t | |
518 | | |
|
518 | | | |
519 | o i-1: a -move-> c, p -move-> s |
|
519 | o i-1: a -move-> c, p -move-> s | |
520 | | |
|
520 | | | |
521 | o i-0 initial commit: a b h |
|
521 | o i-0 initial commit: a b h | |
522 |
|
522 | |||
523 |
|
523 | |||
524 | Subcase: existing copy information overwritten on one branch, with different content) |
|
524 | Subcase: existing copy information overwritten on one branch, with different content) | |
525 | ````````````````````````````````````````````````````````````````````````````````````` |
|
525 | ````````````````````````````````````````````````````````````````````````````````````` | |
526 |
|
526 | |||
527 | Merge: |
|
527 | Merge: | |
528 | - one with change to an unrelated file (b) |
|
528 | - one with change to an unrelated file (b) | |
529 | - one overwriting a file (t) with a rename (from r to x to t), v content is not the same as on the other branch |
|
529 | - one overwriting a file (t) with a rename (from r to x to t), v content is not the same as on the other branch | |
530 |
|
530 | |||
531 | $ case_desc="simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content" |
|
531 | $ case_desc="simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content" | |
532 |
|
532 | |||
533 | $ hg up 'desc("i-2")' |
|
533 | $ hg up 'desc("i-2")' | |
534 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
534 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
535 | $ hg mv r x |
|
535 | $ hg mv r x | |
536 | $ hg commit -m "r-1: rename r -> x" |
|
536 | $ hg commit -m "r-1: rename r -> x" | |
537 | created new head |
|
537 | created new head | |
538 | $ hg mv --force x t |
|
538 | $ hg mv --force x t | |
539 | $ hg commit -m "r-2: rename t -> x" |
|
539 | $ hg commit -m "r-2: rename t -> x" | |
540 | $ hg debugindex t | ../no-linkrev |
|
540 | $ hg debugindex t | ../no-linkrev | |
541 | rev linkrev nodeid p1 p2 |
|
541 | rev linkrev nodeid p1 p2 | |
542 | 0 * d74efbf65309 000000000000 000000000000 (no-changeset !) |
|
542 | 0 * d74efbf65309 000000000000 000000000000 (no-changeset !) | |
543 | 1 * 02a930b9d7ad 000000000000 000000000000 (no-changeset !) |
|
543 | 1 * 02a930b9d7ad 000000000000 000000000000 (no-changeset !) | |
544 | 0 * 5aed6a8dbff0 000000000000 000000000000 (changeset !) |
|
544 | 0 * 5aed6a8dbff0 000000000000 000000000000 (changeset !) | |
545 | 1 * a38b2fa17021 000000000000 000000000000 (changeset !) |
|
545 | 1 * a38b2fa17021 000000000000 000000000000 (changeset !) | |
546 | $ hg up 'desc("b-1")' |
|
546 | $ hg up 'desc("b-1")' | |
547 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
547 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
548 | $ hg merge 'desc("r-2")' |
|
548 | $ hg merge 'desc("r-2")' | |
549 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
549 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
550 | (branch merge, don't forget to commit) |
|
550 | (branch merge, don't forget to commit) | |
551 | $ hg ci -m "mBRm-0 $case_desc - one way" |
|
551 | $ hg ci -m "mBRm-0 $case_desc - one way" | |
552 | $ hg up 'desc("r-2")' |
|
552 | $ hg up 'desc("r-2")' | |
553 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
553 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
554 | $ hg merge 'desc("b-1")' |
|
554 | $ hg merge 'desc("b-1")' | |
555 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
555 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
556 | (branch merge, don't forget to commit) |
|
556 | (branch merge, don't forget to commit) | |
557 | $ hg ci -m "mRBm-0 $case_desc - the other way" |
|
557 | $ hg ci -m "mRBm-0 $case_desc - the other way" | |
558 | created new head |
|
558 | created new head | |
559 | $ hg up null --quiet |
|
559 | $ hg up null --quiet | |
560 | $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))' |
|
560 | $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))' | |
561 | o mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way |
|
561 | o mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way | |
562 | |\ |
|
562 | |\ | |
563 | +---o mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way |
|
563 | +---o mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way | |
564 | | |/ |
|
564 | | |/ | |
565 | | o r-2: rename t -> x |
|
565 | | o r-2: rename t -> x | |
566 | | | |
|
566 | | | | |
567 | | o r-1: rename r -> x |
|
567 | | o r-1: rename r -> x | |
568 | | | |
|
568 | | | | |
569 | o | b-1: b update |
|
569 | o | b-1: b update | |
570 | |/ |
|
570 | |/ | |
571 | o i-2: c -move-> d, s -move-> t |
|
571 | o i-2: c -move-> d, s -move-> t | |
572 | | |
|
572 | | | |
573 | o i-1: a -move-> c, p -move-> s |
|
573 | o i-1: a -move-> c, p -move-> s | |
574 | | |
|
574 | | | |
575 | o i-0 initial commit: a b h |
|
575 | o i-0 initial commit: a b h | |
576 |
|
576 | |||
577 |
|
577 | |||
578 |
|
578 | |||
579 | Subcase: reset of the copy history on one side |
|
579 | Subcase: reset of the copy history on one side | |
580 | `````````````````````````````````````````````` |
|
580 | `````````````````````````````````````````````` | |
581 |
|
581 | |||
582 | Merge: |
|
582 | Merge: | |
583 | - one with change to a file |
|
583 | - one with change to a file | |
584 | - one deleting and recreating the file |
|
584 | - one deleting and recreating the file | |
585 |
|
585 | |||
586 | Unlike in the 'BD/DB' cases, an actual merge happened here. So we should |
|
586 | Unlike in the 'BD/DB' cases, an actual merge happened here. So we should | |
587 | consider history and rename on both branch of the merge. |
|
587 | consider history and rename on both branch of the merge. | |
588 |
|
588 | |||
589 | $ case_desc="actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content" |
|
589 | $ case_desc="actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content" | |
590 |
|
590 | |||
591 | $ hg up 'desc("i-2")' |
|
591 | $ hg up 'desc("i-2")' | |
592 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
592 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
593 | $ echo "some update" >> d |
|
593 | $ echo "some update" >> d | |
594 | $ hg commit -m "g-1: update d" |
|
594 | $ hg commit -m "g-1: update d" | |
595 | created new head |
|
595 | created new head | |
596 | $ hg up 'desc("d-2")' |
|
596 | $ hg up 'desc("d-2")' | |
597 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
597 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
598 | $ hg merge 'desc("g-1")' --tool :union |
|
598 | $ hg merge 'desc("g-1")' --tool :union | |
599 | merging d |
|
599 | merging d | |
600 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
600 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
601 | (branch merge, don't forget to commit) |
|
601 | (branch merge, don't forget to commit) | |
602 | $ hg ci -m "mDGm-0 $case_desc - one way" |
|
602 | $ hg ci -m "mDGm-0 $case_desc - one way" | |
603 | $ hg up 'desc("g-1")' |
|
603 | $ hg up 'desc("g-1")' | |
604 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
604 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
605 | $ hg merge 'desc("d-2")' --tool :union |
|
605 | $ hg merge 'desc("d-2")' --tool :union | |
606 | merging d |
|
606 | merging d | |
607 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
607 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
608 | (branch merge, don't forget to commit) |
|
608 | (branch merge, don't forget to commit) | |
609 | $ hg ci -m "mGDm-0 $case_desc - the other way" |
|
609 | $ hg ci -m "mGDm-0 $case_desc - the other way" | |
610 | created new head |
|
610 | created new head | |
611 | $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))' |
|
611 | $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))' | |
612 | @ mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way |
|
612 | @ mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way | |
613 | |\ |
|
613 | |\ | |
614 | +---o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way |
|
614 | +---o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way | |
615 | | |/ |
|
615 | | |/ | |
616 | | o g-1: update d |
|
616 | | o g-1: update d | |
617 | | | |
|
617 | | | | |
618 | o | d-2 re-add d |
|
618 | o | d-2 re-add d | |
619 | | | |
|
619 | | | | |
620 | o | d-1 delete d |
|
620 | o | d-1 delete d | |
621 | |/ |
|
621 | |/ | |
622 | o i-2: c -move-> d, s -move-> t |
|
622 | o i-2: c -move-> d, s -move-> t | |
623 | | |
|
623 | | | |
624 | o i-1: a -move-> c, p -move-> s |
|
624 | o i-1: a -move-> c, p -move-> s | |
625 | | |
|
625 | | | |
626 | o i-0 initial commit: a b h |
|
626 | o i-0 initial commit: a b h | |
627 |
|
627 | |||
628 |
|
628 | |||
629 | Subcase: merging a change to a file with a "copy overwrite" to that file from another branch |
|
629 | Subcase: merging a change to a file with a "copy overwrite" to that file from another branch | |
630 | ```````````````````````````````````````````````````````````````````````````````````````````` |
|
630 | ```````````````````````````````````````````````````````````````````````````````````````````` | |
631 |
|
631 | |||
632 | Merge: |
|
632 | Merge: | |
633 | - one with change to a file (d) |
|
633 | - one with change to a file (d) | |
634 | - one overwriting that file with a rename (from h to i, to d) |
|
634 | - one overwriting that file with a rename (from h to i, to d) | |
635 |
|
635 | |||
636 | This case is similar to BF/FB, but an actual merge happens, so both side of the |
|
636 | This case is similar to BF/FB, but an actual merge happens, so both side of the | |
637 | history are relevant. |
|
637 | history are relevant. | |
638 |
|
638 | |||
639 | Note: |
|
639 | Note: | |
640 | | In this case, the merge get conflicting information since on one side we have |
|
640 | | In this case, the merge get conflicting information since on one side we have | |
641 | | "a -> c -> d". and one the other one we have "h -> i -> d". |
|
641 | | "a -> c -> d". and one the other one we have "h -> i -> d". | |
642 | | |
|
642 | | | |
643 | | The current code arbitrarily pick one side |
|
643 | | The current code arbitrarily pick one side | |
644 |
|
644 | |||
645 | $ case_desc="merge - G side: content change, F side: copy overwrite, no content change" |
|
645 | $ case_desc="merge - G side: content change, F side: copy overwrite, no content change" | |
646 |
|
646 | |||
647 | $ hg up 'desc("f-2")' |
|
647 | $ hg up 'desc("f-2")' | |
648 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
648 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
649 | $ hg merge 'desc("g-1")' --tool :union |
|
649 | $ hg merge 'desc("g-1")' --tool :union | |
650 | merging d (no-changeset !) |
|
650 | merging d (no-changeset !) | |
651 | 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
651 | 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (no-changeset !) | |
652 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
652 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) | |
653 | (branch merge, don't forget to commit) |
|
653 | (branch merge, don't forget to commit) | |
654 | $ hg ci -m "mFGm-0 $case_desc - one way" |
|
654 | $ hg ci -m "mFGm-0 $case_desc - one way" | |
655 | created new head |
|
655 | created new head | |
656 | $ hg up 'desc("g-1")' |
|
656 | $ hg up 'desc("g-1")' | |
657 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
657 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) | |
658 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
658 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) | |
659 | $ hg merge 'desc("f-2")' --tool :union |
|
659 | $ hg merge 'desc("f-2")' --tool :union | |
660 | merging d (no-changeset !) |
|
660 | merging d (no-changeset !) | |
661 | 0 files updated, 1 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
661 | 0 files updated, 1 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
662 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
662 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
663 | (branch merge, don't forget to commit) |
|
663 | (branch merge, don't forget to commit) | |
664 | $ hg ci -m "mGFm-0 $case_desc - the other way" |
|
664 | $ hg ci -m "mGFm-0 $case_desc - the other way" | |
665 | created new head |
|
665 | created new head | |
666 | $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))' |
|
666 | $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))' | |
667 | @ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
667 | @ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way | |
668 | |\ |
|
668 | |\ | |
669 | +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
669 | +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way | |
670 | | |/ |
|
670 | | |/ | |
671 | | o g-1: update d |
|
671 | | o g-1: update d | |
672 | | | |
|
672 | | | | |
673 | o | f-2: rename i -> d |
|
673 | o | f-2: rename i -> d | |
674 | | | |
|
674 | | | | |
675 | o | f-1: rename h -> i |
|
675 | o | f-1: rename h -> i | |
676 | |/ |
|
676 | |/ | |
677 | o i-2: c -move-> d, s -move-> t |
|
677 | o i-2: c -move-> d, s -move-> t | |
678 | | |
|
678 | | | |
679 | o i-1: a -move-> c, p -move-> s |
|
679 | o i-1: a -move-> c, p -move-> s | |
680 | | |
|
680 | | | |
681 | o i-0 initial commit: a b h |
|
681 | o i-0 initial commit: a b h | |
682 |
|
682 | |||
683 |
|
683 | |||
684 |
|
684 | |||
685 | Comparing with merging with a deletion (and keeping the file) |
|
685 | Comparing with merging with a deletion (and keeping the file) | |
686 | ------------------------------------------------------------- |
|
686 | ------------------------------------------------------------- | |
687 |
|
687 | |||
688 | Merge: |
|
688 | Merge: | |
689 | - one removing a file (d) |
|
689 | - one removing a file (d) | |
690 | - one updating that file |
|
690 | - one updating that file | |
691 | - the merge keep the modified version of the file (canceling the delete) |
|
691 | - the merge keep the modified version of the file (canceling the delete) | |
692 |
|
692 | |||
693 | In this case, the file keep on living after the merge. So we should not drop its |
|
693 | In this case, the file keep on living after the merge. So we should not drop its | |
694 | copy tracing chain. |
|
694 | copy tracing chain. | |
695 |
|
695 | |||
696 | $ case_desc="merge updated/deleted - revive the file (updated content)" |
|
696 | $ case_desc="merge updated/deleted - revive the file (updated content)" | |
697 |
|
697 | |||
698 | $ hg up 'desc("c-1")' |
|
698 | $ hg up 'desc("c-1")' | |
699 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
699 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
700 | $ hg merge 'desc("g-1")' |
|
700 | $ hg merge 'desc("g-1")' | |
701 | file 'd' was deleted in local [working copy] but was modified in other [merge rev]. |
|
701 | file 'd' was deleted in local [working copy] but was modified in other [merge rev]. | |
702 | You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved. |
|
702 | You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved. | |
703 | What do you want to do? u |
|
703 | What do you want to do? u | |
704 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
704 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved | |
705 | use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon |
|
705 | use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon | |
706 | [1] |
|
706 | [1] | |
707 | $ hg resolve -t :other d |
|
707 | $ hg resolve -t :other d | |
708 | (no more unresolved files) |
|
708 | (no more unresolved files) | |
709 | $ hg ci -m "mCGm-0 $case_desc - one way" |
|
709 | $ hg ci -m "mCGm-0 $case_desc - one way" | |
710 | created new head |
|
710 | created new head | |
711 |
|
711 | |||
712 | $ hg up 'desc("g-1")' |
|
712 | $ hg up 'desc("g-1")' | |
713 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
713 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
714 | $ hg merge 'desc("c-1")' |
|
714 | $ hg merge 'desc("c-1")' | |
715 | file 'd' was deleted in other [merge rev] but was modified in local [working copy]. |
|
715 | file 'd' was deleted in other [merge rev] but was modified in local [working copy]. | |
716 | You can use (c)hanged version, (d)elete, or leave (u)nresolved. |
|
716 | You can use (c)hanged version, (d)elete, or leave (u)nresolved. | |
717 | What do you want to do? u |
|
717 | What do you want to do? u | |
718 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
718 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved | |
719 | use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon |
|
719 | use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon | |
720 | [1] |
|
720 | [1] | |
721 | $ hg resolve -t :local d |
|
721 | $ hg resolve -t :local d | |
722 | (no more unresolved files) |
|
722 | (no more unresolved files) | |
723 | $ hg ci -m "mGCm-0 $case_desc - the other way" |
|
723 | $ hg ci -m "mGCm-0 $case_desc - the other way" | |
724 | created new head |
|
724 | created new head | |
725 |
|
725 | |||
726 | $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))' |
|
726 | $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))' | |
727 | @ mGCm-0 merge updated/deleted - revive the file (updated content) - the other way |
|
727 | @ mGCm-0 merge updated/deleted - revive the file (updated content) - the other way | |
728 | |\ |
|
728 | |\ | |
729 | +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way |
|
729 | +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way | |
730 | | |/ |
|
730 | | |/ | |
731 | | o g-1: update d |
|
731 | | o g-1: update d | |
732 | | | |
|
732 | | | | |
733 | o | c-1 delete d |
|
733 | o | c-1 delete d | |
734 | |/ |
|
734 | |/ | |
735 | o i-2: c -move-> d, s -move-> t |
|
735 | o i-2: c -move-> d, s -move-> t | |
736 | | |
|
736 | | | |
737 | o i-1: a -move-> c, p -move-> s |
|
737 | o i-1: a -move-> c, p -move-> s | |
738 | | |
|
738 | | | |
739 | o i-0 initial commit: a b h |
|
739 | o i-0 initial commit: a b h | |
740 |
|
740 | |||
741 |
|
741 | |||
742 |
|
742 | |||
743 |
|
743 | |||
744 | Comparing with merge restoring an untouched deleted file |
|
744 | Comparing with merge restoring an untouched deleted file | |
745 | -------------------------------------------------------- |
|
745 | -------------------------------------------------------- | |
746 |
|
746 | |||
747 | Merge: |
|
747 | Merge: | |
748 | - one removing a file (d) |
|
748 | - one removing a file (d) | |
749 | - one leaving the file untouched |
|
749 | - one leaving the file untouched | |
750 | - the merge actively restore the file to the same content. |
|
750 | - the merge actively restore the file to the same content. | |
751 |
|
751 | |||
752 | In this case, the file keep on living after the merge. So we should not drop its |
|
752 | In this case, the file keep on living after the merge. So we should not drop its | |
753 | copy tracing chain. |
|
753 | copy tracing chain. | |
754 |
|
754 | |||
755 | $ case_desc="merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge)" |
|
755 | $ case_desc="merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge)" | |
756 |
|
756 | |||
757 | $ hg up 'desc("c-1")' |
|
757 | $ hg up 'desc("c-1")' | |
758 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
758 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
759 | $ hg merge 'desc("b-1")' |
|
759 | $ hg merge 'desc("b-1")' | |
760 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
760 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
761 | (branch merge, don't forget to commit) |
|
761 | (branch merge, don't forget to commit) | |
762 | $ hg revert --rev 'desc("b-1")' d |
|
762 | $ hg revert --rev 'desc("b-1")' d | |
763 | $ hg ci -m "mCB-revert-m-0 $case_desc - one way" |
|
763 | $ hg ci -m "mCB-revert-m-0 $case_desc - one way" | |
764 | created new head |
|
764 | created new head | |
765 |
|
765 | |||
766 | $ hg up 'desc("b-1")' |
|
766 | $ hg up 'desc("b-1")' | |
767 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
767 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
768 | $ hg merge 'desc("c-1")' |
|
768 | $ hg merge 'desc("c-1")' | |
769 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
769 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
770 | (branch merge, don't forget to commit) |
|
770 | (branch merge, don't forget to commit) | |
771 | $ hg revert --rev 'desc("b-1")' d |
|
771 | $ hg revert --rev 'desc("b-1")' d | |
772 | $ hg ci -m "mBC-revert-m-0 $case_desc - the other way" |
|
772 | $ hg ci -m "mBC-revert-m-0 $case_desc - the other way" | |
773 | created new head |
|
773 | created new head | |
774 |
|
774 | |||
775 | $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))' |
|
775 | $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))' | |
776 | @ mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way |
|
776 | @ mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way | |
777 | |\ |
|
777 | |\ | |
778 | +---o mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way |
|
778 | +---o mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way | |
779 | | |/ |
|
779 | | |/ | |
780 | | o c-1 delete d |
|
780 | | o c-1 delete d | |
781 | | | |
|
781 | | | | |
782 | o | b-1: b update |
|
782 | o | b-1: b update | |
783 | |/ |
|
783 | |/ | |
784 | o i-2: c -move-> d, s -move-> t |
|
784 | o i-2: c -move-> d, s -move-> t | |
785 | | |
|
785 | | | |
786 | o i-1: a -move-> c, p -move-> s |
|
786 | o i-1: a -move-> c, p -move-> s | |
787 | | |
|
787 | | | |
788 | o i-0 initial commit: a b h |
|
788 | o i-0 initial commit: a b h | |
789 |
|
789 | |||
790 |
|
790 | |||
791 |
|
791 | |||
792 | $ hg up null --quiet |
|
792 | $ hg up null --quiet | |
793 |
|
793 | |||
794 | Merging a branch where a rename was deleted with a branch where the same file was renamed |
|
794 | Merging a branch where a rename was deleted with a branch where the same file was renamed | |
795 | ------------------------------------------------------------------------------------------ |
|
795 | ------------------------------------------------------------------------------------------ | |
796 |
|
796 | |||
797 | Create a "conflicting" merge where `d` get removed on one branch before its |
|
797 | Create a "conflicting" merge where `d` get removed on one branch before its | |
798 | rename information actually conflict with the other branch. |
|
798 | rename information actually conflict with the other branch. | |
799 |
|
799 | |||
800 | (the copy information from the branch that was not deleted should win). |
|
800 | (the copy information from the branch that was not deleted should win). | |
801 |
|
801 | |||
802 | $ case_desc="simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch)" |
|
802 | $ case_desc="simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch)" | |
803 |
|
803 | |||
804 | $ hg up 'desc("i-0")' |
|
804 | $ hg up 'desc("i-0")' | |
805 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
805 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
806 | $ hg mv b d |
|
806 | $ hg mv b d | |
807 | $ hg ci -m "h-1: b -(move)-> d" |
|
807 | $ hg ci -m "h-1: b -(move)-> d" | |
808 | created new head |
|
808 | created new head | |
809 |
|
809 | |||
810 | $ hg up 'desc("c-1")' |
|
810 | $ hg up 'desc("c-1")' | |
811 | 2 files updated, 0 files merged, 3 files removed, 0 files unresolved |
|
811 | 2 files updated, 0 files merged, 3 files removed, 0 files unresolved | |
812 | $ hg merge 'desc("h-1")' |
|
812 | $ hg merge 'desc("h-1")' | |
813 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
813 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
814 | (branch merge, don't forget to commit) |
|
814 | (branch merge, don't forget to commit) | |
815 | $ hg ci -m "mCH-delete-before-conflict-m-0 $case_desc - one way" |
|
815 | $ hg ci -m "mCH-delete-before-conflict-m-0 $case_desc - one way" | |
816 |
|
816 | |||
817 | $ hg up 'desc("h-1")' |
|
817 | $ hg up 'desc("h-1")' | |
818 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
818 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
819 | $ hg merge 'desc("c-1")' |
|
819 | $ hg merge 'desc("c-1")' | |
820 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
820 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved | |
821 | (branch merge, don't forget to commit) |
|
821 | (branch merge, don't forget to commit) | |
822 | $ hg ci -m "mHC-delete-before-conflict-m-0 $case_desc - the other way" |
|
822 | $ hg ci -m "mHC-delete-before-conflict-m-0 $case_desc - the other way" | |
823 | created new head |
|
823 | created new head | |
824 | $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))' |
|
824 | $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))' | |
825 | @ mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way |
|
825 | @ mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way | |
826 | |\ |
|
826 | |\ | |
827 | +---o mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way |
|
827 | +---o mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way | |
828 | | |/ |
|
828 | | |/ | |
829 | | o h-1: b -(move)-> d |
|
829 | | o h-1: b -(move)-> d | |
830 | | | |
|
830 | | | | |
831 | o | c-1 delete d |
|
831 | o | c-1 delete d | |
832 | | | |
|
832 | | | | |
833 | o | i-2: c -move-> d, s -move-> t |
|
833 | o | i-2: c -move-> d, s -move-> t | |
834 | | | |
|
834 | | | | |
835 | o | i-1: a -move-> c, p -move-> s |
|
835 | o | i-1: a -move-> c, p -move-> s | |
836 | |/ |
|
836 | |/ | |
837 | o i-0 initial commit: a b h |
|
837 | o i-0 initial commit: a b h | |
838 |
|
838 | |||
839 |
|
839 | |||
840 | Variant of previous with extra changes introduced by the merge |
|
840 | Variant of previous with extra changes introduced by the merge | |
841 | -------------------------------------------------------------- |
|
841 | -------------------------------------------------------------- | |
842 |
|
842 | |||
843 | Multiple cases above explicitely test cases where content are the same on both side during merge. In this section we will introduce variants for theses cases where new change are introduced to these file content during the merges. |
|
843 | Multiple cases above explicitely test cases where content are the same on both side during merge. In this section we will introduce variants for theses cases where new change are introduced to these file content during the merges. | |
844 |
|
844 | |||
845 |
|
845 | |||
846 | Subcase: merge has same initial content on both side, but merge introduced a change |
|
846 | Subcase: merge has same initial content on both side, but merge introduced a change | |
847 | ``````````````````````````````````````````````````````````````````````````````````` |
|
847 | ``````````````````````````````````````````````````````````````````````````````````` | |
848 |
|
848 | |||
849 | Same as `mAEm` and `mEAm` but with extra change to the file before commiting |
|
849 | Same as `mAEm` and `mEAm` but with extra change to the file before commiting | |
850 |
|
850 | |||
851 | - the "e-" branch renaming b to f (through 'g') |
|
851 | - the "e-" branch renaming b to f (through 'g') | |
852 | - the "a-" branch renaming d to f (through e) |
|
852 | - the "a-" branch renaming d to f (through e) | |
853 |
|
853 | |||
854 | $ case_desc="merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent)" |
|
854 | $ case_desc="merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent)" | |
855 |
|
855 | |||
856 | $ hg up 'desc("a-2")' |
|
856 | $ hg up 'desc("a-2")' | |
857 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
857 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
858 | $ hg merge 'desc("e-2")' |
|
858 | $ hg merge 'desc("e-2")' | |
859 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
859 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
860 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
860 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
861 | (branch merge, don't forget to commit) |
|
861 | (branch merge, don't forget to commit) | |
862 | $ echo "content change for mAE-change-m" > f |
|
862 | $ echo "content change for mAE-change-m" > f | |
863 | $ hg ci -m "mAE-change-m-0 $case_desc - one way" |
|
863 | $ hg ci -m "mAE-change-m-0 $case_desc - one way" | |
864 | created new head |
|
864 | created new head | |
865 | $ hg up 'desc("e-2")' |
|
865 | $ hg up 'desc("e-2")' | |
866 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
866 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
867 | $ hg merge 'desc("a-2")' |
|
867 | $ hg merge 'desc("a-2")' | |
868 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
868 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
869 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
869 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
870 | (branch merge, don't forget to commit) |
|
870 | (branch merge, don't forget to commit) | |
871 | $ echo "content change for mEA-change-m" > f |
|
871 | $ echo "content change for mEA-change-m" > f | |
872 | $ hg ci -m "mEA-change-m-0 $case_desc - the other way" |
|
872 | $ hg ci -m "mEA-change-m-0 $case_desc - the other way" | |
873 | created new head |
|
873 | created new head | |
874 | $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))' |
|
874 | $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))' | |
875 | @ mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way |
|
875 | @ mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way | |
876 | |\ |
|
876 | |\ | |
877 | +---o mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way |
|
877 | +---o mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way | |
878 | | |/ |
|
878 | | |/ | |
879 | | o e-2 g -move-> f |
|
879 | | o e-2 g -move-> f | |
880 | | | |
|
880 | | | | |
881 | | o e-1 b -move-> g |
|
881 | | o e-1 b -move-> g | |
882 | | | |
|
882 | | | | |
883 | o | a-2: e -move-> f |
|
883 | o | a-2: e -move-> f | |
884 | | | |
|
884 | | | | |
885 | o | a-1: d -move-> e |
|
885 | o | a-1: d -move-> e | |
886 | |/ |
|
886 | |/ | |
887 | o i-2: c -move-> d, s -move-> t |
|
887 | o i-2: c -move-> d, s -move-> t | |
888 | | |
|
888 | | | |
889 | o i-1: a -move-> c, p -move-> s |
|
889 | o i-1: a -move-> c, p -move-> s | |
890 | | |
|
890 | | | |
891 | o i-0 initial commit: a b h |
|
891 | o i-0 initial commit: a b h | |
892 |
|
892 | |||
893 |
|
893 | |||
894 | Decision from previous merge are properly chained with later merge |
|
894 | Decision from previous merge are properly chained with later merge | |
895 | ------------------------------------------------------------------ |
|
895 | ------------------------------------------------------------------ | |
896 |
|
896 | |||
897 | Subcase: chaining conflicting rename resolution |
|
897 | Subcase: chaining conflicting rename resolution | |
898 | ``````````````````````````````````````````````` |
|
898 | ``````````````````````````````````````````````` | |
899 |
|
899 | |||
900 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We |
|
900 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We | |
901 | add more change on the respective branch and merge again. These second merge |
|
901 | add more change on the respective branch and merge again. These second merge | |
902 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" |
|
902 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" | |
903 | about that file should stay unchanged. |
|
903 | about that file should stay unchanged. | |
904 |
|
904 | |||
905 | $ case_desc="chained merges (conflict -> simple) - same content everywhere" |
|
905 | $ case_desc="chained merges (conflict -> simple) - same content everywhere" | |
906 |
|
906 | |||
907 | (extra unrelated changes) |
|
907 | (extra unrelated changes) | |
908 |
|
908 | |||
909 | $ hg up 'desc("a-2")' |
|
909 | $ hg up 'desc("a-2")' | |
910 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
910 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
911 | $ echo j > unrelated-j |
|
911 | $ echo j > unrelated-j | |
912 | $ hg add unrelated-j |
|
912 | $ hg add unrelated-j | |
913 | $ hg ci -m 'j-1: unrelated changes (based on the "a" series of changes)' |
|
913 | $ hg ci -m 'j-1: unrelated changes (based on the "a" series of changes)' | |
914 | created new head |
|
914 | created new head | |
915 |
|
915 | |||
916 | $ hg up 'desc("e-2")' |
|
916 | $ hg up 'desc("e-2")' | |
917 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) |
|
917 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) | |
918 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) |
|
918 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) | |
919 | $ echo k > unrelated-k |
|
919 | $ echo k > unrelated-k | |
920 | $ hg add unrelated-k |
|
920 | $ hg add unrelated-k | |
921 | $ hg ci -m 'k-1: unrelated changes (based on "e" changes)' |
|
921 | $ hg ci -m 'k-1: unrelated changes (based on "e" changes)' | |
922 | created new head |
|
922 | created new head | |
923 |
|
923 | |||
924 | (merge variant 1) |
|
924 | (merge variant 1) | |
925 |
|
925 | |||
926 | $ hg up 'desc("mAEm")' |
|
926 | $ hg up 'desc("mAEm")' | |
927 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) |
|
927 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) | |
928 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) |
|
928 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) | |
929 | $ hg merge 'desc("k-1")' |
|
929 | $ hg merge 'desc("k-1")' | |
930 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
930 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
931 | (branch merge, don't forget to commit) |
|
931 | (branch merge, don't forget to commit) | |
932 | $ hg ci -m "mAE,Km: $case_desc" |
|
932 | $ hg ci -m "mAE,Km: $case_desc" | |
933 |
|
933 | |||
934 | (merge variant 2) |
|
934 | (merge variant 2) | |
935 |
|
935 | |||
936 | $ hg up 'desc("k-1")' |
|
936 | $ hg up 'desc("k-1")' | |
937 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
937 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) | |
938 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
938 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) | |
939 |
|
939 | |||
940 | $ hg merge 'desc("mAEm")' |
|
940 | $ hg merge 'desc("mAEm")' | |
941 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
941 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
942 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
942 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
943 | (branch merge, don't forget to commit) |
|
943 | (branch merge, don't forget to commit) | |
944 | $ hg ci -m "mK,AEm: $case_desc" |
|
944 | $ hg ci -m "mK,AEm: $case_desc" | |
945 | created new head |
|
945 | created new head | |
946 |
|
946 | |||
947 | (merge variant 3) |
|
947 | (merge variant 3) | |
948 |
|
948 | |||
949 | $ hg up 'desc("mEAm")' |
|
949 | $ hg up 'desc("mEAm")' | |
950 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
950 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
951 | $ hg merge 'desc("j-1")' |
|
951 | $ hg merge 'desc("j-1")' | |
952 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
952 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
953 | (branch merge, don't forget to commit) |
|
953 | (branch merge, don't forget to commit) | |
954 | $ hg ci -m "mEA,Jm: $case_desc" |
|
954 | $ hg ci -m "mEA,Jm: $case_desc" | |
955 |
|
955 | |||
956 | (merge variant 4) |
|
956 | (merge variant 4) | |
957 |
|
957 | |||
958 | $ hg up 'desc("j-1")' |
|
958 | $ hg up 'desc("j-1")' | |
959 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
959 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) | |
960 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
960 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) | |
961 | $ hg merge 'desc("mEAm")' |
|
961 | $ hg merge 'desc("mEAm")' | |
962 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
962 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
963 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
963 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
964 | (branch merge, don't forget to commit) |
|
964 | (branch merge, don't forget to commit) | |
965 | $ hg ci -m "mJ,EAm: $case_desc" |
|
965 | $ hg ci -m "mJ,EAm: $case_desc" | |
966 | created new head |
|
966 | created new head | |
967 |
|
967 | |||
968 |
|
968 | |||
969 | $ hg log -G --rev '::(desc("mAE,Km") + desc("mK,AEm") + desc("mEA,Jm") + desc("mJ,EAm"))' |
|
969 | $ hg log -G --rev '::(desc("mAE,Km") + desc("mK,AEm") + desc("mEA,Jm") + desc("mJ,EAm"))' | |
970 | @ mJ,EAm: chained merges (conflict -> simple) - same content everywhere |
|
970 | @ mJ,EAm: chained merges (conflict -> simple) - same content everywhere | |
971 | |\ |
|
971 | |\ | |
972 | +---o mEA,Jm: chained merges (conflict -> simple) - same content everywhere |
|
972 | +---o mEA,Jm: chained merges (conflict -> simple) - same content everywhere | |
973 | | |/ |
|
973 | | |/ | |
974 | | | o mK,AEm: chained merges (conflict -> simple) - same content everywhere |
|
974 | | | o mK,AEm: chained merges (conflict -> simple) - same content everywhere | |
975 | | | |\ |
|
975 | | | |\ | |
976 | | | +---o mAE,Km: chained merges (conflict -> simple) - same content everywhere |
|
976 | | | +---o mAE,Km: chained merges (conflict -> simple) - same content everywhere | |
977 | | | | |/ |
|
977 | | | | |/ | |
978 | | | | o k-1: unrelated changes (based on "e" changes) |
|
978 | | | | o k-1: unrelated changes (based on "e" changes) | |
979 | | | | | |
|
979 | | | | | | |
980 | | o | | j-1: unrelated changes (based on the "a" series of changes) |
|
980 | | o | | j-1: unrelated changes (based on the "a" series of changes) | |
981 | | | | | |
|
981 | | | | | | |
982 | o-----+ mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way |
|
982 | o-----+ mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way | |
983 | |/ / / |
|
983 | |/ / / | |
984 | | o / mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way |
|
984 | | o / mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way | |
985 | |/|/ |
|
985 | |/|/ | |
986 | | o e-2 g -move-> f |
|
986 | | o e-2 g -move-> f | |
987 | | | |
|
987 | | | | |
988 | | o e-1 b -move-> g |
|
988 | | o e-1 b -move-> g | |
989 | | | |
|
989 | | | | |
990 | o | a-2: e -move-> f |
|
990 | o | a-2: e -move-> f | |
991 | | | |
|
991 | | | | |
992 | o | a-1: d -move-> e |
|
992 | o | a-1: d -move-> e | |
993 | |/ |
|
993 | |/ | |
994 | o i-2: c -move-> d, s -move-> t |
|
994 | o i-2: c -move-> d, s -move-> t | |
995 | | |
|
995 | | | |
996 | o i-1: a -move-> c, p -move-> s |
|
996 | o i-1: a -move-> c, p -move-> s | |
997 | | |
|
997 | | | |
998 | o i-0 initial commit: a b h |
|
998 | o i-0 initial commit: a b h | |
999 |
|
999 | |||
1000 |
|
1000 | |||
1001 | Subcase: chaining conflicting rename resolution, with actual merging happening |
|
1001 | Subcase: chaining conflicting rename resolution, with actual merging happening | |
1002 | `````````````````````````````````````````````````````````````````````````````` |
|
1002 | `````````````````````````````````````````````````````````````````````````````` | |
1003 |
|
1003 | |||
1004 | The "mPQm" and "mQPm" case create a rename tracking conflict on file 't'. We |
|
1004 | The "mPQm" and "mQPm" case create a rename tracking conflict on file 't'. We | |
1005 | add more change on the respective branch and merge again. These second merge |
|
1005 | add more change on the respective branch and merge again. These second merge | |
1006 | does not involve the file 't' and the arbitration done within "mPQm" and "mQP" |
|
1006 | does not involve the file 't' and the arbitration done within "mPQm" and "mQP" | |
1007 | about that file should stay unchanged. |
|
1007 | about that file should stay unchanged. | |
1008 |
|
1008 | |||
1009 | $ case_desc="chained merges (conflict -> simple) - different content" |
|
1009 | $ case_desc="chained merges (conflict -> simple) - different content" | |
1010 |
|
1010 | |||
1011 | (extra unrelated changes) |
|
1011 | (extra unrelated changes) | |
1012 |
|
1012 | |||
1013 | $ hg up 'desc("p-2")' |
|
1013 | $ hg up 'desc("p-2")' | |
1014 | 3 files updated, 0 files merged, 3 files removed, 0 files unresolved |
|
1014 | 3 files updated, 0 files merged, 3 files removed, 0 files unresolved | |
1015 | $ echo s > unrelated-s |
|
1015 | $ echo s > unrelated-s | |
1016 | $ hg add unrelated-s |
|
1016 | $ hg add unrelated-s | |
1017 | $ hg ci -m 's-1: unrelated changes (based on the "p" series of changes)' |
|
1017 | $ hg ci -m 's-1: unrelated changes (based on the "p" series of changes)' | |
1018 | created new head |
|
1018 | created new head | |
1019 |
|
1019 | |||
1020 | $ hg up 'desc("q-2")' |
|
1020 | $ hg up 'desc("q-2")' | |
1021 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
1021 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved | |
1022 | $ echo t > unrelated-t |
|
1022 | $ echo t > unrelated-t | |
1023 | $ hg add unrelated-t |
|
1023 | $ hg add unrelated-t | |
1024 | $ hg ci -m 't-1: unrelated changes (based on "q" changes)' |
|
1024 | $ hg ci -m 't-1: unrelated changes (based on "q" changes)' | |
1025 | created new head |
|
1025 | created new head | |
1026 |
|
1026 | |||
1027 | (merge variant 1) |
|
1027 | (merge variant 1) | |
1028 |
|
1028 | |||
1029 | $ hg up 'desc("mPQm")' |
|
1029 | $ hg up 'desc("mPQm")' | |
1030 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
1030 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved | |
1031 | $ hg merge 'desc("t-1")' |
|
1031 | $ hg merge 'desc("t-1")' | |
1032 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1032 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1033 | (branch merge, don't forget to commit) |
|
1033 | (branch merge, don't forget to commit) | |
1034 | $ hg ci -m "mPQ,Tm: $case_desc" |
|
1034 | $ hg ci -m "mPQ,Tm: $case_desc" | |
1035 |
|
1035 | |||
1036 | (merge variant 2) |
|
1036 | (merge variant 2) | |
1037 |
|
1037 | |||
1038 | $ hg up 'desc("t-1")' |
|
1038 | $ hg up 'desc("t-1")' | |
1039 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1039 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1040 |
|
1040 | |||
1041 | $ hg merge 'desc("mPQm")' |
|
1041 | $ hg merge 'desc("mPQm")' | |
1042 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1042 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1043 | (branch merge, don't forget to commit) |
|
1043 | (branch merge, don't forget to commit) | |
1044 | $ hg ci -m "mT,PQm: $case_desc" |
|
1044 | $ hg ci -m "mT,PQm: $case_desc" | |
1045 | created new head |
|
1045 | created new head | |
1046 |
|
1046 | |||
1047 | (merge variant 3) |
|
1047 | (merge variant 3) | |
1048 |
|
1048 | |||
1049 | $ hg up 'desc("mQPm")' |
|
1049 | $ hg up 'desc("mQPm")' | |
1050 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1050 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1051 | $ hg merge 'desc("s-1")' |
|
1051 | $ hg merge 'desc("s-1")' | |
1052 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1052 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1053 | (branch merge, don't forget to commit) |
|
1053 | (branch merge, don't forget to commit) | |
1054 | $ hg ci -m "mQP,Sm: $case_desc" |
|
1054 | $ hg ci -m "mQP,Sm: $case_desc" | |
1055 |
|
1055 | |||
1056 | (merge variant 4) |
|
1056 | (merge variant 4) | |
1057 |
|
1057 | |||
1058 | $ hg up 'desc("s-1")' |
|
1058 | $ hg up 'desc("s-1")' | |
1059 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1059 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1060 | $ hg merge 'desc("mQPm")' |
|
1060 | $ hg merge 'desc("mQPm")' | |
1061 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1061 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1062 | (branch merge, don't forget to commit) |
|
1062 | (branch merge, don't forget to commit) | |
1063 | $ hg ci -m "mS,QPm: $case_desc" |
|
1063 | $ hg ci -m "mS,QPm: $case_desc" | |
1064 | created new head |
|
1064 | created new head | |
1065 | $ hg up null --quiet |
|
1065 | $ hg up null --quiet | |
1066 |
|
1066 | |||
1067 |
|
1067 | |||
1068 | $ hg log -G --rev '::(desc("mPQ,Tm") + desc("mT,PQm") + desc("mQP,Sm") + desc("mS,QPm"))' |
|
1068 | $ hg log -G --rev '::(desc("mPQ,Tm") + desc("mT,PQm") + desc("mQP,Sm") + desc("mS,QPm"))' | |
1069 | o mS,QPm: chained merges (conflict -> simple) - different content |
|
1069 | o mS,QPm: chained merges (conflict -> simple) - different content | |
1070 | |\ |
|
1070 | |\ | |
1071 | +---o mQP,Sm: chained merges (conflict -> simple) - different content |
|
1071 | +---o mQP,Sm: chained merges (conflict -> simple) - different content | |
1072 | | |/ |
|
1072 | | |/ | |
1073 | | | o mT,PQm: chained merges (conflict -> simple) - different content |
|
1073 | | | o mT,PQm: chained merges (conflict -> simple) - different content | |
1074 | | | |\ |
|
1074 | | | |\ | |
1075 | | | +---o mPQ,Tm: chained merges (conflict -> simple) - different content |
|
1075 | | | +---o mPQ,Tm: chained merges (conflict -> simple) - different content | |
1076 | | | | |/ |
|
1076 | | | | |/ | |
1077 | | | | o t-1: unrelated changes (based on "q" changes) |
|
1077 | | | | o t-1: unrelated changes (based on "q" changes) | |
1078 | | | | | |
|
1078 | | | | | | |
1079 | | o | | s-1: unrelated changes (based on the "p" series of changes) |
|
1079 | | o | | s-1: unrelated changes (based on the "p" series of changes) | |
1080 | | | | | |
|
1080 | | | | | | |
1081 | o-----+ mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way |
|
1081 | o-----+ mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way | |
1082 | |/ / / |
|
1082 | |/ / / | |
1083 | | o / mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way |
|
1083 | | o / mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way | |
1084 | |/|/ |
|
1084 | |/|/ | |
1085 | | o q-2 w -move-> v |
|
1085 | | o q-2 w -move-> v | |
1086 | | | |
|
1086 | | | | |
1087 | | o q-1 r -move-> w |
|
1087 | | o q-1 r -move-> w | |
1088 | | | |
|
1088 | | | | |
1089 | o | p-2: u -move-> v |
|
1089 | o | p-2: u -move-> v | |
1090 | | | |
|
1090 | | | | |
1091 | o | p-1: t -move-> u |
|
1091 | o | p-1: t -move-> u | |
1092 | |/ |
|
1092 | |/ | |
1093 | o i-2: c -move-> d, s -move-> t |
|
1093 | o i-2: c -move-> d, s -move-> t | |
1094 | | |
|
1094 | | | |
1095 | o i-1: a -move-> c, p -move-> s |
|
1095 | o i-1: a -move-> c, p -move-> s | |
1096 | | |
|
1096 | | | |
1097 | o i-0 initial commit: a b h |
|
1097 | o i-0 initial commit: a b h | |
1098 |
|
1098 | |||
1099 |
|
1099 | |||
1100 | Subcase: chaining salvage information during a merge |
|
1100 | Subcase: chaining salvage information during a merge | |
1101 | ```````````````````````````````````````````````````` |
|
1101 | ```````````````````````````````````````````````````` | |
1102 |
|
1102 | |||
1103 | We add more change on the branch were the file was deleted. merging again |
|
1103 | We add more change on the branch were the file was deleted. merging again | |
1104 | should preserve the fact eh file was salvaged. |
|
1104 | should preserve the fact eh file was salvaged. | |
1105 |
|
1105 | |||
1106 | $ case_desc="chained merges (salvaged -> simple) - same content (when the file exists)" |
|
1106 | $ case_desc="chained merges (salvaged -> simple) - same content (when the file exists)" | |
1107 |
|
1107 | |||
1108 | (creating the change) |
|
1108 | (creating the change) | |
1109 |
|
1109 | |||
1110 | $ hg up 'desc("c-1")' |
|
1110 | $ hg up 'desc("c-1")' | |
1111 | 5 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1111 | 5 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1112 | $ echo l > unrelated-l |
|
1112 | $ echo l > unrelated-l | |
1113 | $ hg add unrelated-l |
|
1113 | $ hg add unrelated-l | |
1114 | $ hg ci -m 'l-1: unrelated changes (based on "c" changes)' |
|
1114 | $ hg ci -m 'l-1: unrelated changes (based on "c" changes)' | |
1115 | created new head |
|
1115 | created new head | |
1116 |
|
1116 | |||
1117 | (Merge variant 1) |
|
1117 | (Merge variant 1) | |
1118 |
|
1118 | |||
1119 | $ hg up 'desc("mBC-revert-m")' |
|
1119 | $ hg up 'desc("mBC-revert-m")' | |
1120 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1120 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1121 | $ hg merge 'desc("l-1")' |
|
1121 | $ hg merge 'desc("l-1")' | |
1122 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1122 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1123 | (branch merge, don't forget to commit) |
|
1123 | (branch merge, don't forget to commit) | |
1124 | $ hg ci -m "mBC+revert,Lm: $case_desc" |
|
1124 | $ hg ci -m "mBC+revert,Lm: $case_desc" | |
1125 |
|
1125 | |||
1126 | (Merge variant 2) |
|
1126 | (Merge variant 2) | |
1127 |
|
1127 | |||
1128 | $ hg up 'desc("mCB-revert-m")' |
|
1128 | $ hg up 'desc("mCB-revert-m")' | |
1129 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1129 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1130 | $ hg merge 'desc("l-1")' |
|
1130 | $ hg merge 'desc("l-1")' | |
1131 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1131 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1132 | (branch merge, don't forget to commit) |
|
1132 | (branch merge, don't forget to commit) | |
1133 | $ hg ci -m "mCB+revert,Lm: $case_desc" |
|
1133 | $ hg ci -m "mCB+revert,Lm: $case_desc" | |
1134 |
|
1134 | |||
1135 | (Merge variant 3) |
|
1135 | (Merge variant 3) | |
1136 |
|
1136 | |||
1137 | $ hg up 'desc("l-1")' |
|
1137 | $ hg up 'desc("l-1")' | |
1138 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1138 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1139 |
|
1139 | |||
1140 | $ hg merge 'desc("mBC-revert-m")' |
|
1140 | $ hg merge 'desc("mBC-revert-m")' | |
1141 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1141 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1142 | (branch merge, don't forget to commit) |
|
1142 | (branch merge, don't forget to commit) | |
1143 | $ hg ci -m "mL,BC+revertm: $case_desc" |
|
1143 | $ hg ci -m "mL,BC+revertm: $case_desc" | |
1144 | created new head |
|
1144 | created new head | |
1145 |
|
1145 | |||
1146 | (Merge variant 4) |
|
1146 | (Merge variant 4) | |
1147 |
|
1147 | |||
1148 | $ hg up 'desc("l-1")' |
|
1148 | $ hg up 'desc("l-1")' | |
1149 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1149 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1150 |
|
1150 | |||
1151 | $ hg merge 'desc("mCB-revert-m")' |
|
1151 | $ hg merge 'desc("mCB-revert-m")' | |
1152 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1152 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1153 | (branch merge, don't forget to commit) |
|
1153 | (branch merge, don't forget to commit) | |
1154 | $ hg ci -m "mL,CB+revertm: $case_desc" |
|
1154 | $ hg ci -m "mL,CB+revertm: $case_desc" | |
1155 | created new head |
|
1155 | created new head | |
1156 |
|
1156 | |||
1157 | $ hg log -G --rev '::(desc("mBC+revert,Lm") + desc("mCB+revert,Lm") + desc("mL,BC+revertm") + desc("mL,CB+revertm"))' |
|
1157 | $ hg log -G --rev '::(desc("mBC+revert,Lm") + desc("mCB+revert,Lm") + desc("mL,BC+revertm") + desc("mL,CB+revertm"))' | |
1158 | @ mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1158 | @ mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists) | |
1159 | |\ |
|
1159 | |\ | |
1160 | | | o mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1160 | | | o mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists) | |
1161 | | |/| |
|
1161 | | |/| | |
1162 | +-+---o mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1162 | +-+---o mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) | |
1163 | | | | |
|
1163 | | | | | |
1164 | | +---o mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1164 | | +---o mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) | |
1165 | | | |/ |
|
1165 | | | |/ | |
1166 | | o | l-1: unrelated changes (based on "c" changes) |
|
1166 | | o | l-1: unrelated changes (based on "c" changes) | |
1167 | | | | |
|
1167 | | | | | |
1168 | | | o mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way |
|
1168 | | | o mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way | |
1169 | | |/| |
|
1169 | | |/| | |
1170 | o---+ mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way |
|
1170 | o---+ mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way | |
1171 | |/ / |
|
1171 | |/ / | |
1172 | o | c-1 delete d |
|
1172 | o | c-1 delete d | |
1173 | | | |
|
1173 | | | | |
1174 | | o b-1: b update |
|
1174 | | o b-1: b update | |
1175 | |/ |
|
1175 | |/ | |
1176 | o i-2: c -move-> d, s -move-> t |
|
1176 | o i-2: c -move-> d, s -move-> t | |
1177 | | |
|
1177 | | | |
1178 | o i-1: a -move-> c, p -move-> s |
|
1178 | o i-1: a -move-> c, p -move-> s | |
1179 | | |
|
1179 | | | |
1180 | o i-0 initial commit: a b h |
|
1180 | o i-0 initial commit: a b h | |
1181 |
|
1181 | |||
1182 |
|
1182 | |||
1183 |
|
1183 | |||
1184 | Subcase: chaining "merged" information during a merge |
|
1184 | Subcase: chaining "merged" information during a merge | |
1185 | `````````````````````````````````````````````````````` |
|
1185 | `````````````````````````````````````````````````````` | |
1186 |
|
1186 | |||
1187 | When a non-rename change are merged with a copy overwrite, the merge pick the copy source from (p1) as the reference. We should preserve this information in subsequent merges. |
|
1187 | When a non-rename change are merged with a copy overwrite, the merge pick the copy source from (p1) as the reference. We should preserve this information in subsequent merges. | |
1188 |
|
1188 | |||
1189 | $ case_desc="chained merges (copy-overwrite -> simple) - same content" |
|
1189 | $ case_desc="chained merges (copy-overwrite -> simple) - same content" | |
1190 |
|
1190 | |||
1191 | (extra unrelated changes) |
|
1191 | (extra unrelated changes) | |
1192 |
|
1192 | |||
1193 | $ hg up 'desc("f-2")' |
|
1193 | $ hg up 'desc("f-2")' | |
1194 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) |
|
1194 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) | |
1195 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) |
|
1195 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) | |
1196 | $ echo n > unrelated-n |
|
1196 | $ echo n > unrelated-n | |
1197 | $ hg add unrelated-n |
|
1197 | $ hg add unrelated-n | |
1198 | $ hg ci -m 'n-1: unrelated changes (based on the "f" series of changes)' |
|
1198 | $ hg ci -m 'n-1: unrelated changes (based on the "f" series of changes)' | |
1199 | created new head |
|
1199 | created new head | |
1200 |
|
1200 | |||
1201 | $ hg up 'desc("g-1")' |
|
1201 | $ hg up 'desc("g-1")' | |
1202 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1202 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1203 | $ echo o > unrelated-o |
|
1203 | $ echo o > unrelated-o | |
1204 | $ hg add unrelated-o |
|
1204 | $ hg add unrelated-o | |
1205 | $ hg ci -m 'o-1: unrelated changes (based on "g" changes)' |
|
1205 | $ hg ci -m 'o-1: unrelated changes (based on "g" changes)' | |
1206 | created new head |
|
1206 | created new head | |
1207 |
|
1207 | |||
1208 | (merge variant 1) |
|
1208 | (merge variant 1) | |
1209 |
|
1209 | |||
1210 | $ hg up 'desc("mFGm")' |
|
1210 | $ hg up 'desc("mFGm")' | |
1211 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) |
|
1211 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) | |
1212 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) |
|
1212 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) | |
1213 | $ hg merge 'desc("o-1")' |
|
1213 | $ hg merge 'desc("o-1")' | |
1214 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1214 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1215 | (branch merge, don't forget to commit) |
|
1215 | (branch merge, don't forget to commit) | |
1216 | $ hg ci -m "mFG,Om: $case_desc" |
|
1216 | $ hg ci -m "mFG,Om: $case_desc" | |
1217 |
|
1217 | |||
1218 | (merge variant 2) |
|
1218 | (merge variant 2) | |
1219 |
|
1219 | |||
1220 | $ hg up 'desc("o-1")' |
|
1220 | $ hg up 'desc("o-1")' | |
1221 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
1221 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) | |
1222 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
1222 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) | |
1223 | $ hg merge 'desc("FGm")' |
|
1223 | $ hg merge 'desc("FGm")' | |
1224 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
1224 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) | |
1225 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
1225 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) | |
1226 | (branch merge, don't forget to commit) |
|
1226 | (branch merge, don't forget to commit) | |
1227 | $ hg ci -m "mO,FGm: $case_desc" |
|
1227 | $ hg ci -m "mO,FGm: $case_desc" | |
1228 | created new head |
|
1228 | created new head | |
1229 |
|
1229 | |||
1230 | (merge variant 3) |
|
1230 | (merge variant 3) | |
1231 |
|
1231 | |||
1232 | $ hg up 'desc("mGFm")' |
|
1232 | $ hg up 'desc("mGFm")' | |
1233 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1233 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1234 | $ hg merge 'desc("n-1")' |
|
1234 | $ hg merge 'desc("n-1")' | |
1235 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1235 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1236 | (branch merge, don't forget to commit) |
|
1236 | (branch merge, don't forget to commit) | |
1237 | $ hg ci -m "mGF,Nm: $case_desc" |
|
1237 | $ hg ci -m "mGF,Nm: $case_desc" | |
1238 |
|
1238 | |||
1239 | (merge variant 4) |
|
1239 | (merge variant 4) | |
1240 |
|
1240 | |||
1241 | $ hg up 'desc("n-1")' |
|
1241 | $ hg up 'desc("n-1")' | |
1242 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1242 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1243 | $ hg merge 'desc("mGFm")' |
|
1243 | $ hg merge 'desc("mGFm")' | |
1244 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1244 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1245 | (branch merge, don't forget to commit) |
|
1245 | (branch merge, don't forget to commit) | |
1246 | $ hg ci -m "mN,GFm: $case_desc" |
|
1246 | $ hg ci -m "mN,GFm: $case_desc" | |
1247 | created new head |
|
1247 | created new head | |
1248 |
|
1248 | |||
1249 | $ hg log -G --rev '::(desc("mFG,Om") + desc("mO,FGm") + desc("mGF,Nm") + desc("mN,GFm"))' |
|
1249 | $ hg log -G --rev '::(desc("mFG,Om") + desc("mO,FGm") + desc("mGF,Nm") + desc("mN,GFm"))' | |
1250 | @ mN,GFm: chained merges (copy-overwrite -> simple) - same content |
|
1250 | @ mN,GFm: chained merges (copy-overwrite -> simple) - same content | |
1251 | |\ |
|
1251 | |\ | |
1252 | +---o mGF,Nm: chained merges (copy-overwrite -> simple) - same content |
|
1252 | +---o mGF,Nm: chained merges (copy-overwrite -> simple) - same content | |
1253 | | |/ |
|
1253 | | |/ | |
1254 | | | o mO,FGm: chained merges (copy-overwrite -> simple) - same content |
|
1254 | | | o mO,FGm: chained merges (copy-overwrite -> simple) - same content | |
1255 | | | |\ |
|
1255 | | | |\ | |
1256 | | | +---o mFG,Om: chained merges (copy-overwrite -> simple) - same content |
|
1256 | | | +---o mFG,Om: chained merges (copy-overwrite -> simple) - same content | |
1257 | | | | |/ |
|
1257 | | | | |/ | |
1258 | | | | o o-1: unrelated changes (based on "g" changes) |
|
1258 | | | | o o-1: unrelated changes (based on "g" changes) | |
1259 | | | | | |
|
1259 | | | | | | |
1260 | | o | | n-1: unrelated changes (based on the "f" series of changes) |
|
1260 | | o | | n-1: unrelated changes (based on the "f" series of changes) | |
1261 | | | | | |
|
1261 | | | | | | |
1262 | o-----+ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
1262 | o-----+ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way | |
1263 | |/ / / |
|
1263 | |/ / / | |
1264 | | o / mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
1264 | | o / mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way | |
1265 | |/|/ |
|
1265 | |/|/ | |
1266 | | o g-1: update d |
|
1266 | | o g-1: update d | |
1267 | | | |
|
1267 | | | | |
1268 | o | f-2: rename i -> d |
|
1268 | o | f-2: rename i -> d | |
1269 | | | |
|
1269 | | | | |
1270 | o | f-1: rename h -> i |
|
1270 | o | f-1: rename h -> i | |
1271 | |/ |
|
1271 | |/ | |
1272 | o i-2: c -move-> d, s -move-> t |
|
1272 | o i-2: c -move-> d, s -move-> t | |
1273 | | |
|
1273 | | | |
1274 | o i-1: a -move-> c, p -move-> s |
|
1274 | o i-1: a -move-> c, p -move-> s | |
1275 | | |
|
1275 | | | |
1276 | o i-0 initial commit: a b h |
|
1276 | o i-0 initial commit: a b h | |
1277 |
|
1277 | |||
1278 |
|
1278 | |||
1279 | Subcase: chaining conflicting rename resolution, with extra change during the merge |
|
1279 | Subcase: chaining conflicting rename resolution, with extra change during the merge | |
1280 | ``````````````````````````````````````````````````````````````````````````````````` |
|
1280 | ``````````````````````````````````````````````````````````````````````````````````` | |
1281 |
|
1281 | |||
1282 | The "mEA-change-m-0" and "mAE-change-m-0" case create a rename tracking conflict on file 'f'. We |
|
1282 | The "mEA-change-m-0" and "mAE-change-m-0" case create a rename tracking conflict on file 'f'. We | |
1283 | add more change on the respective branch and merge again. These second merge |
|
1283 | add more change on the respective branch and merge again. These second merge | |
1284 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" |
|
1284 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" | |
1285 | about that file should stay unchanged. |
|
1285 | about that file should stay unchanged. | |
1286 |
|
1286 | |||
1287 | $ case_desc="chained merges (conflict+change -> simple) - same content on both branch in the initial merge" |
|
1287 | $ case_desc="chained merges (conflict+change -> simple) - same content on both branch in the initial merge" | |
1288 |
|
1288 | |||
1289 |
|
1289 | |||
1290 | (merge variant 1) |
|
1290 | (merge variant 1) | |
1291 |
|
1291 | |||
1292 | $ hg up 'desc("mAE-change-m")' |
|
1292 | $ hg up 'desc("mAE-change-m")' | |
1293 | 2 files updated, 0 files merged, 3 files removed, 0 files unresolved |
|
1293 | 2 files updated, 0 files merged, 3 files removed, 0 files unresolved | |
1294 | $ hg merge 'desc("k-1")' |
|
1294 | $ hg merge 'desc("k-1")' | |
1295 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1295 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1296 | (branch merge, don't forget to commit) |
|
1296 | (branch merge, don't forget to commit) | |
1297 | $ hg ci -m "mAE-change,Km: $case_desc" |
|
1297 | $ hg ci -m "mAE-change,Km: $case_desc" | |
1298 |
|
1298 | |||
1299 | (merge variant 2) |
|
1299 | (merge variant 2) | |
1300 |
|
1300 | |||
1301 | $ hg up 'desc("k-1")' |
|
1301 | $ hg up 'desc("k-1")' | |
1302 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1302 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1303 |
|
1303 | |||
1304 | $ hg merge 'desc("mAE-change-m")' |
|
1304 | $ hg merge 'desc("mAE-change-m")' | |
1305 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1305 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1306 | (branch merge, don't forget to commit) |
|
1306 | (branch merge, don't forget to commit) | |
1307 | $ hg ci -m "mK,AE-change-m: $case_desc" |
|
1307 | $ hg ci -m "mK,AE-change-m: $case_desc" | |
1308 | created new head |
|
1308 | created new head | |
1309 |
|
1309 | |||
1310 | (merge variant 3) |
|
1310 | (merge variant 3) | |
1311 |
|
1311 | |||
1312 | $ hg up 'desc("mEA-change-m")' |
|
1312 | $ hg up 'desc("mEA-change-m")' | |
1313 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1313 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1314 | $ hg merge 'desc("j-1")' |
|
1314 | $ hg merge 'desc("j-1")' | |
1315 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1315 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1316 | (branch merge, don't forget to commit) |
|
1316 | (branch merge, don't forget to commit) | |
1317 | $ hg ci -m "mEA-change,Jm: $case_desc" |
|
1317 | $ hg ci -m "mEA-change,Jm: $case_desc" | |
1318 |
|
1318 | |||
1319 | (merge variant 4) |
|
1319 | (merge variant 4) | |
1320 |
|
1320 | |||
1321 | $ hg up 'desc("j-1")' |
|
1321 | $ hg up 'desc("j-1")' | |
1322 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1322 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
1323 | $ hg merge 'desc("mEA-change-m")' |
|
1323 | $ hg merge 'desc("mEA-change-m")' | |
1324 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1324 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
1325 | (branch merge, don't forget to commit) |
|
1325 | (branch merge, don't forget to commit) | |
1326 | $ hg ci -m "mJ,EA-change-m: $case_desc" |
|
1326 | $ hg ci -m "mJ,EA-change-m: $case_desc" | |
1327 | created new head |
|
1327 | created new head | |
1328 |
|
1328 | |||
1329 |
|
1329 | |||
1330 | $ hg log -G --rev '::(desc("mAE-change,Km") + desc("mK,AE-change-m") + desc("mEA-change,Jm") + desc("mJ,EA-change-m"))' |
|
1330 | $ hg log -G --rev '::(desc("mAE-change,Km") + desc("mK,AE-change-m") + desc("mEA-change,Jm") + desc("mJ,EA-change-m"))' | |
1331 | @ mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1331 | @ mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge | |
1332 | |\ |
|
1332 | |\ | |
1333 | +---o mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1333 | +---o mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge | |
1334 | | |/ |
|
1334 | | |/ | |
1335 | | | o mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1335 | | | o mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge | |
1336 | | | |\ |
|
1336 | | | |\ | |
1337 | | | +---o mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1337 | | | +---o mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge | |
1338 | | | | |/ |
|
1338 | | | | |/ | |
1339 | | | | o k-1: unrelated changes (based on "e" changes) |
|
1339 | | | | o k-1: unrelated changes (based on "e" changes) | |
1340 | | | | | |
|
1340 | | | | | | |
1341 | | o | | j-1: unrelated changes (based on the "a" series of changes) |
|
1341 | | o | | j-1: unrelated changes (based on the "a" series of changes) | |
1342 | | | | | |
|
1342 | | | | | | |
1343 | o-----+ mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way |
|
1343 | o-----+ mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way | |
1344 | |/ / / |
|
1344 | |/ / / | |
1345 | | o / mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way |
|
1345 | | o / mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way | |
1346 | |/|/ |
|
1346 | |/|/ | |
1347 | | o e-2 g -move-> f |
|
1347 | | o e-2 g -move-> f | |
1348 | | | |
|
1348 | | | | |
1349 | | o e-1 b -move-> g |
|
1349 | | o e-1 b -move-> g | |
1350 | | | |
|
1350 | | | | |
1351 | o | a-2: e -move-> f |
|
1351 | o | a-2: e -move-> f | |
1352 | | | |
|
1352 | | | | |
1353 | o | a-1: d -move-> e |
|
1353 | o | a-1: d -move-> e | |
1354 | |/ |
|
1354 | |/ | |
1355 | o i-2: c -move-> d, s -move-> t |
|
1355 | o i-2: c -move-> d, s -move-> t | |
1356 | | |
|
1356 | | | |
1357 | o i-1: a -move-> c, p -move-> s |
|
1357 | o i-1: a -move-> c, p -move-> s | |
1358 | | |
|
1358 | | | |
1359 | o i-0 initial commit: a b h |
|
1359 | o i-0 initial commit: a b h | |
1360 |
|
1360 | |||
1361 |
|
1361 | |||
1362 | Summary of all created cases |
|
1362 | Summary of all created cases | |
1363 | ---------------------------- |
|
1363 | ---------------------------- | |
1364 |
|
1364 | |||
1365 | $ hg up --quiet null |
|
1365 | $ hg up --quiet null | |
1366 |
|
1366 | |||
1367 | (This exists to help keeping a compact list of the various cases we have built) |
|
1367 | (This exists to help keeping a compact list of the various cases we have built) | |
1368 |
|
1368 | |||
1369 | $ hg log -T '{desc|firstline}\n'| sort |
|
1369 | $ hg log -T '{desc|firstline}\n'| sort | |
1370 | a-1: d -move-> e |
|
1370 | a-1: d -move-> e | |
1371 | a-2: e -move-> f |
|
1371 | a-2: e -move-> f | |
1372 | b-1: b update |
|
1372 | b-1: b update | |
1373 | c-1 delete d |
|
1373 | c-1 delete d | |
1374 | d-1 delete d |
|
1374 | d-1 delete d | |
1375 | d-2 re-add d |
|
1375 | d-2 re-add d | |
1376 | e-1 b -move-> g |
|
1376 | e-1 b -move-> g | |
1377 | e-2 g -move-> f |
|
1377 | e-2 g -move-> f | |
1378 | f-1: rename h -> i |
|
1378 | f-1: rename h -> i | |
1379 | f-2: rename i -> d |
|
1379 | f-2: rename i -> d | |
1380 | g-1: update d |
|
1380 | g-1: update d | |
1381 | h-1: b -(move)-> d |
|
1381 | h-1: b -(move)-> d | |
1382 | i-0 initial commit: a b h |
|
1382 | i-0 initial commit: a b h | |
1383 | i-1: a -move-> c, p -move-> s |
|
1383 | i-1: a -move-> c, p -move-> s | |
1384 | i-2: c -move-> d, s -move-> t |
|
1384 | i-2: c -move-> d, s -move-> t | |
1385 | j-1: unrelated changes (based on the "a" series of changes) |
|
1385 | j-1: unrelated changes (based on the "a" series of changes) | |
1386 | k-1: unrelated changes (based on "e" changes) |
|
1386 | k-1: unrelated changes (based on "e" changes) | |
1387 | l-1: unrelated changes (based on "c" changes) |
|
1387 | l-1: unrelated changes (based on "c" changes) | |
1388 | mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way |
|
1388 | mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way | |
1389 | mAE,Km: chained merges (conflict -> simple) - same content everywhere |
|
1389 | mAE,Km: chained merges (conflict -> simple) - same content everywhere | |
1390 | mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1390 | mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge | |
1391 | mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way |
|
1391 | mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way | |
1392 | mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way |
|
1392 | mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way | |
1393 | mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way |
|
1393 | mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way | |
1394 | mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1394 | mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) | |
1395 | mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way |
|
1395 | mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way | |
1396 | mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way |
|
1396 | mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way | |
1397 | mBCm-1 re-add d |
|
1397 | mBCm-1 re-add d | |
1398 | mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way |
|
1398 | mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way | |
1399 | mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way |
|
1399 | mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way | |
1400 | mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way |
|
1400 | mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way | |
1401 | mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1401 | mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) | |
1402 | mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way |
|
1402 | mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way | |
1403 | mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way |
|
1403 | mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way | |
1404 | mCBm-1 re-add d |
|
1404 | mCBm-1 re-add d | |
1405 | mCGm-0 merge updated/deleted - revive the file (updated content) - one way |
|
1405 | mCGm-0 merge updated/deleted - revive the file (updated content) - one way | |
1406 | mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way |
|
1406 | mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way | |
1407 | mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way |
|
1407 | mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way | |
1408 | mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way |
|
1408 | mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way | |
1409 | mEA,Jm: chained merges (conflict -> simple) - same content everywhere |
|
1409 | mEA,Jm: chained merges (conflict -> simple) - same content everywhere | |
1410 | mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1410 | mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge | |
1411 | mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way |
|
1411 | mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way | |
1412 | mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way |
|
1412 | mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way | |
1413 | mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way |
|
1413 | mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way | |
1414 | mFG,Om: chained merges (copy-overwrite -> simple) - same content |
|
1414 | mFG,Om: chained merges (copy-overwrite -> simple) - same content | |
1415 | mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
1415 | mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way | |
1416 | mGCm-0 merge updated/deleted - revive the file (updated content) - the other way |
|
1416 | mGCm-0 merge updated/deleted - revive the file (updated content) - the other way | |
1417 | mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way |
|
1417 | mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way | |
1418 | mGF,Nm: chained merges (copy-overwrite -> simple) - same content |
|
1418 | mGF,Nm: chained merges (copy-overwrite -> simple) - same content | |
1419 | mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
1419 | mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way | |
1420 | mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way |
|
1420 | mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way | |
1421 | mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1421 | mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge | |
1422 | mJ,EAm: chained merges (conflict -> simple) - same content everywhere |
|
1422 | mJ,EAm: chained merges (conflict -> simple) - same content everywhere | |
1423 | mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1423 | mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge | |
1424 | mK,AEm: chained merges (conflict -> simple) - same content everywhere |
|
1424 | mK,AEm: chained merges (conflict -> simple) - same content everywhere | |
1425 | mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1425 | mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists) | |
1426 | mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1426 | mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists) | |
1427 | mN,GFm: chained merges (copy-overwrite -> simple) - same content |
|
1427 | mN,GFm: chained merges (copy-overwrite -> simple) - same content | |
1428 | mO,FGm: chained merges (copy-overwrite -> simple) - same content |
|
1428 | mO,FGm: chained merges (copy-overwrite -> simple) - same content | |
1429 | mPQ,Tm: chained merges (conflict -> simple) - different content |
|
1429 | mPQ,Tm: chained merges (conflict -> simple) - different content | |
1430 | mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way |
|
1430 | mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way | |
1431 | mQP,Sm: chained merges (conflict -> simple) - different content |
|
1431 | mQP,Sm: chained merges (conflict -> simple) - different content | |
1432 | mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way |
|
1432 | mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way | |
1433 | mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way |
|
1433 | mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way | |
1434 | mS,QPm: chained merges (conflict -> simple) - different content |
|
1434 | mS,QPm: chained merges (conflict -> simple) - different content | |
1435 | mT,PQm: chained merges (conflict -> simple) - different content |
|
1435 | mT,PQm: chained merges (conflict -> simple) - different content | |
1436 | n-1: unrelated changes (based on the "f" series of changes) |
|
1436 | n-1: unrelated changes (based on the "f" series of changes) | |
1437 | o-1: unrelated changes (based on "g" changes) |
|
1437 | o-1: unrelated changes (based on "g" changes) | |
1438 | p-1: t -move-> u |
|
1438 | p-1: t -move-> u | |
1439 | p-2: u -move-> v |
|
1439 | p-2: u -move-> v | |
1440 | q-1 r -move-> w |
|
1440 | q-1 r -move-> w | |
1441 | q-2 w -move-> v |
|
1441 | q-2 w -move-> v | |
1442 | r-1: rename r -> x |
|
1442 | r-1: rename r -> x | |
1443 | r-2: rename t -> x |
|
1443 | r-2: rename t -> x | |
1444 | s-1: unrelated changes (based on the "p" series of changes) |
|
1444 | s-1: unrelated changes (based on the "p" series of changes) | |
1445 | t-1: unrelated changes (based on "q" changes) |
|
1445 | t-1: unrelated changes (based on "q" changes) | |
1446 |
|
1446 | |||
1447 |
|
1447 | |||
1448 | Test that sidedata computations during upgrades are correct |
|
1448 | Test that sidedata computations during upgrades are correct | |
1449 | =========================================================== |
|
1449 | =========================================================== | |
1450 |
|
1450 | |||
1451 | We upgrade a repository that is not using sidedata (the filelog case) and |
|
1451 | We upgrade a repository that is not using sidedata (the filelog case) and | |
1452 | check that the same side data have been generated as if they were computed at |
|
1452 | check that the same side data have been generated as if they were computed at | |
1453 | commit time. |
|
1453 | commit time. | |
1454 |
|
1454 | |||
1455 |
|
1455 | |||
1456 | #if upgraded |
|
1456 | #if upgraded | |
1457 | $ cat >> $HGRCPATH << EOF |
|
1457 | $ cat >> $HGRCPATH << EOF | |
1458 | > [format] |
|
1458 | > [format] | |
1459 | > exp-use-side-data = yes |
|
1459 | > exp-use-side-data = yes | |
1460 | > exp-use-copies-side-data-changeset = yes |
|
1460 | > exp-use-copies-side-data-changeset = yes | |
1461 | > EOF |
|
1461 | > EOF | |
1462 | $ hg debugformat -v |
|
1462 | $ hg debugformat -v | |
1463 | format-variant repo config default |
|
1463 | format-variant repo config default | |
1464 | fncache: yes yes yes |
|
1464 | fncache: yes yes yes | |
1465 | dotencode: yes yes yes |
|
1465 | dotencode: yes yes yes | |
1466 | generaldelta: yes yes yes |
|
1466 | generaldelta: yes yes yes | |
1467 | share-safe: no no no |
|
1467 | share-safe: no no no | |
1468 | sparserevlog: yes yes yes |
|
1468 | sparserevlog: yes yes yes | |
1469 | sidedata: no yes no |
|
1469 | sidedata: no yes no | |
1470 | persistent-nodemap: no no no |
|
1470 | persistent-nodemap: no no no | |
1471 | copies-sdc: no yes no |
|
1471 | copies-sdc: no yes no | |
1472 | plain-cl-delta: yes yes yes |
|
1472 | plain-cl-delta: yes yes yes | |
1473 | compression: * (glob) |
|
1473 | compression: * (glob) | |
1474 | compression-level: default default default |
|
1474 | compression-level: default default default | |
1475 | $ hg debugupgraderepo --run --quiet |
|
1475 | $ hg debugupgraderepo --run --quiet | |
1476 | upgrade will perform the following actions: |
|
1476 | upgrade will perform the following actions: | |
1477 |
|
1477 | |||
1478 | requirements |
|
1478 | requirements | |
1479 | preserved: * (glob) |
|
1479 | preserved: * (glob) | |
1480 | added: exp-copies-sidedata-changeset, exp-sidedata-flag |
|
1480 | added: exp-copies-sidedata-changeset, exp-sidedata-flag | |
1481 |
|
1481 | |||
1482 | processed revlogs: |
|
1482 | processed revlogs: | |
1483 | - all-filelogs |
|
1483 | - all-filelogs | |
1484 | - changelog |
|
1484 | - changelog | |
1485 | - manifest |
|
1485 | - manifest | |
1486 |
|
1486 | |||
1487 | #endif |
|
1487 | #endif | |
1488 |
|
1488 | |||
1489 |
|
1489 | |||
1490 | #if no-compatibility no-filelog no-changeset |
|
1490 | #if no-compatibility no-filelog no-changeset | |
1491 |
|
1491 | |||
1492 | $ hg debugchangedfiles --compute 0 |
|
1492 | $ hg debugchangedfiles --compute 0 | |
1493 | added : a, ; |
|
1493 | added : a, ; | |
1494 | added : b, ; |
|
1494 | added : b, ; | |
1495 | added : h, ; |
|
1495 | added : h, ; | |
1496 | added : p, ; |
|
1496 | added : p, ; | |
1497 | added : q, ; |
|
1497 | added : q, ; | |
1498 | added : r, ; |
|
1498 | added : r, ; | |
1499 |
|
1499 | |||
1500 | $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do |
|
1500 | $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do | |
1501 | > case_id=`hg log -r $rev -T '{word(0, desc, ":")}\n'` |
|
1501 | > case_id=`hg log -r $rev -T '{word(0, desc, ":")}\n'` | |
1502 | > echo "##### revision \"$case_id\" #####" |
|
1502 | > echo "##### revision \"$case_id\" #####" | |
1503 | > hg debugsidedata -c -v -- $rev |
|
1503 | > hg debugsidedata -c -v -- $rev | |
1504 | > hg debugchangedfiles $rev |
|
1504 | > hg debugchangedfiles $rev | |
1505 | > done |
|
1505 | > done | |
1506 | ##### revision "i-0 initial commit" ##### |
|
1506 | ##### revision "i-0 initial commit" ##### | |
1507 | 1 sidedata entries |
|
1507 | 1 sidedata entries | |
1508 | entry-0014 size 64 |
|
1508 | entry-0014 size 64 | |
1509 | '\x00\x00\x00\x06\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\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x00abhpqr' |
|
1509 | '\x00\x00\x00\x06\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\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x00abhpqr' | |
1510 | added : a, ; |
|
1510 | added : a, ; | |
1511 | added : b, ; |
|
1511 | added : b, ; | |
1512 | added : h, ; |
|
1512 | added : h, ; | |
1513 | added : p, ; |
|
1513 | added : p, ; | |
1514 | added : q, ; |
|
1514 | added : q, ; | |
1515 | added : r, ; |
|
1515 | added : r, ; | |
1516 | ##### revision "i-1" ##### |
|
1516 | ##### revision "i-1" ##### | |
1517 | 1 sidedata entries |
|
1517 | 1 sidedata entries | |
1518 | entry-0014 size 44 |
|
1518 | entry-0014 size 44 | |
1519 | '\x00\x00\x00\x04\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x02acps' |
|
1519 | '\x00\x00\x00\x04\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x02acps' | |
1520 | removed : a, ; |
|
1520 | removed : a, ; | |
1521 | added p1: c, a; |
|
1521 | added p1: c, a; | |
1522 | removed : p, ; |
|
1522 | removed : p, ; | |
1523 | added p1: s, p; |
|
1523 | added p1: s, p; | |
1524 | ##### revision "i-2" ##### |
|
1524 | ##### revision "i-2" ##### | |
1525 | 1 sidedata entries |
|
1525 | 1 sidedata entries | |
1526 | entry-0014 size 44 |
|
1526 | entry-0014 size 44 | |
1527 | '\x00\x00\x00\x04\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x02cdst' |
|
1527 | '\x00\x00\x00\x04\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x02cdst' | |
1528 | removed : c, ; |
|
1528 | removed : c, ; | |
1529 | added p1: d, c; |
|
1529 | added p1: d, c; | |
1530 | removed : s, ; |
|
1530 | removed : s, ; | |
1531 | added p1: t, s; |
|
1531 | added p1: t, s; | |
1532 | ##### revision "a-1" ##### |
|
1532 | ##### revision "a-1" ##### | |
1533 | 1 sidedata entries |
|
1533 | 1 sidedata entries | |
1534 | entry-0014 size 24 |
|
1534 | entry-0014 size 24 | |
1535 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de' |
|
1535 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de' | |
1536 | removed : d, ; |
|
1536 | removed : d, ; | |
1537 | added p1: e, d; |
|
1537 | added p1: e, d; | |
1538 | ##### revision "a-2" ##### |
|
1538 | ##### revision "a-2" ##### | |
1539 | 1 sidedata entries |
|
1539 | 1 sidedata entries | |
1540 | entry-0014 size 24 |
|
1540 | entry-0014 size 24 | |
1541 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef' |
|
1541 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef' | |
1542 | removed : e, ; |
|
1542 | removed : e, ; | |
1543 | added p1: f, e; |
|
1543 | added p1: f, e; | |
1544 | ##### revision "b-1" ##### |
|
1544 | ##### revision "b-1" ##### | |
1545 | 1 sidedata entries |
|
1545 | 1 sidedata entries | |
1546 | entry-0014 size 14 |
|
1546 | entry-0014 size 14 | |
1547 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b' |
|
1547 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b' | |
1548 | touched : b, ; |
|
1548 | touched : b, ; | |
1549 | ##### revision "c-1 delete d" ##### |
|
1549 | ##### revision "c-1 delete d" ##### | |
1550 | 1 sidedata entries |
|
1550 | 1 sidedata entries | |
1551 | entry-0014 size 14 |
|
1551 | entry-0014 size 14 | |
1552 | '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1552 | '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1553 | removed : d, ; |
|
1553 | removed : d, ; | |
1554 | ##### revision "d-1 delete d" ##### |
|
1554 | ##### revision "d-1 delete d" ##### | |
1555 | 1 sidedata entries |
|
1555 | 1 sidedata entries | |
1556 | entry-0014 size 14 |
|
1556 | entry-0014 size 14 | |
1557 | '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1557 | '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1558 | removed : d, ; |
|
1558 | removed : d, ; | |
1559 | ##### revision "d-2 re-add d" ##### |
|
1559 | ##### revision "d-2 re-add d" ##### | |
1560 | 1 sidedata entries |
|
1560 | 1 sidedata entries | |
1561 | entry-0014 size 14 |
|
1561 | entry-0014 size 14 | |
1562 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1562 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1563 | added : d, ; |
|
1563 | added : d, ; | |
1564 | ##### revision "e-1 b -move-> g" ##### |
|
1564 | ##### revision "e-1 b -move-> g" ##### | |
1565 | 1 sidedata entries |
|
1565 | 1 sidedata entries | |
1566 | entry-0014 size 24 |
|
1566 | entry-0014 size 24 | |
1567 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg' |
|
1567 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg' | |
1568 | removed : b, ; |
|
1568 | removed : b, ; | |
1569 | added p1: g, b; |
|
1569 | added p1: g, b; | |
1570 | ##### revision "e-2 g -move-> f" ##### |
|
1570 | ##### revision "e-2 g -move-> f" ##### | |
1571 | 1 sidedata entries |
|
1571 | 1 sidedata entries | |
1572 | entry-0014 size 24 |
|
1572 | entry-0014 size 24 | |
1573 | '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg' |
|
1573 | '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg' | |
1574 | added p1: f, g; |
|
1574 | added p1: f, g; | |
1575 | removed : g, ; |
|
1575 | removed : g, ; | |
1576 | ##### revision "p-1" ##### |
|
1576 | ##### revision "p-1" ##### | |
1577 | 1 sidedata entries |
|
1577 | 1 sidedata entries | |
1578 | entry-0014 size 24 |
|
1578 | entry-0014 size 24 | |
1579 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00tu' |
|
1579 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00tu' | |
1580 | removed : t, ; |
|
1580 | removed : t, ; | |
1581 | added p1: u, t; |
|
1581 | added p1: u, t; | |
1582 | ##### revision "p-2" ##### |
|
1582 | ##### revision "p-2" ##### | |
1583 | 1 sidedata entries |
|
1583 | 1 sidedata entries | |
1584 | entry-0014 size 24 |
|
1584 | entry-0014 size 24 | |
1585 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00uv' |
|
1585 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00uv' | |
1586 | removed : u, ; |
|
1586 | removed : u, ; | |
1587 | added p1: v, u; |
|
1587 | added p1: v, u; | |
1588 | ##### revision "q-1 r -move-> w" ##### |
|
1588 | ##### revision "q-1 r -move-> w" ##### | |
1589 | 1 sidedata entries |
|
1589 | 1 sidedata entries | |
1590 | entry-0014 size 24 |
|
1590 | entry-0014 size 24 | |
1591 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rw' |
|
1591 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rw' | |
1592 | removed : r, ; |
|
1592 | removed : r, ; | |
1593 | added p1: w, r; |
|
1593 | added p1: w, r; | |
1594 | ##### revision "q-2 w -move-> v" ##### |
|
1594 | ##### revision "q-2 w -move-> v" ##### | |
1595 | 1 sidedata entries |
|
1595 | 1 sidedata entries | |
1596 | entry-0014 size 24 |
|
1596 | entry-0014 size 24 | |
1597 | '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00vw' |
|
1597 | '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00vw' | |
1598 | added p1: v, w; |
|
1598 | added p1: v, w; | |
1599 | removed : w, ; |
|
1599 | removed : w, ; | |
1600 | ##### revision "mBAm-0 simple merge - A side" ##### |
|
1600 | ##### revision "mBAm-0 simple merge - A side" ##### | |
1601 | 1 sidedata entries |
|
1601 | 1 sidedata entries | |
1602 | entry-0014 size 4 |
|
1602 | entry-0014 size 4 | |
1603 | '\x00\x00\x00\x00' |
|
1603 | '\x00\x00\x00\x00' | |
1604 | ##### revision "mABm-0 simple merge - A side" ##### |
|
1604 | ##### revision "mABm-0 simple merge - A side" ##### | |
1605 | 1 sidedata entries |
|
1605 | 1 sidedata entries | |
1606 | entry-0014 size 4 |
|
1606 | entry-0014 size 4 | |
1607 | '\x00\x00\x00\x00' |
|
1607 | '\x00\x00\x00\x00' | |
1608 | ##### revision "mBCm-0 simple merge - C side" ##### |
|
1608 | ##### revision "mBCm-0 simple merge - C side" ##### | |
1609 | 1 sidedata entries |
|
1609 | 1 sidedata entries | |
1610 | entry-0014 size 4 |
|
1610 | entry-0014 size 4 | |
1611 | '\x00\x00\x00\x00' |
|
1611 | '\x00\x00\x00\x00' | |
1612 | ##### revision "mBCm-1 re-add d" ##### |
|
1612 | ##### revision "mBCm-1 re-add d" ##### | |
1613 | 1 sidedata entries |
|
1613 | 1 sidedata entries | |
1614 | entry-0014 size 14 |
|
1614 | entry-0014 size 14 | |
1615 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1615 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1616 | added : d, ; |
|
1616 | added : d, ; | |
1617 | ##### revision "mCBm-0 simple merge - C side" ##### |
|
1617 | ##### revision "mCBm-0 simple merge - C side" ##### | |
1618 | 1 sidedata entries |
|
1618 | 1 sidedata entries | |
1619 | entry-0014 size 4 |
|
1619 | entry-0014 size 4 | |
1620 | '\x00\x00\x00\x00' |
|
1620 | '\x00\x00\x00\x00' | |
1621 | ##### revision "mCBm-1 re-add d" ##### |
|
1621 | ##### revision "mCBm-1 re-add d" ##### | |
1622 | 1 sidedata entries |
|
1622 | 1 sidedata entries | |
1623 | entry-0014 size 14 |
|
1623 | entry-0014 size 14 | |
1624 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1624 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1625 | added : d, ; |
|
1625 | added : d, ; | |
1626 | ##### revision "mBDm-0 simple merge - B side" ##### |
|
1626 | ##### revision "mBDm-0 simple merge - B side" ##### | |
1627 | 1 sidedata entries |
|
1627 | 1 sidedata entries | |
1628 | entry-0014 size 4 |
|
1628 | entry-0014 size 4 | |
1629 | '\x00\x00\x00\x00' |
|
1629 | '\x00\x00\x00\x00' | |
1630 | ##### revision "mDBm-0 simple merge - B side" ##### |
|
1630 | ##### revision "mDBm-0 simple merge - B side" ##### | |
1631 | 1 sidedata entries |
|
1631 | 1 sidedata entries | |
1632 | entry-0014 size 4 |
|
1632 | entry-0014 size 4 | |
1633 | '\x00\x00\x00\x00' |
|
1633 | '\x00\x00\x00\x00' | |
1634 | ##### revision "mAEm-0 merge with copies info on both side - A side" ##### |
|
1634 | ##### revision "mAEm-0 merge with copies info on both side - A side" ##### | |
1635 | 1 sidedata entries |
|
1635 | 1 sidedata entries | |
1636 | entry-0014 size 14 |
|
1636 | entry-0014 size 14 | |
1637 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' |
|
1637 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' | |
1638 | merged : f, ; |
|
1638 | merged : f, ; | |
1639 | ##### revision "mEAm-0 merge with copies info on both side - A side" ##### |
|
1639 | ##### revision "mEAm-0 merge with copies info on both side - A side" ##### | |
1640 | 1 sidedata entries |
|
1640 | 1 sidedata entries | |
1641 | entry-0014 size 14 |
|
1641 | entry-0014 size 14 | |
1642 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' |
|
1642 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' | |
1643 | merged : f, ; |
|
1643 | merged : f, ; | |
1644 | ##### revision "mPQm-0 merge with copies info on both side - P side" ##### |
|
1644 | ##### revision "mPQm-0 merge with copies info on both side - P side" ##### | |
1645 | 1 sidedata entries |
|
1645 | 1 sidedata entries | |
1646 | entry-0014 size 14 |
|
1646 | entry-0014 size 14 | |
1647 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v' |
|
1647 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v' | |
1648 | merged : v, ; |
|
1648 | merged : v, ; | |
1649 | ##### revision "mQPm-0 merge with copies info on both side - P side" ##### |
|
1649 | ##### revision "mQPm-0 merge with copies info on both side - P side" ##### | |
1650 | 1 sidedata entries |
|
1650 | 1 sidedata entries | |
1651 | entry-0014 size 14 |
|
1651 | entry-0014 size 14 | |
1652 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v' |
|
1652 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v' | |
1653 | merged : v, ; |
|
1653 | merged : v, ; | |
1654 | ##### revision "f-1" ##### |
|
1654 | ##### revision "f-1" ##### | |
1655 | 1 sidedata entries |
|
1655 | 1 sidedata entries | |
1656 | entry-0014 size 24 |
|
1656 | entry-0014 size 24 | |
1657 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi' |
|
1657 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi' | |
1658 | removed : h, ; |
|
1658 | removed : h, ; | |
1659 | added p1: i, h; |
|
1659 | added p1: i, h; | |
1660 | ##### revision "f-2" ##### |
|
1660 | ##### revision "f-2" ##### | |
1661 | 1 sidedata entries |
|
1661 | 1 sidedata entries | |
1662 | entry-0014 size 24 |
|
1662 | entry-0014 size 24 | |
1663 | '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di' |
|
1663 | '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di' | |
1664 | touched p1: d, i; |
|
1664 | touched p1: d, i; | |
1665 | removed : i, ; |
|
1665 | removed : i, ; | |
1666 | ##### revision "mBFm-0 simple merge - B side" ##### |
|
1666 | ##### revision "mBFm-0 simple merge - B side" ##### | |
1667 | 1 sidedata entries |
|
1667 | 1 sidedata entries | |
1668 | entry-0014 size 4 |
|
1668 | entry-0014 size 4 | |
1669 | '\x00\x00\x00\x00' |
|
1669 | '\x00\x00\x00\x00' | |
1670 | ##### revision "mFBm-0 simple merge - B side" ##### |
|
1670 | ##### revision "mFBm-0 simple merge - B side" ##### | |
1671 | 1 sidedata entries |
|
1671 | 1 sidedata entries | |
1672 | entry-0014 size 4 |
|
1672 | entry-0014 size 4 | |
1673 | '\x00\x00\x00\x00' |
|
1673 | '\x00\x00\x00\x00' | |
1674 | ##### revision "r-1" ##### |
|
1674 | ##### revision "r-1" ##### | |
1675 | 1 sidedata entries |
|
1675 | 1 sidedata entries | |
1676 | entry-0014 size 24 |
|
1676 | entry-0014 size 24 | |
1677 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rx' |
|
1677 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rx' | |
1678 | removed : r, ; |
|
1678 | removed : r, ; | |
1679 | added p1: x, r; |
|
1679 | added p1: x, r; | |
1680 | ##### revision "r-2" ##### |
|
1680 | ##### revision "r-2" ##### | |
1681 | 1 sidedata entries |
|
1681 | 1 sidedata entries | |
1682 | entry-0014 size 24 |
|
1682 | entry-0014 size 24 | |
1683 | '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00tx' |
|
1683 | '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00tx' | |
1684 | touched p1: t, x; |
|
1684 | touched p1: t, x; | |
1685 | removed : x, ; |
|
1685 | removed : x, ; | |
1686 | ##### revision "mBRm-0 simple merge - B side" ##### |
|
1686 | ##### revision "mBRm-0 simple merge - B side" ##### | |
1687 | 1 sidedata entries |
|
1687 | 1 sidedata entries | |
1688 | entry-0014 size 4 |
|
1688 | entry-0014 size 4 | |
1689 | '\x00\x00\x00\x00' |
|
1689 | '\x00\x00\x00\x00' | |
1690 | ##### revision "mRBm-0 simple merge - B side" ##### |
|
1690 | ##### revision "mRBm-0 simple merge - B side" ##### | |
1691 | 1 sidedata entries |
|
1691 | 1 sidedata entries | |
1692 | entry-0014 size 4 |
|
1692 | entry-0014 size 4 | |
1693 | '\x00\x00\x00\x00' |
|
1693 | '\x00\x00\x00\x00' | |
1694 | ##### revision "g-1" ##### |
|
1694 | ##### revision "g-1" ##### | |
1695 | 1 sidedata entries |
|
1695 | 1 sidedata entries | |
1696 | entry-0014 size 14 |
|
1696 | entry-0014 size 14 | |
1697 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1697 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1698 | touched : d, ; |
|
1698 | touched : d, ; | |
1699 | ##### revision "mDGm-0 actual content merge, copies on one side - D side" ##### |
|
1699 | ##### revision "mDGm-0 actual content merge, copies on one side - D side" ##### | |
1700 | 1 sidedata entries |
|
1700 | 1 sidedata entries | |
1701 | entry-0014 size 14 |
|
1701 | entry-0014 size 14 | |
1702 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1702 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1703 | merged : d, ; |
|
1703 | merged : d, ; | |
1704 | ##### revision "mGDm-0 actual content merge, copies on one side - D side" ##### |
|
1704 | ##### revision "mGDm-0 actual content merge, copies on one side - D side" ##### | |
1705 | 1 sidedata entries |
|
1705 | 1 sidedata entries | |
1706 | entry-0014 size 14 |
|
1706 | entry-0014 size 14 | |
1707 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1707 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1708 | merged : d, ; |
|
1708 | merged : d, ; | |
1709 | ##### revision "mFGm-0 merge - G side" ##### |
|
1709 | ##### revision "mFGm-0 merge - G side" ##### | |
1710 | 1 sidedata entries |
|
1710 | 1 sidedata entries | |
1711 | entry-0014 size 14 |
|
1711 | entry-0014 size 14 | |
1712 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1712 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1713 | merged : d, ; |
|
1713 | merged : d, ; | |
1714 | ##### revision "mGFm-0 merge - G side" ##### |
|
1714 | ##### revision "mGFm-0 merge - G side" ##### | |
1715 | 1 sidedata entries |
|
1715 | 1 sidedata entries | |
1716 | entry-0014 size 14 |
|
1716 | entry-0014 size 14 | |
1717 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1717 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1718 | merged : d, ; |
|
1718 | merged : d, ; | |
1719 | ##### revision "mCGm-0 merge updated/deleted - revive the file (updated content) - one way" ##### |
|
1719 | ##### revision "mCGm-0 merge updated/deleted - revive the file (updated content) - one way" ##### | |
1720 | 1 sidedata entries |
|
1720 | 1 sidedata entries | |
1721 | entry-0014 size 14 |
|
1721 | entry-0014 size 14 | |
1722 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1722 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1723 | salvaged : d, ; |
|
1723 | salvaged : d, ; | |
1724 | ##### revision "mGCm-0 merge updated/deleted - revive the file (updated content) - the other way" ##### |
|
1724 | ##### revision "mGCm-0 merge updated/deleted - revive the file (updated content) - the other way" ##### | |
1725 | 1 sidedata entries |
|
1725 | 1 sidedata entries | |
1726 | entry-0014 size 14 |
|
1726 | entry-0014 size 14 | |
1727 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1727 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1728 | salvaged : d, ; |
|
1728 | salvaged : d, ; | |
1729 | ##### revision "mCB-revert-m-0 merge explicitely revive deleted file - B side" ##### |
|
1729 | ##### revision "mCB-revert-m-0 merge explicitely revive deleted file - B side" ##### | |
1730 | 1 sidedata entries |
|
1730 | 1 sidedata entries | |
1731 | entry-0014 size 14 |
|
1731 | entry-0014 size 14 | |
1732 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1732 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1733 | salvaged : d, ; |
|
1733 | salvaged : d, ; | |
1734 | ##### revision "mBC-revert-m-0 merge explicitely revive deleted file - B side" ##### |
|
1734 | ##### revision "mBC-revert-m-0 merge explicitely revive deleted file - B side" ##### | |
1735 | 1 sidedata entries |
|
1735 | 1 sidedata entries | |
1736 | entry-0014 size 14 |
|
1736 | entry-0014 size 14 | |
1737 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1737 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' | |
1738 | salvaged : d, ; |
|
1738 | salvaged : d, ; | |
1739 | ##### revision "h-1" ##### |
|
1739 | ##### revision "h-1" ##### | |
1740 | 1 sidedata entries |
|
1740 | 1 sidedata entries | |
1741 | entry-0014 size 24 |
|
1741 | entry-0014 size 24 | |
1742 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bd' |
|
1742 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bd' | |
1743 | removed : b, ; |
|
1743 | removed : b, ; | |
1744 | added p1: d, b; |
|
1744 | added p1: d, b; | |
1745 | ##### revision "mCH-delete-before-conflict-m-0 simple merge - C side" ##### |
|
1745 | ##### revision "mCH-delete-before-conflict-m-0 simple merge - C side" ##### | |
1746 | 1 sidedata entries |
|
1746 | 1 sidedata entries | |
1747 | entry-0014 size 4 |
|
1747 | entry-0014 size 4 | |
1748 | '\x00\x00\x00\x00' |
|
1748 | '\x00\x00\x00\x00' | |
1749 | ##### revision "mHC-delete-before-conflict-m-0 simple merge - C side" ##### |
|
1749 | ##### revision "mHC-delete-before-conflict-m-0 simple merge - C side" ##### | |
1750 | 1 sidedata entries |
|
1750 | 1 sidedata entries | |
1751 | entry-0014 size 4 |
|
1751 | entry-0014 size 4 | |
1752 | '\x00\x00\x00\x00' |
|
1752 | '\x00\x00\x00\x00' | |
1753 | ##### revision "mAE-change-m-0 merge with file update and copies info on both side - A side" ##### |
|
1753 | ##### revision "mAE-change-m-0 merge with file update and copies info on both side - A side" ##### | |
1754 | 1 sidedata entries |
|
1754 | 1 sidedata entries | |
1755 | entry-0014 size 14 |
|
1755 | entry-0014 size 14 | |
1756 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' |
|
1756 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' | |
1757 | merged : f, ; |
|
1757 | merged : f, ; | |
1758 | ##### revision "mEA-change-m-0 merge with file update and copies info on both side - A side" ##### |
|
1758 | ##### revision "mEA-change-m-0 merge with file update and copies info on both side - A side" ##### | |
1759 | 1 sidedata entries |
|
1759 | 1 sidedata entries | |
1760 | entry-0014 size 14 |
|
1760 | entry-0014 size 14 | |
1761 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' |
|
1761 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' | |
1762 | merged : f, ; |
|
1762 | merged : f, ; | |
1763 | ##### revision "j-1" ##### |
|
1763 | ##### revision "j-1" ##### | |
1764 | 1 sidedata entries |
|
1764 | 1 sidedata entries | |
1765 | entry-0014 size 24 |
|
1765 | entry-0014 size 24 | |
1766 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j' |
|
1766 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j' | |
1767 | added : unrelated-j, ; |
|
1767 | added : unrelated-j, ; | |
1768 | ##### revision "k-1" ##### |
|
1768 | ##### revision "k-1" ##### | |
1769 | 1 sidedata entries |
|
1769 | 1 sidedata entries | |
1770 | entry-0014 size 24 |
|
1770 | entry-0014 size 24 | |
1771 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-k' |
|
1771 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-k' | |
1772 | added : unrelated-k, ; |
|
1772 | added : unrelated-k, ; | |
1773 | ##### revision "mAE,Km" ##### |
|
1773 | ##### revision "mAE,Km" ##### | |
1774 | 1 sidedata entries |
|
1774 | 1 sidedata entries | |
1775 | entry-0014 size 4 |
|
1775 | entry-0014 size 4 | |
1776 | '\x00\x00\x00\x00' |
|
1776 | '\x00\x00\x00\x00' | |
1777 | ##### revision "mK,AEm" ##### |
|
1777 | ##### revision "mK,AEm" ##### | |
1778 | 1 sidedata entries |
|
1778 | 1 sidedata entries | |
1779 | entry-0014 size 4 |
|
1779 | entry-0014 size 4 | |
1780 | '\x00\x00\x00\x00' |
|
1780 | '\x00\x00\x00\x00' | |
1781 | ##### revision "mEA,Jm" ##### |
|
1781 | ##### revision "mEA,Jm" ##### | |
1782 | 1 sidedata entries |
|
1782 | 1 sidedata entries | |
1783 | entry-0014 size 4 |
|
1783 | entry-0014 size 4 | |
1784 | '\x00\x00\x00\x00' |
|
1784 | '\x00\x00\x00\x00' | |
1785 | ##### revision "mJ,EAm" ##### |
|
1785 | ##### revision "mJ,EAm" ##### | |
1786 | 1 sidedata entries |
|
1786 | 1 sidedata entries | |
1787 | entry-0014 size 4 |
|
1787 | entry-0014 size 4 | |
1788 | '\x00\x00\x00\x00' |
|
1788 | '\x00\x00\x00\x00' | |
1789 | ##### revision "s-1" ##### |
|
1789 | ##### revision "s-1" ##### | |
1790 | 1 sidedata entries |
|
1790 | 1 sidedata entries | |
1791 | entry-0014 size 24 |
|
1791 | entry-0014 size 24 | |
1792 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-s' |
|
1792 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-s' | |
1793 | added : unrelated-s, ; |
|
1793 | added : unrelated-s, ; | |
1794 | ##### revision "t-1" ##### |
|
1794 | ##### revision "t-1" ##### | |
1795 | 1 sidedata entries |
|
1795 | 1 sidedata entries | |
1796 | entry-0014 size 24 |
|
1796 | entry-0014 size 24 | |
1797 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-t' |
|
1797 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-t' | |
1798 | added : unrelated-t, ; |
|
1798 | added : unrelated-t, ; | |
1799 | ##### revision "mPQ,Tm" ##### |
|
1799 | ##### revision "mPQ,Tm" ##### | |
1800 | 1 sidedata entries |
|
1800 | 1 sidedata entries | |
1801 | entry-0014 size 4 |
|
1801 | entry-0014 size 4 | |
1802 | '\x00\x00\x00\x00' |
|
1802 | '\x00\x00\x00\x00' | |
1803 | ##### revision "mT,PQm" ##### |
|
1803 | ##### revision "mT,PQm" ##### | |
1804 | 1 sidedata entries |
|
1804 | 1 sidedata entries | |
1805 | entry-0014 size 4 |
|
1805 | entry-0014 size 4 | |
1806 | '\x00\x00\x00\x00' |
|
1806 | '\x00\x00\x00\x00' | |
1807 | ##### revision "mQP,Sm" ##### |
|
1807 | ##### revision "mQP,Sm" ##### | |
1808 | 1 sidedata entries |
|
1808 | 1 sidedata entries | |
1809 | entry-0014 size 4 |
|
1809 | entry-0014 size 4 | |
1810 | '\x00\x00\x00\x00' |
|
1810 | '\x00\x00\x00\x00' | |
1811 | ##### revision "mS,QPm" ##### |
|
1811 | ##### revision "mS,QPm" ##### | |
1812 | 1 sidedata entries |
|
1812 | 1 sidedata entries | |
1813 | entry-0014 size 4 |
|
1813 | entry-0014 size 4 | |
1814 | '\x00\x00\x00\x00' |
|
1814 | '\x00\x00\x00\x00' | |
1815 | ##### revision "l-1" ##### |
|
1815 | ##### revision "l-1" ##### | |
1816 | 1 sidedata entries |
|
1816 | 1 sidedata entries | |
1817 | entry-0014 size 24 |
|
1817 | entry-0014 size 24 | |
1818 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-l' |
|
1818 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-l' | |
1819 | added : unrelated-l, ; |
|
1819 | added : unrelated-l, ; | |
1820 | ##### revision "mBC+revert,Lm" ##### |
|
1820 | ##### revision "mBC+revert,Lm" ##### | |
1821 | 1 sidedata entries |
|
1821 | 1 sidedata entries | |
1822 | entry-0014 size 4 |
|
1822 | entry-0014 size 4 | |
1823 | '\x00\x00\x00\x00' |
|
1823 | '\x00\x00\x00\x00' | |
1824 | ##### revision "mCB+revert,Lm" ##### |
|
1824 | ##### revision "mCB+revert,Lm" ##### | |
1825 | 1 sidedata entries |
|
1825 | 1 sidedata entries | |
1826 | entry-0014 size 4 |
|
1826 | entry-0014 size 4 | |
1827 | '\x00\x00\x00\x00' |
|
1827 | '\x00\x00\x00\x00' | |
1828 | ##### revision "mL,BC+revertm" ##### |
|
1828 | ##### revision "mL,BC+revertm" ##### | |
1829 | 1 sidedata entries |
|
1829 | 1 sidedata entries | |
1830 | entry-0014 size 4 |
|
1830 | entry-0014 size 4 | |
1831 | '\x00\x00\x00\x00' |
|
1831 | '\x00\x00\x00\x00' | |
1832 | ##### revision "mL,CB+revertm" ##### |
|
1832 | ##### revision "mL,CB+revertm" ##### | |
1833 | 1 sidedata entries |
|
1833 | 1 sidedata entries | |
1834 | entry-0014 size 4 |
|
1834 | entry-0014 size 4 | |
1835 | '\x00\x00\x00\x00' |
|
1835 | '\x00\x00\x00\x00' | |
1836 | ##### revision "n-1" ##### |
|
1836 | ##### revision "n-1" ##### | |
1837 | 1 sidedata entries |
|
1837 | 1 sidedata entries | |
1838 | entry-0014 size 24 |
|
1838 | entry-0014 size 24 | |
1839 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-n' |
|
1839 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-n' | |
1840 | added : unrelated-n, ; |
|
1840 | added : unrelated-n, ; | |
1841 | ##### revision "o-1" ##### |
|
1841 | ##### revision "o-1" ##### | |
1842 | 1 sidedata entries |
|
1842 | 1 sidedata entries | |
1843 | entry-0014 size 24 |
|
1843 | entry-0014 size 24 | |
1844 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-o' |
|
1844 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-o' | |
1845 | added : unrelated-o, ; |
|
1845 | added : unrelated-o, ; | |
1846 | ##### revision "mFG,Om" ##### |
|
1846 | ##### revision "mFG,Om" ##### | |
1847 | 1 sidedata entries |
|
1847 | 1 sidedata entries | |
1848 | entry-0014 size 4 |
|
1848 | entry-0014 size 4 | |
1849 | '\x00\x00\x00\x00' |
|
1849 | '\x00\x00\x00\x00' | |
1850 | ##### revision "mO,FGm" ##### |
|
1850 | ##### revision "mO,FGm" ##### | |
1851 | 1 sidedata entries |
|
1851 | 1 sidedata entries | |
1852 | entry-0014 size 4 |
|
1852 | entry-0014 size 4 | |
1853 | '\x00\x00\x00\x00' |
|
1853 | '\x00\x00\x00\x00' | |
1854 | ##### revision "mGF,Nm" ##### |
|
1854 | ##### revision "mGF,Nm" ##### | |
1855 | 1 sidedata entries |
|
1855 | 1 sidedata entries | |
1856 | entry-0014 size 4 |
|
1856 | entry-0014 size 4 | |
1857 | '\x00\x00\x00\x00' |
|
1857 | '\x00\x00\x00\x00' | |
1858 | ##### revision "mN,GFm" ##### |
|
1858 | ##### revision "mN,GFm" ##### | |
1859 | 1 sidedata entries |
|
1859 | 1 sidedata entries | |
1860 | entry-0014 size 4 |
|
1860 | entry-0014 size 4 | |
1861 | '\x00\x00\x00\x00' |
|
1861 | '\x00\x00\x00\x00' | |
1862 | ##### revision "mAE-change,Km" ##### |
|
1862 | ##### revision "mAE-change,Km" ##### | |
1863 | 1 sidedata entries |
|
1863 | 1 sidedata entries | |
1864 | entry-0014 size 4 |
|
1864 | entry-0014 size 4 | |
1865 | '\x00\x00\x00\x00' |
|
1865 | '\x00\x00\x00\x00' | |
1866 | ##### revision "mK,AE-change-m" ##### |
|
1866 | ##### revision "mK,AE-change-m" ##### | |
1867 | 1 sidedata entries |
|
1867 | 1 sidedata entries | |
1868 | entry-0014 size 4 |
|
1868 | entry-0014 size 4 | |
1869 | '\x00\x00\x00\x00' |
|
1869 | '\x00\x00\x00\x00' | |
1870 | ##### revision "mEA-change,Jm" ##### |
|
1870 | ##### revision "mEA-change,Jm" ##### | |
1871 | 1 sidedata entries |
|
1871 | 1 sidedata entries | |
1872 | entry-0014 size 4 |
|
1872 | entry-0014 size 4 | |
1873 | '\x00\x00\x00\x00' |
|
1873 | '\x00\x00\x00\x00' | |
1874 | ##### revision "mJ,EA-change-m" ##### |
|
1874 | ##### revision "mJ,EA-change-m" ##### | |
1875 | 1 sidedata entries |
|
1875 | 1 sidedata entries | |
1876 | entry-0014 size 4 |
|
1876 | entry-0014 size 4 | |
1877 | '\x00\x00\x00\x00' |
|
1877 | '\x00\x00\x00\x00' | |
1878 |
|
1878 | |||
1879 | #endif |
|
1879 | #endif | |
1880 |
|
1880 | |||
1881 |
|
1881 | |||
1882 | Test copy information chaining |
|
1882 | Test copy information chaining | |
1883 | ============================== |
|
1883 | ============================== | |
1884 |
|
1884 | |||
1885 | Check that matching only affect the destination and not intermediate path |
|
1885 | Check that matching only affect the destination and not intermediate path | |
1886 | ------------------------------------------------------------------------- |
|
1886 | ------------------------------------------------------------------------- | |
1887 |
|
1887 | |||
1888 | The two status call should give the same value for f |
|
1888 | The two status call should give the same value for f | |
1889 |
|
1889 | |||
1890 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' |
|
1890 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' | |
1891 | A f |
|
1891 | A f | |
1892 | a |
|
1892 | a | |
1893 | A t |
|
1893 | A t | |
1894 | p |
|
1894 | p | |
1895 | R a |
|
1895 | R a | |
1896 | R p |
|
1896 | R p | |
1897 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' f |
|
1897 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' f | |
1898 | A f |
|
1898 | A f | |
1899 | a (no-changeset no-compatibility !) |
|
1899 | a (no-changeset no-compatibility !) | |
1900 |
|
1900 | |||
1901 | merging with unrelated change does not interfere with the renames |
|
1901 | merging with unrelated change does not interfere with the renames | |
1902 | --------------------------------------------------------------- |
|
1902 | --------------------------------------------------------------- | |
1903 |
|
1903 | |||
1904 | - rename on one side |
|
1904 | - rename on one side | |
1905 | - unrelated change on the other side |
|
1905 | - unrelated change on the other side | |
1906 |
|
1906 | |||
1907 | $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))' |
|
1907 | $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))' | |
1908 | o mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way |
|
1908 | o mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way | |
1909 | |\ |
|
1909 | |\ | |
1910 | +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way |
|
1910 | +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way | |
1911 | | |/ |
|
1911 | | |/ | |
1912 | | o b-1: b update |
|
1912 | | o b-1: b update | |
1913 | | | |
|
1913 | | | | |
1914 | o | a-2: e -move-> f |
|
1914 | o | a-2: e -move-> f | |
1915 | | | |
|
1915 | | | | |
1916 | o | a-1: d -move-> e |
|
1916 | o | a-1: d -move-> e | |
1917 | |/ |
|
1917 | |/ | |
1918 | o i-2: c -move-> d, s -move-> t |
|
1918 | o i-2: c -move-> d, s -move-> t | |
1919 | | |
|
1919 | | | |
1920 | o i-1: a -move-> c, p -move-> s |
|
1920 | o i-1: a -move-> c, p -move-> s | |
1921 | | |
|
1921 | | | |
1922 | o i-0 initial commit: a b h |
|
1922 | o i-0 initial commit: a b h | |
1923 |
|
1923 | |||
1924 |
|
1924 | |||
1925 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")' |
|
1925 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")' | |
1926 | A f |
|
1926 | A f | |
1927 | d |
|
1927 | d | |
1928 | R d |
|
1928 | R d | |
1929 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")' |
|
1929 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")' | |
1930 | A f |
|
1930 | A f | |
1931 | d |
|
1931 | d | |
1932 | R d |
|
1932 | R d | |
1933 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")' |
|
1933 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")' | |
1934 | M b |
|
1934 | M b | |
1935 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")' |
|
1935 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")' | |
1936 | M b |
|
1936 | M b | |
1937 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")' |
|
1937 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")' | |
1938 | M b |
|
1938 | M b | |
1939 | A f |
|
1939 | A f | |
1940 | d |
|
1940 | d | |
1941 | R d |
|
1941 | R d | |
1942 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")' |
|
1942 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")' | |
1943 | M b |
|
1943 | M b | |
1944 | A f |
|
1944 | A f | |
1945 | d |
|
1945 | d | |
1946 | R d |
|
1946 | R d | |
1947 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")' |
|
1947 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")' | |
1948 | M b |
|
1948 | M b | |
1949 | A f |
|
1949 | A f | |
1950 | a |
|
1950 | a | |
1951 | A t |
|
1951 | A t | |
1952 | p |
|
1952 | p | |
1953 | R a |
|
1953 | R a | |
1954 | R p |
|
1954 | R p | |
1955 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")' |
|
1955 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")' | |
1956 | M b |
|
1956 | M b | |
1957 | A f |
|
1957 | A f | |
1958 | a |
|
1958 | a | |
1959 | A t |
|
1959 | A t | |
1960 | p |
|
1960 | p | |
1961 | R a |
|
1961 | R a | |
1962 | R p |
|
1962 | R p | |
1963 |
|
1963 | |||
1964 | merging with the side having a delete |
|
1964 | merging with the side having a delete | |
1965 | ------------------------------------- |
|
1965 | ------------------------------------- | |
1966 |
|
1966 | |||
1967 | case summary: |
|
1967 | case summary: | |
1968 | - one with change to an unrelated file |
|
1968 | - one with change to an unrelated file | |
1969 | - one deleting the change |
|
1969 | - one deleting the change | |
1970 | and recreate an unrelated file after the merge |
|
1970 | and recreate an unrelated file after the merge | |
1971 |
|
1971 | |||
1972 | $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))' |
|
1972 | $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))' | |
1973 | o mCBm-1 re-add d |
|
1973 | o mCBm-1 re-add d | |
1974 | | |
|
1974 | | | |
1975 | o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way |
|
1975 | o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way | |
1976 | |\ |
|
1976 | |\ | |
1977 | | | o mBCm-1 re-add d |
|
1977 | | | o mBCm-1 re-add d | |
1978 | | | | |
|
1978 | | | | | |
1979 | +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way |
|
1979 | +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way | |
1980 | | |/ |
|
1980 | | |/ | |
1981 | | o c-1 delete d |
|
1981 | | o c-1 delete d | |
1982 | | | |
|
1982 | | | | |
1983 | o | b-1: b update |
|
1983 | o | b-1: b update | |
1984 | |/ |
|
1984 | |/ | |
1985 | o i-2: c -move-> d, s -move-> t |
|
1985 | o i-2: c -move-> d, s -move-> t | |
1986 | | |
|
1986 | | | |
1987 | o i-1: a -move-> c, p -move-> s |
|
1987 | o i-1: a -move-> c, p -move-> s | |
1988 | | |
|
1988 | | | |
1989 | o i-0 initial commit: a b h |
|
1989 | o i-0 initial commit: a b h | |
1990 |
|
1990 | |||
1991 | - comparing from the merge |
|
1991 | - comparing from the merge | |
1992 |
|
1992 | |||
1993 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")' |
|
1993 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")' | |
1994 | R d |
|
1994 | R d | |
1995 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")' |
|
1995 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")' | |
1996 | R d |
|
1996 | R d | |
1997 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")' |
|
1997 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")' | |
1998 | M b |
|
1998 | M b | |
1999 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")' |
|
1999 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")' | |
2000 | M b |
|
2000 | M b | |
2001 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")' |
|
2001 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")' | |
2002 | M b |
|
2002 | M b | |
2003 | R d |
|
2003 | R d | |
2004 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")' |
|
2004 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")' | |
2005 | M b |
|
2005 | M b | |
2006 | R d |
|
2006 | R d | |
2007 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")' |
|
2007 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")' | |
2008 | M b |
|
2008 | M b | |
2009 | A t |
|
2009 | A t | |
2010 | p |
|
2010 | p | |
2011 | R a |
|
2011 | R a | |
2012 | R p |
|
2012 | R p | |
2013 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")' |
|
2013 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")' | |
2014 | M b |
|
2014 | M b | |
2015 | A t |
|
2015 | A t | |
2016 | p |
|
2016 | p | |
2017 | R a |
|
2017 | R a | |
2018 | R p |
|
2018 | R p | |
2019 |
|
2019 | |||
2020 | - comparing with the merge children re-adding the file |
|
2020 | - comparing with the merge children re-adding the file | |
2021 |
|
2021 | |||
2022 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")' |
|
2022 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")' | |
2023 | M d |
|
2023 | M d | |
2024 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")' |
|
2024 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")' | |
2025 | M d |
|
2025 | M d | |
2026 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")' |
|
2026 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")' | |
2027 | M b |
|
2027 | M b | |
2028 | A d |
|
2028 | A d | |
2029 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")' |
|
2029 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")' | |
2030 | M b |
|
2030 | M b | |
2031 | A d |
|
2031 | A d | |
2032 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")' |
|
2032 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")' | |
2033 | M b |
|
2033 | M b | |
2034 | M d |
|
2034 | M d | |
2035 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")' |
|
2035 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")' | |
2036 | M b |
|
2036 | M b | |
2037 | M d |
|
2037 | M d | |
2038 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")' |
|
2038 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")' | |
2039 | M b |
|
2039 | M b | |
2040 | A d |
|
2040 | A d | |
2041 | A t |
|
2041 | A t | |
2042 | p |
|
2042 | p | |
2043 | R a |
|
2043 | R a | |
2044 | R p |
|
2044 | R p | |
2045 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")' |
|
2045 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")' | |
2046 | M b |
|
2046 | M b | |
2047 | A d |
|
2047 | A d | |
2048 | A t |
|
2048 | A t | |
2049 | p |
|
2049 | p | |
2050 | R a |
|
2050 | R a | |
2051 | R p |
|
2051 | R p | |
2052 |
|
2052 | |||
2053 | Comparing with a merge re-adding the file afterward |
|
2053 | Comparing with a merge re-adding the file afterward | |
2054 | --------------------------------------------------- |
|
2054 | --------------------------------------------------- | |
2055 |
|
2055 | |||
2056 | Merge: |
|
2056 | Merge: | |
2057 | - one with change to an unrelated file |
|
2057 | - one with change to an unrelated file | |
2058 | - one deleting and recreating the change |
|
2058 | - one deleting and recreating the change | |
2059 |
|
2059 | |||
2060 | $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))' |
|
2060 | $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))' | |
2061 | o mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way |
|
2061 | o mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way | |
2062 | |\ |
|
2062 | |\ | |
2063 | +---o mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way |
|
2063 | +---o mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way | |
2064 | | |/ |
|
2064 | | |/ | |
2065 | | o d-2 re-add d |
|
2065 | | o d-2 re-add d | |
2066 | | | |
|
2066 | | | | |
2067 | | o d-1 delete d |
|
2067 | | o d-1 delete d | |
2068 | | | |
|
2068 | | | | |
2069 | o | b-1: b update |
|
2069 | o | b-1: b update | |
2070 | |/ |
|
2070 | |/ | |
2071 | o i-2: c -move-> d, s -move-> t |
|
2071 | o i-2: c -move-> d, s -move-> t | |
2072 | | |
|
2072 | | | |
2073 | o i-1: a -move-> c, p -move-> s |
|
2073 | o i-1: a -move-> c, p -move-> s | |
2074 | | |
|
2074 | | | |
2075 | o i-0 initial commit: a b h |
|
2075 | o i-0 initial commit: a b h | |
2076 |
|
2076 | |||
2077 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")' |
|
2077 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")' | |
2078 | M d |
|
2078 | M d | |
2079 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")' |
|
2079 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")' | |
2080 | M d |
|
2080 | M d | |
2081 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")' |
|
2081 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")' | |
2082 | M b |
|
2082 | M b | |
2083 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")' |
|
2083 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")' | |
2084 | M b |
|
2084 | M b | |
2085 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")' |
|
2085 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")' | |
2086 | M b |
|
2086 | M b | |
2087 | M d |
|
2087 | M d | |
2088 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")' |
|
2088 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")' | |
2089 | M b |
|
2089 | M b | |
2090 | M d |
|
2090 | M d | |
2091 |
|
2091 | |||
2092 | The bugs makes recorded copy is different depending of where we started the merge from since |
|
2092 | The bugs makes recorded copy is different depending of where we started the merge from since | |
2093 |
|
2093 | |||
2094 | $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d' |
|
2094 | $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d' | |
2095 | b004912a8510032a0350a74daa2803dadfb00e12 644 d |
|
2095 | b004912a8510032a0350a74daa2803dadfb00e12 644 d | |
2096 | $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d' |
|
2096 | $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d' | |
2097 | b004912a8510032a0350a74daa2803dadfb00e12 644 d |
|
2097 | b004912a8510032a0350a74daa2803dadfb00e12 644 d | |
2098 |
|
2098 | |||
2099 | $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d' |
|
2099 | $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d' | |
2100 | b004912a8510032a0350a74daa2803dadfb00e12 644 d |
|
2100 | b004912a8510032a0350a74daa2803dadfb00e12 644 d | |
2101 | $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d' |
|
2101 | $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d' | |
2102 | d8252ab2e760b0d4e5288fd44cbd15a0fa567e16 644 d (no-changeset !) |
|
2102 | d8252ab2e760b0d4e5288fd44cbd15a0fa567e16 644 d (no-changeset !) | |
2103 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !) |
|
2103 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !) | |
2104 | $ hg debugindex d | head -n 4 | ../no-linkrev |
|
2104 | $ hg debugindex d | head -n 4 | ../no-linkrev | |
2105 | rev linkrev nodeid p1 p2 |
|
2105 | rev linkrev nodeid p1 p2 | |
2106 | 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !) |
|
2106 | 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !) | |
2107 | 0 * ae258f702dfe 000000000000 000000000000 (changeset !) |
|
2107 | 0 * ae258f702dfe 000000000000 000000000000 (changeset !) | |
2108 | 1 * b004912a8510 000000000000 000000000000 |
|
2108 | 1 * b004912a8510 000000000000 000000000000 | |
2109 | 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !) |
|
2109 | 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !) | |
2110 | 2 * 5cce88bf349f ae258f702dfe 000000000000 (changeset !) |
|
2110 | 2 * 5cce88bf349f ae258f702dfe 000000000000 (changeset !) | |
2111 |
|
2111 | |||
2112 | Log output should not include a merge commit as it did not happen |
|
2112 | Log output should not include a merge commit as it did not happen | |
2113 |
|
2113 | |||
2114 | $ hg log -Gfr 'desc("mBDm-0")' d |
|
2114 | $ hg log -Gfr 'desc("mBDm-0")' d | |
2115 | o d-2 re-add d |
|
2115 | o d-2 re-add d | |
2116 | | |
|
2116 | | | |
2117 | ~ |
|
2117 | ~ | |
2118 |
|
2118 | |||
2119 | $ hg log -Gfr 'desc("mDBm-0")' d |
|
2119 | $ hg log -Gfr 'desc("mDBm-0")' d | |
2120 | o d-2 re-add d |
|
2120 | o d-2 re-add d | |
2121 | | |
|
2121 | | | |
2122 | ~ |
|
2122 | ~ | |
2123 |
|
2123 | |||
2124 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")' |
|
2124 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")' | |
2125 | M b |
|
2125 | M b | |
2126 | A d |
|
2126 | A d | |
2127 | A t |
|
2127 | A t | |
2128 | p |
|
2128 | p | |
2129 | R a |
|
2129 | R a | |
2130 | R p |
|
2130 | R p | |
2131 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")' |
|
2131 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")' | |
2132 | M b |
|
2132 | M b | |
2133 | A d |
|
2133 | A d | |
2134 | A t |
|
2134 | A t | |
2135 | p |
|
2135 | p | |
2136 | R a |
|
2136 | R a | |
2137 | R p |
|
2137 | R p | |
2138 |
|
2138 | |||
2139 |
|
2139 | |||
2140 | Comparing with a merge with colliding rename |
|
2140 | Comparing with a merge with colliding rename | |
2141 | -------------------------------------------- |
|
2141 | -------------------------------------------- | |
2142 |
|
2142 | |||
2143 | Subcase: new copy information on both side |
|
2143 | Subcase: new copy information on both side | |
2144 | `````````````````````````````````````````` |
|
2144 | `````````````````````````````````````````` | |
2145 |
|
2145 | |||
2146 | - the "e-" branch renaming b to f (through 'g') |
|
2146 | - the "e-" branch renaming b to f (through 'g') | |
2147 | - the "a-" branch renaming d to f (through e) |
|
2147 | - the "a-" branch renaming d to f (through e) | |
2148 |
|
2148 | |||
2149 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' |
|
2149 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' | |
2150 | o mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way |
|
2150 | o mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way | |
2151 | |\ |
|
2151 | |\ | |
2152 | +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way |
|
2152 | +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way | |
2153 | | |/ |
|
2153 | | |/ | |
2154 | | o e-2 g -move-> f |
|
2154 | | o e-2 g -move-> f | |
2155 | | | |
|
2155 | | | | |
2156 | | o e-1 b -move-> g |
|
2156 | | o e-1 b -move-> g | |
2157 | | | |
|
2157 | | | | |
2158 | o | a-2: e -move-> f |
|
2158 | o | a-2: e -move-> f | |
2159 | | | |
|
2159 | | | | |
2160 | o | a-1: d -move-> e |
|
2160 | o | a-1: d -move-> e | |
2161 | |/ |
|
2161 | |/ | |
2162 | o i-2: c -move-> d, s -move-> t |
|
2162 | o i-2: c -move-> d, s -move-> t | |
2163 | | |
|
2163 | | | |
2164 | o i-1: a -move-> c, p -move-> s |
|
2164 | o i-1: a -move-> c, p -move-> s | |
2165 | | |
|
2165 | | | |
2166 | o i-0 initial commit: a b h |
|
2166 | o i-0 initial commit: a b h | |
2167 |
|
2167 | |||
2168 | #if no-changeset |
|
2168 | #if no-changeset | |
2169 | $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f' |
|
2169 | $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f' | |
2170 | 2ff93c643948464ee1f871867910ae43a45b0bea 644 f |
|
2170 | 2ff93c643948464ee1f871867910ae43a45b0bea 644 f | |
2171 | $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f' |
|
2171 | $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f' | |
2172 | 2ff93c643948464ee1f871867910ae43a45b0bea 644 f |
|
2172 | 2ff93c643948464ee1f871867910ae43a45b0bea 644 f | |
2173 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' |
|
2173 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' | |
2174 | b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f |
|
2174 | b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f | |
2175 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' |
|
2175 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' | |
2176 | e8825b386367b29fec957283a80bb47b47483fe1 644 f |
|
2176 | e8825b386367b29fec957283a80bb47b47483fe1 644 f | |
2177 | $ hg debugindex f | ../no-linkrev |
|
2177 | $ hg debugindex f | ../no-linkrev | |
2178 | rev linkrev nodeid p1 p2 |
|
2178 | rev linkrev nodeid p1 p2 | |
2179 | 0 * b76eb76580df 000000000000 000000000000 |
|
2179 | 0 * b76eb76580df 000000000000 000000000000 | |
2180 | 1 * e8825b386367 000000000000 000000000000 |
|
2180 | 1 * e8825b386367 000000000000 000000000000 | |
2181 | 2 * 2ff93c643948 b76eb76580df e8825b386367 |
|
2181 | 2 * 2ff93c643948 b76eb76580df e8825b386367 | |
2182 | 3 * 2f649fba7eb2 b76eb76580df e8825b386367 |
|
2182 | 3 * 2f649fba7eb2 b76eb76580df e8825b386367 | |
2183 | 4 * 774e7c1637d5 e8825b386367 b76eb76580df |
|
2183 | 4 * 774e7c1637d5 e8825b386367 b76eb76580df | |
2184 | #else |
|
2184 | #else | |
2185 | $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f' |
|
2185 | $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f' | |
2186 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
2186 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f | |
2187 | $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f' |
|
2187 | $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f' | |
2188 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
2188 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f | |
2189 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' |
|
2189 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' | |
2190 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
2190 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f | |
2191 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' |
|
2191 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' | |
2192 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
2192 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f | |
2193 | $ hg debugindex f | ../no-linkrev |
|
2193 | $ hg debugindex f | ../no-linkrev | |
2194 | rev linkrev nodeid p1 p2 |
|
2194 | rev linkrev nodeid p1 p2 | |
2195 | 0 * ae258f702dfe 000000000000 000000000000 |
|
2195 | 0 * ae258f702dfe 000000000000 000000000000 | |
2196 | 1 * d3613c1ec831 ae258f702dfe 000000000000 |
|
2196 | 1 * d3613c1ec831 ae258f702dfe 000000000000 | |
2197 | 2 * 05e03c868bbc ae258f702dfe 000000000000 |
|
2197 | 2 * 05e03c868bbc ae258f702dfe 000000000000 | |
2198 | #endif |
|
2198 | #endif | |
2199 |
|
2199 | |||
2200 | # Here the filelog based implementation is not looking at the rename |
|
2200 | # Here the filelog based implementation is not looking at the rename | |
2201 | # information (because the file exist on both side). However the changelog |
|
2201 | # information (because the file exist on both side). However the changelog | |
2202 | # based on works fine. We have different output. |
|
2202 | # based on works fine. We have different output. | |
2203 |
|
2203 | |||
2204 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")' |
|
2204 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")' | |
2205 | M f (no-changeset !) |
|
2205 | M f (no-changeset !) | |
2206 | b (no-filelog no-changeset !) |
|
2206 | b (no-filelog no-changeset !) | |
2207 | R b |
|
2207 | R b | |
2208 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")' |
|
2208 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")' | |
2209 | M f (no-changeset !) |
|
2209 | M f (no-changeset !) | |
2210 | b (no-filelog no-changeset !) |
|
2210 | b (no-filelog no-changeset !) | |
2211 | R b |
|
2211 | R b | |
2212 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")' |
|
2212 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")' | |
2213 | M f (no-changeset !) |
|
2213 | M f (no-changeset !) | |
2214 | d (no-filelog no-changeset !) |
|
2214 | d (no-filelog no-changeset !) | |
2215 | R d |
|
2215 | R d | |
2216 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")' |
|
2216 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")' | |
2217 | M f (no-changeset !) |
|
2217 | M f (no-changeset !) | |
2218 | d (no-filelog no-changeset !) |
|
2218 | d (no-filelog no-changeset !) | |
2219 | R d |
|
2219 | R d | |
2220 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")' |
|
2220 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")' | |
2221 | A f |
|
2221 | A f | |
2222 | d |
|
2222 | d | |
2223 | R d |
|
2223 | R d | |
2224 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")' |
|
2224 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")' | |
2225 | A f |
|
2225 | A f | |
2226 | b |
|
2226 | b | |
2227 | R b |
|
2227 | R b | |
2228 |
|
2228 | |||
2229 | # From here, we run status against revision where both source file exists. |
|
2229 | # From here, we run status against revision where both source file exists. | |
2230 | # |
|
2230 | # | |
2231 | # The filelog based implementation picks an arbitrary side based on revision |
|
2231 | # The filelog based implementation picks an arbitrary side based on revision | |
2232 | # numbers. So the same side "wins" whatever the parents order is. This is |
|
2232 | # numbers. So the same side "wins" whatever the parents order is. This is | |
2233 | # sub-optimal because depending on revision numbers means the result can be |
|
2233 | # sub-optimal because depending on revision numbers means the result can be | |
2234 | # different from one repository to the next. |
|
2234 | # different from one repository to the next. | |
2235 | # |
|
2235 | # | |
2236 | # The changeset based algorithm use the parent order to break tie on conflicting |
|
2236 | # The changeset based algorithm use the parent order to break tie on conflicting | |
2237 | # information and will have a different order depending on who is p1 and p2. |
|
2237 | # information and will have a different order depending on who is p1 and p2. | |
2238 | # That order is stable accross repositories. (data from p1 prevails) |
|
2238 | # That order is stable accross repositories. (data from p1 prevails) | |
2239 |
|
2239 | |||
2240 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")' |
|
2240 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")' | |
2241 | A f |
|
2241 | A f | |
2242 | d |
|
2242 | d | |
2243 | R b |
|
2243 | R b | |
2244 | R d |
|
2244 | R d | |
2245 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")' |
|
2245 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")' | |
2246 | A f |
|
2246 | A f | |
2247 | d (filelog !) |
|
2247 | d (filelog !) | |
2248 | b (no-filelog !) |
|
2248 | b (no-filelog !) | |
2249 | R b |
|
2249 | R b | |
2250 | R d |
|
2250 | R d | |
2251 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")' |
|
2251 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")' | |
2252 | A f |
|
2252 | A f | |
2253 | a |
|
2253 | a | |
2254 | A t |
|
2254 | A t | |
2255 | p |
|
2255 | p | |
2256 | R a |
|
2256 | R a | |
2257 | R b |
|
2257 | R b | |
2258 | R p |
|
2258 | R p | |
2259 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")' |
|
2259 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")' | |
2260 | A f |
|
2260 | A f | |
2261 | a (filelog !) |
|
2261 | a (filelog !) | |
2262 | b (no-filelog !) |
|
2262 | b (no-filelog !) | |
2263 | A t |
|
2263 | A t | |
2264 | p |
|
2264 | p | |
2265 | R a |
|
2265 | R a | |
2266 | R b |
|
2266 | R b | |
2267 | R p |
|
2267 | R p | |
2268 |
|
2268 | |||
2269 |
|
2269 | |||
2270 | Subcase: existing copy information overwritten on one branch |
|
2270 | Subcase: existing copy information overwritten on one branch | |
2271 | ```````````````````````````````````````````````````````````` |
|
2271 | ```````````````````````````````````````````````````````````` | |
2272 |
|
2272 | |||
2273 | Note: |
|
2273 | Note: | |
2274 | | In this case, one of the merge wrongly record a merge while there is none. |
|
2274 | | In this case, one of the merge wrongly record a merge while there is none. | |
2275 | | This lead to bad copy tracing information to be dug up. |
|
2275 | | This lead to bad copy tracing information to be dug up. | |
2276 |
|
2276 | |||
2277 |
|
2277 | |||
2278 | Merge: |
|
2278 | Merge: | |
2279 | - one with change to an unrelated file (b) |
|
2279 | - one with change to an unrelated file (b) | |
2280 | - one overwriting a file (d) with a rename (from h to i to d) |
|
2280 | - one overwriting a file (d) with a rename (from h to i to d) | |
2281 |
|
2281 | |||
2282 | $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))' |
|
2282 | $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))' | |
2283 | o mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way |
|
2283 | o mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way | |
2284 | |\ |
|
2284 | |\ | |
2285 | +---o mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way |
|
2285 | +---o mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way | |
2286 | | |/ |
|
2286 | | |/ | |
2287 | | o f-2: rename i -> d |
|
2287 | | o f-2: rename i -> d | |
2288 | | | |
|
2288 | | | | |
2289 | | o f-1: rename h -> i |
|
2289 | | o f-1: rename h -> i | |
2290 | | | |
|
2290 | | | | |
2291 | o | b-1: b update |
|
2291 | o | b-1: b update | |
2292 | |/ |
|
2292 | |/ | |
2293 | o i-2: c -move-> d, s -move-> t |
|
2293 | o i-2: c -move-> d, s -move-> t | |
2294 | | |
|
2294 | | | |
2295 | o i-1: a -move-> c, p -move-> s |
|
2295 | o i-1: a -move-> c, p -move-> s | |
2296 | | |
|
2296 | | | |
2297 | o i-0 initial commit: a b h |
|
2297 | o i-0 initial commit: a b h | |
2298 |
|
2298 | |||
2299 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")' |
|
2299 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")' | |
2300 | M b |
|
2300 | M b | |
2301 | A d |
|
2301 | A d | |
2302 | h |
|
2302 | h | |
2303 | A t |
|
2303 | A t | |
2304 | p |
|
2304 | p | |
2305 | R a |
|
2305 | R a | |
2306 | R h |
|
2306 | R h | |
2307 | R p |
|
2307 | R p | |
2308 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")' |
|
2308 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")' | |
2309 | M b |
|
2309 | M b | |
2310 | A d |
|
2310 | A d | |
2311 | h |
|
2311 | h | |
2312 | A t |
|
2312 | A t | |
2313 | p |
|
2313 | p | |
2314 | R a |
|
2314 | R a | |
2315 | R h |
|
2315 | R h | |
2316 | R p |
|
2316 | R p | |
2317 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")' |
|
2317 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")' | |
2318 | M d (no-changeset !) |
|
2318 | M d (no-changeset !) | |
2319 | h (no-filelog no-changeset !) |
|
2319 | h (no-filelog no-changeset !) | |
2320 | R h |
|
2320 | R h | |
2321 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")' |
|
2321 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")' | |
2322 | M b |
|
2322 | M b | |
2323 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")' |
|
2323 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")' | |
2324 | M b |
|
2324 | M b | |
2325 | M d (no-changeset !) |
|
2325 | M d (no-changeset !) | |
2326 | i (no-filelog no-changeset !) |
|
2326 | i (no-filelog no-changeset !) | |
2327 | R i |
|
2327 | R i | |
2328 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")' |
|
2328 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")' | |
2329 | M d (no-changeset !) |
|
2329 | M d (no-changeset !) | |
2330 | h (no-filelog no-changeset !) |
|
2330 | h (no-filelog no-changeset !) | |
2331 | R h |
|
2331 | R h | |
2332 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")' |
|
2332 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")' | |
2333 | M b |
|
2333 | M b | |
2334 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")' |
|
2334 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")' | |
2335 | M b |
|
2335 | M b | |
2336 | M d (no-changeset !) |
|
2336 | M d (no-changeset !) | |
2337 | i (no-filelog no-changeset !) |
|
2337 | i (no-filelog no-changeset !) | |
2338 | R i |
|
2338 | R i | |
2339 |
|
2339 | |||
2340 | #if no-changeset |
|
2340 | #if no-changeset | |
2341 | $ hg log -Gfr 'desc("mBFm-0")' d |
|
2341 | $ hg log -Gfr 'desc("mBFm-0")' d | |
2342 | o f-2: rename i -> d |
|
2342 | o f-2: rename i -> d | |
2343 | | |
|
2343 | | | |
2344 | o f-1: rename h -> i |
|
2344 | o f-1: rename h -> i | |
2345 | : |
|
2345 | : | |
2346 | o i-0 initial commit: a b h |
|
2346 | o i-0 initial commit: a b h | |
2347 |
|
2347 | |||
2348 | #else |
|
2348 | #else | |
2349 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2349 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work | |
2350 | $ hg log -Gfr 'desc("mBFm-0")' d |
|
2350 | $ hg log -Gfr 'desc("mBFm-0")' d | |
2351 | o i-2: c -move-> d, s -move-> t |
|
2351 | o i-2: c -move-> d, s -move-> t | |
2352 | | |
|
2352 | | | |
2353 | ~ |
|
2353 | ~ | |
2354 | #endif |
|
2354 | #endif | |
2355 |
|
2355 | |||
2356 | #if no-changeset |
|
2356 | #if no-changeset | |
2357 | $ hg log -Gfr 'desc("mFBm-0")' d |
|
2357 | $ hg log -Gfr 'desc("mFBm-0")' d | |
2358 | o f-2: rename i -> d |
|
2358 | o f-2: rename i -> d | |
2359 | | |
|
2359 | | | |
2360 | o f-1: rename h -> i |
|
2360 | o f-1: rename h -> i | |
2361 | : |
|
2361 | : | |
2362 | o i-0 initial commit: a b h |
|
2362 | o i-0 initial commit: a b h | |
2363 |
|
2363 | |||
2364 | #else |
|
2364 | #else | |
2365 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2365 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work | |
2366 | $ hg log -Gfr 'desc("mFBm-0")' d |
|
2366 | $ hg log -Gfr 'desc("mFBm-0")' d | |
2367 | o i-2: c -move-> d, s -move-> t |
|
2367 | o i-2: c -move-> d, s -move-> t | |
2368 | | |
|
2368 | | | |
2369 | ~ |
|
2369 | ~ | |
2370 | #endif |
|
2370 | #endif | |
2371 |
|
2371 | |||
2372 |
|
2372 | |||
2373 | Subcase: existing copy information overwritten on one branch, with different content) |
|
2373 | Subcase: existing copy information overwritten on one branch, with different content) | |
2374 | ````````````````````````````````````````````````````````````````````````````````````` |
|
2374 | ````````````````````````````````````````````````````````````````````````````````````` | |
2375 |
|
2375 | |||
2376 | Merge: |
|
2376 | Merge: | |
2377 | - one with change to an unrelated file (b) |
|
2377 | - one with change to an unrelated file (b) | |
2378 | - one overwriting a file (t) with a rename (from r to x to t), v content is not the same as on the other branch |
|
2378 | - one overwriting a file (t) with a rename (from r to x to t), v content is not the same as on the other branch | |
2379 |
|
2379 | |||
2380 | $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))' |
|
2380 | $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))' | |
2381 | o mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way |
|
2381 | o mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way | |
2382 | |\ |
|
2382 | |\ | |
2383 | +---o mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way |
|
2383 | +---o mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way | |
2384 | | |/ |
|
2384 | | |/ | |
2385 | | o r-2: rename t -> x |
|
2385 | | o r-2: rename t -> x | |
2386 | | | |
|
2386 | | | | |
2387 | | o r-1: rename r -> x |
|
2387 | | o r-1: rename r -> x | |
2388 | | | |
|
2388 | | | | |
2389 | o | b-1: b update |
|
2389 | o | b-1: b update | |
2390 | |/ |
|
2390 | |/ | |
2391 | o i-2: c -move-> d, s -move-> t |
|
2391 | o i-2: c -move-> d, s -move-> t | |
2392 | | |
|
2392 | | | |
2393 | o i-1: a -move-> c, p -move-> s |
|
2393 | o i-1: a -move-> c, p -move-> s | |
2394 | | |
|
2394 | | | |
2395 | o i-0 initial commit: a b h |
|
2395 | o i-0 initial commit: a b h | |
2396 |
|
2396 | |||
2397 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBRm-0")' |
|
2397 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBRm-0")' | |
2398 | M b |
|
2398 | M b | |
2399 | A d |
|
2399 | A d | |
2400 | a |
|
2400 | a | |
2401 | A t |
|
2401 | A t | |
2402 | r |
|
2402 | r | |
2403 | R a |
|
2403 | R a | |
2404 | R p |
|
2404 | R p | |
2405 | R r |
|
2405 | R r | |
2406 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mRBm-0")' |
|
2406 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mRBm-0")' | |
2407 | M b |
|
2407 | M b | |
2408 | A d |
|
2408 | A d | |
2409 | a |
|
2409 | a | |
2410 | A t |
|
2410 | A t | |
2411 | r |
|
2411 | r | |
2412 | R a |
|
2412 | R a | |
2413 | R p |
|
2413 | R p | |
2414 | R r |
|
2414 | R r | |
2415 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBRm-0")' |
|
2415 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBRm-0")' | |
2416 | M t |
|
2416 | M t | |
2417 | r (no-filelog !) |
|
2417 | r (no-filelog !) | |
2418 | R r |
|
2418 | R r | |
2419 | $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mBRm-0")' |
|
2419 | $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mBRm-0")' | |
2420 | M b |
|
2420 | M b | |
2421 | $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mBRm-0")' |
|
2421 | $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mBRm-0")' | |
2422 | M b |
|
2422 | M b | |
2423 | M t |
|
2423 | M t | |
2424 | x (no-filelog !) |
|
2424 | x (no-filelog !) | |
2425 | R x |
|
2425 | R x | |
2426 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mRBm-0")' |
|
2426 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mRBm-0")' | |
2427 | M t |
|
2427 | M t | |
2428 | r (no-filelog !) |
|
2428 | r (no-filelog !) | |
2429 | R r |
|
2429 | R r | |
2430 | $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mRBm-0")' |
|
2430 | $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mRBm-0")' | |
2431 | M b |
|
2431 | M b | |
2432 | $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mRBm-0")' |
|
2432 | $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mRBm-0")' | |
2433 | M b |
|
2433 | M b | |
2434 | M t |
|
2434 | M t | |
2435 | x (no-filelog !) |
|
2435 | x (no-filelog !) | |
2436 | R x |
|
2436 | R x | |
2437 |
|
2437 | |||
2438 | #if no-changeset |
|
2438 | #if no-changeset | |
2439 | $ hg log -Gfr 'desc("mBRm-0")' d |
|
2439 | $ hg log -Gfr 'desc("mBRm-0")' d | |
2440 | o i-2: c -move-> d, s -move-> t |
|
2440 | o i-2: c -move-> d, s -move-> t | |
2441 | | |
|
2441 | | | |
2442 | o i-1: a -move-> c, p -move-> s |
|
2442 | o i-1: a -move-> c, p -move-> s | |
2443 | | |
|
2443 | | | |
2444 | o i-0 initial commit: a b h |
|
2444 | o i-0 initial commit: a b h | |
2445 |
|
2445 | |||
2446 | #else |
|
2446 | #else | |
2447 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2447 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work | |
2448 | $ hg log -Gfr 'desc("mBRm-0")' d |
|
2448 | $ hg log -Gfr 'desc("mBRm-0")' d | |
2449 | o i-2: c -move-> d, s -move-> t |
|
2449 | o i-2: c -move-> d, s -move-> t | |
2450 | | |
|
2450 | | | |
2451 | ~ |
|
2451 | ~ | |
2452 | #endif |
|
2452 | #endif | |
2453 |
|
2453 | |||
2454 | #if no-changeset |
|
2454 | #if no-changeset | |
2455 | $ hg log -Gfr 'desc("mRBm-0")' d |
|
2455 | $ hg log -Gfr 'desc("mRBm-0")' d | |
2456 | o i-2: c -move-> d, s -move-> t |
|
2456 | o i-2: c -move-> d, s -move-> t | |
2457 | | |
|
2457 | | | |
2458 | o i-1: a -move-> c, p -move-> s |
|
2458 | o i-1: a -move-> c, p -move-> s | |
2459 | | |
|
2459 | | | |
2460 | o i-0 initial commit: a b h |
|
2460 | o i-0 initial commit: a b h | |
2461 |
|
2461 | |||
2462 | #else |
|
2462 | #else | |
2463 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2463 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work | |
2464 | $ hg log -Gfr 'desc("mRBm-0")' d |
|
2464 | $ hg log -Gfr 'desc("mRBm-0")' d | |
2465 | o i-2: c -move-> d, s -move-> t |
|
2465 | o i-2: c -move-> d, s -move-> t | |
2466 | | |
|
2466 | | | |
2467 | ~ |
|
2467 | ~ | |
2468 | #endif |
|
2468 | #endif | |
2469 |
|
2469 | |||
2470 | Subcase: reset of the copy history on one side |
|
2470 | Subcase: reset of the copy history on one side | |
2471 | `````````````````````````````````````````````` |
|
2471 | `````````````````````````````````````````````` | |
2472 |
|
2472 | |||
2473 | Merge: |
|
2473 | Merge: | |
2474 | - one with change to a file |
|
2474 | - one with change to a file | |
2475 | - one deleting and recreating the file |
|
2475 | - one deleting and recreating the file | |
2476 |
|
2476 | |||
2477 | Unlike in the 'BD/DB' cases, an actual merge happened here. So we should |
|
2477 | Unlike in the 'BD/DB' cases, an actual merge happened here. So we should | |
2478 | consider history and rename on both branch of the merge. |
|
2478 | consider history and rename on both branch of the merge. | |
2479 |
|
2479 | |||
2480 | $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))' |
|
2480 | $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))' | |
2481 | o mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way |
|
2481 | o mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way | |
2482 | |\ |
|
2482 | |\ | |
2483 | +---o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way |
|
2483 | +---o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way | |
2484 | | |/ |
|
2484 | | |/ | |
2485 | | o g-1: update d |
|
2485 | | o g-1: update d | |
2486 | | | |
|
2486 | | | | |
2487 | o | d-2 re-add d |
|
2487 | o | d-2 re-add d | |
2488 | | | |
|
2488 | | | | |
2489 | o | d-1 delete d |
|
2489 | o | d-1 delete d | |
2490 | |/ |
|
2490 | |/ | |
2491 | o i-2: c -move-> d, s -move-> t |
|
2491 | o i-2: c -move-> d, s -move-> t | |
2492 | | |
|
2492 | | | |
2493 | o i-1: a -move-> c, p -move-> s |
|
2493 | o i-1: a -move-> c, p -move-> s | |
2494 | | |
|
2494 | | | |
2495 | o i-0 initial commit: a b h |
|
2495 | o i-0 initial commit: a b h | |
2496 |
|
2496 | |||
2497 | One side of the merge have a long history with rename. The other side of the |
|
2497 | One side of the merge have a long history with rename. The other side of the | |
2498 | merge point to a new file with a smaller history. Each side is "valid". |
|
2498 | merge point to a new file with a smaller history. Each side is "valid". | |
2499 |
|
2499 | |||
2500 | (and again the filelog based algorithm only explore one, with a pick based on |
|
2500 | (and again the filelog based algorithm only explore one, with a pick based on | |
2501 | revision numbers) |
|
2501 | revision numbers) | |
2502 |
|
2502 | |||
2503 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")' |
|
2503 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")' | |
2504 | A d |
|
2504 | A d | |
2505 | a (filelog !) |
|
2505 | a (filelog !) | |
2506 | A t |
|
2506 | A t | |
2507 | p |
|
2507 | p | |
2508 | R a |
|
2508 | R a | |
2509 | R p |
|
2509 | R p | |
2510 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")' |
|
2510 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")' | |
2511 | A d |
|
2511 | A d | |
2512 | a |
|
2512 | a | |
2513 | A t |
|
2513 | A t | |
2514 | p |
|
2514 | p | |
2515 | R a |
|
2515 | R a | |
2516 | R p |
|
2516 | R p | |
2517 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")' |
|
2517 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")' | |
2518 | M d |
|
2518 | M d | |
2519 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")' |
|
2519 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")' | |
2520 | M d |
|
2520 | M d | |
2521 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")' |
|
2521 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")' | |
2522 | M d |
|
2522 | M d | |
2523 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")' |
|
2523 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")' | |
2524 | M d |
|
2524 | M d | |
2525 |
|
2525 | |||
2526 | #if no-changeset |
|
2526 | #if no-changeset | |
2527 | $ hg log -Gfr 'desc("mDGm-0")' d |
|
2527 | $ hg log -Gfr 'desc("mDGm-0")' d | |
2528 | o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way |
|
2528 | o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way | |
2529 | |\ |
|
2529 | |\ | |
2530 | | o g-1: update d |
|
2530 | | o g-1: update d | |
2531 | | | |
|
2531 | | | | |
2532 | o | d-2 re-add d |
|
2532 | o | d-2 re-add d | |
2533 | |/ |
|
2533 | |/ | |
2534 | o i-2: c -move-> d, s -move-> t |
|
2534 | o i-2: c -move-> d, s -move-> t | |
2535 | | |
|
2535 | | | |
2536 | o i-1: a -move-> c, p -move-> s |
|
2536 | o i-1: a -move-> c, p -move-> s | |
2537 | | |
|
2537 | | | |
2538 | o i-0 initial commit: a b h |
|
2538 | o i-0 initial commit: a b h | |
2539 |
|
2539 | |||
2540 | #else |
|
2540 | #else | |
2541 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2541 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work | |
2542 | $ hg log -Gfr 'desc("mDGm-0")' d |
|
2542 | $ hg log -Gfr 'desc("mDGm-0")' d | |
2543 | o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way |
|
2543 | o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way | |
2544 | |\ |
|
2544 | |\ | |
2545 | | o g-1: update d |
|
2545 | | o g-1: update d | |
2546 | | | |
|
2546 | | | | |
2547 | o | d-2 re-add d |
|
2547 | o | d-2 re-add d | |
2548 | |/ |
|
2548 | |/ | |
2549 | o i-2: c -move-> d, s -move-> t |
|
2549 | o i-2: c -move-> d, s -move-> t | |
2550 | | |
|
2550 | | | |
2551 | ~ |
|
2551 | ~ | |
2552 | #endif |
|
2552 | #endif | |
2553 |
|
2553 | |||
2554 |
|
2554 | |||
2555 | #if no-changeset |
|
2555 | #if no-changeset | |
2556 | $ hg log -Gfr 'desc("mDGm-0")' d |
|
2556 | $ hg log -Gfr 'desc("mDGm-0")' d | |
2557 | o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way |
|
2557 | o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way | |
2558 | |\ |
|
2558 | |\ | |
2559 | | o g-1: update d |
|
2559 | | o g-1: update d | |
2560 | | | |
|
2560 | | | | |
2561 | o | d-2 re-add d |
|
2561 | o | d-2 re-add d | |
2562 | |/ |
|
2562 | |/ | |
2563 | o i-2: c -move-> d, s -move-> t |
|
2563 | o i-2: c -move-> d, s -move-> t | |
2564 | | |
|
2564 | | | |
2565 | o i-1: a -move-> c, p -move-> s |
|
2565 | o i-1: a -move-> c, p -move-> s | |
2566 | | |
|
2566 | | | |
2567 | o i-0 initial commit: a b h |
|
2567 | o i-0 initial commit: a b h | |
2568 |
|
2568 | |||
2569 | #else |
|
2569 | #else | |
2570 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2570 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work | |
2571 | $ hg log -Gfr 'desc("mDGm-0")' d |
|
2571 | $ hg log -Gfr 'desc("mDGm-0")' d | |
2572 | o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way |
|
2572 | o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way | |
2573 | |\ |
|
2573 | |\ | |
2574 | | o g-1: update d |
|
2574 | | o g-1: update d | |
2575 | | | |
|
2575 | | | | |
2576 | o | d-2 re-add d |
|
2576 | o | d-2 re-add d | |
2577 | |/ |
|
2577 | |/ | |
2578 | o i-2: c -move-> d, s -move-> t |
|
2578 | o i-2: c -move-> d, s -move-> t | |
2579 | | |
|
2579 | | | |
2580 | ~ |
|
2580 | ~ | |
2581 | #endif |
|
2581 | #endif | |
2582 |
|
2582 | |||
2583 | Subcase: merging a change to a file with a "copy overwrite" to that file from another branch |
|
2583 | Subcase: merging a change to a file with a "copy overwrite" to that file from another branch | |
2584 | ```````````````````````````````````````````````````````````````````````````````````````````` |
|
2584 | ```````````````````````````````````````````````````````````````````````````````````````````` | |
2585 |
|
2585 | |||
2586 | Merge: |
|
2586 | Merge: | |
2587 | - one with change to a file (d) |
|
2587 | - one with change to a file (d) | |
2588 | - one overwriting that file with a rename (from h to i, to d) |
|
2588 | - one overwriting that file with a rename (from h to i, to d) | |
2589 |
|
2589 | |||
2590 | This case is similar to BF/FB, but an actual merge happens, so both side of the |
|
2590 | This case is similar to BF/FB, but an actual merge happens, so both side of the | |
2591 | history are relevant. |
|
2591 | history are relevant. | |
2592 |
|
2592 | |||
2593 |
|
2593 | |||
2594 | $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))' |
|
2594 | $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))' | |
2595 | o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
2595 | o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way | |
2596 | |\ |
|
2596 | |\ | |
2597 | +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
2597 | +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way | |
2598 | | |/ |
|
2598 | | |/ | |
2599 | | o g-1: update d |
|
2599 | | o g-1: update d | |
2600 | | | |
|
2600 | | | | |
2601 | o | f-2: rename i -> d |
|
2601 | o | f-2: rename i -> d | |
2602 | | | |
|
2602 | | | | |
2603 | o | f-1: rename h -> i |
|
2603 | o | f-1: rename h -> i | |
2604 | |/ |
|
2604 | |/ | |
2605 | o i-2: c -move-> d, s -move-> t |
|
2605 | o i-2: c -move-> d, s -move-> t | |
2606 | | |
|
2606 | | | |
2607 | o i-1: a -move-> c, p -move-> s |
|
2607 | o i-1: a -move-> c, p -move-> s | |
2608 | | |
|
2608 | | | |
2609 | o i-0 initial commit: a b h |
|
2609 | o i-0 initial commit: a b h | |
2610 |
|
2610 | |||
2611 |
|
2611 | |||
2612 | Note: |
|
2612 | Note: | |
2613 | | In this case, the merge get conflicting information since on one side we have |
|
2613 | | In this case, the merge get conflicting information since on one side we have | |
2614 | | "a -> c -> d". and one the other one we have "h -> i -> d". |
|
2614 | | "a -> c -> d". and one the other one we have "h -> i -> d". | |
2615 | | |
|
2615 | | | |
2616 | | The current code arbitrarily pick one side depending the ordering of the merged hash: |
|
2616 | | The current code arbitrarily pick one side depending the ordering of the merged hash: | |
2617 |
|
2617 | |||
2618 | In this case, the file hash from "f-2" is lower, so it will be `p1` of the resulting filenode its copy tracing information will win (and trace back to "h"): |
|
2618 | In this case, the file hash from "f-2" is lower, so it will be `p1` of the resulting filenode its copy tracing information will win (and trace back to "h"): | |
2619 |
|
2619 | |||
2620 | Details on this hash ordering pick: |
|
2620 | Details on this hash ordering pick: | |
2621 |
|
2621 | |||
2622 | $ hg manifest --debug 'desc("g-1")' | egrep 'd$' |
|
2622 | $ hg manifest --debug 'desc("g-1")' | egrep 'd$' | |
2623 | 17ec97e605773eb44a117d1136b3849bcdc1924f 644 d (no-changeset !) |
|
2623 | 17ec97e605773eb44a117d1136b3849bcdc1924f 644 d (no-changeset !) | |
2624 | 5cce88bf349f7c742bb440f2c53f81db9c294279 644 d (changeset !) |
|
2624 | 5cce88bf349f7c742bb440f2c53f81db9c294279 644 d (changeset !) | |
2625 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("g-1")' d |
|
2625 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("g-1")' d | |
2626 | A d |
|
2626 | A d | |
2627 | a (no-changeset no-compatibility !) |
|
2627 | a (no-changeset no-compatibility !) | |
2628 |
|
2628 | |||
2629 | $ hg manifest --debug 'desc("f-2")' | egrep 'd$' |
|
2629 | $ hg manifest --debug 'desc("f-2")' | egrep 'd$' | |
2630 | 7b79e2fe0c8924e0e598a82f048a7b024afa4d96 644 d (no-changeset !) |
|
2630 | 7b79e2fe0c8924e0e598a82f048a7b024afa4d96 644 d (no-changeset !) | |
2631 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !) |
|
2631 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !) | |
2632 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("f-2")' d |
|
2632 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("f-2")' d | |
2633 | A d |
|
2633 | A d | |
2634 | h (no-changeset no-compatibility !) |
|
2634 | h (no-changeset no-compatibility !) | |
2635 |
|
2635 | |||
2636 | Copy tracing data on the resulting merge: |
|
2636 | Copy tracing data on the resulting merge: | |
2637 |
|
2637 | |||
2638 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")' |
|
2638 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")' | |
2639 | A d |
|
2639 | A d | |
2640 | h (no-filelog !) |
|
2640 | h (no-filelog !) | |
2641 | a (filelog !) |
|
2641 | a (filelog !) | |
2642 | A t |
|
2642 | A t | |
2643 | p |
|
2643 | p | |
2644 | R a |
|
2644 | R a | |
2645 | R h |
|
2645 | R h | |
2646 | R p |
|
2646 | R p | |
2647 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")' |
|
2647 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")' | |
2648 | A d |
|
2648 | A d | |
2649 | a (no-changeset !) |
|
2649 | a (no-changeset !) | |
2650 | h (changeset !) |
|
2650 | h (changeset !) | |
2651 | A t |
|
2651 | A t | |
2652 | p |
|
2652 | p | |
2653 | R a |
|
2653 | R a | |
2654 | R h |
|
2654 | R h | |
2655 | R p |
|
2655 | R p | |
2656 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")' |
|
2656 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")' | |
2657 | M d |
|
2657 | M d | |
2658 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")' |
|
2658 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")' | |
2659 | M d |
|
2659 | M d | |
2660 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")' |
|
2660 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")' | |
2661 | M d |
|
2661 | M d | |
2662 | i (no-filelog !) |
|
2662 | i (no-filelog !) | |
2663 | R i |
|
2663 | R i | |
2664 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")' |
|
2664 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")' | |
2665 | M d |
|
2665 | M d | |
2666 | i (no-filelog !) |
|
2666 | i (no-filelog !) | |
2667 | R i |
|
2667 | R i | |
2668 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")' |
|
2668 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")' | |
2669 | M d (no-changeset !) |
|
2669 | M d (no-changeset !) | |
2670 | h (no-filelog no-changeset !) |
|
2670 | h (no-filelog no-changeset !) | |
2671 | R h |
|
2671 | R h | |
2672 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")' |
|
2672 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")' | |
2673 | M d (no-changeset !) |
|
2673 | M d (no-changeset !) | |
2674 | h (no-filelog no-changeset !) |
|
2674 | h (no-filelog no-changeset !) | |
2675 | R h |
|
2675 | R h | |
2676 |
|
2676 | |||
2677 | #if no-changeset |
|
2677 | #if no-changeset | |
2678 | $ hg log -Gfr 'desc("mFGm-0")' d |
|
2678 | $ hg log -Gfr 'desc("mFGm-0")' d | |
2679 | o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
2679 | o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way | |
2680 | |\ |
|
2680 | |\ | |
2681 | | o g-1: update d |
|
2681 | | o g-1: update d | |
2682 | | | |
|
2682 | | | | |
2683 | o | f-2: rename i -> d |
|
2683 | o | f-2: rename i -> d | |
2684 | | | |
|
2684 | | | | |
2685 | o | f-1: rename h -> i |
|
2685 | o | f-1: rename h -> i | |
2686 | |/ |
|
2686 | |/ | |
2687 | o i-2: c -move-> d, s -move-> t |
|
2687 | o i-2: c -move-> d, s -move-> t | |
2688 | | |
|
2688 | | | |
2689 | o i-1: a -move-> c, p -move-> s |
|
2689 | o i-1: a -move-> c, p -move-> s | |
2690 | | |
|
2690 | | | |
2691 | o i-0 initial commit: a b h |
|
2691 | o i-0 initial commit: a b h | |
2692 |
|
2692 | |||
2693 | #else |
|
2693 | #else | |
2694 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2694 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work | |
2695 | $ hg log -Gfr 'desc("mFGm-0")' d |
|
2695 | $ hg log -Gfr 'desc("mFGm-0")' d | |
2696 | o g-1: update d |
|
2696 | o g-1: update d | |
2697 | | |
|
2697 | | | |
2698 | o i-2: c -move-> d, s -move-> t |
|
2698 | o i-2: c -move-> d, s -move-> t | |
2699 | | |
|
2699 | | | |
2700 | ~ |
|
2700 | ~ | |
2701 | #endif |
|
2701 | #endif | |
2702 |
|
2702 | |||
2703 | #if no-changeset |
|
2703 | #if no-changeset | |
2704 | $ hg log -Gfr 'desc("mGFm-0")' d |
|
2704 | $ hg log -Gfr 'desc("mGFm-0")' d | |
2705 | o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
2705 | o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way | |
2706 | |\ |
|
2706 | |\ | |
2707 | | o g-1: update d |
|
2707 | | o g-1: update d | |
2708 | | | |
|
2708 | | | | |
2709 | o | f-2: rename i -> d |
|
2709 | o | f-2: rename i -> d | |
2710 | | | |
|
2710 | | | | |
2711 | o | f-1: rename h -> i |
|
2711 | o | f-1: rename h -> i | |
2712 | |/ |
|
2712 | |/ | |
2713 | o i-2: c -move-> d, s -move-> t |
|
2713 | o i-2: c -move-> d, s -move-> t | |
2714 | | |
|
2714 | | | |
2715 | o i-1: a -move-> c, p -move-> s |
|
2715 | o i-1: a -move-> c, p -move-> s | |
2716 | | |
|
2716 | | | |
2717 | o i-0 initial commit: a b h |
|
2717 | o i-0 initial commit: a b h | |
2718 |
|
2718 | |||
2719 | #else |
|
2719 | #else | |
2720 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2720 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work | |
2721 | $ hg log -Gfr 'desc("mGFm-0")' d |
|
2721 | $ hg log -Gfr 'desc("mGFm-0")' d | |
2722 | o g-1: update d |
|
2722 | o g-1: update d | |
2723 | | |
|
2723 | | | |
2724 | o i-2: c -move-> d, s -move-> t |
|
2724 | o i-2: c -move-> d, s -move-> t | |
2725 | | |
|
2725 | | | |
2726 | ~ |
|
2726 | ~ | |
2727 | #endif |
|
2727 | #endif | |
2728 |
|
2728 | |||
2729 | Subcase: new copy information on both side with an actual merge happening |
|
2729 | Subcase: new copy information on both side with an actual merge happening | |
2730 | ````````````````````````````````````````````````````````````````````````` |
|
2730 | ````````````````````````````````````````````````````````````````````````` | |
2731 |
|
2731 | |||
2732 | - the "p-" branch renaming 't' to 'v' (through 'u') |
|
2732 | - the "p-" branch renaming 't' to 'v' (through 'u') | |
2733 | - the "q-" branch renaming 'r' to 'v' (through 'w') |
|
2733 | - the "q-" branch renaming 'r' to 'v' (through 'w') | |
2734 |
|
2734 | |||
2735 |
|
2735 | |||
2736 | $ hg log -G --rev '::(desc("mPQm")+desc("mQPm"))' |
|
2736 | $ hg log -G --rev '::(desc("mPQm")+desc("mQPm"))' | |
2737 | o mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way |
|
2737 | o mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way | |
2738 | |\ |
|
2738 | |\ | |
2739 | +---o mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way |
|
2739 | +---o mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way | |
2740 | | |/ |
|
2740 | | |/ | |
2741 | | o q-2 w -move-> v |
|
2741 | | o q-2 w -move-> v | |
2742 | | | |
|
2742 | | | | |
2743 | | o q-1 r -move-> w |
|
2743 | | o q-1 r -move-> w | |
2744 | | | |
|
2744 | | | | |
2745 | o | p-2: u -move-> v |
|
2745 | o | p-2: u -move-> v | |
2746 | | | |
|
2746 | | | | |
2747 | o | p-1: t -move-> u |
|
2747 | o | p-1: t -move-> u | |
2748 | |/ |
|
2748 | |/ | |
2749 | o i-2: c -move-> d, s -move-> t |
|
2749 | o i-2: c -move-> d, s -move-> t | |
2750 | | |
|
2750 | | | |
2751 | o i-1: a -move-> c, p -move-> s |
|
2751 | o i-1: a -move-> c, p -move-> s | |
2752 | | |
|
2752 | | | |
2753 | o i-0 initial commit: a b h |
|
2753 | o i-0 initial commit: a b h | |
2754 |
|
2754 | |||
2755 |
|
2755 | |||
2756 | #if no-changeset |
|
2756 | #if no-changeset | |
2757 | $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v' |
|
2757 | $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v' | |
2758 | 0946c662ef16e4e67397fd717389eb6693d41749 644 v |
|
2758 | 0946c662ef16e4e67397fd717389eb6693d41749 644 v | |
2759 | $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v' |
|
2759 | $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v' | |
2760 | 0db3aad7fcc1ec27fab57060e327b9e864ea0cc9 644 v |
|
2760 | 0db3aad7fcc1ec27fab57060e327b9e864ea0cc9 644 v | |
2761 | $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v' |
|
2761 | $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v' | |
2762 | 3f91841cd75cadc9a1f1b4e7c1aa6d411f76032e 644 v |
|
2762 | 3f91841cd75cadc9a1f1b4e7c1aa6d411f76032e 644 v | |
2763 | $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v' |
|
2763 | $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v' | |
2764 | c43c088b811fd27983c0a9aadf44f3343cd4cd7e 644 v |
|
2764 | c43c088b811fd27983c0a9aadf44f3343cd4cd7e 644 v | |
2765 | $ hg debugindex v | ../no-linkrev |
|
2765 | $ hg debugindex v | ../no-linkrev | |
2766 | rev linkrev nodeid p1 p2 |
|
2766 | rev linkrev nodeid p1 p2 | |
2767 | 0 * 3f91841cd75c 000000000000 000000000000 |
|
2767 | 0 * 3f91841cd75c 000000000000 000000000000 | |
2768 | 1 * c43c088b811f 000000000000 000000000000 |
|
2768 | 1 * c43c088b811f 000000000000 000000000000 | |
2769 | 2 * 0946c662ef16 3f91841cd75c c43c088b811f |
|
2769 | 2 * 0946c662ef16 3f91841cd75c c43c088b811f | |
2770 | 3 * 0db3aad7fcc1 c43c088b811f 3f91841cd75c |
|
2770 | 3 * 0db3aad7fcc1 c43c088b811f 3f91841cd75c | |
2771 | #else |
|
2771 | #else | |
2772 | $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v' |
|
2772 | $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v' | |
2773 | 65fde9f6e4d4da23b3f610e07b53673ea9541d75 644 v |
|
2773 | 65fde9f6e4d4da23b3f610e07b53673ea9541d75 644 v | |
2774 | $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v' |
|
2774 | $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v' | |
2775 | a098dda6413aecf154eefc976afc38b295acb7e5 644 v |
|
2775 | a098dda6413aecf154eefc976afc38b295acb7e5 644 v | |
2776 | $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v' |
|
2776 | $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v' | |
2777 | 5aed6a8dbff0301328c08360d24354d3d064cf0d 644 v |
|
2777 | 5aed6a8dbff0301328c08360d24354d3d064cf0d 644 v | |
2778 | $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v' |
|
2778 | $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v' | |
2779 | a38b2fa170219750dac9bc7d19df831f213ba708 644 v |
|
2779 | a38b2fa170219750dac9bc7d19df831f213ba708 644 v | |
2780 | $ hg debugindex v | ../no-linkrev |
|
2780 | $ hg debugindex v | ../no-linkrev | |
2781 | rev linkrev nodeid p1 p2 |
|
2781 | rev linkrev nodeid p1 p2 | |
2782 | 0 * 5aed6a8dbff0 000000000000 000000000000 |
|
2782 | 0 * 5aed6a8dbff0 000000000000 000000000000 | |
2783 | 1 * a38b2fa17021 000000000000 000000000000 |
|
2783 | 1 * a38b2fa17021 000000000000 000000000000 | |
2784 | 2 * 65fde9f6e4d4 5aed6a8dbff0 a38b2fa17021 |
|
2784 | 2 * 65fde9f6e4d4 5aed6a8dbff0 a38b2fa17021 | |
2785 | 3 * a098dda6413a a38b2fa17021 5aed6a8dbff0 |
|
2785 | 3 * a098dda6413a a38b2fa17021 5aed6a8dbff0 | |
2786 | #endif |
|
2786 | #endif | |
2787 |
|
2787 | |||
2788 | # Here the filelog based implementation is not looking at the rename |
|
2788 | # Here the filelog based implementation is not looking at the rename | |
2789 | # information (because the file exist on both side). However the changelog |
|
2789 | # information (because the file exist on both side). However the changelog | |
2790 | # based on works fine. We have different output. |
|
2790 | # based on works fine. We have different output. | |
2791 |
|
2791 | |||
2792 | $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mPQm-0")' |
|
2792 | $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mPQm-0")' | |
2793 | M v |
|
2793 | M v | |
2794 | r (no-filelog !) |
|
2794 | r (no-filelog !) | |
2795 | R r |
|
2795 | R r | |
2796 | $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mQPm-0")' |
|
2796 | $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mQPm-0")' | |
2797 | M v |
|
2797 | M v | |
2798 | r (no-filelog !) |
|
2798 | r (no-filelog !) | |
2799 | R r |
|
2799 | R r | |
2800 | $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mPQm-0")' |
|
2800 | $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mPQm-0")' | |
2801 | M v |
|
2801 | M v | |
2802 | t (no-filelog !) |
|
2802 | t (no-filelog !) | |
2803 | R t |
|
2803 | R t | |
2804 | $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mQPm-0")' |
|
2804 | $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mQPm-0")' | |
2805 | M v |
|
2805 | M v | |
2806 | t (no-filelog !) |
|
2806 | t (no-filelog !) | |
2807 | R t |
|
2807 | R t | |
2808 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("p-2")' |
|
2808 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("p-2")' | |
2809 | A v |
|
2809 | A v | |
2810 | t |
|
2810 | t | |
2811 | R t |
|
2811 | R t | |
2812 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("q-2")' |
|
2812 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("q-2")' | |
2813 | A v |
|
2813 | A v | |
2814 | r |
|
2814 | r | |
2815 | R r |
|
2815 | R r | |
2816 |
|
2816 | |||
2817 | # From here, we run status against revision where both source file exists. |
|
2817 | # From here, we run status against revision where both source file exists. | |
2818 | # |
|
2818 | # | |
2819 | # The filelog based implementation picks an arbitrary side based on revision |
|
2819 | # The filelog based implementation picks an arbitrary side based on revision | |
2820 | # numbers. So the same side "wins" whatever the parents order is. This is |
|
2820 | # numbers. So the same side "wins" whatever the parents order is. This is | |
2821 | # sub-optimal because depending on revision numbers means the result can be |
|
2821 | # sub-optimal because depending on revision numbers means the result can be | |
2822 | # different from one repository to the next. |
|
2822 | # different from one repository to the next. | |
2823 | # |
|
2823 | # | |
2824 | # The changeset based algorithm use the parent order to break tie on conflicting |
|
2824 | # The changeset based algorithm use the parent order to break tie on conflicting | |
2825 | # information and will have a different order depending on who is p1 and p2. |
|
2825 | # information and will have a different order depending on who is p1 and p2. | |
2826 | # That order is stable accross repositories. (data from p1 prevails) |
|
2826 | # That order is stable accross repositories. (data from p1 prevails) | |
2827 |
|
2827 | |||
2828 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mPQm-0")' |
|
2828 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mPQm-0")' | |
2829 | A v |
|
2829 | A v | |
2830 | t |
|
2830 | t | |
2831 | R r |
|
2831 | R r | |
2832 | R t |
|
2832 | R t | |
2833 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mQPm-0")' |
|
2833 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mQPm-0")' | |
2834 | A v |
|
2834 | A v | |
2835 | t (filelog !) |
|
2835 | t (filelog !) | |
2836 | r (no-filelog !) |
|
2836 | r (no-filelog !) | |
2837 | R r |
|
2837 | R r | |
2838 | R t |
|
2838 | R t | |
2839 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm-0")' |
|
2839 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm-0")' | |
2840 | A d |
|
2840 | A d | |
2841 | a |
|
2841 | a | |
2842 | A v |
|
2842 | A v | |
2843 | r (filelog !) |
|
2843 | r (filelog !) | |
2844 | p (no-filelog !) |
|
2844 | p (no-filelog !) | |
2845 | R a |
|
2845 | R a | |
2846 | R p |
|
2846 | R p | |
2847 | R r |
|
2847 | R r | |
2848 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm-0")' |
|
2848 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm-0")' | |
2849 | A d |
|
2849 | A d | |
2850 | a |
|
2850 | a | |
2851 | A v |
|
2851 | A v | |
2852 | r |
|
2852 | r | |
2853 | R a |
|
2853 | R a | |
2854 | R p |
|
2854 | R p | |
2855 | R r |
|
2855 | R r | |
2856 |
|
2856 | |||
2857 |
|
2857 | |||
2858 | Comparing with merging with a deletion (and keeping the file) |
|
2858 | Comparing with merging with a deletion (and keeping the file) | |
2859 | ------------------------------------------------------------- |
|
2859 | ------------------------------------------------------------- | |
2860 |
|
2860 | |||
2861 | Merge: |
|
2861 | Merge: | |
2862 | - one removing a file (d) |
|
2862 | - one removing a file (d) | |
2863 | - one updating that file |
|
2863 | - one updating that file | |
2864 | - the merge keep the modified version of the file (canceling the delete) |
|
2864 | - the merge keep the modified version of the file (canceling the delete) | |
2865 |
|
2865 | |||
2866 | In this case, the file keep on living after the merge. So we should not drop its |
|
2866 | In this case, the file keep on living after the merge. So we should not drop its | |
2867 | copy tracing chain. |
|
2867 | copy tracing chain. | |
2868 |
|
2868 | |||
2869 | $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))' |
|
2869 | $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))' | |
2870 | o mGCm-0 merge updated/deleted - revive the file (updated content) - the other way |
|
2870 | o mGCm-0 merge updated/deleted - revive the file (updated content) - the other way | |
2871 | |\ |
|
2871 | |\ | |
2872 | +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way |
|
2872 | +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way | |
2873 | | |/ |
|
2873 | | |/ | |
2874 | | o g-1: update d |
|
2874 | | o g-1: update d | |
2875 | | | |
|
2875 | | | | |
2876 | o | c-1 delete d |
|
2876 | o | c-1 delete d | |
2877 | |/ |
|
2877 | |/ | |
2878 | o i-2: c -move-> d, s -move-> t |
|
2878 | o i-2: c -move-> d, s -move-> t | |
2879 | | |
|
2879 | | | |
2880 | o i-1: a -move-> c, p -move-> s |
|
2880 | o i-1: a -move-> c, p -move-> s | |
2881 | | |
|
2881 | | | |
2882 | o i-0 initial commit: a b h |
|
2882 | o i-0 initial commit: a b h | |
2883 |
|
2883 | |||
2884 |
|
2884 | |||
2885 | 'a' is the copy source of 'd' |
|
2885 | 'a' is the copy source of 'd' | |
2886 |
|
2886 | |||
2887 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")' |
|
2887 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")' | |
2888 | A d |
|
2888 | A d | |
2889 | a (no-compatibility no-changeset !) |
|
2889 | a (no-compatibility no-changeset !) | |
2890 | A t |
|
2890 | A t | |
2891 | p |
|
2891 | p | |
2892 | R a |
|
2892 | R a | |
2893 | R p |
|
2893 | R p | |
2894 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")' |
|
2894 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")' | |
2895 | A d |
|
2895 | A d | |
2896 | a (no-compatibility no-changeset !) |
|
2896 | a (no-compatibility no-changeset !) | |
2897 | A t |
|
2897 | A t | |
2898 | p |
|
2898 | p | |
2899 | R a |
|
2899 | R a | |
2900 | R p |
|
2900 | R p | |
2901 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")' |
|
2901 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")' | |
2902 | A d |
|
2902 | A d | |
2903 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")' |
|
2903 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")' | |
2904 | A d |
|
2904 | A d | |
2905 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")' |
|
2905 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")' | |
2906 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")' |
|
2906 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")' | |
2907 |
|
2907 | |||
2908 |
|
2908 | |||
2909 | Comparing with merge restoring an untouched deleted file |
|
2909 | Comparing with merge restoring an untouched deleted file | |
2910 | -------------------------------------------------------- |
|
2910 | -------------------------------------------------------- | |
2911 |
|
2911 | |||
2912 | Merge: |
|
2912 | Merge: | |
2913 | - one removing a file (d) |
|
2913 | - one removing a file (d) | |
2914 | - one leaving the file untouched |
|
2914 | - one leaving the file untouched | |
2915 | - the merge actively restore the file to the same content. |
|
2915 | - the merge actively restore the file to the same content. | |
2916 |
|
2916 | |||
2917 | In this case, the file keep on living after the merge. So we should not drop its |
|
2917 | In this case, the file keep on living after the merge. So we should not drop its | |
2918 | copy tracing chain. |
|
2918 | copy tracing chain. | |
2919 |
|
2919 | |||
2920 | $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))' |
|
2920 | $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))' | |
2921 | o mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way |
|
2921 | o mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way | |
2922 | |\ |
|
2922 | |\ | |
2923 | +---o mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way |
|
2923 | +---o mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way | |
2924 | | |/ |
|
2924 | | |/ | |
2925 | | o c-1 delete d |
|
2925 | | o c-1 delete d | |
2926 | | | |
|
2926 | | | | |
2927 | o | b-1: b update |
|
2927 | o | b-1: b update | |
2928 | |/ |
|
2928 | |/ | |
2929 | o i-2: c -move-> d, s -move-> t |
|
2929 | o i-2: c -move-> d, s -move-> t | |
2930 | | |
|
2930 | | | |
2931 | o i-1: a -move-> c, p -move-> s |
|
2931 | o i-1: a -move-> c, p -move-> s | |
2932 | | |
|
2932 | | | |
2933 | o i-0 initial commit: a b h |
|
2933 | o i-0 initial commit: a b h | |
2934 |
|
2934 | |||
2935 |
|
2935 | |||
2936 | 'a' is the the copy source of 'd' |
|
2936 | 'a' is the the copy source of 'd' | |
2937 |
|
2937 | |||
2938 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")' |
|
2938 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")' | |
2939 | M b |
|
2939 | M b | |
2940 | A d |
|
2940 | A d | |
2941 | a (no-compatibility no-changeset !) |
|
2941 | a (no-compatibility no-changeset !) | |
2942 | A t |
|
2942 | A t | |
2943 | p |
|
2943 | p | |
2944 | R a |
|
2944 | R a | |
2945 | R p |
|
2945 | R p | |
2946 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")' |
|
2946 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")' | |
2947 | M b |
|
2947 | M b | |
2948 | A d |
|
2948 | A d | |
2949 | a (no-compatibility no-changeset !) |
|
2949 | a (no-compatibility no-changeset !) | |
2950 | A t |
|
2950 | A t | |
2951 | p |
|
2951 | p | |
2952 | R a |
|
2952 | R a | |
2953 | R p |
|
2953 | R p | |
2954 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")' |
|
2954 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")' | |
2955 | M b |
|
2955 | M b | |
2956 | A d |
|
2956 | A d | |
2957 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")' |
|
2957 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")' | |
2958 | M b |
|
2958 | M b | |
2959 | A d |
|
2959 | A d | |
2960 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")' |
|
2960 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")' | |
2961 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")' |
|
2961 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")' | |
2962 |
|
2962 | |||
2963 |
|
2963 | |||
2964 | Merging a branch where a rename was deleted with a branch where the same file was renamed |
|
2964 | Merging a branch where a rename was deleted with a branch where the same file was renamed | |
2965 | ------------------------------------------------------------------------------------------ |
|
2965 | ------------------------------------------------------------------------------------------ | |
2966 |
|
2966 | |||
2967 | Create a "conflicting" merge where `d` get removed on one branch before its |
|
2967 | Create a "conflicting" merge where `d` get removed on one branch before its | |
2968 | rename information actually conflict with the other branch. |
|
2968 | rename information actually conflict with the other branch. | |
2969 |
|
2969 | |||
2970 | (the copy information from the branch that was not deleted should win). |
|
2970 | (the copy information from the branch that was not deleted should win). | |
2971 |
|
2971 | |||
2972 | $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))' |
|
2972 | $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))' | |
2973 | o mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way |
|
2973 | o mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way | |
2974 | |\ |
|
2974 | |\ | |
2975 | +---o mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way |
|
2975 | +---o mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way | |
2976 | | |/ |
|
2976 | | |/ | |
2977 | | o h-1: b -(move)-> d |
|
2977 | | o h-1: b -(move)-> d | |
2978 | | | |
|
2978 | | | | |
2979 | o | c-1 delete d |
|
2979 | o | c-1 delete d | |
2980 | | | |
|
2980 | | | | |
2981 | o | i-2: c -move-> d, s -move-> t |
|
2981 | o | i-2: c -move-> d, s -move-> t | |
2982 | | | |
|
2982 | | | | |
2983 | o | i-1: a -move-> c, p -move-> s |
|
2983 | o | i-1: a -move-> c, p -move-> s | |
2984 | |/ |
|
2984 | |/ | |
2985 | o i-0 initial commit: a b h |
|
2985 | o i-0 initial commit: a b h | |
2986 |
|
2986 | |||
2987 |
|
2987 | |||
2988 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCH-delete-before-conflict-m")' |
|
2988 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCH-delete-before-conflict-m")' | |
2989 | A d |
|
2989 | A d | |
2990 | b (no-compatibility no-changeset !) |
|
2990 | b (no-compatibility no-changeset !) | |
2991 | A t |
|
2991 | A t | |
2992 | p |
|
2992 | p | |
2993 | R a |
|
2993 | R a | |
2994 | R b |
|
2994 | R b | |
2995 | R p |
|
2995 | R p | |
2996 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mHC-delete-before-conflict-m")' |
|
2996 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mHC-delete-before-conflict-m")' | |
2997 | A d |
|
2997 | A d | |
2998 | b |
|
2998 | b | |
2999 | A t |
|
2999 | A t | |
3000 | p |
|
3000 | p | |
3001 | R a |
|
3001 | R a | |
3002 | R b |
|
3002 | R b | |
3003 | R p |
|
3003 | R p | |
3004 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCH-delete-before-conflict-m")' |
|
3004 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCH-delete-before-conflict-m")' | |
3005 | A d |
|
3005 | A d | |
3006 | b |
|
3006 | b | |
3007 | R b |
|
3007 | R b | |
3008 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mHC-delete-before-conflict-m")' |
|
3008 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mHC-delete-before-conflict-m")' | |
3009 | A d |
|
3009 | A d | |
3010 | b |
|
3010 | b | |
3011 | R b |
|
3011 | R b | |
3012 | $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mCH-delete-before-conflict-m")' |
|
3012 | $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mCH-delete-before-conflict-m")' | |
3013 | A t |
|
3013 | A t | |
3014 | p |
|
3014 | p | |
3015 | R a |
|
3015 | R a | |
3016 | R p |
|
3016 | R p | |
3017 | $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mHC-delete-before-conflict-m")' |
|
3017 | $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mHC-delete-before-conflict-m")' | |
3018 | A t |
|
3018 | A t | |
3019 | p |
|
3019 | p | |
3020 | R a |
|
3020 | R a | |
3021 | R p |
|
3021 | R p | |
3022 |
|
3022 | |||
3023 | Variant of previous with extra changes introduced by the merge |
|
3023 | Variant of previous with extra changes introduced by the merge | |
3024 | -------------------------------------------------------------- |
|
3024 | -------------------------------------------------------------- | |
3025 |
|
3025 | |||
3026 | (see case declaration for details) |
|
3026 | (see case declaration for details) | |
3027 |
|
3027 | |||
3028 | Subcase: merge has same initial content on both side, but merge introduced a change |
|
3028 | Subcase: merge has same initial content on both side, but merge introduced a change | |
3029 | ``````````````````````````````````````````````````````````````````````````````````` |
|
3029 | ``````````````````````````````````````````````````````````````````````````````````` | |
3030 |
|
3030 | |||
3031 | - the "e-" branch renaming b to f (through 'g') |
|
3031 | - the "e-" branch renaming b to f (through 'g') | |
3032 | - the "a-" branch renaming d to f (through e) |
|
3032 | - the "a-" branch renaming d to f (through e) | |
3033 | - the merge add new change to b |
|
3033 | - the merge add new change to b | |
3034 |
|
3034 | |||
3035 | $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))' |
|
3035 | $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))' | |
3036 | o mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way |
|
3036 | o mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way | |
3037 | |\ |
|
3037 | |\ | |
3038 | +---o mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way |
|
3038 | +---o mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way | |
3039 | | |/ |
|
3039 | | |/ | |
3040 | | o e-2 g -move-> f |
|
3040 | | o e-2 g -move-> f | |
3041 | | | |
|
3041 | | | | |
3042 | | o e-1 b -move-> g |
|
3042 | | o e-1 b -move-> g | |
3043 | | | |
|
3043 | | | | |
3044 | o | a-2: e -move-> f |
|
3044 | o | a-2: e -move-> f | |
3045 | | | |
|
3045 | | | | |
3046 | o | a-1: d -move-> e |
|
3046 | o | a-1: d -move-> e | |
3047 | |/ |
|
3047 | |/ | |
3048 | o i-2: c -move-> d, s -move-> t |
|
3048 | o i-2: c -move-> d, s -move-> t | |
3049 | | |
|
3049 | | | |
3050 | o i-1: a -move-> c, p -move-> s |
|
3050 | o i-1: a -move-> c, p -move-> s | |
3051 | | |
|
3051 | | | |
3052 | o i-0 initial commit: a b h |
|
3052 | o i-0 initial commit: a b h | |
3053 |
|
3053 | |||
3054 | #if no-changeset |
|
3054 | #if no-changeset | |
3055 | $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f' |
|
3055 | $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f' | |
3056 | 2f649fba7eb284e720d02b61f0546fcef694c045 644 f |
|
3056 | 2f649fba7eb284e720d02b61f0546fcef694c045 644 f | |
3057 | $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f' |
|
3057 | $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f' | |
3058 | 774e7c1637d536b99e2d8ef16fd731f87a82bd09 644 f |
|
3058 | 774e7c1637d536b99e2d8ef16fd731f87a82bd09 644 f | |
3059 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' |
|
3059 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' | |
3060 | b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f |
|
3060 | b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f | |
3061 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' |
|
3061 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' | |
3062 | e8825b386367b29fec957283a80bb47b47483fe1 644 f |
|
3062 | e8825b386367b29fec957283a80bb47b47483fe1 644 f | |
3063 | $ hg debugindex f | ../no-linkrev |
|
3063 | $ hg debugindex f | ../no-linkrev | |
3064 | rev linkrev nodeid p1 p2 |
|
3064 | rev linkrev nodeid p1 p2 | |
3065 | 0 * b76eb76580df 000000000000 000000000000 |
|
3065 | 0 * b76eb76580df 000000000000 000000000000 | |
3066 | 1 * e8825b386367 000000000000 000000000000 |
|
3066 | 1 * e8825b386367 000000000000 000000000000 | |
3067 | 2 * 2ff93c643948 b76eb76580df e8825b386367 |
|
3067 | 2 * 2ff93c643948 b76eb76580df e8825b386367 | |
3068 | 3 * 2f649fba7eb2 b76eb76580df e8825b386367 |
|
3068 | 3 * 2f649fba7eb2 b76eb76580df e8825b386367 | |
3069 | 4 * 774e7c1637d5 e8825b386367 b76eb76580df |
|
3069 | 4 * 774e7c1637d5 e8825b386367 b76eb76580df | |
3070 | #else |
|
3070 | #else | |
3071 | $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f' |
|
3071 | $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f' | |
3072 | d3613c1ec8310a812ac4268fd853ac576b6caea5 644 f |
|
3072 | d3613c1ec8310a812ac4268fd853ac576b6caea5 644 f | |
3073 | $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f' |
|
3073 | $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f' | |
3074 | 05e03c868bbcab4a649cb33a238d7aa07398a469 644 f |
|
3074 | 05e03c868bbcab4a649cb33a238d7aa07398a469 644 f | |
3075 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' |
|
3075 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' | |
3076 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
3076 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f | |
3077 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' |
|
3077 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' | |
3078 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
3078 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f | |
3079 | $ hg debugindex f | ../no-linkrev |
|
3079 | $ hg debugindex f | ../no-linkrev | |
3080 | rev linkrev nodeid p1 p2 |
|
3080 | rev linkrev nodeid p1 p2 | |
3081 | 0 * ae258f702dfe 000000000000 000000000000 |
|
3081 | 0 * ae258f702dfe 000000000000 000000000000 | |
3082 | 1 * d3613c1ec831 ae258f702dfe 000000000000 |
|
3082 | 1 * d3613c1ec831 ae258f702dfe 000000000000 | |
3083 | 2 * 05e03c868bbc ae258f702dfe 000000000000 |
|
3083 | 2 * 05e03c868bbc ae258f702dfe 000000000000 | |
3084 | #endif |
|
3084 | #endif | |
3085 |
|
3085 | |||
3086 | # Here the filelog based implementation is not looking at the rename |
|
3086 | # Here the filelog based implementation is not looking at the rename | |
3087 | # information (because the file exist on both side). However the changelog |
|
3087 | # information (because the file exist on both side). However the changelog | |
3088 | # based on works fine. We have different output. |
|
3088 | # based on works fine. We have different output. | |
3089 |
|
3089 | |||
3090 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAE-change-m-0")' |
|
3090 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAE-change-m-0")' | |
3091 | M f |
|
3091 | M f | |
3092 | b (no-filelog !) |
|
3092 | b (no-filelog !) | |
3093 | R b |
|
3093 | R b | |
3094 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEA-change-m-0")' |
|
3094 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEA-change-m-0")' | |
3095 | M f |
|
3095 | M f | |
3096 | b (no-filelog !) |
|
3096 | b (no-filelog !) | |
3097 | R b |
|
3097 | R b | |
3098 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAE-change-m-0")' |
|
3098 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAE-change-m-0")' | |
3099 | M f |
|
3099 | M f | |
3100 | d (no-filelog !) |
|
3100 | d (no-filelog !) | |
3101 | R d |
|
3101 | R d | |
3102 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEA-change-m-0")' |
|
3102 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEA-change-m-0")' | |
3103 | M f |
|
3103 | M f | |
3104 | d (no-filelog !) |
|
3104 | d (no-filelog !) | |
3105 | R d |
|
3105 | R d | |
3106 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")' |
|
3106 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")' | |
3107 | A f |
|
3107 | A f | |
3108 | d |
|
3108 | d | |
3109 | R d |
|
3109 | R d | |
3110 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")' |
|
3110 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")' | |
3111 | A f |
|
3111 | A f | |
3112 | b |
|
3112 | b | |
3113 | R b |
|
3113 | R b | |
3114 |
|
3114 | |||
3115 | # From here, we run status against revision where both source file exists. |
|
3115 | # From here, we run status against revision where both source file exists. | |
3116 | # |
|
3116 | # | |
3117 | # The filelog based implementation picks an arbitrary side based on revision |
|
3117 | # The filelog based implementation picks an arbitrary side based on revision | |
3118 | # numbers. So the same side "wins" whatever the parents order is. This is |
|
3118 | # numbers. So the same side "wins" whatever the parents order is. This is | |
3119 | # sub-optimal because depending on revision numbers means the result can be |
|
3119 | # sub-optimal because depending on revision numbers means the result can be | |
3120 | # different from one repository to the next. |
|
3120 | # different from one repository to the next. | |
3121 | # |
|
3121 | # | |
3122 | # The changeset based algorithm use the parent order to break tie on conflicting |
|
3122 | # The changeset based algorithm use the parent order to break tie on conflicting | |
3123 | # information and will have a different order depending on who is p1 and p2. |
|
3123 | # information and will have a different order depending on who is p1 and p2. | |
3124 | # That order is stable accross repositories. (data from p1 prevails) |
|
3124 | # That order is stable accross repositories. (data from p1 prevails) | |
3125 |
|
3125 | |||
3126 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAE-change-m-0")' |
|
3126 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAE-change-m-0")' | |
3127 | A f |
|
3127 | A f | |
3128 | d |
|
3128 | d | |
3129 | R b |
|
3129 | R b | |
3130 | R d |
|
3130 | R d | |
3131 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEA-change-m-0")' |
|
3131 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEA-change-m-0")' | |
3132 | A f |
|
3132 | A f | |
3133 | d (filelog !) |
|
3133 | d (filelog !) | |
3134 | b (no-filelog !) |
|
3134 | b (no-filelog !) | |
3135 | R b |
|
3135 | R b | |
3136 | R d |
|
3136 | R d | |
3137 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m-0")' |
|
3137 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m-0")' | |
3138 | A f |
|
3138 | A f | |
3139 | a |
|
3139 | a | |
3140 | A t |
|
3140 | A t | |
3141 | p |
|
3141 | p | |
3142 | R a |
|
3142 | R a | |
3143 | R b |
|
3143 | R b | |
3144 | R p |
|
3144 | R p | |
3145 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m-0")' |
|
3145 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m-0")' | |
3146 | A f |
|
3146 | A f | |
3147 | a (filelog !) |
|
3147 | a (filelog !) | |
3148 | b (no-filelog !) |
|
3148 | b (no-filelog !) | |
3149 | A t |
|
3149 | A t | |
3150 | p |
|
3150 | p | |
3151 | R a |
|
3151 | R a | |
3152 | R b |
|
3152 | R b | |
3153 | R p |
|
3153 | R p | |
3154 |
|
3154 | |||
3155 |
|
3155 | |||
3156 | Decision from previous merge are properly chained with later merge |
|
3156 | Decision from previous merge are properly chained with later merge | |
3157 | ------------------------------------------------------------------ |
|
3157 | ------------------------------------------------------------------ | |
3158 |
|
3158 | |||
3159 |
|
3159 | |||
3160 | Subcase: chaining conflicting rename resolution |
|
3160 | Subcase: chaining conflicting rename resolution | |
3161 | ``````````````````````````````````````````````` |
|
3161 | ``````````````````````````````````````````````` | |
3162 |
|
3162 | |||
3163 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We |
|
3163 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We | |
3164 | add more change on the respective branch and merge again. These second merge |
|
3164 | add more change on the respective branch and merge again. These second merge | |
3165 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" |
|
3165 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" | |
3166 | about that file should stay unchanged. |
|
3166 | about that file should stay unchanged. | |
3167 |
|
3167 | |||
3168 | The result from mAEm is the same for the subsequent merge: |
|
3168 | The result from mAEm is the same for the subsequent merge: | |
3169 |
|
3169 | |||
3170 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm")' f |
|
3170 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm")' f | |
3171 | A f |
|
3171 | A f | |
3172 | a (filelog !) |
|
3172 | a (filelog !) | |
3173 | a (sidedata !) |
|
3173 | a (sidedata !) | |
3174 | a (upgraded !) |
|
3174 | a (upgraded !) | |
3175 |
|
3175 | |||
3176 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE,Km")' f |
|
3176 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE,Km")' f | |
3177 | A f |
|
3177 | A f | |
3178 | a (filelog !) |
|
3178 | a (filelog !) | |
3179 | a (sidedata !) |
|
3179 | a (sidedata !) | |
3180 | a (upgraded !) |
|
3180 | a (upgraded !) | |
3181 |
|
3181 | |||
3182 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AEm")' f |
|
3182 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AEm")' f | |
3183 | A f |
|
3183 | A f | |
3184 | a (filelog !) |
|
3184 | a (filelog !) | |
3185 |
a ( |
|
3185 | a (sidedata !) | |
3186 |
a ( |
|
3186 | a (upgraded !) | |
3187 | b (known-bad-output sidedata !) |
|
|||
3188 | b (known-bad-output upgraded !) |
|
|||
3189 |
|
3187 | |||
3190 |
|
3188 | |||
3191 | The result from mEAm is the same for the subsequent merge: |
|
3189 | The result from mEAm is the same for the subsequent merge: | |
3192 |
|
3190 | |||
3193 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm")' f |
|
3191 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm")' f | |
3194 | A f |
|
3192 | A f | |
3195 | a (filelog !) |
|
3193 | a (filelog !) | |
3196 | b (sidedata !) |
|
3194 | b (sidedata !) | |
3197 | b (upgraded !) |
|
3195 | b (upgraded !) | |
3198 |
|
3196 | |||
3199 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA,Jm")' f |
|
3197 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA,Jm")' f | |
3200 | A f |
|
3198 | A f | |
3201 | a (filelog !) |
|
3199 | a (filelog !) | |
3202 | b (sidedata !) |
|
3200 | b (sidedata !) | |
3203 | b (upgraded !) |
|
3201 | b (upgraded !) | |
3204 |
|
3202 | |||
3205 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EAm")' f |
|
3203 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EAm")' f | |
3206 | A f |
|
3204 | A f | |
3207 | a (filelog !) |
|
3205 | a (filelog !) | |
3208 |
b ( |
|
3206 | b (sidedata !) | |
3209 |
b ( |
|
3207 | b (upgraded !) | |
3210 | a (known-bad-output sidedata !) |
|
|||
3211 | a (known-bad-output upgraded !) |
|
|||
3212 |
|
3208 | |||
3213 | Subcase: chaining conflicting rename resolution |
|
3209 | Subcase: chaining conflicting rename resolution | |
3214 | ``````````````````````````````````````````````` |
|
3210 | ``````````````````````````````````````````````` | |
3215 |
|
3211 | |||
3216 | The "mPQm" and "mQPm" case create a rename tracking conflict on file 'v'. We |
|
3212 | The "mPQm" and "mQPm" case create a rename tracking conflict on file 'v'. We | |
3217 | add more change on the respective branch and merge again. These second merge |
|
3213 | add more change on the respective branch and merge again. These second merge | |
3218 | does not involve the file 'v' and the arbitration done within "mPQm" and "mQP" |
|
3214 | does not involve the file 'v' and the arbitration done within "mPQm" and "mQP" | |
3219 | about that file should stay unchanged. |
|
3215 | about that file should stay unchanged. | |
3220 |
|
3216 | |||
3221 | The result from mPQm is the same for the subsequent merge: |
|
3217 | The result from mPQm is the same for the subsequent merge: | |
3222 |
|
3218 | |||
3223 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm")' v |
|
3219 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm")' v | |
3224 | A v |
|
3220 | A v | |
3225 | r (filelog !) |
|
3221 | r (filelog !) | |
3226 | p (sidedata !) |
|
3222 | p (sidedata !) | |
3227 | p (upgraded !) |
|
3223 | p (upgraded !) | |
3228 |
|
3224 | |||
3229 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQ,Tm")' v |
|
3225 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQ,Tm")' v | |
3230 | A v |
|
3226 | A v | |
3231 | r (filelog !) |
|
3227 | r (filelog !) | |
3232 | p (sidedata !) |
|
3228 | p (sidedata !) | |
3233 | p (upgraded !) |
|
3229 | p (upgraded !) | |
3234 |
|
3230 | |||
3235 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mT,PQm")' v |
|
3231 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mT,PQm")' v | |
3236 | A v |
|
3232 | A v | |
3237 | r (filelog !) |
|
3233 | r (filelog !) | |
3238 |
p ( |
|
3234 | p (sidedata !) | |
3239 |
p ( |
|
3235 | p (upgraded !) | |
3240 | r (known-bad-output sidedata !) |
|
|||
3241 | r (known-bad-output upgraded !) |
|
|||
3242 |
|
3236 | |||
3243 |
|
3237 | |||
3244 | The result from mQPm is the same for the subsequent merge: |
|
3238 | The result from mQPm is the same for the subsequent merge: | |
3245 |
|
3239 | |||
3246 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm")' v |
|
3240 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm")' v | |
3247 | A v |
|
3241 | A v | |
3248 | r (no-changeset no-compatibility !) |
|
3242 | r (no-changeset no-compatibility !) | |
3249 |
|
3243 | |||
3250 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQP,Sm")' v |
|
3244 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQP,Sm")' v | |
3251 | A v |
|
3245 | A v | |
3252 | r (no-changeset no-compatibility !) |
|
3246 | r (no-changeset no-compatibility !) | |
3253 |
|
3247 | |||
3254 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mS,QPm")' v |
|
3248 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mS,QPm")' v | |
3255 | A v |
|
3249 | A v | |
3256 | r (filelog !) |
|
3250 | r (filelog !) | |
3257 |
r ( |
|
3251 | r (sidedata !) | |
3258 |
r ( |
|
3252 | r (upgraded !) | |
3259 | p (known-bad-output sidedata !) |
|
|||
3260 | p (known-bad-output upgraded !) |
|
|||
3261 |
|
3253 | |||
3262 |
|
3254 | |||
3263 | Subcase: chaining salvage information during a merge |
|
3255 | Subcase: chaining salvage information during a merge | |
3264 | ```````````````````````````````````````````````````` |
|
3256 | ```````````````````````````````````````````````````` | |
3265 |
|
3257 | |||
3266 | We add more change on the branch were the file was deleted. merging again |
|
3258 | We add more change on the branch were the file was deleted. merging again | |
3267 | should preserve the fact eh file was salvaged. |
|
3259 | should preserve the fact eh file was salvaged. | |
3268 |
|
3260 | |||
3269 | reference output: |
|
3261 | reference output: | |
3270 |
|
3262 | |||
3271 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")' |
|
3263 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")' | |
3272 | M b |
|
3264 | M b | |
3273 | A d |
|
3265 | A d | |
3274 | a (filelog !) |
|
3266 | a (no-changeset no-compatibility !) | |
3275 | a (sidedata !) |
|
|||
3276 | a (upgraded !) |
|
|||
3277 | A t |
|
3267 | A t | |
3278 | p |
|
3268 | p | |
3279 | R a |
|
3269 | R a | |
3280 | R p |
|
3270 | R p | |
3281 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")' |
|
3271 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")' | |
3282 | M b |
|
3272 | M b | |
3283 | A d |
|
3273 | A d | |
3284 | a (filelog !) |
|
3274 | a (no-changeset no-compatibility !) | |
3285 | a (sidedata !) |
|
|||
3286 | a (upgraded !) |
|
|||
3287 | A t |
|
3275 | A t | |
3288 | p |
|
3276 | p | |
3289 | R a |
|
3277 | R a | |
3290 | R p |
|
3278 | R p | |
3291 |
|
3279 | |||
3292 | chained output |
|
3280 | chained output | |
3293 |
|
||||
3294 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC+revert,Lm")' |
|
3281 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC+revert,Lm")' | |
3295 | M b |
|
3282 | M b | |
3296 | A d |
|
3283 | A d | |
3297 | a (filelog !) |
|
3284 | a (no-changeset no-compatibility !) | |
3298 | a (missing-correct-output sidedata !) |
|
|||
3299 | a (missing-correct-output upgraded !) |
|
|||
3300 | A t |
|
3285 | A t | |
3301 | p |
|
3286 | p | |
3302 | A unrelated-l |
|
3287 | A unrelated-l | |
3303 | R a |
|
3288 | R a | |
3304 | R p |
|
3289 | R p | |
3305 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB+revert,Lm")' |
|
3290 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB+revert,Lm")' | |
3306 | M b |
|
3291 | M b | |
3307 | A d |
|
3292 | A d | |
3308 | a (filelog !) |
|
3293 | a (no-changeset no-compatibility !) | |
3309 | a (missing-correct-output sidedata !) |
|
|||
3310 | a (missing-correct-output upgraded !) |
|
|||
3311 | A t |
|
3294 | A t | |
3312 | p |
|
3295 | p | |
3313 | A unrelated-l |
|
3296 | A unrelated-l | |
3314 | R a |
|
3297 | R a | |
3315 | R p |
|
3298 | R p | |
3316 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,BC+revertm")' |
|
3299 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,BC+revertm")' | |
3317 | M b |
|
3300 | M b | |
3318 | A d |
|
3301 | A d | |
3319 | a (filelog !) |
|
3302 | a (no-changeset no-compatibility !) | |
3320 | a (missing-correct-output sidedata !) |
|
|||
3321 | a (missing-correct-output upgraded !) |
|
|||
3322 | A t |
|
3303 | A t | |
3323 | p |
|
3304 | p | |
3324 | A unrelated-l |
|
3305 | A unrelated-l | |
3325 | R a |
|
3306 | R a | |
3326 | R p |
|
3307 | R p | |
3327 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,CB+revertm")' |
|
3308 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,CB+revertm")' | |
3328 | M b |
|
3309 | M b | |
3329 | A d |
|
3310 | A d | |
3330 | a (filelog !) |
|
3311 | a (no-changeset no-compatibility !) | |
3331 | a (missing-correct-output sidedata !) |
|
|||
3332 | a (missing-correct-output upgraded !) |
|
|||
3333 | A t |
|
3312 | A t | |
3334 | p |
|
3313 | p | |
3335 | A unrelated-l |
|
3314 | A unrelated-l | |
3336 | R a |
|
3315 | R a | |
3337 | R p |
|
3316 | R p | |
3338 |
|
3317 | |||
3339 | Subcase: chaining "merged" information during a merge |
|
3318 | Subcase: chaining "merged" information during a merge | |
3340 | `````````````````````````````````````````````````````` |
|
3319 | `````````````````````````````````````````````````````` | |
3341 |
|
3320 | |||
3342 | When a non-rename change are merged with a copy overwrite, the merge pick the copy source from (p1) as the reference. We should preserve this information in subsequent merges. |
|
3321 | When a non-rename change are merged with a copy overwrite, the merge pick the copy source from (p1) as the reference. We should preserve this information in subsequent merges. | |
3343 |
|
3322 | |||
3344 |
|
3323 | |||
3345 | reference output: |
|
3324 | reference output: | |
3346 |
|
3325 | |||
3347 | (for details about the filelog pick, check the mFGm/mGFm case) |
|
3326 | (for details about the filelog pick, check the mFGm/mGFm case) | |
3348 |
|
3327 | |||
3349 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm")' d |
|
3328 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm")' d | |
3350 | A d |
|
3329 | A d | |
3351 | a (filelog !) |
|
3330 | a (filelog !) | |
3352 | h (sidedata !) |
|
3331 | h (sidedata !) | |
3353 | h (upgraded !) |
|
3332 | h (upgraded !) | |
3354 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm")' d |
|
3333 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm")' d | |
3355 | A d |
|
3334 | A d | |
3356 | a (filelog !) |
|
3335 | a (filelog !) | |
3357 | a (sidedata !) |
|
3336 | a (sidedata !) | |
3358 | a (upgraded !) |
|
3337 | a (upgraded !) | |
3359 |
|
3338 | |||
3360 | Chained output |
|
3339 | Chained output | |
3361 |
|
3340 | |||
3362 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mO,FGm")' d |
|
3341 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mO,FGm")' d | |
3363 | A d |
|
3342 | A d | |
3364 | a (filelog !) |
|
3343 | a (filelog !) | |
3365 | h (sidedata !) |
|
3344 | h (sidedata !) | |
3366 | h (upgraded !) |
|
3345 | h (upgraded !) | |
3367 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFG,Om")' d |
|
3346 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFG,Om")' d | |
3368 | A d |
|
3347 | A d | |
3369 | a (filelog !) |
|
3348 | a (filelog !) | |
3370 | h (sidedata !) |
|
3349 | h (sidedata !) | |
3371 | h (upgraded !) |
|
3350 | h (upgraded !) | |
3372 |
|
3351 | |||
3373 |
|
3352 | |||
3374 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGF,Nm")' d |
|
3353 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGF,Nm")' d | |
3375 | A d |
|
3354 | A d | |
3376 | a (filelog !) |
|
3355 | a (no-changeset no-compatibility !) | |
3377 | a (missing-correct-output sidedata !) |
|
|||
3378 | a (missing-correct-output upgraded !) |
|
|||
3379 | h (known-bad-output sidedata !) |
|
|||
3380 | h (known-bad-output upgraded !) |
|
|||
3381 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mN,GFm")' d |
|
3356 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mN,GFm")' d | |
3382 | A d |
|
3357 | A d | |
3383 | a (filelog !) |
|
3358 | a (no-changeset no-compatibility !) | |
3384 | a (missing-correct-output sidedata !) |
|
|||
3385 | a (missing-correct-output upgraded !) |
|
|||
3386 | h (known-bad-output sidedata !) |
|
|||
3387 | h (known-bad-output upgraded !) |
|
|||
3388 |
|
3359 | |||
3389 |
|
3360 | |||
3390 | Subcase: chaining conflicting rename resolution, with extra change during the merge |
|
3361 | Subcase: chaining conflicting rename resolution, with extra change during the merge | |
3391 | ``````````````````````````````````````````````````````````````````````````````````` |
|
3362 | ``````````````````````````````````````````````````````````````````````````````````` | |
3392 |
|
3363 | |||
3393 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We |
|
3364 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We | |
3394 | add more change on the respective branch and merge again. These second merge |
|
3365 | add more change on the respective branch and merge again. These second merge | |
3395 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" |
|
3366 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" | |
3396 | about that file should stay unchanged. |
|
3367 | about that file should stay unchanged. | |
3397 |
|
3368 | |||
3398 | The result from mAEm is the same for the subsequent merge: |
|
3369 | The result from mAEm is the same for the subsequent merge: | |
3399 |
|
3370 | |||
3400 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m")' f |
|
3371 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m")' f | |
3401 | A f |
|
3372 | A f | |
3402 | a (filelog !) |
|
3373 | a (filelog !) | |
3403 | a (sidedata !) |
|
3374 | a (sidedata !) | |
3404 | a (upgraded !) |
|
3375 | a (upgraded !) | |
3405 |
|
3376 | |||
3406 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change,Km")' f |
|
3377 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change,Km")' f | |
3407 | A f |
|
3378 | A f | |
3408 | a (filelog !) |
|
3379 | a (filelog !) | |
3409 | a (sidedata !) |
|
3380 | a (sidedata !) | |
3410 | a (upgraded !) |
|
3381 | a (upgraded !) | |
3411 |
|
3382 | |||
3412 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AE-change-m")' f |
|
3383 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AE-change-m")' f | |
3413 | A f |
|
3384 | A f | |
3414 | a (filelog !) |
|
3385 | a (no-changeset no-compatibility !) | |
3415 | a (missing-correct-output sidedata !) |
|
|||
3416 | a (missing-correct-output upgraded !) |
|
|||
3417 | b (known-bad-output sidedata !) |
|
|||
3418 | b (known-bad-output upgraded !) |
|
|||
3419 |
|
3386 | |||
3420 |
|
3387 | |||
3421 | The result from mEAm is the same for the subsequent merge: |
|
3388 | The result from mEAm is the same for the subsequent merge: | |
3422 |
|
3389 | |||
3423 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m")' f |
|
3390 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m")' f | |
3424 | A f |
|
3391 | A f | |
3425 | a (filelog !) |
|
3392 | a (filelog !) | |
3426 | b (sidedata !) |
|
3393 | b (sidedata !) | |
3427 | b (upgraded !) |
|
3394 | b (upgraded !) | |
3428 |
|
3395 | |||
3429 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change,Jm")' f |
|
3396 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change,Jm")' f | |
3430 | A f |
|
3397 | A f | |
3431 | a (filelog !) |
|
3398 | a (filelog !) | |
3432 | b (sidedata !) |
|
3399 | b (sidedata !) | |
3433 | b (upgraded !) |
|
3400 | b (upgraded !) | |
3434 |
|
3401 | |||
3435 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EA-change-m")' f |
|
3402 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EA-change-m")' f | |
3436 | A f |
|
3403 | A f | |
3437 | a (filelog !) |
|
3404 | a (filelog !) | |
3438 |
b ( |
|
3405 | b (sidedata !) | |
3439 |
b ( |
|
3406 | b (upgraded !) | |
3440 | a (known-bad-output sidedata !) |
|
|||
3441 | a (known-bad-output upgraded !) |
|
General Comments 0
You need to be logged in to leave comments.
Login now