##// END OF EJS Templates
merge: avoid superfluous filemerges when grafting through renames (issue5407)...
Gábor Stefanik -
r30229:69ffbbe7 stable
parent child Browse files
Show More
@@ -1,710 +1,714 b''
1 # copies.py - copy detection for Mercurial
1 # copies.py - copy detection for Mercurial
2 #
2 #
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import heapq
10 import heapq
11
11
12 from . import (
12 from . import (
13 node,
13 node,
14 pathutil,
14 pathutil,
15 scmutil,
15 scmutil,
16 util,
16 util,
17 )
17 )
18
18
19 def _findlimit(repo, a, b):
19 def _findlimit(repo, a, b):
20 """
20 """
21 Find the last revision that needs to be checked to ensure that a full
21 Find the last revision that needs to be checked to ensure that a full
22 transitive closure for file copies can be properly calculated.
22 transitive closure for file copies can be properly calculated.
23 Generally, this means finding the earliest revision number that's an
23 Generally, this means finding the earliest revision number that's an
24 ancestor of a or b but not both, except when a or b is a direct descendent
24 ancestor of a or b but not both, except when a or b is a direct descendent
25 of the other, in which case we can return the minimum revnum of a and b.
25 of the other, in which case we can return the minimum revnum of a and b.
26 None if no such revision exists.
26 None if no such revision exists.
27 """
27 """
28
28
29 # basic idea:
29 # basic idea:
30 # - mark a and b with different sides
30 # - mark a and b with different sides
31 # - if a parent's children are all on the same side, the parent is
31 # - if a parent's children are all on the same side, the parent is
32 # on that side, otherwise it is on no side
32 # on that side, otherwise it is on no side
33 # - walk the graph in topological order with the help of a heap;
33 # - walk the graph in topological order with the help of a heap;
34 # - add unseen parents to side map
34 # - add unseen parents to side map
35 # - clear side of any parent that has children on different sides
35 # - clear side of any parent that has children on different sides
36 # - track number of interesting revs that might still be on a side
36 # - track number of interesting revs that might still be on a side
37 # - track the lowest interesting rev seen
37 # - track the lowest interesting rev seen
38 # - quit when interesting revs is zero
38 # - quit when interesting revs is zero
39
39
40 cl = repo.changelog
40 cl = repo.changelog
41 working = len(cl) # pseudo rev for the working directory
41 working = len(cl) # pseudo rev for the working directory
42 if a is None:
42 if a is None:
43 a = working
43 a = working
44 if b is None:
44 if b is None:
45 b = working
45 b = working
46
46
47 side = {a: -1, b: 1}
47 side = {a: -1, b: 1}
48 visit = [-a, -b]
48 visit = [-a, -b]
49 heapq.heapify(visit)
49 heapq.heapify(visit)
50 interesting = len(visit)
50 interesting = len(visit)
51 hascommonancestor = False
51 hascommonancestor = False
52 limit = working
52 limit = working
53
53
54 while interesting:
54 while interesting:
55 r = -heapq.heappop(visit)
55 r = -heapq.heappop(visit)
56 if r == working:
56 if r == working:
57 parents = [cl.rev(p) for p in repo.dirstate.parents()]
57 parents = [cl.rev(p) for p in repo.dirstate.parents()]
58 else:
58 else:
59 parents = cl.parentrevs(r)
59 parents = cl.parentrevs(r)
60 for p in parents:
60 for p in parents:
61 if p < 0:
61 if p < 0:
62 continue
62 continue
63 if p not in side:
63 if p not in side:
64 # first time we see p; add it to visit
64 # first time we see p; add it to visit
65 side[p] = side[r]
65 side[p] = side[r]
66 if side[p]:
66 if side[p]:
67 interesting += 1
67 interesting += 1
68 heapq.heappush(visit, -p)
68 heapq.heappush(visit, -p)
69 elif side[p] and side[p] != side[r]:
69 elif side[p] and side[p] != side[r]:
70 # p was interesting but now we know better
70 # p was interesting but now we know better
71 side[p] = 0
71 side[p] = 0
72 interesting -= 1
72 interesting -= 1
73 hascommonancestor = True
73 hascommonancestor = True
74 if side[r]:
74 if side[r]:
75 limit = r # lowest rev visited
75 limit = r # lowest rev visited
76 interesting -= 1
76 interesting -= 1
77
77
78 if not hascommonancestor:
78 if not hascommonancestor:
79 return None
79 return None
80
80
81 # Consider the following flow (see test-commit-amend.t under issue4405):
81 # Consider the following flow (see test-commit-amend.t under issue4405):
82 # 1/ File 'a0' committed
82 # 1/ File 'a0' committed
83 # 2/ File renamed from 'a0' to 'a1' in a new commit (call it 'a1')
83 # 2/ File renamed from 'a0' to 'a1' in a new commit (call it 'a1')
84 # 3/ Move back to first commit
84 # 3/ Move back to first commit
85 # 4/ Create a new commit via revert to contents of 'a1' (call it 'a1-amend')
85 # 4/ Create a new commit via revert to contents of 'a1' (call it 'a1-amend')
86 # 5/ Rename file from 'a1' to 'a2' and commit --amend 'a1-msg'
86 # 5/ Rename file from 'a1' to 'a2' and commit --amend 'a1-msg'
87 #
87 #
88 # During the amend in step five, we will be in this state:
88 # During the amend in step five, we will be in this state:
89 #
89 #
90 # @ 3 temporary amend commit for a1-amend
90 # @ 3 temporary amend commit for a1-amend
91 # |
91 # |
92 # o 2 a1-amend
92 # o 2 a1-amend
93 # |
93 # |
94 # | o 1 a1
94 # | o 1 a1
95 # |/
95 # |/
96 # o 0 a0
96 # o 0 a0
97 #
97 #
98 # When _findlimit is called, a and b are revs 3 and 0, so limit will be 2,
98 # When _findlimit is called, a and b are revs 3 and 0, so limit will be 2,
99 # yet the filelog has the copy information in rev 1 and we will not look
99 # yet the filelog has the copy information in rev 1 and we will not look
100 # back far enough unless we also look at the a and b as candidates.
100 # back far enough unless we also look at the a and b as candidates.
101 # This only occurs when a is a descendent of b or visa-versa.
101 # This only occurs when a is a descendent of b or visa-versa.
102 return min(limit, a, b)
102 return min(limit, a, b)
103
103
104 def _chain(src, dst, a, b):
104 def _chain(src, dst, a, b):
105 '''chain two sets of copies a->b'''
105 '''chain two sets of copies a->b'''
106 t = a.copy()
106 t = a.copy()
107 for k, v in b.iteritems():
107 for k, v in b.iteritems():
108 if v in t:
108 if v in t:
109 # found a chain
109 # found a chain
110 if t[v] != k:
110 if t[v] != k:
111 # file wasn't renamed back to itself
111 # file wasn't renamed back to itself
112 t[k] = t[v]
112 t[k] = t[v]
113 if v not in dst:
113 if v not in dst:
114 # chain was a rename, not a copy
114 # chain was a rename, not a copy
115 del t[v]
115 del t[v]
116 if v in src:
116 if v in src:
117 # file is a copy of an existing file
117 # file is a copy of an existing file
118 t[k] = v
118 t[k] = v
119
119
120 # remove criss-crossed copies
120 # remove criss-crossed copies
121 for k, v in t.items():
121 for k, v in t.items():
122 if k in src and v in dst:
122 if k in src and v in dst:
123 del t[k]
123 del t[k]
124
124
125 return t
125 return t
126
126
127 def _tracefile(fctx, am, limit=-1):
127 def _tracefile(fctx, am, limit=-1):
128 '''return file context that is the ancestor of fctx present in ancestor
128 '''return file context that is the ancestor of fctx present in ancestor
129 manifest am, stopping after the first ancestor lower than limit'''
129 manifest am, stopping after the first ancestor lower than limit'''
130
130
131 for f in fctx.ancestors():
131 for f in fctx.ancestors():
132 if am.get(f.path(), None) == f.filenode():
132 if am.get(f.path(), None) == f.filenode():
133 return f
133 return f
134 if limit >= 0 and f.linkrev() < limit and f.rev() < limit:
134 if limit >= 0 and f.linkrev() < limit and f.rev() < limit:
135 return None
135 return None
136
136
137 def _dirstatecopies(d):
137 def _dirstatecopies(d):
138 ds = d._repo.dirstate
138 ds = d._repo.dirstate
139 c = ds.copies().copy()
139 c = ds.copies().copy()
140 for k in c.keys():
140 for k in c.keys():
141 if ds[k] not in 'anm':
141 if ds[k] not in 'anm':
142 del c[k]
142 del c[k]
143 return c
143 return c
144
144
145 def _computeforwardmissing(a, b, match=None):
145 def _computeforwardmissing(a, b, match=None):
146 """Computes which files are in b but not a.
146 """Computes which files are in b but not a.
147 This is its own function so extensions can easily wrap this call to see what
147 This is its own function so extensions can easily wrap this call to see what
148 files _forwardcopies is about to process.
148 files _forwardcopies is about to process.
149 """
149 """
150 ma = a.manifest()
150 ma = a.manifest()
151 mb = b.manifest()
151 mb = b.manifest()
152 if match:
152 if match:
153 ma = ma.matches(match)
153 ma = ma.matches(match)
154 mb = mb.matches(match)
154 mb = mb.matches(match)
155 return mb.filesnotin(ma)
155 return mb.filesnotin(ma)
156
156
157 def _forwardcopies(a, b, match=None):
157 def _forwardcopies(a, b, match=None):
158 '''find {dst@b: src@a} copy mapping where a is an ancestor of b'''
158 '''find {dst@b: src@a} copy mapping where a is an ancestor of b'''
159
159
160 # check for working copy
160 # check for working copy
161 w = None
161 w = None
162 if b.rev() is None:
162 if b.rev() is None:
163 w = b
163 w = b
164 b = w.p1()
164 b = w.p1()
165 if a == b:
165 if a == b:
166 # short-circuit to avoid issues with merge states
166 # short-circuit to avoid issues with merge states
167 return _dirstatecopies(w)
167 return _dirstatecopies(w)
168
168
169 # files might have to be traced back to the fctx parent of the last
169 # files might have to be traced back to the fctx parent of the last
170 # one-side-only changeset, but not further back than that
170 # one-side-only changeset, but not further back than that
171 limit = _findlimit(a._repo, a.rev(), b.rev())
171 limit = _findlimit(a._repo, a.rev(), b.rev())
172 if limit is None:
172 if limit is None:
173 limit = -1
173 limit = -1
174 am = a.manifest()
174 am = a.manifest()
175
175
176 # find where new files came from
176 # find where new files came from
177 # we currently don't try to find where old files went, too expensive
177 # we currently don't try to find where old files went, too expensive
178 # this means we can miss a case like 'hg rm b; hg cp a b'
178 # this means we can miss a case like 'hg rm b; hg cp a b'
179 cm = {}
179 cm = {}
180
180
181 # Computing the forward missing is quite expensive on large manifests, since
181 # Computing the forward missing is quite expensive on large manifests, since
182 # it compares the entire manifests. We can optimize it in the common use
182 # it compares the entire manifests. We can optimize it in the common use
183 # case of computing what copies are in a commit versus its parent (like
183 # case of computing what copies are in a commit versus its parent (like
184 # during a rebase or histedit). Note, we exclude merge commits from this
184 # during a rebase or histedit). Note, we exclude merge commits from this
185 # optimization, since the ctx.files() for a merge commit is not correct for
185 # optimization, since the ctx.files() for a merge commit is not correct for
186 # this comparison.
186 # this comparison.
187 forwardmissingmatch = match
187 forwardmissingmatch = match
188 if not match and b.p1() == a and b.p2().node() == node.nullid:
188 if not match and b.p1() == a and b.p2().node() == node.nullid:
189 forwardmissingmatch = scmutil.matchfiles(a._repo, b.files())
189 forwardmissingmatch = scmutil.matchfiles(a._repo, b.files())
190 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
190 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
191
191
192 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
192 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
193 for f in missing:
193 for f in missing:
194 fctx = b[f]
194 fctx = b[f]
195 fctx._ancestrycontext = ancestrycontext
195 fctx._ancestrycontext = ancestrycontext
196 ofctx = _tracefile(fctx, am, limit)
196 ofctx = _tracefile(fctx, am, limit)
197 if ofctx:
197 if ofctx:
198 cm[f] = ofctx.path()
198 cm[f] = ofctx.path()
199
199
200 # combine copies from dirstate if necessary
200 # combine copies from dirstate if necessary
201 if w is not None:
201 if w is not None:
202 cm = _chain(a, w, cm, _dirstatecopies(w))
202 cm = _chain(a, w, cm, _dirstatecopies(w))
203
203
204 return cm
204 return cm
205
205
206 def _backwardrenames(a, b):
206 def _backwardrenames(a, b):
207 if a._repo.ui.configbool('experimental', 'disablecopytrace'):
207 if a._repo.ui.configbool('experimental', 'disablecopytrace'):
208 return {}
208 return {}
209
209
210 # Even though we're not taking copies into account, 1:n rename situations
210 # Even though we're not taking copies into account, 1:n rename situations
211 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
211 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
212 # arbitrarily pick one of the renames.
212 # arbitrarily pick one of the renames.
213 f = _forwardcopies(b, a)
213 f = _forwardcopies(b, a)
214 r = {}
214 r = {}
215 for k, v in sorted(f.iteritems()):
215 for k, v in sorted(f.iteritems()):
216 # remove copies
216 # remove copies
217 if v in a:
217 if v in a:
218 continue
218 continue
219 r[v] = k
219 r[v] = k
220 return r
220 return r
221
221
222 def pathcopies(x, y, match=None):
222 def pathcopies(x, y, match=None):
223 '''find {dst@y: src@x} copy mapping for directed compare'''
223 '''find {dst@y: src@x} copy mapping for directed compare'''
224 if x == y or not x or not y:
224 if x == y or not x or not y:
225 return {}
225 return {}
226 a = y.ancestor(x)
226 a = y.ancestor(x)
227 if a == x:
227 if a == x:
228 return _forwardcopies(x, y, match=match)
228 return _forwardcopies(x, y, match=match)
229 if a == y:
229 if a == y:
230 return _backwardrenames(x, y)
230 return _backwardrenames(x, y)
231 return _chain(x, y, _backwardrenames(x, a),
231 return _chain(x, y, _backwardrenames(x, a),
232 _forwardcopies(a, y, match=match))
232 _forwardcopies(a, y, match=match))
233
233
234 def _computenonoverlap(repo, c1, c2, addedinm1, addedinm2, baselabel=''):
234 def _computenonoverlap(repo, c1, c2, addedinm1, addedinm2, baselabel=''):
235 """Computes, based on addedinm1 and addedinm2, the files exclusive to c1
235 """Computes, based on addedinm1 and addedinm2, the files exclusive to c1
236 and c2. This is its own function so extensions can easily wrap this call
236 and c2. This is its own function so extensions can easily wrap this call
237 to see what files mergecopies is about to process.
237 to see what files mergecopies is about to process.
238
238
239 Even though c1 and c2 are not used in this function, they are useful in
239 Even though c1 and c2 are not used in this function, they are useful in
240 other extensions for being able to read the file nodes of the changed files.
240 other extensions for being able to read the file nodes of the changed files.
241
241
242 "baselabel" can be passed to help distinguish the multiple computations
242 "baselabel" can be passed to help distinguish the multiple computations
243 done in the graft case.
243 done in the graft case.
244 """
244 """
245 u1 = sorted(addedinm1 - addedinm2)
245 u1 = sorted(addedinm1 - addedinm2)
246 u2 = sorted(addedinm2 - addedinm1)
246 u2 = sorted(addedinm2 - addedinm1)
247
247
248 header = " unmatched files in %s"
248 header = " unmatched files in %s"
249 if baselabel:
249 if baselabel:
250 header += ' (from %s)' % baselabel
250 header += ' (from %s)' % baselabel
251 if u1:
251 if u1:
252 repo.ui.debug("%s:\n %s\n" % (header % 'local', "\n ".join(u1)))
252 repo.ui.debug("%s:\n %s\n" % (header % 'local', "\n ".join(u1)))
253 if u2:
253 if u2:
254 repo.ui.debug("%s:\n %s\n" % (header % 'other', "\n ".join(u2)))
254 repo.ui.debug("%s:\n %s\n" % (header % 'other', "\n ".join(u2)))
255 return u1, u2
255 return u1, u2
256
256
257 def _makegetfctx(ctx):
257 def _makegetfctx(ctx):
258 """return a 'getfctx' function suitable for _checkcopies usage
258 """return a 'getfctx' function suitable for _checkcopies usage
259
259
260 We have to re-setup the function building 'filectx' for each
260 We have to re-setup the function building 'filectx' for each
261 '_checkcopies' to ensure the linkrev adjustment is properly setup for
261 '_checkcopies' to ensure the linkrev adjustment is properly setup for
262 each. Linkrev adjustment is important to avoid bug in rename
262 each. Linkrev adjustment is important to avoid bug in rename
263 detection. Moreover, having a proper '_ancestrycontext' setup ensures
263 detection. Moreover, having a proper '_ancestrycontext' setup ensures
264 the performance impact of this adjustment is kept limited. Without it,
264 the performance impact of this adjustment is kept limited. Without it,
265 each file could do a full dag traversal making the time complexity of
265 each file could do a full dag traversal making the time complexity of
266 the operation explode (see issue4537).
266 the operation explode (see issue4537).
267
267
268 This function exists here mostly to limit the impact on stable. Feel
268 This function exists here mostly to limit the impact on stable. Feel
269 free to refactor on default.
269 free to refactor on default.
270 """
270 """
271 rev = ctx.rev()
271 rev = ctx.rev()
272 repo = ctx._repo
272 repo = ctx._repo
273 ac = getattr(ctx, '_ancestrycontext', None)
273 ac = getattr(ctx, '_ancestrycontext', None)
274 if ac is None:
274 if ac is None:
275 revs = [rev]
275 revs = [rev]
276 if rev is None:
276 if rev is None:
277 revs = [p.rev() for p in ctx.parents()]
277 revs = [p.rev() for p in ctx.parents()]
278 ac = repo.changelog.ancestors(revs, inclusive=True)
278 ac = repo.changelog.ancestors(revs, inclusive=True)
279 ctx._ancestrycontext = ac
279 ctx._ancestrycontext = ac
280 def makectx(f, n):
280 def makectx(f, n):
281 if len(n) != 20: # in a working context?
281 if len(n) != 20: # in a working context?
282 if ctx.rev() is None:
282 if ctx.rev() is None:
283 return ctx.filectx(f)
283 return ctx.filectx(f)
284 return repo[None][f]
284 return repo[None][f]
285 fctx = repo.filectx(f, fileid=n)
285 fctx = repo.filectx(f, fileid=n)
286 # setup only needed for filectx not create from a changectx
286 # setup only needed for filectx not create from a changectx
287 fctx._ancestrycontext = ac
287 fctx._ancestrycontext = ac
288 fctx._descendantrev = rev
288 fctx._descendantrev = rev
289 return fctx
289 return fctx
290 return util.lrucachefunc(makectx)
290 return util.lrucachefunc(makectx)
291
291
292 def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
292 def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
293 """combine partial copy paths"""
293 """combine partial copy paths"""
294 remainder = {}
294 remainder = {}
295 for f in copyfrom:
295 for f in copyfrom:
296 if f in copyto:
296 if f in copyto:
297 finalcopy[copyto[f]] = copyfrom[f]
297 finalcopy[copyto[f]] = copyfrom[f]
298 del copyto[f]
298 del copyto[f]
299 for f in incompletediverge:
299 for f in incompletediverge:
300 assert f not in diverge
300 assert f not in diverge
301 ic = incompletediverge[f]
301 ic = incompletediverge[f]
302 if ic[0] in copyto:
302 if ic[0] in copyto:
303 diverge[f] = [copyto[ic[0]], ic[1]]
303 diverge[f] = [copyto[ic[0]], ic[1]]
304 else:
304 else:
305 remainder[f] = ic
305 remainder[f] = ic
306 return remainder
306 return remainder
307
307
308 def mergecopies(repo, c1, c2, base):
308 def mergecopies(repo, c1, c2, base):
309 """
309 """
310 Find moves and copies between context c1 and c2 that are relevant
310 Find moves and copies between context c1 and c2 that are relevant
311 for merging. 'base' will be used as the merge base.
311 for merging. 'base' will be used as the merge base.
312
312
313 Returns four dicts: "copy", "movewithdir", "diverge", and
313 Returns four dicts: "copy", "movewithdir", "diverge", and
314 "renamedelete".
314 "renamedelete".
315
315
316 "copy" is a mapping from destination name -> source name,
316 "copy" is a mapping from destination name -> source name,
317 where source is in c1 and destination is in c2 or vice-versa.
317 where source is in c1 and destination is in c2 or vice-versa.
318
318
319 "movewithdir" is a mapping from source name -> destination name,
319 "movewithdir" is a mapping from source name -> destination name,
320 where the file at source present in one context but not the other
320 where the file at source present in one context but not the other
321 needs to be moved to destination by the merge process, because the
321 needs to be moved to destination by the merge process, because the
322 other context moved the directory it is in.
322 other context moved the directory it is in.
323
323
324 "diverge" is a mapping of source name -> list of destination names
324 "diverge" is a mapping of source name -> list of destination names
325 for divergent renames.
325 for divergent renames.
326
326
327 "renamedelete" is a mapping of source name -> list of destination
327 "renamedelete" is a mapping of source name -> list of destination
328 names for files deleted in c1 that were renamed in c2 or vice-versa.
328 names for files deleted in c1 that were renamed in c2 or vice-versa.
329 """
329 """
330 # avoid silly behavior for update from empty dir
330 # avoid silly behavior for update from empty dir
331 if not c1 or not c2 or c1 == c2:
331 if not c1 or not c2 or c1 == c2:
332 return {}, {}, {}, {}
332 return {}, {}, {}, {}
333
333
334 # avoid silly behavior for parent -> working dir
334 # avoid silly behavior for parent -> working dir
335 if c2.node() is None and c1.node() == repo.dirstate.p1():
335 if c2.node() is None and c1.node() == repo.dirstate.p1():
336 return repo.dirstate.copies(), {}, {}, {}
336 return repo.dirstate.copies(), {}, {}, {}
337
337
338 # Copy trace disabling is explicitly below the node == p1 logic above
338 # Copy trace disabling is explicitly below the node == p1 logic above
339 # because the logic above is required for a simple copy to be kept across a
339 # because the logic above is required for a simple copy to be kept across a
340 # rebase.
340 # rebase.
341 if repo.ui.configbool('experimental', 'disablecopytrace'):
341 if repo.ui.configbool('experimental', 'disablecopytrace'):
342 return {}, {}, {}, {}
342 return {}, {}, {}, {}
343
343
344 # In certain scenarios (e.g. graft, update or rebase), base can be
344 # In certain scenarios (e.g. graft, update or rebase), base can be
345 # overridden We still need to know a real common ancestor in this case We
345 # overridden We still need to know a real common ancestor in this case We
346 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
346 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
347 # can be multiple common ancestors, e.g. in case of bidmerge. Because our
347 # can be multiple common ancestors, e.g. in case of bidmerge. Because our
348 # caller may not know if the revision passed in lieu of the CA is a genuine
348 # caller may not know if the revision passed in lieu of the CA is a genuine
349 # common ancestor or not without explicitly checking it, it's better to
349 # common ancestor or not without explicitly checking it, it's better to
350 # determine that here.
350 # determine that here.
351 #
351 #
352 # base.descendant(wc) and base.descendant(base) are False, work around that
352 # base.descendant(wc) and base.descendant(base) are False, work around that
353 _c1 = c1.p1() if c1.rev() is None else c1
353 _c1 = c1.p1() if c1.rev() is None else c1
354 _c2 = c2.p1() if c2.rev() is None else c2
354 _c2 = c2.p1() if c2.rev() is None else c2
355 # an endpoint is "dirty" if it isn't a descendant of the merge base
355 # an endpoint is "dirty" if it isn't a descendant of the merge base
356 # if we have a dirty endpoint, we need to trigger graft logic, and also
356 # if we have a dirty endpoint, we need to trigger graft logic, and also
357 # keep track of which endpoint is dirty
357 # keep track of which endpoint is dirty
358 dirtyc1 = not (base == _c1 or base.descendant(_c1))
358 dirtyc1 = not (base == _c1 or base.descendant(_c1))
359 dirtyc2 = not (base== _c2 or base.descendant(_c2))
359 dirtyc2 = not (base== _c2 or base.descendant(_c2))
360 graft = dirtyc1 or dirtyc2
360 graft = dirtyc1 or dirtyc2
361 tca = base
361 tca = base
362 if graft:
362 if graft:
363 tca = _c1.ancestor(_c2)
363 tca = _c1.ancestor(_c2)
364
364
365 limit = _findlimit(repo, c1.rev(), c2.rev())
365 limit = _findlimit(repo, c1.rev(), c2.rev())
366 if limit is None:
366 if limit is None:
367 # no common ancestor, no copies
367 # no common ancestor, no copies
368 return {}, {}, {}, {}
368 return {}, {}, {}, {}
369 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
369 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
370
370
371 m1 = c1.manifest()
371 m1 = c1.manifest()
372 m2 = c2.manifest()
372 m2 = c2.manifest()
373 mb = base.manifest()
373 mb = base.manifest()
374
374
375 # gather data from _checkcopies:
375 # gather data from _checkcopies:
376 # - diverge = record all diverges in this dict
376 # - diverge = record all diverges in this dict
377 # - copy = record all non-divergent copies in this dict
377 # - copy = record all non-divergent copies in this dict
378 # - fullcopy = record all copies in this dict
378 # - fullcopy = record all copies in this dict
379 # - incomplete = record non-divergent partial copies here
379 # - incomplete = record non-divergent partial copies here
380 # - incompletediverge = record divergent partial copies here
380 # - incompletediverge = record divergent partial copies here
381 diverge = {} # divergence data is shared
381 diverge = {} # divergence data is shared
382 incompletediverge = {}
382 incompletediverge = {}
383 data1 = {'copy': {},
383 data1 = {'copy': {},
384 'fullcopy': {},
384 'fullcopy': {},
385 'incomplete': {},
385 'incomplete': {},
386 'diverge': diverge,
386 'diverge': diverge,
387 'incompletediverge': incompletediverge,
387 'incompletediverge': incompletediverge,
388 }
388 }
389 data2 = {'copy': {},
389 data2 = {'copy': {},
390 'fullcopy': {},
390 'fullcopy': {},
391 'incomplete': {},
391 'incomplete': {},
392 'diverge': diverge,
392 'diverge': diverge,
393 'incompletediverge': incompletediverge,
393 'incompletediverge': incompletediverge,
394 }
394 }
395
395
396 # find interesting file sets from manifests
396 # find interesting file sets from manifests
397 addedinm1 = m1.filesnotin(mb)
397 addedinm1 = m1.filesnotin(mb)
398 addedinm2 = m2.filesnotin(mb)
398 addedinm2 = m2.filesnotin(mb)
399 bothnew = sorted(addedinm1 & addedinm2)
399 bothnew = sorted(addedinm1 & addedinm2)
400 if tca == base:
400 if tca == base:
401 # unmatched file from base
401 # unmatched file from base
402 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
402 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
403 u1u, u2u = u1r, u2r
403 u1u, u2u = u1r, u2r
404 else:
404 else:
405 # unmatched file from base (DAG rotation in the graft case)
405 # unmatched file from base (DAG rotation in the graft case)
406 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2,
406 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2,
407 baselabel='base')
407 baselabel='base')
408 # unmatched file from topological common ancestors (no DAG rotation)
408 # unmatched file from topological common ancestors (no DAG rotation)
409 # need to recompute this for directory move handling when grafting
409 # need to recompute this for directory move handling when grafting
410 mta = tca.manifest()
410 mta = tca.manifest()
411 u1u, u2u = _computenonoverlap(repo, c1, c2, m1.filesnotin(mta),
411 u1u, u2u = _computenonoverlap(repo, c1, c2, m1.filesnotin(mta),
412 m2.filesnotin(mta),
412 m2.filesnotin(mta),
413 baselabel='topological common ancestor')
413 baselabel='topological common ancestor')
414
414
415 for f in u1u:
415 for f in u1u:
416 _checkcopies(c1, f, m1, m2, base, tca, dirtyc1, limit, data1)
416 _checkcopies(c1, f, m1, m2, base, tca, dirtyc1, limit, data1)
417
417
418 for f in u2u:
418 for f in u2u:
419 _checkcopies(c2, f, m2, m1, base, tca, dirtyc2, limit, data2)
419 _checkcopies(c2, f, m2, m1, base, tca, dirtyc2, limit, data2)
420
420
421 copy = dict(data1['copy'].items() + data2['copy'].items())
421 copy = dict(data1['copy'].items() + data2['copy'].items())
422 fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items())
422 fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items())
423
423
424 if dirtyc1:
424 if dirtyc1:
425 _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
425 _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
426 incompletediverge)
426 incompletediverge)
427 else:
427 else:
428 _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
428 _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
429 incompletediverge)
429 incompletediverge)
430
430
431 renamedelete = {}
431 renamedelete = {}
432 renamedeleteset = set()
432 renamedeleteset = set()
433 divergeset = set()
433 divergeset = set()
434 for of, fl in diverge.items():
434 for of, fl in diverge.items():
435 if len(fl) == 1 or of in c1 or of in c2:
435 if len(fl) == 1 or of in c1 or of in c2:
436 del diverge[of] # not actually divergent, or not a rename
436 del diverge[of] # not actually divergent, or not a rename
437 if of not in c1 and of not in c2:
437 if of not in c1 and of not in c2:
438 # renamed on one side, deleted on the other side, but filter
438 # renamed on one side, deleted on the other side, but filter
439 # out files that have been renamed and then deleted
439 # out files that have been renamed and then deleted
440 renamedelete[of] = [f for f in fl if f in c1 or f in c2]
440 renamedelete[of] = [f for f in fl if f in c1 or f in c2]
441 renamedeleteset.update(fl) # reverse map for below
441 renamedeleteset.update(fl) # reverse map for below
442 else:
442 else:
443 divergeset.update(fl) # reverse map for below
443 divergeset.update(fl) # reverse map for below
444
444
445 if bothnew:
445 if bothnew:
446 repo.ui.debug(" unmatched files new in both:\n %s\n"
446 repo.ui.debug(" unmatched files new in both:\n %s\n"
447 % "\n ".join(bothnew))
447 % "\n ".join(bothnew))
448 bothdiverge = {}
448 bothdiverge = {}
449 bothincompletediverge = {}
449 bothincompletediverge = {}
450 remainder = {}
450 remainder = {}
451 both1 = {'copy': {},
451 both1 = {'copy': {},
452 'fullcopy': {},
452 'fullcopy': {},
453 'incomplete': {},
453 'incomplete': {},
454 'diverge': bothdiverge,
454 'diverge': bothdiverge,
455 'incompletediverge': bothincompletediverge
455 'incompletediverge': bothincompletediverge
456 }
456 }
457 both2 = {'copy': {},
457 both2 = {'copy': {},
458 'fullcopy': {},
458 'fullcopy': {},
459 'incomplete': {},
459 'incomplete': {},
460 'diverge': bothdiverge,
460 'diverge': bothdiverge,
461 'incompletediverge': bothincompletediverge
461 'incompletediverge': bothincompletediverge
462 }
462 }
463 for f in bothnew:
463 for f in bothnew:
464 _checkcopies(c1, f, m1, m2, base, tca, dirtyc1, limit, both1)
464 _checkcopies(c1, f, m1, m2, base, tca, dirtyc1, limit, both1)
465 _checkcopies(c2, f, m2, m1, base, tca, dirtyc2, limit, both2)
465 _checkcopies(c2, f, m2, m1, base, tca, dirtyc2, limit, both2)
466 if dirtyc1:
466 if dirtyc1:
467 # incomplete copies may only be found on the "dirty" side for bothnew
467 # incomplete copies may only be found on the "dirty" side for bothnew
468 assert not both2['incomplete']
468 assert not both2['incomplete']
469 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
469 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
470 bothincompletediverge)
470 bothincompletediverge)
471 elif dirtyc2:
471 elif dirtyc2:
472 assert not both1['incomplete']
472 assert not both1['incomplete']
473 remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
473 remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
474 bothincompletediverge)
474 bothincompletediverge)
475 else:
475 else:
476 # incomplete copies and divergences can't happen outside grafts
476 # incomplete copies and divergences can't happen outside grafts
477 assert not both1['incomplete']
477 assert not both1['incomplete']
478 assert not both2['incomplete']
478 assert not both2['incomplete']
479 assert not bothincompletediverge
479 assert not bothincompletediverge
480 for f in remainder:
480 for f in remainder:
481 assert f not in bothdiverge
481 assert f not in bothdiverge
482 ic = remainder[f]
482 ic = remainder[f]
483 if ic[0] in (m1 if dirtyc1 else m2):
483 if ic[0] in (m1 if dirtyc1 else m2):
484 # backed-out rename on one side, but watch out for deleted files
484 # backed-out rename on one side, but watch out for deleted files
485 bothdiverge[f] = ic
485 bothdiverge[f] = ic
486 for of, fl in bothdiverge.items():
486 for of, fl in bothdiverge.items():
487 if len(fl) == 2 and fl[0] == fl[1]:
487 if len(fl) == 2 and fl[0] == fl[1]:
488 copy[fl[0]] = of # not actually divergent, just matching renames
488 copy[fl[0]] = of # not actually divergent, just matching renames
489
489
490 if fullcopy and repo.ui.debugflag:
490 if fullcopy and repo.ui.debugflag:
491 repo.ui.debug(" all copies found (* = to merge, ! = divergent, "
491 repo.ui.debug(" all copies found (* = to merge, ! = divergent, "
492 "% = renamed and deleted):\n")
492 "% = renamed and deleted):\n")
493 for f in sorted(fullcopy):
493 for f in sorted(fullcopy):
494 note = ""
494 note = ""
495 if f in copy:
495 if f in copy:
496 note += "*"
496 note += "*"
497 if f in divergeset:
497 if f in divergeset:
498 note += "!"
498 note += "!"
499 if f in renamedeleteset:
499 if f in renamedeleteset:
500 note += "%"
500 note += "%"
501 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
501 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
502 note))
502 note))
503 del divergeset
503 del divergeset
504
504
505 if not fullcopy:
505 if not fullcopy:
506 return copy, {}, diverge, renamedelete
506 return copy, {}, diverge, renamedelete
507
507
508 repo.ui.debug(" checking for directory renames\n")
508 repo.ui.debug(" checking for directory renames\n")
509
509
510 # generate a directory move map
510 # generate a directory move map
511 d1, d2 = c1.dirs(), c2.dirs()
511 d1, d2 = c1.dirs(), c2.dirs()
512 # Hack for adding '', which is not otherwise added, to d1 and d2
512 # Hack for adding '', which is not otherwise added, to d1 and d2
513 d1.addpath('/')
513 d1.addpath('/')
514 d2.addpath('/')
514 d2.addpath('/')
515 invalid = set()
515 invalid = set()
516 dirmove = {}
516 dirmove = {}
517
517
518 # examine each file copy for a potential directory move, which is
518 # examine each file copy for a potential directory move, which is
519 # when all the files in a directory are moved to a new directory
519 # when all the files in a directory are moved to a new directory
520 for dst, src in fullcopy.iteritems():
520 for dst, src in fullcopy.iteritems():
521 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
521 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
522 if dsrc in invalid:
522 if dsrc in invalid:
523 # already seen to be uninteresting
523 # already seen to be uninteresting
524 continue
524 continue
525 elif dsrc in d1 and ddst in d1:
525 elif dsrc in d1 and ddst in d1:
526 # directory wasn't entirely moved locally
526 # directory wasn't entirely moved locally
527 invalid.add(dsrc + "/")
527 invalid.add(dsrc + "/")
528 elif dsrc in d2 and ddst in d2:
528 elif dsrc in d2 and ddst in d2:
529 # directory wasn't entirely moved remotely
529 # directory wasn't entirely moved remotely
530 invalid.add(dsrc + "/")
530 invalid.add(dsrc + "/")
531 elif dsrc + "/" in dirmove and dirmove[dsrc + "/"] != ddst + "/":
531 elif dsrc + "/" in dirmove and dirmove[dsrc + "/"] != ddst + "/":
532 # files from the same directory moved to two different places
532 # files from the same directory moved to two different places
533 invalid.add(dsrc + "/")
533 invalid.add(dsrc + "/")
534 else:
534 else:
535 # looks good so far
535 # looks good so far
536 dirmove[dsrc + "/"] = ddst + "/"
536 dirmove[dsrc + "/"] = ddst + "/"
537
537
538 for i in invalid:
538 for i in invalid:
539 if i in dirmove:
539 if i in dirmove:
540 del dirmove[i]
540 del dirmove[i]
541 del d1, d2, invalid
541 del d1, d2, invalid
542
542
543 if not dirmove:
543 if not dirmove:
544 return copy, {}, diverge, renamedelete
544 return copy, {}, diverge, renamedelete
545
545
546 for d in dirmove:
546 for d in dirmove:
547 repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
547 repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
548 (d, dirmove[d]))
548 (d, dirmove[d]))
549
549
550 movewithdir = {}
550 movewithdir = {}
551 # check unaccounted nonoverlapping files against directory moves
551 # check unaccounted nonoverlapping files against directory moves
552 for f in u1r + u2r:
552 for f in u1r + u2r:
553 if f not in fullcopy:
553 if f not in fullcopy:
554 for d in dirmove:
554 for d in dirmove:
555 if f.startswith(d):
555 if f.startswith(d):
556 # new file added in a directory that was moved, move it
556 # new file added in a directory that was moved, move it
557 df = dirmove[d] + f[len(d):]
557 df = dirmove[d] + f[len(d):]
558 if df not in copy:
558 if df not in copy:
559 movewithdir[f] = df
559 movewithdir[f] = df
560 repo.ui.debug((" pending file src: '%s' -> "
560 repo.ui.debug((" pending file src: '%s' -> "
561 "dst: '%s'\n") % (f, df))
561 "dst: '%s'\n") % (f, df))
562 break
562 break
563
563
564 return copy, movewithdir, diverge, renamedelete
564 return copy, movewithdir, diverge, renamedelete
565
565
566 def _related(f1, f2, limit):
566 def _related(f1, f2, limit):
567 """return True if f1 and f2 filectx have a common ancestor
567 """return True if f1 and f2 filectx have a common ancestor
568
568
569 Walk back to common ancestor to see if the two files originate
569 Walk back to common ancestor to see if the two files originate
570 from the same file. Since workingfilectx's rev() is None it messes
570 from the same file. Since workingfilectx's rev() is None it messes
571 up the integer comparison logic, hence the pre-step check for
571 up the integer comparison logic, hence the pre-step check for
572 None (f1 and f2 can only be workingfilectx's initially).
572 None (f1 and f2 can only be workingfilectx's initially).
573 """
573 """
574
574
575 if f1 == f2:
575 if f1 == f2:
576 return f1 # a match
576 return f1 # a match
577
577
578 g1, g2 = f1.ancestors(), f2.ancestors()
578 g1, g2 = f1.ancestors(), f2.ancestors()
579 try:
579 try:
580 f1r, f2r = f1.linkrev(), f2.linkrev()
580 f1r, f2r = f1.linkrev(), f2.linkrev()
581
581
582 if f1r is None:
582 if f1r is None:
583 f1 = next(g1)
583 f1 = next(g1)
584 if f2r is None:
584 if f2r is None:
585 f2 = next(g2)
585 f2 = next(g2)
586
586
587 while True:
587 while True:
588 f1r, f2r = f1.linkrev(), f2.linkrev()
588 f1r, f2r = f1.linkrev(), f2.linkrev()
589 if f1r > f2r:
589 if f1r > f2r:
590 f1 = next(g1)
590 f1 = next(g1)
591 elif f2r > f1r:
591 elif f2r > f1r:
592 f2 = next(g2)
592 f2 = next(g2)
593 elif f1 == f2:
593 elif f1 == f2:
594 return f1 # a match
594 return f1 # a match
595 elif f1r == f2r or f1r < limit or f2r < limit:
595 elif f1r == f2r or f1r < limit or f2r < limit:
596 return False # copy no longer relevant
596 return False # copy no longer relevant
597 except StopIteration:
597 except StopIteration:
598 return False
598 return False
599
599
600 def _checkcopies(ctx, f, m1, m2, base, tca, remotebase, limit, data):
600 def _checkcopies(ctx, f, m1, m2, base, tca, remotebase, limit, data):
601 """
601 """
602 check possible copies of f from m1 to m2
602 check possible copies of f from m1 to m2
603
603
604 ctx = starting context for f in m1
604 ctx = starting context for f in m1
605 f = the filename to check (as in m1)
605 f = the filename to check (as in m1)
606 m1 = the source manifest
606 m1 = the source manifest
607 m2 = the destination manifest
607 m2 = the destination manifest
608 base = the changectx used as a merge base
608 base = the changectx used as a merge base
609 tca = topological common ancestor for graft-like scenarios
609 tca = topological common ancestor for graft-like scenarios
610 remotebase = True if base is outside tca::ctx, False otherwise
610 remotebase = True if base is outside tca::ctx, False otherwise
611 limit = the rev number to not search beyond
611 limit = the rev number to not search beyond
612 data = dictionary of dictionary to store copy data. (see mergecopies)
612 data = dictionary of dictionary to store copy data. (see mergecopies)
613
613
614 note: limit is only an optimization, and there is no guarantee that
614 note: limit is only an optimization, and there is no guarantee that
615 irrelevant revisions will not be limited
615 irrelevant revisions will not be limited
616 there is no easy way to make this algorithm stop in a guaranteed way
616 there is no easy way to make this algorithm stop in a guaranteed way
617 once it "goes behind a certain revision".
617 once it "goes behind a certain revision".
618 """
618 """
619
619
620 mb = base.manifest()
620 mb = base.manifest()
621 mta = tca.manifest()
621 mta = tca.manifest()
622 # Might be true if this call is about finding backward renames,
622 # Might be true if this call is about finding backward renames,
623 # This happens in the case of grafts because the DAG is then rotated.
623 # This happens in the case of grafts because the DAG is then rotated.
624 # If the file exists in both the base and the source, we are not looking
624 # If the file exists in both the base and the source, we are not looking
625 # for a rename on the source side, but on the part of the DAG that is
625 # for a rename on the source side, but on the part of the DAG that is
626 # traversed backwards.
626 # traversed backwards.
627 #
627 #
628 # In the case there is both backward and forward renames (before and after
628 # In the case there is both backward and forward renames (before and after
629 # the base) this is more complicated as we must detect a divergence.
629 # the base) this is more complicated as we must detect a divergence.
630 # We use 'backwards = False' in that case.
630 # We use 'backwards = False' in that case.
631 backwards = not remotebase and base != tca and f in mb
631 backwards = not remotebase and base != tca and f in mb
632 getfctx = _makegetfctx(ctx)
632 getfctx = _makegetfctx(ctx)
633
633
634 if m1[f] == mb.get(f) and not remotebase:
635 # Nothing to merge
636 return
637
634 of = None
638 of = None
635 seen = set([f])
639 seen = set([f])
636 for oc in getfctx(f, m1[f]).ancestors():
640 for oc in getfctx(f, m1[f]).ancestors():
637 ocr = oc.linkrev()
641 ocr = oc.linkrev()
638 of = oc.path()
642 of = oc.path()
639 if of in seen:
643 if of in seen:
640 # check limit late - grab last rename before
644 # check limit late - grab last rename before
641 if ocr < limit:
645 if ocr < limit:
642 break
646 break
643 continue
647 continue
644 seen.add(of)
648 seen.add(of)
645
649
646 # remember for dir rename detection
650 # remember for dir rename detection
647 if backwards:
651 if backwards:
648 data['fullcopy'][of] = f # grafting backwards through renames
652 data['fullcopy'][of] = f # grafting backwards through renames
649 else:
653 else:
650 data['fullcopy'][f] = of
654 data['fullcopy'][f] = of
651 if of not in m2:
655 if of not in m2:
652 continue # no match, keep looking
656 continue # no match, keep looking
653 if m2[of] == mb.get(of):
657 if m2[of] == mb.get(of):
654 return # no merge needed, quit early
658 return # no merge needed, quit early
655 c2 = getfctx(of, m2[of])
659 c2 = getfctx(of, m2[of])
656 # c2 might be a plain new file on added on destination side that is
660 # c2 might be a plain new file on added on destination side that is
657 # unrelated to the droids we are looking for.
661 # unrelated to the droids we are looking for.
658 cr = _related(oc, c2, tca.rev())
662 cr = _related(oc, c2, tca.rev())
659 if cr and (of == f or of == c2.path()): # non-divergent
663 if cr and (of == f or of == c2.path()): # non-divergent
660 if backwards:
664 if backwards:
661 data['copy'][of] = f
665 data['copy'][of] = f
662 elif of in mb:
666 elif of in mb:
663 data['copy'][f] = of
667 data['copy'][f] = of
664 elif remotebase: # special case: a <- b <- a -> b "ping-pong" rename
668 elif remotebase: # special case: a <- b <- a -> b "ping-pong" rename
665 data['copy'][of] = f
669 data['copy'][of] = f
666 del data['fullcopy'][f]
670 del data['fullcopy'][f]
667 data['fullcopy'][of] = f
671 data['fullcopy'][of] = f
668 else: # divergence w.r.t. graft CA on one side of topological CA
672 else: # divergence w.r.t. graft CA on one side of topological CA
669 for sf in seen:
673 for sf in seen:
670 if sf in mb:
674 if sf in mb:
671 assert sf not in data['diverge']
675 assert sf not in data['diverge']
672 data['diverge'][sf] = [f, of]
676 data['diverge'][sf] = [f, of]
673 break
677 break
674 return
678 return
675
679
676 if of in mta:
680 if of in mta:
677 if backwards or remotebase:
681 if backwards or remotebase:
678 data['incomplete'][of] = f
682 data['incomplete'][of] = f
679 else:
683 else:
680 for sf in seen:
684 for sf in seen:
681 if sf in mb:
685 if sf in mb:
682 if tca == base:
686 if tca == base:
683 data['diverge'].setdefault(sf, []).append(f)
687 data['diverge'].setdefault(sf, []).append(f)
684 else:
688 else:
685 data['incompletediverge'][sf] = [of, f]
689 data['incompletediverge'][sf] = [of, f]
686 return
690 return
687
691
688 def duplicatecopies(repo, rev, fromrev, skiprev=None):
692 def duplicatecopies(repo, rev, fromrev, skiprev=None):
689 '''reproduce copies from fromrev to rev in the dirstate
693 '''reproduce copies from fromrev to rev in the dirstate
690
694
691 If skiprev is specified, it's a revision that should be used to
695 If skiprev is specified, it's a revision that should be used to
692 filter copy records. Any copies that occur between fromrev and
696 filter copy records. Any copies that occur between fromrev and
693 skiprev will not be duplicated, even if they appear in the set of
697 skiprev will not be duplicated, even if they appear in the set of
694 copies between fromrev and rev.
698 copies between fromrev and rev.
695 '''
699 '''
696 exclude = {}
700 exclude = {}
697 if (skiprev is not None and
701 if (skiprev is not None and
698 not repo.ui.configbool('experimental', 'disablecopytrace')):
702 not repo.ui.configbool('experimental', 'disablecopytrace')):
699 # disablecopytrace skips this line, but not the entire function because
703 # disablecopytrace skips this line, but not the entire function because
700 # the line below is O(size of the repo) during a rebase, while the rest
704 # the line below is O(size of the repo) during a rebase, while the rest
701 # of the function is much faster (and is required for carrying copy
705 # of the function is much faster (and is required for carrying copy
702 # metadata across the rebase anyway).
706 # metadata across the rebase anyway).
703 exclude = pathcopies(repo[fromrev], repo[skiprev])
707 exclude = pathcopies(repo[fromrev], repo[skiprev])
704 for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
708 for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
705 # copies.pathcopies returns backward renames, so dst might not
709 # copies.pathcopies returns backward renames, so dst might not
706 # actually be in the dirstate
710 # actually be in the dirstate
707 if dst in exclude:
711 if dst in exclude:
708 continue
712 continue
709 if repo.dirstate[dst] in "nma":
713 if repo.dirstate[dst] in "nma":
710 repo.dirstate.copy(src, dst)
714 repo.dirstate.copy(src, dst)
@@ -1,1282 +1,1288 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extdiff]
2 > [extdiff]
3 > # for portability:
3 > # for portability:
4 > pdiff = sh "$RUNTESTDIR/pdiff"
4 > pdiff = sh "$RUNTESTDIR/pdiff"
5 > EOF
5 > EOF
6
6
7 Create a repo with some stuff in it:
7 Create a repo with some stuff in it:
8
8
9 $ hg init a
9 $ hg init a
10 $ cd a
10 $ cd a
11 $ echo a > a
11 $ echo a > a
12 $ echo a > d
12 $ echo a > d
13 $ echo a > e
13 $ echo a > e
14 $ hg ci -qAm0
14 $ hg ci -qAm0
15 $ echo b > a
15 $ echo b > a
16 $ hg ci -m1 -u bar
16 $ hg ci -m1 -u bar
17 $ hg mv a b
17 $ hg mv a b
18 $ hg ci -m2
18 $ hg ci -m2
19 $ hg cp b c
19 $ hg cp b c
20 $ hg ci -m3 -u baz
20 $ hg ci -m3 -u baz
21 $ echo b > d
21 $ echo b > d
22 $ echo f > e
22 $ echo f > e
23 $ hg ci -m4
23 $ hg ci -m4
24 $ hg up -q 3
24 $ hg up -q 3
25 $ echo b > e
25 $ echo b > e
26 $ hg branch -q stable
26 $ hg branch -q stable
27 $ hg ci -m5
27 $ hg ci -m5
28 $ hg merge -q default --tool internal:local
28 $ hg merge -q default --tool internal:local
29 $ hg branch -q default
29 $ hg branch -q default
30 $ hg ci -m6
30 $ hg ci -m6
31 $ hg phase --public 3
31 $ hg phase --public 3
32 $ hg phase --force --secret 6
32 $ hg phase --force --secret 6
33
33
34 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
34 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
35 @ test@6.secret: 6
35 @ test@6.secret: 6
36 |\
36 |\
37 | o test@5.draft: 5
37 | o test@5.draft: 5
38 | |
38 | |
39 o | test@4.draft: 4
39 o | test@4.draft: 4
40 |/
40 |/
41 o baz@3.public: 3
41 o baz@3.public: 3
42 |
42 |
43 o test@2.public: 2
43 o test@2.public: 2
44 |
44 |
45 o bar@1.public: 1
45 o bar@1.public: 1
46 |
46 |
47 o test@0.public: 0
47 o test@0.public: 0
48
48
49 Can't continue without starting:
49 Can't continue without starting:
50
50
51 $ hg rm -q e
51 $ hg rm -q e
52 $ hg graft --continue
52 $ hg graft --continue
53 abort: no graft in progress
53 abort: no graft in progress
54 [255]
54 [255]
55 $ hg revert -r . -q e
55 $ hg revert -r . -q e
56
56
57 Need to specify a rev:
57 Need to specify a rev:
58
58
59 $ hg graft
59 $ hg graft
60 abort: no revisions specified
60 abort: no revisions specified
61 [255]
61 [255]
62
62
63 Can't graft ancestor:
63 Can't graft ancestor:
64
64
65 $ hg graft 1 2
65 $ hg graft 1 2
66 skipping ancestor revision 1:5d205f8b35b6
66 skipping ancestor revision 1:5d205f8b35b6
67 skipping ancestor revision 2:5c095ad7e90f
67 skipping ancestor revision 2:5c095ad7e90f
68 [255]
68 [255]
69
69
70 Specify revisions with -r:
70 Specify revisions with -r:
71
71
72 $ hg graft -r 1 -r 2
72 $ hg graft -r 1 -r 2
73 skipping ancestor revision 1:5d205f8b35b6
73 skipping ancestor revision 1:5d205f8b35b6
74 skipping ancestor revision 2:5c095ad7e90f
74 skipping ancestor revision 2:5c095ad7e90f
75 [255]
75 [255]
76
76
77 $ hg graft -r 1 2
77 $ hg graft -r 1 2
78 warning: inconsistent use of --rev might give unexpected revision ordering!
78 warning: inconsistent use of --rev might give unexpected revision ordering!
79 skipping ancestor revision 2:5c095ad7e90f
79 skipping ancestor revision 2:5c095ad7e90f
80 skipping ancestor revision 1:5d205f8b35b6
80 skipping ancestor revision 1:5d205f8b35b6
81 [255]
81 [255]
82
82
83 Can't graft with dirty wd:
83 Can't graft with dirty wd:
84
84
85 $ hg up -q 0
85 $ hg up -q 0
86 $ echo foo > a
86 $ echo foo > a
87 $ hg graft 1
87 $ hg graft 1
88 abort: uncommitted changes
88 abort: uncommitted changes
89 [255]
89 [255]
90 $ hg revert a
90 $ hg revert a
91
91
92 Graft a rename:
92 Graft a rename:
93 (this also tests that editor is invoked if '--edit' is specified)
93 (this also tests that editor is invoked if '--edit' is specified)
94
94
95 $ hg status --rev "2^1" --rev 2
95 $ hg status --rev "2^1" --rev 2
96 A b
96 A b
97 R a
97 R a
98 $ HGEDITOR=cat hg graft 2 -u foo --edit
98 $ HGEDITOR=cat hg graft 2 -u foo --edit
99 grafting 2:5c095ad7e90f "2"
99 grafting 2:5c095ad7e90f "2"
100 merging a and b to b
100 merging a and b to b
101 2
101 2
102
102
103
103
104 HG: Enter commit message. Lines beginning with 'HG:' are removed.
104 HG: Enter commit message. Lines beginning with 'HG:' are removed.
105 HG: Leave message empty to abort commit.
105 HG: Leave message empty to abort commit.
106 HG: --
106 HG: --
107 HG: user: foo
107 HG: user: foo
108 HG: branch 'default'
108 HG: branch 'default'
109 HG: added b
109 HG: added b
110 HG: removed a
110 HG: removed a
111 $ hg export tip --git
111 $ hg export tip --git
112 # HG changeset patch
112 # HG changeset patch
113 # User foo
113 # User foo
114 # Date 0 0
114 # Date 0 0
115 # Thu Jan 01 00:00:00 1970 +0000
115 # Thu Jan 01 00:00:00 1970 +0000
116 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
116 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
117 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
117 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
118 2
118 2
119
119
120 diff --git a/a b/b
120 diff --git a/a b/b
121 rename from a
121 rename from a
122 rename to b
122 rename to b
123
123
124 Look for extra:source
124 Look for extra:source
125
125
126 $ hg log --debug -r tip
126 $ hg log --debug -r tip
127 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
127 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
128 tag: tip
128 tag: tip
129 phase: draft
129 phase: draft
130 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
130 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
131 parent: -1:0000000000000000000000000000000000000000
131 parent: -1:0000000000000000000000000000000000000000
132 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
132 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
133 user: foo
133 user: foo
134 date: Thu Jan 01 00:00:00 1970 +0000
134 date: Thu Jan 01 00:00:00 1970 +0000
135 files+: b
135 files+: b
136 files-: a
136 files-: a
137 extra: branch=default
137 extra: branch=default
138 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
138 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
139 description:
139 description:
140 2
140 2
141
141
142
142
143
143
144 Graft out of order, skipping a merge and a duplicate
144 Graft out of order, skipping a merge and a duplicate
145 (this also tests that editor is not invoked if '--edit' is not specified)
145 (this also tests that editor is not invoked if '--edit' is not specified)
146
146
147 $ hg graft 1 5 4 3 'merge()' 2 -n
147 $ hg graft 1 5 4 3 'merge()' 2 -n
148 skipping ungraftable merge revision 6
148 skipping ungraftable merge revision 6
149 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
149 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
150 grafting 1:5d205f8b35b6 "1"
150 grafting 1:5d205f8b35b6 "1"
151 grafting 5:97f8bfe72746 "5"
151 grafting 5:97f8bfe72746 "5"
152 grafting 4:9c233e8e184d "4"
152 grafting 4:9c233e8e184d "4"
153 grafting 3:4c60f11aa304 "3"
153 grafting 3:4c60f11aa304 "3"
154
154
155 $ HGEDITOR=cat hg graft 1 5 'merge()' 2 --debug
155 $ HGEDITOR=cat hg graft 1 5 'merge()' 2 --debug
156 skipping ungraftable merge revision 6
156 skipping ungraftable merge revision 6
157 scanning for duplicate grafts
157 scanning for duplicate grafts
158 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
158 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
159 grafting 1:5d205f8b35b6 "1"
159 grafting 1:5d205f8b35b6 "1"
160 searching for copies back to rev 1
160 searching for copies back to rev 1
161 unmatched files in local:
161 unmatched files in local:
162 b
162 b
163 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
163 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
164 src: 'a' -> dst: 'b' *
164 src: 'a' -> dst: 'b' *
165 checking for directory renames
165 checking for directory renames
166 resolving manifests
166 resolving manifests
167 branchmerge: True, force: True, partial: False
167 branchmerge: True, force: True, partial: False
168 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
168 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
169 preserving b for resolve of b
169 preserving b for resolve of b
170 starting 4 threads for background file closing (?)
170 starting 4 threads for background file closing (?)
171 b: local copied/moved from a -> m (premerge)
171 b: local copied/moved from a -> m (premerge)
172 picked tool ':merge' for b (binary False symlink False changedelete False)
172 picked tool ':merge' for b (binary False symlink False changedelete False)
173 merging b and a to b
173 merging b and a to b
174 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
174 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
175 premerge successful
175 premerge successful
176 committing files:
176 committing files:
177 b
177 b
178 committing manifest
178 committing manifest
179 committing changelog
179 committing changelog
180 grafting 5:97f8bfe72746 "5"
180 grafting 5:97f8bfe72746 "5"
181 searching for copies back to rev 1
181 searching for copies back to rev 1
182 unmatched files in other (from topological common ancestor):
182 unmatched files in other (from topological common ancestor):
183 c
183 c
184 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
185 src: 'c' -> dst: 'b' *
186 checking for directory renames
187 resolving manifests
184 resolving manifests
188 branchmerge: True, force: True, partial: False
185 branchmerge: True, force: True, partial: False
189 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
186 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
190 e: remote is newer -> g
187 e: remote is newer -> g
191 getting e
188 getting e
192 b: remote unchanged -> k
189 b: remote unchanged -> k
193 committing files:
190 committing files:
194 e
191 e
195 committing manifest
192 committing manifest
196 committing changelog
193 committing changelog
197 $ HGEDITOR=cat hg graft 4 3 --log --debug
194 $ HGEDITOR=cat hg graft 4 3 --log --debug
198 scanning for duplicate grafts
195 scanning for duplicate grafts
199 grafting 4:9c233e8e184d "4"
196 grafting 4:9c233e8e184d "4"
200 searching for copies back to rev 1
197 searching for copies back to rev 1
201 unmatched files in other (from topological common ancestor):
198 unmatched files in other (from topological common ancestor):
202 c
199 c
203 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
204 src: 'c' -> dst: 'b' *
205 checking for directory renames
206 resolving manifests
200 resolving manifests
207 branchmerge: True, force: True, partial: False
201 branchmerge: True, force: True, partial: False
208 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
202 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
209 preserving e for resolve of e
203 preserving e for resolve of e
210 d: remote is newer -> g
204 d: remote is newer -> g
211 getting d
205 getting d
212 b: remote unchanged -> k
206 b: remote unchanged -> k
213 e: versions differ -> m (premerge)
207 e: versions differ -> m (premerge)
214 picked tool ':merge' for e (binary False symlink False changedelete False)
208 picked tool ':merge' for e (binary False symlink False changedelete False)
215 merging e
209 merging e
216 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
210 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
217 e: versions differ -> m (merge)
211 e: versions differ -> m (merge)
218 picked tool ':merge' for e (binary False symlink False changedelete False)
212 picked tool ':merge' for e (binary False symlink False changedelete False)
219 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
213 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
220 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
214 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
221 abort: unresolved conflicts, can't continue
215 abort: unresolved conflicts, can't continue
222 (use 'hg resolve' and 'hg graft --continue --log')
216 (use 'hg resolve' and 'hg graft --continue --log')
223 [255]
217 [255]
224
218
225 Summary should mention graft:
219 Summary should mention graft:
226
220
227 $ hg summary |grep graft
221 $ hg summary |grep graft
228 commit: 2 modified, 2 unknown, 1 unresolved (graft in progress)
222 commit: 2 modified, 2 unknown, 1 unresolved (graft in progress)
229
223
230 Commit while interrupted should fail:
224 Commit while interrupted should fail:
231
225
232 $ hg ci -m 'commit interrupted graft'
226 $ hg ci -m 'commit interrupted graft'
233 abort: graft in progress
227 abort: graft in progress
234 (use 'hg graft --continue' or 'hg update' to abort)
228 (use 'hg graft --continue' or 'hg update' to abort)
235 [255]
229 [255]
236
230
237 Abort the graft and try committing:
231 Abort the graft and try committing:
238
232
239 $ hg up -C .
233 $ hg up -C .
240 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
234 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 $ echo c >> e
235 $ echo c >> e
242 $ hg ci -mtest
236 $ hg ci -mtest
243
237
244 $ hg strip . --config extensions.strip=
238 $ hg strip . --config extensions.strip=
245 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
240 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
247
241
248 Graft again:
242 Graft again:
249
243
250 $ hg graft 1 5 4 3 'merge()' 2
244 $ hg graft 1 5 4 3 'merge()' 2
251 skipping ungraftable merge revision 6
245 skipping ungraftable merge revision 6
252 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
246 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
253 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
247 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
254 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
248 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
255 grafting 4:9c233e8e184d "4"
249 grafting 4:9c233e8e184d "4"
256 merging e
250 merging e
257 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
251 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
258 abort: unresolved conflicts, can't continue
252 abort: unresolved conflicts, can't continue
259 (use 'hg resolve' and 'hg graft --continue')
253 (use 'hg resolve' and 'hg graft --continue')
260 [255]
254 [255]
261
255
262 Continue without resolve should fail:
256 Continue without resolve should fail:
263
257
264 $ hg graft -c
258 $ hg graft -c
265 grafting 4:9c233e8e184d "4"
259 grafting 4:9c233e8e184d "4"
266 abort: unresolved merge conflicts (see 'hg help resolve')
260 abort: unresolved merge conflicts (see 'hg help resolve')
267 [255]
261 [255]
268
262
269 Fix up:
263 Fix up:
270
264
271 $ echo b > e
265 $ echo b > e
272 $ hg resolve -m e
266 $ hg resolve -m e
273 (no more unresolved files)
267 (no more unresolved files)
274 continue: hg graft --continue
268 continue: hg graft --continue
275
269
276 Continue with a revision should fail:
270 Continue with a revision should fail:
277
271
278 $ hg graft -c 6
272 $ hg graft -c 6
279 abort: can't specify --continue and revisions
273 abort: can't specify --continue and revisions
280 [255]
274 [255]
281
275
282 $ hg graft -c -r 6
276 $ hg graft -c -r 6
283 abort: can't specify --continue and revisions
277 abort: can't specify --continue and revisions
284 [255]
278 [255]
285
279
286 Continue for real, clobber usernames
280 Continue for real, clobber usernames
287
281
288 $ hg graft -c -U
282 $ hg graft -c -U
289 grafting 4:9c233e8e184d "4"
283 grafting 4:9c233e8e184d "4"
290 grafting 3:4c60f11aa304 "3"
284 grafting 3:4c60f11aa304 "3"
291
285
292 Compare with original:
286 Compare with original:
293
287
294 $ hg diff -r 6
288 $ hg diff -r 6
295 $ hg status --rev 0:. -C
289 $ hg status --rev 0:. -C
296 M d
290 M d
297 M e
291 M e
298 A b
292 A b
299 a
293 a
300 A c
294 A c
301 a
295 a
302 R a
296 R a
303
297
304 View graph:
298 View graph:
305
299
306 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
300 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
307 @ test@11.draft: 3
301 @ test@11.draft: 3
308 |
302 |
309 o test@10.draft: 4
303 o test@10.draft: 4
310 |
304 |
311 o test@9.draft: 5
305 o test@9.draft: 5
312 |
306 |
313 o bar@8.draft: 1
307 o bar@8.draft: 1
314 |
308 |
315 o foo@7.draft: 2
309 o foo@7.draft: 2
316 |
310 |
317 | o test@6.secret: 6
311 | o test@6.secret: 6
318 | |\
312 | |\
319 | | o test@5.draft: 5
313 | | o test@5.draft: 5
320 | | |
314 | | |
321 | o | test@4.draft: 4
315 | o | test@4.draft: 4
322 | |/
316 | |/
323 | o baz@3.public: 3
317 | o baz@3.public: 3
324 | |
318 | |
325 | o test@2.public: 2
319 | o test@2.public: 2
326 | |
320 | |
327 | o bar@1.public: 1
321 | o bar@1.public: 1
328 |/
322 |/
329 o test@0.public: 0
323 o test@0.public: 0
330
324
331 Graft again onto another branch should preserve the original source
325 Graft again onto another branch should preserve the original source
332 $ hg up -q 0
326 $ hg up -q 0
333 $ echo 'g'>g
327 $ echo 'g'>g
334 $ hg add g
328 $ hg add g
335 $ hg ci -m 7
329 $ hg ci -m 7
336 created new head
330 created new head
337 $ hg graft 7
331 $ hg graft 7
338 grafting 7:ef0ef43d49e7 "2"
332 grafting 7:ef0ef43d49e7 "2"
339
333
340 $ hg log -r 7 --template '{rev}:{node}\n'
334 $ hg log -r 7 --template '{rev}:{node}\n'
341 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
335 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
342 $ hg log -r 2 --template '{rev}:{node}\n'
336 $ hg log -r 2 --template '{rev}:{node}\n'
343 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
337 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
344
338
345 $ hg log --debug -r tip
339 $ hg log --debug -r tip
346 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
340 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
347 tag: tip
341 tag: tip
348 phase: draft
342 phase: draft
349 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
343 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
350 parent: -1:0000000000000000000000000000000000000000
344 parent: -1:0000000000000000000000000000000000000000
351 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
345 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
352 user: foo
346 user: foo
353 date: Thu Jan 01 00:00:00 1970 +0000
347 date: Thu Jan 01 00:00:00 1970 +0000
354 files+: b
348 files+: b
355 files-: a
349 files-: a
356 extra: branch=default
350 extra: branch=default
357 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
351 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
358 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
352 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
359 description:
353 description:
360 2
354 2
361
355
362
356
363 Disallow grafting an already grafted cset onto its original branch
357 Disallow grafting an already grafted cset onto its original branch
364 $ hg up -q 6
358 $ hg up -q 6
365 $ hg graft 7
359 $ hg graft 7
366 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
360 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
367 [255]
361 [255]
368
362
369 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13
363 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13
370 --- */hg-5c095ad7e90f.patch * (glob)
364 --- */hg-5c095ad7e90f.patch * (glob)
371 +++ */hg-7a4785234d87.patch * (glob)
365 +++ */hg-7a4785234d87.patch * (glob)
372 @@ -1,18 +1,18 @@
366 @@ -1,18 +1,18 @@
373 # HG changeset patch
367 # HG changeset patch
374 -# User test
368 -# User test
375 +# User foo
369 +# User foo
376 # Date 0 0
370 # Date 0 0
377 # Thu Jan 01 00:00:00 1970 +0000
371 # Thu Jan 01 00:00:00 1970 +0000
378 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
372 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
379 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
373 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
380 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
374 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
381 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
375 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
382 2
376 2
383
377
384 -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
378 -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
385 +diff -r b592ea63bb0c -r 7a4785234d87 a
379 +diff -r b592ea63bb0c -r 7a4785234d87 a
386 --- a/a Thu Jan 01 00:00:00 1970 +0000
380 --- a/a Thu Jan 01 00:00:00 1970 +0000
387 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
381 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
388 @@ -1,1 +0,0 @@
382 @@ -1,1 +0,0 @@
389 --b
383 --b
390 -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
384 -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
391 +-a
385 +-a
392 +diff -r b592ea63bb0c -r 7a4785234d87 b
386 +diff -r b592ea63bb0c -r 7a4785234d87 b
393 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
387 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
394 +++ b/b Thu Jan 01 00:00:00 1970 +0000
388 +++ b/b Thu Jan 01 00:00:00 1970 +0000
395 @@ -0,0 +1,1 @@
389 @@ -0,0 +1,1 @@
396 -+b
390 -+b
397 ++a
391 ++a
398 [1]
392 [1]
399
393
400 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
394 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
401 --- */hg-5c095ad7e90f.patch * (glob)
395 --- */hg-5c095ad7e90f.patch * (glob)
402 +++ */hg-7a4785234d87.patch * (glob)
396 +++ */hg-7a4785234d87.patch * (glob)
403 @@ -1,8 +1,8 @@
397 @@ -1,8 +1,8 @@
404 # HG changeset patch
398 # HG changeset patch
405 -# User test
399 -# User test
406 +# User foo
400 +# User foo
407 # Date 0 0
401 # Date 0 0
408 # Thu Jan 01 00:00:00 1970 +0000
402 # Thu Jan 01 00:00:00 1970 +0000
409 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
403 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
410 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
404 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
411 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
405 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
412 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
406 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
413 2
407 2
414
408
415 [1]
409 [1]
416
410
417 Disallow grafting already grafted csets with the same origin onto each other
411 Disallow grafting already grafted csets with the same origin onto each other
418 $ hg up -q 13
412 $ hg up -q 13
419 $ hg graft 2
413 $ hg graft 2
420 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
414 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
421 [255]
415 [255]
422 $ hg graft 7
416 $ hg graft 7
423 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
417 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
424 [255]
418 [255]
425
419
426 $ hg up -q 7
420 $ hg up -q 7
427 $ hg graft 2
421 $ hg graft 2
428 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
422 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
429 [255]
423 [255]
430 $ hg graft tip
424 $ hg graft tip
431 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
425 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
432 [255]
426 [255]
433
427
434 Graft with --log
428 Graft with --log
435
429
436 $ hg up -Cq 1
430 $ hg up -Cq 1
437 $ hg graft 3 --log -u foo
431 $ hg graft 3 --log -u foo
438 grafting 3:4c60f11aa304 "3"
432 grafting 3:4c60f11aa304 "3"
439 warning: can't find ancestor for 'c' copied from 'b'!
433 warning: can't find ancestor for 'c' copied from 'b'!
440 $ hg log --template '{rev}:{node|short} {parents} {desc}\n' -r tip
434 $ hg log --template '{rev}:{node|short} {parents} {desc}\n' -r tip
441 14:0c921c65ef1e 1:5d205f8b35b6 3
435 14:0c921c65ef1e 1:5d205f8b35b6 3
442 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
436 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
443
437
444 Resolve conflicted graft
438 Resolve conflicted graft
445 $ hg up -q 0
439 $ hg up -q 0
446 $ echo b > a
440 $ echo b > a
447 $ hg ci -m 8
441 $ hg ci -m 8
448 created new head
442 created new head
449 $ echo c > a
443 $ echo c > a
450 $ hg ci -m 9
444 $ hg ci -m 9
451 $ hg graft 1 --tool internal:fail
445 $ hg graft 1 --tool internal:fail
452 grafting 1:5d205f8b35b6 "1"
446 grafting 1:5d205f8b35b6 "1"
453 abort: unresolved conflicts, can't continue
447 abort: unresolved conflicts, can't continue
454 (use 'hg resolve' and 'hg graft --continue')
448 (use 'hg resolve' and 'hg graft --continue')
455 [255]
449 [255]
456 $ hg resolve --all
450 $ hg resolve --all
457 merging a
451 merging a
458 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
452 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
459 [1]
453 [1]
460 $ cat a
454 $ cat a
461 <<<<<<< local: aaa4406d4f0a - test: 9
455 <<<<<<< local: aaa4406d4f0a - test: 9
462 c
456 c
463 =======
457 =======
464 b
458 b
465 >>>>>>> graft: 5d205f8b35b6 - bar: 1
459 >>>>>>> graft: 5d205f8b35b6 - bar: 1
466 $ echo b > a
460 $ echo b > a
467 $ hg resolve -m a
461 $ hg resolve -m a
468 (no more unresolved files)
462 (no more unresolved files)
469 continue: hg graft --continue
463 continue: hg graft --continue
470 $ hg graft -c
464 $ hg graft -c
471 grafting 1:5d205f8b35b6 "1"
465 grafting 1:5d205f8b35b6 "1"
472 $ hg export tip --git
466 $ hg export tip --git
473 # HG changeset patch
467 # HG changeset patch
474 # User bar
468 # User bar
475 # Date 0 0
469 # Date 0 0
476 # Thu Jan 01 00:00:00 1970 +0000
470 # Thu Jan 01 00:00:00 1970 +0000
477 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
471 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
478 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
472 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
479 1
473 1
480
474
481 diff --git a/a b/a
475 diff --git a/a b/a
482 --- a/a
476 --- a/a
483 +++ b/a
477 +++ b/a
484 @@ -1,1 +1,1 @@
478 @@ -1,1 +1,1 @@
485 -c
479 -c
486 +b
480 +b
487
481
488 Resolve conflicted graft with rename
482 Resolve conflicted graft with rename
489 $ echo c > a
483 $ echo c > a
490 $ hg ci -m 10
484 $ hg ci -m 10
491 $ hg graft 2 --tool internal:fail
485 $ hg graft 2 --tool internal:fail
492 grafting 2:5c095ad7e90f "2"
486 grafting 2:5c095ad7e90f "2"
493 abort: unresolved conflicts, can't continue
487 abort: unresolved conflicts, can't continue
494 (use 'hg resolve' and 'hg graft --continue')
488 (use 'hg resolve' and 'hg graft --continue')
495 [255]
489 [255]
496 $ hg resolve --all
490 $ hg resolve --all
497 merging a and b to b
491 merging a and b to b
498 (no more unresolved files)
492 (no more unresolved files)
499 continue: hg graft --continue
493 continue: hg graft --continue
500 $ hg graft -c
494 $ hg graft -c
501 grafting 2:5c095ad7e90f "2"
495 grafting 2:5c095ad7e90f "2"
502 $ hg export tip --git
496 $ hg export tip --git
503 # HG changeset patch
497 # HG changeset patch
504 # User test
498 # User test
505 # Date 0 0
499 # Date 0 0
506 # Thu Jan 01 00:00:00 1970 +0000
500 # Thu Jan 01 00:00:00 1970 +0000
507 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
501 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
508 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
502 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
509 2
503 2
510
504
511 diff --git a/a b/b
505 diff --git a/a b/b
512 rename from a
506 rename from a
513 rename to b
507 rename to b
514
508
515 Test simple origin(), with and without args
509 Test simple origin(), with and without args
516 $ hg log -r 'origin()'
510 $ hg log -r 'origin()'
517 changeset: 1:5d205f8b35b6
511 changeset: 1:5d205f8b35b6
518 user: bar
512 user: bar
519 date: Thu Jan 01 00:00:00 1970 +0000
513 date: Thu Jan 01 00:00:00 1970 +0000
520 summary: 1
514 summary: 1
521
515
522 changeset: 2:5c095ad7e90f
516 changeset: 2:5c095ad7e90f
523 user: test
517 user: test
524 date: Thu Jan 01 00:00:00 1970 +0000
518 date: Thu Jan 01 00:00:00 1970 +0000
525 summary: 2
519 summary: 2
526
520
527 changeset: 3:4c60f11aa304
521 changeset: 3:4c60f11aa304
528 user: baz
522 user: baz
529 date: Thu Jan 01 00:00:00 1970 +0000
523 date: Thu Jan 01 00:00:00 1970 +0000
530 summary: 3
524 summary: 3
531
525
532 changeset: 4:9c233e8e184d
526 changeset: 4:9c233e8e184d
533 user: test
527 user: test
534 date: Thu Jan 01 00:00:00 1970 +0000
528 date: Thu Jan 01 00:00:00 1970 +0000
535 summary: 4
529 summary: 4
536
530
537 changeset: 5:97f8bfe72746
531 changeset: 5:97f8bfe72746
538 branch: stable
532 branch: stable
539 parent: 3:4c60f11aa304
533 parent: 3:4c60f11aa304
540 user: test
534 user: test
541 date: Thu Jan 01 00:00:00 1970 +0000
535 date: Thu Jan 01 00:00:00 1970 +0000
542 summary: 5
536 summary: 5
543
537
544 $ hg log -r 'origin(7)'
538 $ hg log -r 'origin(7)'
545 changeset: 2:5c095ad7e90f
539 changeset: 2:5c095ad7e90f
546 user: test
540 user: test
547 date: Thu Jan 01 00:00:00 1970 +0000
541 date: Thu Jan 01 00:00:00 1970 +0000
548 summary: 2
542 summary: 2
549
543
550 Now transplant a graft to test following through copies
544 Now transplant a graft to test following through copies
551 $ hg up -q 0
545 $ hg up -q 0
552 $ hg branch -q dev
546 $ hg branch -q dev
553 $ hg ci -qm "dev branch"
547 $ hg ci -qm "dev branch"
554 $ hg --config extensions.transplant= transplant -q 7
548 $ hg --config extensions.transplant= transplant -q 7
555 $ hg log -r 'origin(.)'
549 $ hg log -r 'origin(.)'
556 changeset: 2:5c095ad7e90f
550 changeset: 2:5c095ad7e90f
557 user: test
551 user: test
558 date: Thu Jan 01 00:00:00 1970 +0000
552 date: Thu Jan 01 00:00:00 1970 +0000
559 summary: 2
553 summary: 2
560
554
561 Test that the graft and transplant markers in extra are converted, allowing
555 Test that the graft and transplant markers in extra are converted, allowing
562 origin() to still work. Note that these recheck the immediately preceeding two
556 origin() to still work. Note that these recheck the immediately preceeding two
563 tests.
557 tests.
564 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
558 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
565
559
566 The graft case
560 The graft case
567 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
561 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
568 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
562 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
569 branch=default
563 branch=default
570 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
564 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
571 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
565 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
572 $ hg -R ../converted log -r 'origin(7)'
566 $ hg -R ../converted log -r 'origin(7)'
573 changeset: 2:e0213322b2c1
567 changeset: 2:e0213322b2c1
574 user: test
568 user: test
575 date: Thu Jan 01 00:00:00 1970 +0000
569 date: Thu Jan 01 00:00:00 1970 +0000
576 summary: 2
570 summary: 2
577
571
578 Test that template correctly expands more than one 'extra' (issue4362), and that
572 Test that template correctly expands more than one 'extra' (issue4362), and that
579 'intermediate-source' is converted.
573 'intermediate-source' is converted.
580 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
574 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
581 Extra: branch=default
575 Extra: branch=default
582 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
576 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
583 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
577 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
584 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
578 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
585
579
586 The transplant case
580 The transplant case
587 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
581 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
588 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
582 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
589 branch=dev
583 branch=dev
590 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
584 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
591 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
585 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
592 `h\x9b (esc)
586 `h\x9b (esc)
593 $ hg -R ../converted log -r 'origin(tip)'
587 $ hg -R ../converted log -r 'origin(tip)'
594 changeset: 2:e0213322b2c1
588 changeset: 2:e0213322b2c1
595 user: test
589 user: test
596 date: Thu Jan 01 00:00:00 1970 +0000
590 date: Thu Jan 01 00:00:00 1970 +0000
597 summary: 2
591 summary: 2
598
592
599
593
600 Test simple destination
594 Test simple destination
601 $ hg log -r 'destination()'
595 $ hg log -r 'destination()'
602 changeset: 7:ef0ef43d49e7
596 changeset: 7:ef0ef43d49e7
603 parent: 0:68795b066622
597 parent: 0:68795b066622
604 user: foo
598 user: foo
605 date: Thu Jan 01 00:00:00 1970 +0000
599 date: Thu Jan 01 00:00:00 1970 +0000
606 summary: 2
600 summary: 2
607
601
608 changeset: 8:6b9e5368ca4e
602 changeset: 8:6b9e5368ca4e
609 user: bar
603 user: bar
610 date: Thu Jan 01 00:00:00 1970 +0000
604 date: Thu Jan 01 00:00:00 1970 +0000
611 summary: 1
605 summary: 1
612
606
613 changeset: 9:1905859650ec
607 changeset: 9:1905859650ec
614 user: test
608 user: test
615 date: Thu Jan 01 00:00:00 1970 +0000
609 date: Thu Jan 01 00:00:00 1970 +0000
616 summary: 5
610 summary: 5
617
611
618 changeset: 10:52dc0b4c6907
612 changeset: 10:52dc0b4c6907
619 user: test
613 user: test
620 date: Thu Jan 01 00:00:00 1970 +0000
614 date: Thu Jan 01 00:00:00 1970 +0000
621 summary: 4
615 summary: 4
622
616
623 changeset: 11:882b35362a6b
617 changeset: 11:882b35362a6b
624 user: test
618 user: test
625 date: Thu Jan 01 00:00:00 1970 +0000
619 date: Thu Jan 01 00:00:00 1970 +0000
626 summary: 3
620 summary: 3
627
621
628 changeset: 13:7a4785234d87
622 changeset: 13:7a4785234d87
629 user: foo
623 user: foo
630 date: Thu Jan 01 00:00:00 1970 +0000
624 date: Thu Jan 01 00:00:00 1970 +0000
631 summary: 2
625 summary: 2
632
626
633 changeset: 14:0c921c65ef1e
627 changeset: 14:0c921c65ef1e
634 parent: 1:5d205f8b35b6
628 parent: 1:5d205f8b35b6
635 user: foo
629 user: foo
636 date: Thu Jan 01 00:00:00 1970 +0000
630 date: Thu Jan 01 00:00:00 1970 +0000
637 summary: 3
631 summary: 3
638
632
639 changeset: 17:f67661df0c48
633 changeset: 17:f67661df0c48
640 user: bar
634 user: bar
641 date: Thu Jan 01 00:00:00 1970 +0000
635 date: Thu Jan 01 00:00:00 1970 +0000
642 summary: 1
636 summary: 1
643
637
644 changeset: 19:9627f653b421
638 changeset: 19:9627f653b421
645 user: test
639 user: test
646 date: Thu Jan 01 00:00:00 1970 +0000
640 date: Thu Jan 01 00:00:00 1970 +0000
647 summary: 2
641 summary: 2
648
642
649 changeset: 21:7e61b508e709
643 changeset: 21:7e61b508e709
650 branch: dev
644 branch: dev
651 tag: tip
645 tag: tip
652 user: foo
646 user: foo
653 date: Thu Jan 01 00:00:00 1970 +0000
647 date: Thu Jan 01 00:00:00 1970 +0000
654 summary: 2
648 summary: 2
655
649
656 $ hg log -r 'destination(2)'
650 $ hg log -r 'destination(2)'
657 changeset: 7:ef0ef43d49e7
651 changeset: 7:ef0ef43d49e7
658 parent: 0:68795b066622
652 parent: 0:68795b066622
659 user: foo
653 user: foo
660 date: Thu Jan 01 00:00:00 1970 +0000
654 date: Thu Jan 01 00:00:00 1970 +0000
661 summary: 2
655 summary: 2
662
656
663 changeset: 13:7a4785234d87
657 changeset: 13:7a4785234d87
664 user: foo
658 user: foo
665 date: Thu Jan 01 00:00:00 1970 +0000
659 date: Thu Jan 01 00:00:00 1970 +0000
666 summary: 2
660 summary: 2
667
661
668 changeset: 19:9627f653b421
662 changeset: 19:9627f653b421
669 user: test
663 user: test
670 date: Thu Jan 01 00:00:00 1970 +0000
664 date: Thu Jan 01 00:00:00 1970 +0000
671 summary: 2
665 summary: 2
672
666
673 changeset: 21:7e61b508e709
667 changeset: 21:7e61b508e709
674 branch: dev
668 branch: dev
675 tag: tip
669 tag: tip
676 user: foo
670 user: foo
677 date: Thu Jan 01 00:00:00 1970 +0000
671 date: Thu Jan 01 00:00:00 1970 +0000
678 summary: 2
672 summary: 2
679
673
680 Transplants of grafts can find a destination...
674 Transplants of grafts can find a destination...
681 $ hg log -r 'destination(7)'
675 $ hg log -r 'destination(7)'
682 changeset: 21:7e61b508e709
676 changeset: 21:7e61b508e709
683 branch: dev
677 branch: dev
684 tag: tip
678 tag: tip
685 user: foo
679 user: foo
686 date: Thu Jan 01 00:00:00 1970 +0000
680 date: Thu Jan 01 00:00:00 1970 +0000
687 summary: 2
681 summary: 2
688
682
689 ... grafts of grafts unfortunately can't
683 ... grafts of grafts unfortunately can't
690 $ hg graft -q 13
684 $ hg graft -q 13
691 warning: can't find ancestor for 'b' copied from 'a'!
685 warning: can't find ancestor for 'b' copied from 'a'!
692 $ hg log -r 'destination(13)'
686 $ hg log -r 'destination(13)'
693 All copies of a cset
687 All copies of a cset
694 $ hg log -r 'origin(13) or destination(origin(13))'
688 $ hg log -r 'origin(13) or destination(origin(13))'
695 changeset: 2:5c095ad7e90f
689 changeset: 2:5c095ad7e90f
696 user: test
690 user: test
697 date: Thu Jan 01 00:00:00 1970 +0000
691 date: Thu Jan 01 00:00:00 1970 +0000
698 summary: 2
692 summary: 2
699
693
700 changeset: 7:ef0ef43d49e7
694 changeset: 7:ef0ef43d49e7
701 parent: 0:68795b066622
695 parent: 0:68795b066622
702 user: foo
696 user: foo
703 date: Thu Jan 01 00:00:00 1970 +0000
697 date: Thu Jan 01 00:00:00 1970 +0000
704 summary: 2
698 summary: 2
705
699
706 changeset: 13:7a4785234d87
700 changeset: 13:7a4785234d87
707 user: foo
701 user: foo
708 date: Thu Jan 01 00:00:00 1970 +0000
702 date: Thu Jan 01 00:00:00 1970 +0000
709 summary: 2
703 summary: 2
710
704
711 changeset: 19:9627f653b421
705 changeset: 19:9627f653b421
712 user: test
706 user: test
713 date: Thu Jan 01 00:00:00 1970 +0000
707 date: Thu Jan 01 00:00:00 1970 +0000
714 summary: 2
708 summary: 2
715
709
716 changeset: 21:7e61b508e709
710 changeset: 21:7e61b508e709
717 branch: dev
711 branch: dev
718 user: foo
712 user: foo
719 date: Thu Jan 01 00:00:00 1970 +0000
713 date: Thu Jan 01 00:00:00 1970 +0000
720 summary: 2
714 summary: 2
721
715
722 changeset: 22:d1cb6591fa4b
716 changeset: 22:d1cb6591fa4b
723 branch: dev
717 branch: dev
724 tag: tip
718 tag: tip
725 user: foo
719 user: foo
726 date: Thu Jan 01 00:00:00 1970 +0000
720 date: Thu Jan 01 00:00:00 1970 +0000
727 summary: 2
721 summary: 2
728
722
729
723
730 graft works on complex revset
724 graft works on complex revset
731
725
732 $ hg graft 'origin(13) or destination(origin(13))'
726 $ hg graft 'origin(13) or destination(origin(13))'
733 skipping ancestor revision 21:7e61b508e709
727 skipping ancestor revision 21:7e61b508e709
734 skipping ancestor revision 22:d1cb6591fa4b
728 skipping ancestor revision 22:d1cb6591fa4b
735 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
729 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
736 grafting 7:ef0ef43d49e7 "2"
730 grafting 7:ef0ef43d49e7 "2"
737 warning: can't find ancestor for 'b' copied from 'a'!
731 warning: can't find ancestor for 'b' copied from 'a'!
738 grafting 13:7a4785234d87 "2"
732 grafting 13:7a4785234d87 "2"
739 warning: can't find ancestor for 'b' copied from 'a'!
733 warning: can't find ancestor for 'b' copied from 'a'!
740 grafting 19:9627f653b421 "2"
734 grafting 19:9627f653b421 "2"
741 merging b
735 merging b
742 warning: can't find ancestor for 'b' copied from 'a'!
736 warning: can't find ancestor for 'b' copied from 'a'!
743
737
744 graft with --force (still doesn't graft merges)
738 graft with --force (still doesn't graft merges)
745
739
746 $ hg graft 19 0 6
740 $ hg graft 19 0 6
747 skipping ungraftable merge revision 6
741 skipping ungraftable merge revision 6
748 skipping ancestor revision 0:68795b066622
742 skipping ancestor revision 0:68795b066622
749 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
743 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
750 [255]
744 [255]
751 $ hg graft 19 0 6 --force
745 $ hg graft 19 0 6 --force
752 skipping ungraftable merge revision 6
746 skipping ungraftable merge revision 6
753 grafting 19:9627f653b421 "2"
747 grafting 19:9627f653b421 "2"
754 merging b
748 merging b
755 warning: can't find ancestor for 'b' copied from 'a'!
749 warning: can't find ancestor for 'b' copied from 'a'!
756 grafting 0:68795b066622 "0"
750 grafting 0:68795b066622 "0"
757
751
758 graft --force after backout
752 graft --force after backout
759
753
760 $ echo abc > a
754 $ echo abc > a
761 $ hg ci -m 28
755 $ hg ci -m 28
762 $ hg backout 28
756 $ hg backout 28
763 reverting a
757 reverting a
764 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
758 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
765 $ hg graft 28
759 $ hg graft 28
766 skipping ancestor revision 28:50a516bb8b57
760 skipping ancestor revision 28:50a516bb8b57
767 [255]
761 [255]
768 $ hg graft 28 --force
762 $ hg graft 28 --force
769 grafting 28:50a516bb8b57 "28"
763 grafting 28:50a516bb8b57 "28"
770 merging a
764 merging a
771 $ cat a
765 $ cat a
772 abc
766 abc
773
767
774 graft --continue after --force
768 graft --continue after --force
775
769
776 $ echo def > a
770 $ echo def > a
777 $ hg ci -m 31
771 $ hg ci -m 31
778 $ hg graft 28 --force --tool internal:fail
772 $ hg graft 28 --force --tool internal:fail
779 grafting 28:50a516bb8b57 "28"
773 grafting 28:50a516bb8b57 "28"
780 abort: unresolved conflicts, can't continue
774 abort: unresolved conflicts, can't continue
781 (use 'hg resolve' and 'hg graft --continue')
775 (use 'hg resolve' and 'hg graft --continue')
782 [255]
776 [255]
783 $ hg resolve --all
777 $ hg resolve --all
784 merging a
778 merging a
785 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
779 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
786 [1]
780 [1]
787 $ echo abc > a
781 $ echo abc > a
788 $ hg resolve -m a
782 $ hg resolve -m a
789 (no more unresolved files)
783 (no more unresolved files)
790 continue: hg graft --continue
784 continue: hg graft --continue
791 $ hg graft -c
785 $ hg graft -c
792 grafting 28:50a516bb8b57 "28"
786 grafting 28:50a516bb8b57 "28"
793 $ cat a
787 $ cat a
794 abc
788 abc
795
789
796 Continue testing same origin policy, using revision numbers from test above
790 Continue testing same origin policy, using revision numbers from test above
797 but do some destructive editing of the repo:
791 but do some destructive editing of the repo:
798
792
799 $ hg up -qC 7
793 $ hg up -qC 7
800 $ hg tag -l -r 13 tmp
794 $ hg tag -l -r 13 tmp
801 $ hg --config extensions.strip= strip 2
795 $ hg --config extensions.strip= strip 2
802 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
796 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
803 $ hg graft tmp
797 $ hg graft tmp
804 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
798 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
805 [255]
799 [255]
806
800
807 Empty graft
801 Empty graft
808
802
809 $ hg up -qr 26
803 $ hg up -qr 26
810 $ hg tag -f something
804 $ hg tag -f something
811 $ hg graft -qr 27
805 $ hg graft -qr 27
812 $ hg graft -f 27
806 $ hg graft -f 27
813 grafting 27:ed6c7e54e319 "28"
807 grafting 27:ed6c7e54e319 "28"
814 note: graft of 27:ed6c7e54e319 created no changes to commit
808 note: graft of 27:ed6c7e54e319 created no changes to commit
815
809
816 $ cd ..
810 $ cd ..
817
811
818 Graft to duplicate a commit
812 Graft to duplicate a commit
819
813
820 $ hg init graftsibling
814 $ hg init graftsibling
821 $ cd graftsibling
815 $ cd graftsibling
822 $ touch a
816 $ touch a
823 $ hg commit -qAm a
817 $ hg commit -qAm a
824 $ touch b
818 $ touch b
825 $ hg commit -qAm b
819 $ hg commit -qAm b
826 $ hg log -G -T '{rev}\n'
820 $ hg log -G -T '{rev}\n'
827 @ 1
821 @ 1
828 |
822 |
829 o 0
823 o 0
830
824
831 $ hg up -q 0
825 $ hg up -q 0
832 $ hg graft -r 1
826 $ hg graft -r 1
833 grafting 1:0e067c57feba "b" (tip)
827 grafting 1:0e067c57feba "b" (tip)
834 $ hg log -G -T '{rev}\n'
828 $ hg log -G -T '{rev}\n'
835 @ 2
829 @ 2
836 |
830 |
837 | o 1
831 | o 1
838 |/
832 |/
839 o 0
833 o 0
840
834
841 Graft to duplicate a commit twice
835 Graft to duplicate a commit twice
842
836
843 $ hg up -q 0
837 $ hg up -q 0
844 $ hg graft -r 2
838 $ hg graft -r 2
845 grafting 2:044ec77f6389 "b" (tip)
839 grafting 2:044ec77f6389 "b" (tip)
846 $ hg log -G -T '{rev}\n'
840 $ hg log -G -T '{rev}\n'
847 @ 3
841 @ 3
848 |
842 |
849 | o 2
843 | o 2
850 |/
844 |/
851 | o 1
845 | o 1
852 |/
846 |/
853 o 0
847 o 0
854
848
855 Graft from behind a move or rename
849 Graft from behind a move or rename
856 ==================================
850 ==================================
857
851
858 NOTE: This is affected by issue5343, and will need updating when it's fixed
852 NOTE: This is affected by issue5343, and will need updating when it's fixed
859
853
860 Possible cases during a regular graft (when ca is between cta and c2):
854 Possible cases during a regular graft (when ca is between cta and c2):
861
855
862 name | c1<-cta | cta<->ca | ca->c2
856 name | c1<-cta | cta<->ca | ca->c2
863 A.0 | | |
857 A.0 | | |
864 A.1 | X | |
858 A.1 | X | |
865 A.2 | | X |
859 A.2 | | X |
866 A.3 | | | X
860 A.3 | | | X
867 A.4 | X | X |
861 A.4 | X | X |
868 A.5 | X | | X
862 A.5 | X | | X
869 A.6 | | X | X
863 A.6 | | X | X
870 A.7 | X | X | X
864 A.7 | X | X | X
871
865
872 A.0 is trivial, and doesn't need copy tracking.
866 A.0 is trivial, and doesn't need copy tracking.
873 For A.1, a forward rename is recorded in the c1 pass, to be followed later.
867 For A.1, a forward rename is recorded in the c1 pass, to be followed later.
874 In A.2, the rename is recorded in the c2 pass and followed backwards.
868 In A.2, the rename is recorded in the c2 pass and followed backwards.
875 A.3 is recorded in the c2 pass as a forward rename to be duplicated on target.
869 A.3 is recorded in the c2 pass as a forward rename to be duplicated on target.
876 In A.4, both passes of checkcopies record incomplete renames, which are
870 In A.4, both passes of checkcopies record incomplete renames, which are
877 then joined in mergecopies to record a rename to be followed.
871 then joined in mergecopies to record a rename to be followed.
878 In A.5 and A.7, the c1 pass records an incomplete rename, while the c2 pass
872 In A.5 and A.7, the c1 pass records an incomplete rename, while the c2 pass
879 records an incomplete divergence. The incomplete rename is then joined to the
873 records an incomplete divergence. The incomplete rename is then joined to the
880 appropriate side of the incomplete divergence, and the result is recorded as a
874 appropriate side of the incomplete divergence, and the result is recorded as a
881 divergence. The code doesn't distinguish at all between these two cases, since
875 divergence. The code doesn't distinguish at all between these two cases, since
882 the end result of them is the same: an incomplete divergence joined with an
876 the end result of them is the same: an incomplete divergence joined with an
883 incomplete rename into a divergence.
877 incomplete rename into a divergence.
884 Finally, A.6 records a divergence entirely in the c2 pass.
878 Finally, A.6 records a divergence entirely in the c2 pass.
885
879
886 A.4 has a degenerate case a<-b<-a->a, where checkcopies isn't needed at all.
880 A.4 has a degenerate case a<-b<-a->a, where checkcopies isn't needed at all.
887 A.5 has a special case a<-b<-b->a, which is treated like a<-b->a in a merge.
881 A.5 has a special case a<-b<-b->a, which is treated like a<-b->a in a merge.
888 A.6 has a special case a<-a<-b->a. Here, checkcopies will find a spurious
882 A.6 has a special case a<-a<-b->a. Here, checkcopies will find a spurious
889 incomplete divergence, which is in fact complete. This is handled later in
883 incomplete divergence, which is in fact complete. This is handled later in
890 mergecopies.
884 mergecopies.
891 A.7 has 4 special cases: a<-b<-a->b (the "ping-pong" case), a<-b<-c->b,
885 A.7 has 4 special cases: a<-b<-a->b (the "ping-pong" case), a<-b<-c->b,
892 a<-b<-a->c and a<-b<-c->a. Of these, only the "ping-pong" case is interesting,
886 a<-b<-a->c and a<-b<-c->a. Of these, only the "ping-pong" case is interesting,
893 the others are fairly trivial (a<-b<-c->b and a<-b<-a->c proceed like the base
887 the others are fairly trivial (a<-b<-c->b and a<-b<-a->c proceed like the base
894 case, a<-b<-c->a is treated the same as a<-b<-b->a).
888 case, a<-b<-c->a is treated the same as a<-b<-b->a).
895
889
896 f5a therefore tests the "ping-pong" rename case, where a file is renamed to the
890 f5a therefore tests the "ping-pong" rename case, where a file is renamed to the
897 same name on both branches, then the rename is backed out on one branch, and
891 same name on both branches, then the rename is backed out on one branch, and
898 the backout is grafted to the other branch. This creates a challenging rename
892 the backout is grafted to the other branch. This creates a challenging rename
899 sequence of a<-b<-a->b in the graft target, topological CA, graft CA and graft
893 sequence of a<-b<-a->b in the graft target, topological CA, graft CA and graft
900 source, respectively. Since rename detection will run on the c1 side for such a
894 source, respectively. Since rename detection will run on the c1 side for such a
901 sequence (as for technical reasons, we split the c1 and c2 sides not at the
895 sequence (as for technical reasons, we split the c1 and c2 sides not at the
902 graft CA, but rather at the topological CA), it will pick up a false rename,
896 graft CA, but rather at the topological CA), it will pick up a false rename,
903 and cause a spurious merge conflict. This false rename is always exactly the
897 and cause a spurious merge conflict. This false rename is always exactly the
904 reverse of the true rename that would be detected on the c2 side, so we can
898 reverse of the true rename that would be detected on the c2 side, so we can
905 correct for it by detecting this condition and reversing as necessary.
899 correct for it by detecting this condition and reversing as necessary.
906
900
907 First, set up the repository with commits to be grafted
901 First, set up the repository with commits to be grafted
908
902
909 $ hg init ../graftmove
903 $ hg init ../graftmove
910 $ cd ../graftmove
904 $ cd ../graftmove
911 $ echo c1a > f1a
905 $ echo c1a > f1a
912 $ echo c2a > f2a
906 $ echo c2a > f2a
913 $ echo c3a > f3a
907 $ echo c3a > f3a
914 $ echo c4a > f4a
908 $ echo c4a > f4a
915 $ echo c5a > f5a
909 $ echo c5a > f5a
916 $ hg ci -qAm A0
910 $ hg ci -qAm A0
917 $ hg mv f1a f1b
911 $ hg mv f1a f1b
918 $ hg mv f3a f3b
912 $ hg mv f3a f3b
919 $ hg mv f5a f5b
913 $ hg mv f5a f5b
920 $ hg ci -qAm B0
914 $ hg ci -qAm B0
921 $ echo c1c > f1b
915 $ echo c1c > f1b
922 $ hg mv f2a f2c
916 $ hg mv f2a f2c
923 $ hg mv f5b f5a
917 $ hg mv f5b f5a
924 $ echo c5c > f5a
918 $ echo c5c > f5a
925 $ hg ci -qAm C0
919 $ hg ci -qAm C0
926 $ hg mv f3b f3d
920 $ hg mv f3b f3d
927 $ echo c4d > f4a
921 $ echo c4d > f4a
928 $ hg ci -qAm D0
922 $ hg ci -qAm D0
929 $ hg log -G
923 $ hg log -G
930 @ changeset: 3:b69f5839d2d9
924 @ changeset: 3:b69f5839d2d9
931 | tag: tip
925 | tag: tip
932 | user: test
926 | user: test
933 | date: Thu Jan 01 00:00:00 1970 +0000
927 | date: Thu Jan 01 00:00:00 1970 +0000
934 | summary: D0
928 | summary: D0
935 |
929 |
936 o changeset: 2:f58c7e2b28fa
930 o changeset: 2:f58c7e2b28fa
937 | user: test
931 | user: test
938 | date: Thu Jan 01 00:00:00 1970 +0000
932 | date: Thu Jan 01 00:00:00 1970 +0000
939 | summary: C0
933 | summary: C0
940 |
934 |
941 o changeset: 1:3d7bba921b5d
935 o changeset: 1:3d7bba921b5d
942 | user: test
936 | user: test
943 | date: Thu Jan 01 00:00:00 1970 +0000
937 | date: Thu Jan 01 00:00:00 1970 +0000
944 | summary: B0
938 | summary: B0
945 |
939 |
946 o changeset: 0:11f7a1b56675
940 o changeset: 0:11f7a1b56675
947 user: test
941 user: test
948 date: Thu Jan 01 00:00:00 1970 +0000
942 date: Thu Jan 01 00:00:00 1970 +0000
949 summary: A0
943 summary: A0
950
944
951
945
952 Test the cases A.2 (f1x), A.3 (f2x) and a special case of A.6 (f5x) where the
946 Test the cases A.2 (f1x), A.3 (f2x) and a special case of A.6 (f5x) where the
953 two renames actually converge to the same name (thus no actual divergence).
947 two renames actually converge to the same name (thus no actual divergence).
954
948
955 $ hg up -q 'desc("A0")'
949 $ hg up -q 'desc("A0")'
956 $ HGEDITOR="echo C1 >" hg graft -r 'desc("C0")' --edit
950 $ HGEDITOR="echo C1 >" hg graft -r 'desc("C0")' --edit
957 grafting 2:f58c7e2b28fa "C0"
951 grafting 2:f58c7e2b28fa "C0"
958 merging f1a and f1b to f1a
952 merging f1a and f1b to f1a
959 merging f5a
953 merging f5a
960 warning: can't find ancestor for 'f5a' copied from 'f5b'!
954 warning: can't find ancestor for 'f5a' copied from 'f5b'!
961 $ hg status --change .
955 $ hg status --change .
962 M f1a
956 M f1a
963 M f5a
957 M f5a
964 A f2c
958 A f2c
965 R f2a
959 R f2a
966 $ hg cat f1a
960 $ hg cat f1a
967 c1c
961 c1c
968 $ hg cat f1b
962 $ hg cat f1b
969 f1b: no such file in rev c9763722f9bd
963 f1b: no such file in rev c9763722f9bd
970 [1]
964 [1]
971
965
972 Test the cases A.0 (f4x) and A.6 (f3x)
966 Test the cases A.0 (f4x) and A.6 (f3x)
973
967
974 $ HGEDITOR="echo D1 >" hg graft -r 'desc("D0")' --edit
968 $ HGEDITOR="echo D1 >" hg graft -r 'desc("D0")' --edit
975 grafting 3:b69f5839d2d9 "D0"
969 grafting 3:b69f5839d2d9 "D0"
976 note: possible conflict - f3b was renamed multiple times to:
970 note: possible conflict - f3b was renamed multiple times to:
977 f3d
971 f3d
978 f3a
972 f3a
979 warning: can't find ancestor for 'f3d' copied from 'f3b'!
973 warning: can't find ancestor for 'f3d' copied from 'f3b'!
980
974
981 Set up the repository for some further tests
975 Set up the repository for some further tests
982
976
983 $ hg up -q "min(desc("A0"))"
977 $ hg up -q "min(desc("A0"))"
984 $ hg mv f1a f1e
978 $ hg mv f1a f1e
985 $ echo c2e > f2a
979 $ echo c2e > f2a
986 $ hg mv f3a f3e
980 $ hg mv f3a f3e
987 $ hg mv f4a f4e
981 $ hg mv f4a f4e
988 $ hg mv f5a f5b
982 $ hg mv f5a f5b
989 $ hg ci -qAm "E0"
983 $ hg ci -qAm "E0"
990 $ hg log -G
984 $ hg log -G
991 @ changeset: 6:6bd1736cab86
985 @ changeset: 6:6bd1736cab86
992 | tag: tip
986 | tag: tip
993 | parent: 0:11f7a1b56675
987 | parent: 0:11f7a1b56675
994 | user: test
988 | user: test
995 | date: Thu Jan 01 00:00:00 1970 +0000
989 | date: Thu Jan 01 00:00:00 1970 +0000
996 | summary: E0
990 | summary: E0
997 |
991 |
998 | o changeset: 5:560daee679da
992 | o changeset: 5:560daee679da
999 | | user: test
993 | | user: test
1000 | | date: Thu Jan 01 00:00:00 1970 +0000
994 | | date: Thu Jan 01 00:00:00 1970 +0000
1001 | | summary: D1
995 | | summary: D1
1002 | |
996 | |
1003 | o changeset: 4:c9763722f9bd
997 | o changeset: 4:c9763722f9bd
1004 |/ parent: 0:11f7a1b56675
998 |/ parent: 0:11f7a1b56675
1005 | user: test
999 | user: test
1006 | date: Thu Jan 01 00:00:00 1970 +0000
1000 | date: Thu Jan 01 00:00:00 1970 +0000
1007 | summary: C1
1001 | summary: C1
1008 |
1002 |
1009 | o changeset: 3:b69f5839d2d9
1003 | o changeset: 3:b69f5839d2d9
1010 | | user: test
1004 | | user: test
1011 | | date: Thu Jan 01 00:00:00 1970 +0000
1005 | | date: Thu Jan 01 00:00:00 1970 +0000
1012 | | summary: D0
1006 | | summary: D0
1013 | |
1007 | |
1014 | o changeset: 2:f58c7e2b28fa
1008 | o changeset: 2:f58c7e2b28fa
1015 | | user: test
1009 | | user: test
1016 | | date: Thu Jan 01 00:00:00 1970 +0000
1010 | | date: Thu Jan 01 00:00:00 1970 +0000
1017 | | summary: C0
1011 | | summary: C0
1018 | |
1012 | |
1019 | o changeset: 1:3d7bba921b5d
1013 | o changeset: 1:3d7bba921b5d
1020 |/ user: test
1014 |/ user: test
1021 | date: Thu Jan 01 00:00:00 1970 +0000
1015 | date: Thu Jan 01 00:00:00 1970 +0000
1022 | summary: B0
1016 | summary: B0
1023 |
1017 |
1024 o changeset: 0:11f7a1b56675
1018 o changeset: 0:11f7a1b56675
1025 user: test
1019 user: test
1026 date: Thu Jan 01 00:00:00 1970 +0000
1020 date: Thu Jan 01 00:00:00 1970 +0000
1027 summary: A0
1021 summary: A0
1028
1022
1029
1023
1030 Test the cases A.4 (f1x), the "ping-pong" special case of A.7 (f5x),
1024 Test the cases A.4 (f1x), the "ping-pong" special case of A.7 (f5x),
1031 and A.3 with a local content change to be preserved (f2x).
1025 and A.3 with a local content change to be preserved (f2x).
1032
1026
1033 $ HGEDITOR="echo C2 >" hg graft -r 'desc("C0")' --edit
1027 $ HGEDITOR="echo C2 >" hg graft -r 'desc("C0")' --edit
1034 grafting 2:f58c7e2b28fa "C0"
1028 grafting 2:f58c7e2b28fa "C0"
1035 merging f1e and f1b to f1e
1029 merging f1e and f1b to f1e
1036 merging f2a and f2c to f2c
1030 merging f2a and f2c to f2c
1037 merging f5b and f5a to f5a
1031 merging f5b and f5a to f5a
1038
1032
1039 Test the cases A.1 (f4x) and A.7 (f3x).
1033 Test the cases A.1 (f4x) and A.7 (f3x).
1040
1034
1041 $ HGEDITOR="echo D2 >" hg graft -r 'desc("D0")' --edit
1035 $ HGEDITOR="echo D2 >" hg graft -r 'desc("D0")' --edit
1042 grafting 3:b69f5839d2d9 "D0"
1036 grafting 3:b69f5839d2d9 "D0"
1043 note: possible conflict - f3b was renamed multiple times to:
1037 note: possible conflict - f3b was renamed multiple times to:
1044 f3e
1038 f3e
1045 f3d
1039 f3d
1046 merging f4e and f4a to f4e
1040 merging f4e and f4a to f4e
1047 warning: can't find ancestor for 'f3d' copied from 'f3b'!
1041 warning: can't find ancestor for 'f3d' copied from 'f3b'!
1048
1042
1049 Check the results of the grafts tested
1043 Check the results of the grafts tested
1050
1044
1051 $ hg log -CGv --patch --git
1045 $ hg log -CGv --patch --git
1052 @ changeset: 8:93ee502e8b0a
1046 @ changeset: 8:93ee502e8b0a
1053 | tag: tip
1047 | tag: tip
1054 | user: test
1048 | user: test
1055 | date: Thu Jan 01 00:00:00 1970 +0000
1049 | date: Thu Jan 01 00:00:00 1970 +0000
1056 | files: f3d f4e
1050 | files: f3d f4e
1057 | description:
1051 | description:
1058 | D2
1052 | D2
1059 |
1053 |
1060 |
1054 |
1061 | diff --git a/f3d b/f3d
1055 | diff --git a/f3d b/f3d
1062 | new file mode 100644
1056 | new file mode 100644
1063 | --- /dev/null
1057 | --- /dev/null
1064 | +++ b/f3d
1058 | +++ b/f3d
1065 | @@ -0,0 +1,1 @@
1059 | @@ -0,0 +1,1 @@
1066 | +c3a
1060 | +c3a
1067 | diff --git a/f4e b/f4e
1061 | diff --git a/f4e b/f4e
1068 | --- a/f4e
1062 | --- a/f4e
1069 | +++ b/f4e
1063 | +++ b/f4e
1070 | @@ -1,1 +1,1 @@
1064 | @@ -1,1 +1,1 @@
1071 | -c4a
1065 | -c4a
1072 | +c4d
1066 | +c4d
1073 |
1067 |
1074 o changeset: 7:539cf145f496
1068 o changeset: 7:539cf145f496
1075 | user: test
1069 | user: test
1076 | date: Thu Jan 01 00:00:00 1970 +0000
1070 | date: Thu Jan 01 00:00:00 1970 +0000
1077 | files: f1e f2a f2c f5a f5b
1071 | files: f1e f2a f2c f5a f5b
1078 | copies: f2c (f2a) f5a (f5b)
1072 | copies: f2c (f2a) f5a (f5b)
1079 | description:
1073 | description:
1080 | C2
1074 | C2
1081 |
1075 |
1082 |
1076 |
1083 | diff --git a/f1e b/f1e
1077 | diff --git a/f1e b/f1e
1084 | --- a/f1e
1078 | --- a/f1e
1085 | +++ b/f1e
1079 | +++ b/f1e
1086 | @@ -1,1 +1,1 @@
1080 | @@ -1,1 +1,1 @@
1087 | -c1a
1081 | -c1a
1088 | +c1c
1082 | +c1c
1089 | diff --git a/f2a b/f2c
1083 | diff --git a/f2a b/f2c
1090 | rename from f2a
1084 | rename from f2a
1091 | rename to f2c
1085 | rename to f2c
1092 | diff --git a/f5b b/f5a
1086 | diff --git a/f5b b/f5a
1093 | rename from f5b
1087 | rename from f5b
1094 | rename to f5a
1088 | rename to f5a
1095 | --- a/f5b
1089 | --- a/f5b
1096 | +++ b/f5a
1090 | +++ b/f5a
1097 | @@ -1,1 +1,1 @@
1091 | @@ -1,1 +1,1 @@
1098 | -c5a
1092 | -c5a
1099 | +c5c
1093 | +c5c
1100 |
1094 |
1101 o changeset: 6:6bd1736cab86
1095 o changeset: 6:6bd1736cab86
1102 | parent: 0:11f7a1b56675
1096 | parent: 0:11f7a1b56675
1103 | user: test
1097 | user: test
1104 | date: Thu Jan 01 00:00:00 1970 +0000
1098 | date: Thu Jan 01 00:00:00 1970 +0000
1105 | files: f1a f1e f2a f3a f3e f4a f4e f5a f5b
1099 | files: f1a f1e f2a f3a f3e f4a f4e f5a f5b
1106 | copies: f1e (f1a) f3e (f3a) f4e (f4a) f5b (f5a)
1100 | copies: f1e (f1a) f3e (f3a) f4e (f4a) f5b (f5a)
1107 | description:
1101 | description:
1108 | E0
1102 | E0
1109 |
1103 |
1110 |
1104 |
1111 | diff --git a/f1a b/f1e
1105 | diff --git a/f1a b/f1e
1112 | rename from f1a
1106 | rename from f1a
1113 | rename to f1e
1107 | rename to f1e
1114 | diff --git a/f2a b/f2a
1108 | diff --git a/f2a b/f2a
1115 | --- a/f2a
1109 | --- a/f2a
1116 | +++ b/f2a
1110 | +++ b/f2a
1117 | @@ -1,1 +1,1 @@
1111 | @@ -1,1 +1,1 @@
1118 | -c2a
1112 | -c2a
1119 | +c2e
1113 | +c2e
1120 | diff --git a/f3a b/f3e
1114 | diff --git a/f3a b/f3e
1121 | rename from f3a
1115 | rename from f3a
1122 | rename to f3e
1116 | rename to f3e
1123 | diff --git a/f4a b/f4e
1117 | diff --git a/f4a b/f4e
1124 | rename from f4a
1118 | rename from f4a
1125 | rename to f4e
1119 | rename to f4e
1126 | diff --git a/f5a b/f5b
1120 | diff --git a/f5a b/f5b
1127 | rename from f5a
1121 | rename from f5a
1128 | rename to f5b
1122 | rename to f5b
1129 |
1123 |
1130 | o changeset: 5:560daee679da
1124 | o changeset: 5:560daee679da
1131 | | user: test
1125 | | user: test
1132 | | date: Thu Jan 01 00:00:00 1970 +0000
1126 | | date: Thu Jan 01 00:00:00 1970 +0000
1133 | | files: f3d f4a
1127 | | files: f3d f4a
1134 | | description:
1128 | | description:
1135 | | D1
1129 | | D1
1136 | |
1130 | |
1137 | |
1131 | |
1138 | | diff --git a/f3d b/f3d
1132 | | diff --git a/f3d b/f3d
1139 | | new file mode 100644
1133 | | new file mode 100644
1140 | | --- /dev/null
1134 | | --- /dev/null
1141 | | +++ b/f3d
1135 | | +++ b/f3d
1142 | | @@ -0,0 +1,1 @@
1136 | | @@ -0,0 +1,1 @@
1143 | | +c3a
1137 | | +c3a
1144 | | diff --git a/f4a b/f4a
1138 | | diff --git a/f4a b/f4a
1145 | | --- a/f4a
1139 | | --- a/f4a
1146 | | +++ b/f4a
1140 | | +++ b/f4a
1147 | | @@ -1,1 +1,1 @@
1141 | | @@ -1,1 +1,1 @@
1148 | | -c4a
1142 | | -c4a
1149 | | +c4d
1143 | | +c4d
1150 | |
1144 | |
1151 | o changeset: 4:c9763722f9bd
1145 | o changeset: 4:c9763722f9bd
1152 |/ parent: 0:11f7a1b56675
1146 |/ parent: 0:11f7a1b56675
1153 | user: test
1147 | user: test
1154 | date: Thu Jan 01 00:00:00 1970 +0000
1148 | date: Thu Jan 01 00:00:00 1970 +0000
1155 | files: f1a f2a f2c f5a
1149 | files: f1a f2a f2c f5a
1156 | copies: f2c (f2a)
1150 | copies: f2c (f2a)
1157 | description:
1151 | description:
1158 | C1
1152 | C1
1159 |
1153 |
1160 |
1154 |
1161 | diff --git a/f1a b/f1a
1155 | diff --git a/f1a b/f1a
1162 | --- a/f1a
1156 | --- a/f1a
1163 | +++ b/f1a
1157 | +++ b/f1a
1164 | @@ -1,1 +1,1 @@
1158 | @@ -1,1 +1,1 @@
1165 | -c1a
1159 | -c1a
1166 | +c1c
1160 | +c1c
1167 | diff --git a/f2a b/f2c
1161 | diff --git a/f2a b/f2c
1168 | rename from f2a
1162 | rename from f2a
1169 | rename to f2c
1163 | rename to f2c
1170 | diff --git a/f5a b/f5a
1164 | diff --git a/f5a b/f5a
1171 | --- a/f5a
1165 | --- a/f5a
1172 | +++ b/f5a
1166 | +++ b/f5a
1173 | @@ -1,1 +1,1 @@
1167 | @@ -1,1 +1,1 @@
1174 | -c5a
1168 | -c5a
1175 | +c5c
1169 | +c5c
1176 |
1170 |
1177 | o changeset: 3:b69f5839d2d9
1171 | o changeset: 3:b69f5839d2d9
1178 | | user: test
1172 | | user: test
1179 | | date: Thu Jan 01 00:00:00 1970 +0000
1173 | | date: Thu Jan 01 00:00:00 1970 +0000
1180 | | files: f3b f3d f4a
1174 | | files: f3b f3d f4a
1181 | | copies: f3d (f3b)
1175 | | copies: f3d (f3b)
1182 | | description:
1176 | | description:
1183 | | D0
1177 | | D0
1184 | |
1178 | |
1185 | |
1179 | |
1186 | | diff --git a/f3b b/f3d
1180 | | diff --git a/f3b b/f3d
1187 | | rename from f3b
1181 | | rename from f3b
1188 | | rename to f3d
1182 | | rename to f3d
1189 | | diff --git a/f4a b/f4a
1183 | | diff --git a/f4a b/f4a
1190 | | --- a/f4a
1184 | | --- a/f4a
1191 | | +++ b/f4a
1185 | | +++ b/f4a
1192 | | @@ -1,1 +1,1 @@
1186 | | @@ -1,1 +1,1 @@
1193 | | -c4a
1187 | | -c4a
1194 | | +c4d
1188 | | +c4d
1195 | |
1189 | |
1196 | o changeset: 2:f58c7e2b28fa
1190 | o changeset: 2:f58c7e2b28fa
1197 | | user: test
1191 | | user: test
1198 | | date: Thu Jan 01 00:00:00 1970 +0000
1192 | | date: Thu Jan 01 00:00:00 1970 +0000
1199 | | files: f1b f2a f2c f5a f5b
1193 | | files: f1b f2a f2c f5a f5b
1200 | | copies: f2c (f2a) f5a (f5b)
1194 | | copies: f2c (f2a) f5a (f5b)
1201 | | description:
1195 | | description:
1202 | | C0
1196 | | C0
1203 | |
1197 | |
1204 | |
1198 | |
1205 | | diff --git a/f1b b/f1b
1199 | | diff --git a/f1b b/f1b
1206 | | --- a/f1b
1200 | | --- a/f1b
1207 | | +++ b/f1b
1201 | | +++ b/f1b
1208 | | @@ -1,1 +1,1 @@
1202 | | @@ -1,1 +1,1 @@
1209 | | -c1a
1203 | | -c1a
1210 | | +c1c
1204 | | +c1c
1211 | | diff --git a/f2a b/f2c
1205 | | diff --git a/f2a b/f2c
1212 | | rename from f2a
1206 | | rename from f2a
1213 | | rename to f2c
1207 | | rename to f2c
1214 | | diff --git a/f5b b/f5a
1208 | | diff --git a/f5b b/f5a
1215 | | rename from f5b
1209 | | rename from f5b
1216 | | rename to f5a
1210 | | rename to f5a
1217 | | --- a/f5b
1211 | | --- a/f5b
1218 | | +++ b/f5a
1212 | | +++ b/f5a
1219 | | @@ -1,1 +1,1 @@
1213 | | @@ -1,1 +1,1 @@
1220 | | -c5a
1214 | | -c5a
1221 | | +c5c
1215 | | +c5c
1222 | |
1216 | |
1223 | o changeset: 1:3d7bba921b5d
1217 | o changeset: 1:3d7bba921b5d
1224 |/ user: test
1218 |/ user: test
1225 | date: Thu Jan 01 00:00:00 1970 +0000
1219 | date: Thu Jan 01 00:00:00 1970 +0000
1226 | files: f1a f1b f3a f3b f5a f5b
1220 | files: f1a f1b f3a f3b f5a f5b
1227 | copies: f1b (f1a) f3b (f3a) f5b (f5a)
1221 | copies: f1b (f1a) f3b (f3a) f5b (f5a)
1228 | description:
1222 | description:
1229 | B0
1223 | B0
1230 |
1224 |
1231 |
1225 |
1232 | diff --git a/f1a b/f1b
1226 | diff --git a/f1a b/f1b
1233 | rename from f1a
1227 | rename from f1a
1234 | rename to f1b
1228 | rename to f1b
1235 | diff --git a/f3a b/f3b
1229 | diff --git a/f3a b/f3b
1236 | rename from f3a
1230 | rename from f3a
1237 | rename to f3b
1231 | rename to f3b
1238 | diff --git a/f5a b/f5b
1232 | diff --git a/f5a b/f5b
1239 | rename from f5a
1233 | rename from f5a
1240 | rename to f5b
1234 | rename to f5b
1241 |
1235 |
1242 o changeset: 0:11f7a1b56675
1236 o changeset: 0:11f7a1b56675
1243 user: test
1237 user: test
1244 date: Thu Jan 01 00:00:00 1970 +0000
1238 date: Thu Jan 01 00:00:00 1970 +0000
1245 files: f1a f2a f3a f4a f5a
1239 files: f1a f2a f3a f4a f5a
1246 description:
1240 description:
1247 A0
1241 A0
1248
1242
1249
1243
1250 diff --git a/f1a b/f1a
1244 diff --git a/f1a b/f1a
1251 new file mode 100644
1245 new file mode 100644
1252 --- /dev/null
1246 --- /dev/null
1253 +++ b/f1a
1247 +++ b/f1a
1254 @@ -0,0 +1,1 @@
1248 @@ -0,0 +1,1 @@
1255 +c1a
1249 +c1a
1256 diff --git a/f2a b/f2a
1250 diff --git a/f2a b/f2a
1257 new file mode 100644
1251 new file mode 100644
1258 --- /dev/null
1252 --- /dev/null
1259 +++ b/f2a
1253 +++ b/f2a
1260 @@ -0,0 +1,1 @@
1254 @@ -0,0 +1,1 @@
1261 +c2a
1255 +c2a
1262 diff --git a/f3a b/f3a
1256 diff --git a/f3a b/f3a
1263 new file mode 100644
1257 new file mode 100644
1264 --- /dev/null
1258 --- /dev/null
1265 +++ b/f3a
1259 +++ b/f3a
1266 @@ -0,0 +1,1 @@
1260 @@ -0,0 +1,1 @@
1267 +c3a
1261 +c3a
1268 diff --git a/f4a b/f4a
1262 diff --git a/f4a b/f4a
1269 new file mode 100644
1263 new file mode 100644
1270 --- /dev/null
1264 --- /dev/null
1271 +++ b/f4a
1265 +++ b/f4a
1272 @@ -0,0 +1,1 @@
1266 @@ -0,0 +1,1 @@
1273 +c4a
1267 +c4a
1274 diff --git a/f5a b/f5a
1268 diff --git a/f5a b/f5a
1275 new file mode 100644
1269 new file mode 100644
1276 --- /dev/null
1270 --- /dev/null
1277 +++ b/f5a
1271 +++ b/f5a
1278 @@ -0,0 +1,1 @@
1272 @@ -0,0 +1,1 @@
1279 +c5a
1273 +c5a
1280
1274
1281 $ hg cat f2c
1275 $ hg cat f2c
1282 c2e
1276 c2e
1277
1278 Check superfluous filemerge of files renamed in the past but untouched by graft
1279
1280 $ echo a > a
1281 $ hg ci -qAma
1282 $ hg mv a b
1283 $ echo b > b
1284 $ hg ci -qAmb
1285 $ echo c > c
1286 $ hg ci -qAmc
1287 $ hg up -q .~2
1288 $ hg graft tip -qt:fail
@@ -1,151 +1,151 b''
1 $ hg init
1 $ hg init
2
2
3 Revision 0:
3 Revision 0:
4
4
5 $ echo "unchanged" > unchanged
5 $ echo "unchanged" > unchanged
6 $ echo "remove me" > remove
6 $ echo "remove me" > remove
7 $ echo "copy me" > copy
7 $ echo "copy me" > copy
8 $ echo "move me" > move
8 $ echo "move me" > move
9 $ for i in 1 2 3 4 5 6 7 8 9; do
9 $ for i in 1 2 3 4 5 6 7 8 9; do
10 > echo "merge ok $i" >> zzz1_merge_ok
10 > echo "merge ok $i" >> zzz1_merge_ok
11 > done
11 > done
12 $ echo "merge bad" > zzz2_merge_bad
12 $ echo "merge bad" > zzz2_merge_bad
13 $ hg ci -Am "revision 0"
13 $ hg ci -Am "revision 0"
14 adding copy
14 adding copy
15 adding move
15 adding move
16 adding remove
16 adding remove
17 adding unchanged
17 adding unchanged
18 adding zzz1_merge_ok
18 adding zzz1_merge_ok
19 adding zzz2_merge_bad
19 adding zzz2_merge_bad
20
20
21 Revision 1:
21 Revision 1:
22
22
23 $ hg rm remove
23 $ hg rm remove
24 $ hg mv move moved
24 $ hg mv move moved
25 $ hg cp copy copied
25 $ hg cp copy copied
26 $ echo "added" > added
26 $ echo "added" > added
27 $ hg add added
27 $ hg add added
28 $ echo "new first line" > zzz1_merge_ok
28 $ echo "new first line" > zzz1_merge_ok
29 $ hg cat zzz1_merge_ok >> zzz1_merge_ok
29 $ hg cat zzz1_merge_ok >> zzz1_merge_ok
30 $ echo "new last line" >> zzz2_merge_bad
30 $ echo "new last line" >> zzz2_merge_bad
31 $ hg ci -m "revision 1"
31 $ hg ci -m "revision 1"
32
32
33 Local changes to revision 0:
33 Local changes to revision 0:
34
34
35 $ hg co 0
35 $ hg co 0
36 4 files updated, 0 files merged, 3 files removed, 0 files unresolved
36 4 files updated, 0 files merged, 3 files removed, 0 files unresolved
37 $ echo "new last line" >> zzz1_merge_ok
37 $ echo "new last line" >> zzz1_merge_ok
38 $ echo "another last line" >> zzz2_merge_bad
38 $ echo "another last line" >> zzz2_merge_bad
39
39
40 $ hg diff --nodates | grep "^[+-][^<>]"
40 $ hg diff --nodates | grep "^[+-][^<>]"
41 --- a/zzz1_merge_ok
41 --- a/zzz1_merge_ok
42 +++ b/zzz1_merge_ok
42 +++ b/zzz1_merge_ok
43 +new last line
43 +new last line
44 --- a/zzz2_merge_bad
44 --- a/zzz2_merge_bad
45 +++ b/zzz2_merge_bad
45 +++ b/zzz2_merge_bad
46 +another last line
46 +another last line
47
47
48 $ hg st
48 $ hg st
49 M zzz1_merge_ok
49 M zzz1_merge_ok
50 M zzz2_merge_bad
50 M zzz2_merge_bad
51
51
52 Local merge with bad merge tool:
52 Local merge with bad merge tool:
53
53
54 $ HGMERGE=false hg co
54 $ HGMERGE=false hg co
55 merging zzz1_merge_ok
55 merging zzz1_merge_ok
56 merging zzz2_merge_bad
56 merging zzz2_merge_bad
57 merging zzz2_merge_bad failed!
57 merging zzz2_merge_bad failed!
58 3 files updated, 1 files merged, 2 files removed, 1 files unresolved
58 3 files updated, 1 files merged, 2 files removed, 1 files unresolved
59 use 'hg resolve' to retry unresolved file merges
59 use 'hg resolve' to retry unresolved file merges
60 [1]
60 [1]
61
61
62 $ hg resolve -m
62 $ hg resolve -m
63 (no more unresolved files)
63 (no more unresolved files)
64
64
65 $ hg co 0
65 $ hg co 0
66 merging zzz1_merge_ok
66 merging zzz1_merge_ok
67 merging zzz2_merge_bad
67 merging zzz2_merge_bad
68 warning: conflicts while merging zzz2_merge_bad! (edit, then use 'hg resolve --mark')
68 warning: conflicts while merging zzz2_merge_bad! (edit, then use 'hg resolve --mark')
69 2 files updated, 1 files merged, 2 files removed, 1 files unresolved
69 2 files updated, 1 files merged, 3 files removed, 1 files unresolved
70 use 'hg resolve' to retry unresolved file merges
70 use 'hg resolve' to retry unresolved file merges
71 [1]
71 [1]
72
72
73 $ hg diff --nodates | grep "^[+-][^<>]"
73 $ hg diff --nodates | grep "^[+-][^<>]"
74 --- a/zzz1_merge_ok
74 --- a/zzz1_merge_ok
75 +++ b/zzz1_merge_ok
75 +++ b/zzz1_merge_ok
76 +new last line
76 +new last line
77 --- a/zzz2_merge_bad
77 --- a/zzz2_merge_bad
78 +++ b/zzz2_merge_bad
78 +++ b/zzz2_merge_bad
79 +another last line
79 +another last line
80 +=======
80 +=======
81
81
82 $ hg st
82 $ hg st
83 M zzz1_merge_ok
83 M zzz1_merge_ok
84 M zzz2_merge_bad
84 M zzz2_merge_bad
85 ? zzz2_merge_bad.orig
85 ? zzz2_merge_bad.orig
86
86
87 Local merge with conflicts:
87 Local merge with conflicts:
88
88
89 $ hg resolve -m
89 $ hg resolve -m
90 (no more unresolved files)
90 (no more unresolved files)
91
91
92 $ hg co
92 $ hg co
93 merging zzz1_merge_ok
93 merging zzz1_merge_ok
94 merging zzz2_merge_bad
94 merging zzz2_merge_bad
95 warning: conflicts while merging zzz2_merge_bad! (edit, then use 'hg resolve --mark')
95 warning: conflicts while merging zzz2_merge_bad! (edit, then use 'hg resolve --mark')
96 3 files updated, 1 files merged, 2 files removed, 1 files unresolved
96 3 files updated, 1 files merged, 2 files removed, 1 files unresolved
97 use 'hg resolve' to retry unresolved file merges
97 use 'hg resolve' to retry unresolved file merges
98 [1]
98 [1]
99
99
100 $ hg resolve -m
100 $ hg resolve -m
101 (no more unresolved files)
101 (no more unresolved files)
102
102
103 $ hg co 0 --config 'ui.origbackuppath=.hg/origbackups'
103 $ hg co 0 --config 'ui.origbackuppath=.hg/origbackups'
104 merging zzz1_merge_ok
104 merging zzz1_merge_ok
105 merging zzz2_merge_bad
105 merging zzz2_merge_bad
106 warning: conflicts while merging zzz2_merge_bad! (edit, then use 'hg resolve --mark')
106 warning: conflicts while merging zzz2_merge_bad! (edit, then use 'hg resolve --mark')
107 2 files updated, 1 files merged, 2 files removed, 1 files unresolved
107 2 files updated, 1 files merged, 3 files removed, 1 files unresolved
108 use 'hg resolve' to retry unresolved file merges
108 use 'hg resolve' to retry unresolved file merges
109 [1]
109 [1]
110
110
111 Are orig files from the last commit where we want them?
111 Are orig files from the last commit where we want them?
112 $ ls .hg/origbackups
112 $ ls .hg/origbackups
113 zzz2_merge_bad.orig
113 zzz2_merge_bad.orig
114
114
115 $ hg diff --nodates | grep "^[+-][^<>]"
115 $ hg diff --nodates | grep "^[+-][^<>]"
116 --- a/zzz1_merge_ok
116 --- a/zzz1_merge_ok
117 +++ b/zzz1_merge_ok
117 +++ b/zzz1_merge_ok
118 +new last line
118 +new last line
119 --- a/zzz2_merge_bad
119 --- a/zzz2_merge_bad
120 +++ b/zzz2_merge_bad
120 +++ b/zzz2_merge_bad
121 +another last line
121 +another last line
122 +=======
122 +=======
123 +=======
123 +=======
124 +new last line
124 +new last line
125 +=======
125 +=======
126
126
127 $ hg st
127 $ hg st
128 M zzz1_merge_ok
128 M zzz1_merge_ok
129 M zzz2_merge_bad
129 M zzz2_merge_bad
130 ? zzz2_merge_bad.orig
130 ? zzz2_merge_bad.orig
131
131
132 Local merge without conflicts:
132 Local merge without conflicts:
133
133
134 $ hg revert zzz2_merge_bad
134 $ hg revert zzz2_merge_bad
135
135
136 $ hg resolve -m
136 $ hg resolve -m
137 (no more unresolved files)
137 (no more unresolved files)
138
138
139 $ hg co
139 $ hg co
140 merging zzz1_merge_ok
140 merging zzz1_merge_ok
141 4 files updated, 1 files merged, 2 files removed, 0 files unresolved
141 4 files updated, 1 files merged, 2 files removed, 0 files unresolved
142
142
143 $ hg diff --nodates | grep "^[+-][^<>]"
143 $ hg diff --nodates | grep "^[+-][^<>]"
144 --- a/zzz1_merge_ok
144 --- a/zzz1_merge_ok
145 +++ b/zzz1_merge_ok
145 +++ b/zzz1_merge_ok
146 +new last line
146 +new last line
147
147
148 $ hg st
148 $ hg st
149 M zzz1_merge_ok
149 M zzz1_merge_ok
150 ? zzz2_merge_bad.orig
150 ? zzz2_merge_bad.orig
151
151
@@ -1,245 +1,252 b''
1 $ HGMERGE=true; export HGMERGE
1 $ HGMERGE=true; export HGMERGE
2
2
3 $ hg init r1
3 $ hg init r1
4 $ cd r1
4 $ cd r1
5 $ echo a > a
5 $ echo a > a
6 $ hg addremove
6 $ hg addremove
7 adding a
7 adding a
8 $ hg commit -m "1"
8 $ hg commit -m "1"
9
9
10 $ hg clone . ../r2
10 $ hg clone . ../r2
11 updating to branch default
11 updating to branch default
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 $ cd ../r2
13 $ cd ../r2
14 $ hg up
14 $ hg up
15 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 $ echo abc > a
16 $ echo abc > a
17 $ hg diff --nodates
17 $ hg diff --nodates
18 diff -r c19d34741b0a a
18 diff -r c19d34741b0a a
19 --- a/a
19 --- a/a
20 +++ b/a
20 +++ b/a
21 @@ -1,1 +1,1 @@
21 @@ -1,1 +1,1 @@
22 -a
22 -a
23 +abc
23 +abc
24
24
25 $ cd ../r1
25 $ cd ../r1
26 $ echo b > b
26 $ echo b > b
27 $ echo a2 > a
27 $ echo a2 > a
28 $ hg addremove
28 $ hg addremove
29 adding b
29 adding b
30 $ hg commit -m "2"
30 $ hg commit -m "2"
31
31
32 $ cd ../r2
32 $ cd ../r2
33 $ hg -q pull ../r1
33 $ hg -q pull ../r1
34 $ hg status
34 $ hg status
35 M a
35 M a
36 $ hg parents
36 $ hg parents
37 changeset: 0:c19d34741b0a
37 changeset: 0:c19d34741b0a
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:00 1970 +0000
39 date: Thu Jan 01 00:00:00 1970 +0000
40 summary: 1
40 summary: 1
41
41
42 $ hg --debug up
42 $ hg --debug up
43 searching for copies back to rev 1
43 searching for copies back to rev 1
44 unmatched files in other:
44 unmatched files in other:
45 b
45 b
46 resolving manifests
46 resolving manifests
47 branchmerge: False, force: False, partial: False
47 branchmerge: False, force: False, partial: False
48 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
48 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
49 preserving a for resolve of a
49 preserving a for resolve of a
50 b: remote created -> g
50 b: remote created -> g
51 getting b
51 getting b
52 a: versions differ -> m (premerge)
52 a: versions differ -> m (premerge)
53 picked tool 'true' for a (binary False symlink False changedelete False)
53 picked tool 'true' for a (binary False symlink False changedelete False)
54 merging a
54 merging a
55 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
55 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
56 a: versions differ -> m (merge)
56 a: versions differ -> m (merge)
57 picked tool 'true' for a (binary False symlink False changedelete False)
57 picked tool 'true' for a (binary False symlink False changedelete False)
58 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
58 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
59 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
59 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
60 merge tool returned: 0
60 merge tool returned: 0
61 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
61 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
62 $ hg parents
62 $ hg parents
63 changeset: 1:1e71731e6fbb
63 changeset: 1:1e71731e6fbb
64 tag: tip
64 tag: tip
65 user: test
65 user: test
66 date: Thu Jan 01 00:00:00 1970 +0000
66 date: Thu Jan 01 00:00:00 1970 +0000
67 summary: 2
67 summary: 2
68
68
69 $ hg --debug up 0
69 $ hg --debug up 0
70 starting 4 threads for background file closing (?)
70 starting 4 threads for background file closing (?)
71 searching for copies back to rev 0
71 searching for copies back to rev 0
72 unmatched files in local (from topological common ancestor):
72 unmatched files in local (from topological common ancestor):
73 b
73 b
74 resolving manifests
74 resolving manifests
75 branchmerge: False, force: False, partial: False
75 branchmerge: False, force: False, partial: False
76 ancestor: 1e71731e6fbb, local: 1e71731e6fbb+, remote: c19d34741b0a
76 ancestor: 1e71731e6fbb, local: 1e71731e6fbb+, remote: c19d34741b0a
77 preserving a for resolve of a
77 preserving a for resolve of a
78 b: other deleted -> r
78 b: other deleted -> r
79 removing b
79 removing b
80 starting 4 threads for background file closing (?)
80 starting 4 threads for background file closing (?)
81 a: versions differ -> m (premerge)
81 a: versions differ -> m (premerge)
82 picked tool 'true' for a (binary False symlink False changedelete False)
82 picked tool 'true' for a (binary False symlink False changedelete False)
83 merging a
83 merging a
84 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
84 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
85 a: versions differ -> m (merge)
85 a: versions differ -> m (merge)
86 picked tool 'true' for a (binary False symlink False changedelete False)
86 picked tool 'true' for a (binary False symlink False changedelete False)
87 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
87 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
88 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
88 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
89 merge tool returned: 0
89 merge tool returned: 0
90 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
90 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
91 $ hg parents
91 $ hg parents
92 changeset: 0:c19d34741b0a
92 changeset: 0:c19d34741b0a
93 user: test
93 user: test
94 date: Thu Jan 01 00:00:00 1970 +0000
94 date: Thu Jan 01 00:00:00 1970 +0000
95 summary: 1
95 summary: 1
96
96
97 $ hg --debug up
97 $ hg --debug up
98 searching for copies back to rev 1
98 searching for copies back to rev 1
99 unmatched files in other:
99 unmatched files in other:
100 b
100 b
101 resolving manifests
101 resolving manifests
102 branchmerge: False, force: False, partial: False
102 branchmerge: False, force: False, partial: False
103 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
103 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
104 preserving a for resolve of a
104 preserving a for resolve of a
105 b: remote created -> g
105 b: remote created -> g
106 getting b
106 getting b
107 a: versions differ -> m (premerge)
107 a: versions differ -> m (premerge)
108 picked tool 'true' for a (binary False symlink False changedelete False)
108 picked tool 'true' for a (binary False symlink False changedelete False)
109 merging a
109 merging a
110 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
110 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
111 a: versions differ -> m (merge)
111 a: versions differ -> m (merge)
112 picked tool 'true' for a (binary False symlink False changedelete False)
112 picked tool 'true' for a (binary False symlink False changedelete False)
113 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
113 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
114 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
114 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
115 merge tool returned: 0
115 merge tool returned: 0
116 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
116 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
117 $ hg parents
117 $ hg parents
118 changeset: 1:1e71731e6fbb
118 changeset: 1:1e71731e6fbb
119 tag: tip
119 tag: tip
120 user: test
120 user: test
121 date: Thu Jan 01 00:00:00 1970 +0000
121 date: Thu Jan 01 00:00:00 1970 +0000
122 summary: 2
122 summary: 2
123
123
124 $ hg -v history
124 $ hg -v history
125 changeset: 1:1e71731e6fbb
125 changeset: 1:1e71731e6fbb
126 tag: tip
126 tag: tip
127 user: test
127 user: test
128 date: Thu Jan 01 00:00:00 1970 +0000
128 date: Thu Jan 01 00:00:00 1970 +0000
129 files: a b
129 files: a b
130 description:
130 description:
131 2
131 2
132
132
133
133
134 changeset: 0:c19d34741b0a
134 changeset: 0:c19d34741b0a
135 user: test
135 user: test
136 date: Thu Jan 01 00:00:00 1970 +0000
136 date: Thu Jan 01 00:00:00 1970 +0000
137 files: a
137 files: a
138 description:
138 description:
139 1
139 1
140
140
141
141
142 $ hg diff --nodates
142 $ hg diff --nodates
143 diff -r 1e71731e6fbb a
143 diff -r 1e71731e6fbb a
144 --- a/a
144 --- a/a
145 +++ b/a
145 +++ b/a
146 @@ -1,1 +1,1 @@
146 @@ -1,1 +1,1 @@
147 -a2
147 -a2
148 +abc
148 +abc
149
149
150
150
151 create a second head
151 create a second head
152
152
153 $ cd ../r1
153 $ cd ../r1
154 $ hg up 0
154 $ hg up 0
155 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
155 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
156 $ echo b2 > b
156 $ echo b2 > b
157 $ echo a3 > a
157 $ echo a3 > a
158 $ hg addremove
158 $ hg addremove
159 adding b
159 adding b
160 $ hg commit -m "3"
160 $ hg commit -m "3"
161 created new head
161 created new head
162
162
163 $ cd ../r2
163 $ cd ../r2
164 $ hg -q pull ../r1
164 $ hg -q pull ../r1
165 $ hg status
165 $ hg status
166 M a
166 M a
167 $ hg parents
167 $ hg parents
168 changeset: 1:1e71731e6fbb
168 changeset: 1:1e71731e6fbb
169 user: test
169 user: test
170 date: Thu Jan 01 00:00:00 1970 +0000
170 date: Thu Jan 01 00:00:00 1970 +0000
171 summary: 2
171 summary: 2
172
172
173 $ hg --debug up
173 $ hg --debug up
174 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 1 other heads for branch "default"
175 1 other heads for branch "default"
176
176
177 test conflicting untracked files
177 test conflicting untracked files
178
178
179 $ hg up -qC 0
179 $ hg up -qC 0
180 $ echo untracked > b
180 $ echo untracked > b
181 $ hg st
181 $ hg st
182 ? b
182 ? b
183 $ hg up 1
183 $ hg up 1
184 b: untracked file differs
184 b: untracked file differs
185 abort: untracked files in working directory differ from files in requested revision
185 abort: untracked files in working directory differ from files in requested revision
186 [255]
186 [255]
187 $ rm b
187 $ rm b
188
188
189 test conflicting untracked ignored file
189 test conflicting untracked ignored file
190
190
191 $ hg up -qC 0
191 $ hg up -qC 0
192 $ echo ignored > .hgignore
192 $ echo ignored > .hgignore
193 $ hg add .hgignore
193 $ hg add .hgignore
194 $ hg ci -m 'add .hgignore'
194 $ hg ci -m 'add .hgignore'
195 created new head
195 created new head
196 $ echo ignored > ignored
196 $ echo ignored > ignored
197 $ hg add ignored
197 $ hg add ignored
198 $ hg ci -m 'add ignored file'
198 $ hg ci -m 'add ignored file'
199
199
200 $ hg up -q 'desc("add .hgignore")'
200 $ hg up -q 'desc("add .hgignore")'
201 $ echo untracked > ignored
201 $ echo untracked > ignored
202 $ hg st
202 $ hg st
203 $ hg up 'desc("add ignored file")'
203 $ hg up 'desc("add ignored file")'
204 ignored: untracked file differs
204 ignored: untracked file differs
205 abort: untracked files in working directory differ from files in requested revision
205 abort: untracked files in working directory differ from files in requested revision
206 [255]
206 [255]
207
207
208 test a local add
208 test a local add
209
209
210 $ cd ..
210 $ cd ..
211 $ hg init a
211 $ hg init a
212 $ hg init b
212 $ hg init b
213 $ echo a > a/a
213 $ echo a > a/a
214 $ echo a > b/a
214 $ echo a > b/a
215 $ hg --cwd a commit -A -m a
215 $ hg --cwd a commit -A -m a
216 adding a
216 adding a
217 $ cd b
217 $ cd b
218 $ hg add a
218 $ hg add a
219 $ hg pull -u ../a
219 $ hg pull -u ../a
220 pulling from ../a
220 pulling from ../a
221 requesting all changes
221 requesting all changes
222 adding changesets
222 adding changesets
223 adding manifests
223 adding manifests
224 adding file changes
224 adding file changes
225 added 1 changesets with 1 changes to 1 files
225 added 1 changesets with 1 changes to 1 files
226 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 $ hg st
227 $ hg st
228
228
229 test updating backwards through a rename
229 test updating backwards through a rename
230
230
231 $ hg mv a b
231 $ hg mv a b
232 $ hg ci -m b
232 $ hg ci -m b
233 $ echo b > b
233 $ echo b > b
234 $ hg up -q 0
234 $ hg up -q 0
235 $ hg st
235 $ hg st
236 M a
236 M a
237 $ hg diff --nodates
237 $ hg diff --nodates
238 diff -r cb9a9f314b8b a
238 diff -r cb9a9f314b8b a
239 --- a/a
239 --- a/a
240 +++ b/a
240 +++ b/a
241 @@ -1,1 +1,1 @@
241 @@ -1,1 +1,1 @@
242 -a
242 -a
243 +b
243 +b
244
244
245 test for superfluous filemerge of clean files renamed in the past
246
247 $ hg up -qC tip
248 $ echo c > c
249 $ hg add c
250 $ hg up -qt:fail 0
251
245 $ cd ..
252 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now