##// END OF EJS Templates
transplant: use check_incompatible_arguments()...
Martin von Zweigbergk -
r44355:d50b4ad1 default
parent child Browse files
Show More
@@ -1,937 +1,929 b''
1 # Patch transplanting extension for Mercurial
1 # Patch transplanting extension for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Brendan Cully <brendan@kublai.com>
3 # Copyright 2006, 2007 Brendan Cully <brendan@kublai.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 '''command to transplant changesets from another branch
8 '''command to transplant changesets from another branch
9
9
10 This extension allows you to transplant changes to another parent revision,
10 This extension allows you to transplant changes to another parent revision,
11 possibly in another repository. The transplant is done using 'diff' patches.
11 possibly in another repository. The transplant is done using 'diff' patches.
12
12
13 Transplanted patches are recorded in .hg/transplant/transplants, as a
13 Transplanted patches are recorded in .hg/transplant/transplants, as a
14 map from a changeset hash to its hash in the source repository.
14 map from a changeset hash to its hash in the source repository.
15 '''
15 '''
16 from __future__ import absolute_import
16 from __future__ import absolute_import
17
17
18 import os
18 import os
19
19
20 from mercurial.i18n import _
20 from mercurial.i18n import _
21 from mercurial.pycompat import open
21 from mercurial.pycompat import open
22 from mercurial import (
22 from mercurial import (
23 bundlerepo,
23 bundlerepo,
24 cmdutil,
24 cmdutil,
25 error,
25 error,
26 exchange,
26 exchange,
27 hg,
27 hg,
28 logcmdutil,
28 logcmdutil,
29 match,
29 match,
30 merge,
30 merge,
31 node as nodemod,
31 node as nodemod,
32 patch,
32 patch,
33 pycompat,
33 pycompat,
34 registrar,
34 registrar,
35 revlog,
35 revlog,
36 revset,
36 revset,
37 scmutil,
37 scmutil,
38 smartset,
38 smartset,
39 state as statemod,
39 state as statemod,
40 util,
40 util,
41 vfs as vfsmod,
41 vfs as vfsmod,
42 )
42 )
43 from mercurial.utils import (
43 from mercurial.utils import (
44 procutil,
44 procutil,
45 stringutil,
45 stringutil,
46 )
46 )
47
47
48
48
49 class TransplantError(error.Abort):
49 class TransplantError(error.Abort):
50 pass
50 pass
51
51
52
52
53 cmdtable = {}
53 cmdtable = {}
54 command = registrar.command(cmdtable)
54 command = registrar.command(cmdtable)
55 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
55 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
56 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
56 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
57 # be specifying the version(s) of Mercurial they are tested with, or
57 # be specifying the version(s) of Mercurial they are tested with, or
58 # leave the attribute unspecified.
58 # leave the attribute unspecified.
59 testedwith = b'ships-with-hg-core'
59 testedwith = b'ships-with-hg-core'
60
60
61 configtable = {}
61 configtable = {}
62 configitem = registrar.configitem(configtable)
62 configitem = registrar.configitem(configtable)
63
63
64 configitem(
64 configitem(
65 b'transplant', b'filter', default=None,
65 b'transplant', b'filter', default=None,
66 )
66 )
67 configitem(
67 configitem(
68 b'transplant', b'log', default=None,
68 b'transplant', b'log', default=None,
69 )
69 )
70
70
71
71
72 class transplantentry(object):
72 class transplantentry(object):
73 def __init__(self, lnode, rnode):
73 def __init__(self, lnode, rnode):
74 self.lnode = lnode
74 self.lnode = lnode
75 self.rnode = rnode
75 self.rnode = rnode
76
76
77
77
78 class transplants(object):
78 class transplants(object):
79 def __init__(self, path=None, transplantfile=None, opener=None):
79 def __init__(self, path=None, transplantfile=None, opener=None):
80 self.path = path
80 self.path = path
81 self.transplantfile = transplantfile
81 self.transplantfile = transplantfile
82 self.opener = opener
82 self.opener = opener
83
83
84 if not opener:
84 if not opener:
85 self.opener = vfsmod.vfs(self.path)
85 self.opener = vfsmod.vfs(self.path)
86 self.transplants = {}
86 self.transplants = {}
87 self.dirty = False
87 self.dirty = False
88 self.read()
88 self.read()
89
89
90 def read(self):
90 def read(self):
91 abspath = os.path.join(self.path, self.transplantfile)
91 abspath = os.path.join(self.path, self.transplantfile)
92 if self.transplantfile and os.path.exists(abspath):
92 if self.transplantfile and os.path.exists(abspath):
93 for line in self.opener.read(self.transplantfile).splitlines():
93 for line in self.opener.read(self.transplantfile).splitlines():
94 lnode, rnode = map(revlog.bin, line.split(b':'))
94 lnode, rnode = map(revlog.bin, line.split(b':'))
95 list = self.transplants.setdefault(rnode, [])
95 list = self.transplants.setdefault(rnode, [])
96 list.append(transplantentry(lnode, rnode))
96 list.append(transplantentry(lnode, rnode))
97
97
98 def write(self):
98 def write(self):
99 if self.dirty and self.transplantfile:
99 if self.dirty and self.transplantfile:
100 if not os.path.isdir(self.path):
100 if not os.path.isdir(self.path):
101 os.mkdir(self.path)
101 os.mkdir(self.path)
102 fp = self.opener(self.transplantfile, b'w')
102 fp = self.opener(self.transplantfile, b'w')
103 for list in pycompat.itervalues(self.transplants):
103 for list in pycompat.itervalues(self.transplants):
104 for t in list:
104 for t in list:
105 l, r = map(nodemod.hex, (t.lnode, t.rnode))
105 l, r = map(nodemod.hex, (t.lnode, t.rnode))
106 fp.write(l + b':' + r + b'\n')
106 fp.write(l + b':' + r + b'\n')
107 fp.close()
107 fp.close()
108 self.dirty = False
108 self.dirty = False
109
109
110 def get(self, rnode):
110 def get(self, rnode):
111 return self.transplants.get(rnode) or []
111 return self.transplants.get(rnode) or []
112
112
113 def set(self, lnode, rnode):
113 def set(self, lnode, rnode):
114 list = self.transplants.setdefault(rnode, [])
114 list = self.transplants.setdefault(rnode, [])
115 list.append(transplantentry(lnode, rnode))
115 list.append(transplantentry(lnode, rnode))
116 self.dirty = True
116 self.dirty = True
117
117
118 def remove(self, transplant):
118 def remove(self, transplant):
119 list = self.transplants.get(transplant.rnode)
119 list = self.transplants.get(transplant.rnode)
120 if list:
120 if list:
121 del list[list.index(transplant)]
121 del list[list.index(transplant)]
122 self.dirty = True
122 self.dirty = True
123
123
124
124
125 class transplanter(object):
125 class transplanter(object):
126 def __init__(self, ui, repo, opts):
126 def __init__(self, ui, repo, opts):
127 self.ui = ui
127 self.ui = ui
128 self.path = repo.vfs.join(b'transplant')
128 self.path = repo.vfs.join(b'transplant')
129 self.opener = vfsmod.vfs(self.path)
129 self.opener = vfsmod.vfs(self.path)
130 self.transplants = transplants(
130 self.transplants = transplants(
131 self.path, b'transplants', opener=self.opener
131 self.path, b'transplants', opener=self.opener
132 )
132 )
133
133
134 def getcommiteditor():
134 def getcommiteditor():
135 editform = cmdutil.mergeeditform(repo[None], b'transplant')
135 editform = cmdutil.mergeeditform(repo[None], b'transplant')
136 return cmdutil.getcommiteditor(
136 return cmdutil.getcommiteditor(
137 editform=editform, **pycompat.strkwargs(opts)
137 editform=editform, **pycompat.strkwargs(opts)
138 )
138 )
139
139
140 self.getcommiteditor = getcommiteditor
140 self.getcommiteditor = getcommiteditor
141
141
142 def applied(self, repo, node, parent):
142 def applied(self, repo, node, parent):
143 '''returns True if a node is already an ancestor of parent
143 '''returns True if a node is already an ancestor of parent
144 or is parent or has already been transplanted'''
144 or is parent or has already been transplanted'''
145 if hasnode(repo, parent):
145 if hasnode(repo, parent):
146 parentrev = repo.changelog.rev(parent)
146 parentrev = repo.changelog.rev(parent)
147 if hasnode(repo, node):
147 if hasnode(repo, node):
148 rev = repo.changelog.rev(node)
148 rev = repo.changelog.rev(node)
149 reachable = repo.changelog.ancestors(
149 reachable = repo.changelog.ancestors(
150 [parentrev], rev, inclusive=True
150 [parentrev], rev, inclusive=True
151 )
151 )
152 if rev in reachable:
152 if rev in reachable:
153 return True
153 return True
154 for t in self.transplants.get(node):
154 for t in self.transplants.get(node):
155 # it might have been stripped
155 # it might have been stripped
156 if not hasnode(repo, t.lnode):
156 if not hasnode(repo, t.lnode):
157 self.transplants.remove(t)
157 self.transplants.remove(t)
158 return False
158 return False
159 lnoderev = repo.changelog.rev(t.lnode)
159 lnoderev = repo.changelog.rev(t.lnode)
160 if lnoderev in repo.changelog.ancestors(
160 if lnoderev in repo.changelog.ancestors(
161 [parentrev], lnoderev, inclusive=True
161 [parentrev], lnoderev, inclusive=True
162 ):
162 ):
163 return True
163 return True
164 return False
164 return False
165
165
166 def apply(self, repo, source, revmap, merges, opts=None):
166 def apply(self, repo, source, revmap, merges, opts=None):
167 '''apply the revisions in revmap one by one in revision order'''
167 '''apply the revisions in revmap one by one in revision order'''
168 if opts is None:
168 if opts is None:
169 opts = {}
169 opts = {}
170 revs = sorted(revmap)
170 revs = sorted(revmap)
171 p1 = repo.dirstate.p1()
171 p1 = repo.dirstate.p1()
172 pulls = []
172 pulls = []
173 diffopts = patch.difffeatureopts(self.ui, opts)
173 diffopts = patch.difffeatureopts(self.ui, opts)
174 diffopts.git = True
174 diffopts.git = True
175
175
176 lock = tr = None
176 lock = tr = None
177 try:
177 try:
178 lock = repo.lock()
178 lock = repo.lock()
179 tr = repo.transaction(b'transplant')
179 tr = repo.transaction(b'transplant')
180 for rev in revs:
180 for rev in revs:
181 node = revmap[rev]
181 node = revmap[rev]
182 revstr = b'%d:%s' % (rev, nodemod.short(node))
182 revstr = b'%d:%s' % (rev, nodemod.short(node))
183
183
184 if self.applied(repo, node, p1):
184 if self.applied(repo, node, p1):
185 self.ui.warn(
185 self.ui.warn(
186 _(b'skipping already applied revision %s\n') % revstr
186 _(b'skipping already applied revision %s\n') % revstr
187 )
187 )
188 continue
188 continue
189
189
190 parents = source.changelog.parents(node)
190 parents = source.changelog.parents(node)
191 if not (opts.get(b'filter') or opts.get(b'log')):
191 if not (opts.get(b'filter') or opts.get(b'log')):
192 # If the changeset parent is the same as the
192 # If the changeset parent is the same as the
193 # wdir's parent, just pull it.
193 # wdir's parent, just pull it.
194 if parents[0] == p1:
194 if parents[0] == p1:
195 pulls.append(node)
195 pulls.append(node)
196 p1 = node
196 p1 = node
197 continue
197 continue
198 if pulls:
198 if pulls:
199 if source != repo:
199 if source != repo:
200 exchange.pull(repo, source.peer(), heads=pulls)
200 exchange.pull(repo, source.peer(), heads=pulls)
201 merge.update(
201 merge.update(
202 repo, pulls[-1], branchmerge=False, force=False
202 repo, pulls[-1], branchmerge=False, force=False
203 )
203 )
204 p1 = repo.dirstate.p1()
204 p1 = repo.dirstate.p1()
205 pulls = []
205 pulls = []
206
206
207 domerge = False
207 domerge = False
208 if node in merges:
208 if node in merges:
209 # pulling all the merge revs at once would mean we
209 # pulling all the merge revs at once would mean we
210 # couldn't transplant after the latest even if
210 # couldn't transplant after the latest even if
211 # transplants before them fail.
211 # transplants before them fail.
212 domerge = True
212 domerge = True
213 if not hasnode(repo, node):
213 if not hasnode(repo, node):
214 exchange.pull(repo, source.peer(), heads=[node])
214 exchange.pull(repo, source.peer(), heads=[node])
215
215
216 skipmerge = False
216 skipmerge = False
217 if parents[1] != revlog.nullid:
217 if parents[1] != revlog.nullid:
218 if not opts.get(b'parent'):
218 if not opts.get(b'parent'):
219 self.ui.note(
219 self.ui.note(
220 _(b'skipping merge changeset %d:%s\n')
220 _(b'skipping merge changeset %d:%s\n')
221 % (rev, nodemod.short(node))
221 % (rev, nodemod.short(node))
222 )
222 )
223 skipmerge = True
223 skipmerge = True
224 else:
224 else:
225 parent = source.lookup(opts[b'parent'])
225 parent = source.lookup(opts[b'parent'])
226 if parent not in parents:
226 if parent not in parents:
227 raise error.Abort(
227 raise error.Abort(
228 _(b'%s is not a parent of %s')
228 _(b'%s is not a parent of %s')
229 % (nodemod.short(parent), nodemod.short(node))
229 % (nodemod.short(parent), nodemod.short(node))
230 )
230 )
231 else:
231 else:
232 parent = parents[0]
232 parent = parents[0]
233
233
234 if skipmerge:
234 if skipmerge:
235 patchfile = None
235 patchfile = None
236 else:
236 else:
237 fd, patchfile = pycompat.mkstemp(prefix=b'hg-transplant-')
237 fd, patchfile = pycompat.mkstemp(prefix=b'hg-transplant-')
238 fp = os.fdopen(fd, 'wb')
238 fp = os.fdopen(fd, 'wb')
239 gen = patch.diff(source, parent, node, opts=diffopts)
239 gen = patch.diff(source, parent, node, opts=diffopts)
240 for chunk in gen:
240 for chunk in gen:
241 fp.write(chunk)
241 fp.write(chunk)
242 fp.close()
242 fp.close()
243
243
244 del revmap[rev]
244 del revmap[rev]
245 if patchfile or domerge:
245 if patchfile or domerge:
246 try:
246 try:
247 try:
247 try:
248 n = self.applyone(
248 n = self.applyone(
249 repo,
249 repo,
250 node,
250 node,
251 source.changelog.read(node),
251 source.changelog.read(node),
252 patchfile,
252 patchfile,
253 merge=domerge,
253 merge=domerge,
254 log=opts.get(b'log'),
254 log=opts.get(b'log'),
255 filter=opts.get(b'filter'),
255 filter=opts.get(b'filter'),
256 )
256 )
257 except TransplantError:
257 except TransplantError:
258 # Do not rollback, it is up to the user to
258 # Do not rollback, it is up to the user to
259 # fix the merge or cancel everything
259 # fix the merge or cancel everything
260 tr.close()
260 tr.close()
261 raise
261 raise
262 if n and domerge:
262 if n and domerge:
263 self.ui.status(
263 self.ui.status(
264 _(b'%s merged at %s\n')
264 _(b'%s merged at %s\n')
265 % (revstr, nodemod.short(n))
265 % (revstr, nodemod.short(n))
266 )
266 )
267 elif n:
267 elif n:
268 self.ui.status(
268 self.ui.status(
269 _(b'%s transplanted to %s\n')
269 _(b'%s transplanted to %s\n')
270 % (nodemod.short(node), nodemod.short(n))
270 % (nodemod.short(node), nodemod.short(n))
271 )
271 )
272 finally:
272 finally:
273 if patchfile:
273 if patchfile:
274 os.unlink(patchfile)
274 os.unlink(patchfile)
275 tr.close()
275 tr.close()
276 if pulls:
276 if pulls:
277 exchange.pull(repo, source.peer(), heads=pulls)
277 exchange.pull(repo, source.peer(), heads=pulls)
278 merge.update(repo, pulls[-1], branchmerge=False, force=False)
278 merge.update(repo, pulls[-1], branchmerge=False, force=False)
279 finally:
279 finally:
280 self.saveseries(revmap, merges)
280 self.saveseries(revmap, merges)
281 self.transplants.write()
281 self.transplants.write()
282 if tr:
282 if tr:
283 tr.release()
283 tr.release()
284 if lock:
284 if lock:
285 lock.release()
285 lock.release()
286
286
287 def filter(self, filter, node, changelog, patchfile):
287 def filter(self, filter, node, changelog, patchfile):
288 '''arbitrarily rewrite changeset before applying it'''
288 '''arbitrarily rewrite changeset before applying it'''
289
289
290 self.ui.status(_(b'filtering %s\n') % patchfile)
290 self.ui.status(_(b'filtering %s\n') % patchfile)
291 user, date, msg = (changelog[1], changelog[2], changelog[4])
291 user, date, msg = (changelog[1], changelog[2], changelog[4])
292 fd, headerfile = pycompat.mkstemp(prefix=b'hg-transplant-')
292 fd, headerfile = pycompat.mkstemp(prefix=b'hg-transplant-')
293 fp = os.fdopen(fd, 'wb')
293 fp = os.fdopen(fd, 'wb')
294 fp.write(b"# HG changeset patch\n")
294 fp.write(b"# HG changeset patch\n")
295 fp.write(b"# User %s\n" % user)
295 fp.write(b"# User %s\n" % user)
296 fp.write(b"# Date %d %d\n" % date)
296 fp.write(b"# Date %d %d\n" % date)
297 fp.write(msg + b'\n')
297 fp.write(msg + b'\n')
298 fp.close()
298 fp.close()
299
299
300 try:
300 try:
301 self.ui.system(
301 self.ui.system(
302 b'%s %s %s'
302 b'%s %s %s'
303 % (
303 % (
304 filter,
304 filter,
305 procutil.shellquote(headerfile),
305 procutil.shellquote(headerfile),
306 procutil.shellquote(patchfile),
306 procutil.shellquote(patchfile),
307 ),
307 ),
308 environ={
308 environ={
309 b'HGUSER': changelog[1],
309 b'HGUSER': changelog[1],
310 b'HGREVISION': nodemod.hex(node),
310 b'HGREVISION': nodemod.hex(node),
311 },
311 },
312 onerr=error.Abort,
312 onerr=error.Abort,
313 errprefix=_(b'filter failed'),
313 errprefix=_(b'filter failed'),
314 blockedtag=b'transplant_filter',
314 blockedtag=b'transplant_filter',
315 )
315 )
316 user, date, msg = self.parselog(open(headerfile, b'rb'))[1:4]
316 user, date, msg = self.parselog(open(headerfile, b'rb'))[1:4]
317 finally:
317 finally:
318 os.unlink(headerfile)
318 os.unlink(headerfile)
319
319
320 return (user, date, msg)
320 return (user, date, msg)
321
321
322 def applyone(
322 def applyone(
323 self, repo, node, cl, patchfile, merge=False, log=False, filter=None
323 self, repo, node, cl, patchfile, merge=False, log=False, filter=None
324 ):
324 ):
325 '''apply the patch in patchfile to the repository as a transplant'''
325 '''apply the patch in patchfile to the repository as a transplant'''
326 (manifest, user, (time, timezone), files, message) = cl[:5]
326 (manifest, user, (time, timezone), files, message) = cl[:5]
327 date = b"%d %d" % (time, timezone)
327 date = b"%d %d" % (time, timezone)
328 extra = {b'transplant_source': node}
328 extra = {b'transplant_source': node}
329 if filter:
329 if filter:
330 (user, date, message) = self.filter(filter, node, cl, patchfile)
330 (user, date, message) = self.filter(filter, node, cl, patchfile)
331
331
332 if log:
332 if log:
333 # we don't translate messages inserted into commits
333 # we don't translate messages inserted into commits
334 message += b'\n(transplanted from %s)' % nodemod.hex(node)
334 message += b'\n(transplanted from %s)' % nodemod.hex(node)
335
335
336 self.ui.status(_(b'applying %s\n') % nodemod.short(node))
336 self.ui.status(_(b'applying %s\n') % nodemod.short(node))
337 self.ui.note(b'%s %s\n%s\n' % (user, date, message))
337 self.ui.note(b'%s %s\n%s\n' % (user, date, message))
338
338
339 if not patchfile and not merge:
339 if not patchfile and not merge:
340 raise error.Abort(_(b'can only omit patchfile if merging'))
340 raise error.Abort(_(b'can only omit patchfile if merging'))
341 if patchfile:
341 if patchfile:
342 try:
342 try:
343 files = set()
343 files = set()
344 patch.patch(self.ui, repo, patchfile, files=files, eolmode=None)
344 patch.patch(self.ui, repo, patchfile, files=files, eolmode=None)
345 files = list(files)
345 files = list(files)
346 except Exception as inst:
346 except Exception as inst:
347 seriespath = os.path.join(self.path, b'series')
347 seriespath = os.path.join(self.path, b'series')
348 if os.path.exists(seriespath):
348 if os.path.exists(seriespath):
349 os.unlink(seriespath)
349 os.unlink(seriespath)
350 p1 = repo.dirstate.p1()
350 p1 = repo.dirstate.p1()
351 p2 = node
351 p2 = node
352 self.log(user, date, message, p1, p2, merge=merge)
352 self.log(user, date, message, p1, p2, merge=merge)
353 self.ui.write(stringutil.forcebytestr(inst) + b'\n')
353 self.ui.write(stringutil.forcebytestr(inst) + b'\n')
354 raise TransplantError(
354 raise TransplantError(
355 _(
355 _(
356 b'fix up the working directory and run '
356 b'fix up the working directory and run '
357 b'hg transplant --continue'
357 b'hg transplant --continue'
358 )
358 )
359 )
359 )
360 else:
360 else:
361 files = None
361 files = None
362 if merge:
362 if merge:
363 p1 = repo.dirstate.p1()
363 p1 = repo.dirstate.p1()
364 repo.setparents(p1, node)
364 repo.setparents(p1, node)
365 m = match.always()
365 m = match.always()
366 else:
366 else:
367 m = match.exact(files)
367 m = match.exact(files)
368
368
369 n = repo.commit(
369 n = repo.commit(
370 message,
370 message,
371 user,
371 user,
372 date,
372 date,
373 extra=extra,
373 extra=extra,
374 match=m,
374 match=m,
375 editor=self.getcommiteditor(),
375 editor=self.getcommiteditor(),
376 )
376 )
377 if not n:
377 if not n:
378 self.ui.warn(
378 self.ui.warn(
379 _(b'skipping emptied changeset %s\n') % nodemod.short(node)
379 _(b'skipping emptied changeset %s\n') % nodemod.short(node)
380 )
380 )
381 return None
381 return None
382 if not merge:
382 if not merge:
383 self.transplants.set(n, node)
383 self.transplants.set(n, node)
384
384
385 return n
385 return n
386
386
387 def canresume(self):
387 def canresume(self):
388 return os.path.exists(os.path.join(self.path, b'journal'))
388 return os.path.exists(os.path.join(self.path, b'journal'))
389
389
390 def resume(self, repo, source, opts):
390 def resume(self, repo, source, opts):
391 '''recover last transaction and apply remaining changesets'''
391 '''recover last transaction and apply remaining changesets'''
392 if os.path.exists(os.path.join(self.path, b'journal')):
392 if os.path.exists(os.path.join(self.path, b'journal')):
393 n, node = self.recover(repo, source, opts)
393 n, node = self.recover(repo, source, opts)
394 if n:
394 if n:
395 self.ui.status(
395 self.ui.status(
396 _(b'%s transplanted as %s\n')
396 _(b'%s transplanted as %s\n')
397 % (nodemod.short(node), nodemod.short(n))
397 % (nodemod.short(node), nodemod.short(n))
398 )
398 )
399 else:
399 else:
400 self.ui.status(
400 self.ui.status(
401 _(b'%s skipped due to empty diff\n')
401 _(b'%s skipped due to empty diff\n')
402 % (nodemod.short(node),)
402 % (nodemod.short(node),)
403 )
403 )
404 seriespath = os.path.join(self.path, b'series')
404 seriespath = os.path.join(self.path, b'series')
405 if not os.path.exists(seriespath):
405 if not os.path.exists(seriespath):
406 self.transplants.write()
406 self.transplants.write()
407 return
407 return
408 nodes, merges = self.readseries()
408 nodes, merges = self.readseries()
409 revmap = {}
409 revmap = {}
410 for n in nodes:
410 for n in nodes:
411 revmap[source.changelog.rev(n)] = n
411 revmap[source.changelog.rev(n)] = n
412 os.unlink(seriespath)
412 os.unlink(seriespath)
413
413
414 self.apply(repo, source, revmap, merges, opts)
414 self.apply(repo, source, revmap, merges, opts)
415
415
416 def recover(self, repo, source, opts):
416 def recover(self, repo, source, opts):
417 '''commit working directory using journal metadata'''
417 '''commit working directory using journal metadata'''
418 node, user, date, message, parents = self.readlog()
418 node, user, date, message, parents = self.readlog()
419 merge = False
419 merge = False
420
420
421 if not user or not date or not message or not parents[0]:
421 if not user or not date or not message or not parents[0]:
422 raise error.Abort(_(b'transplant log file is corrupt'))
422 raise error.Abort(_(b'transplant log file is corrupt'))
423
423
424 parent = parents[0]
424 parent = parents[0]
425 if len(parents) > 1:
425 if len(parents) > 1:
426 if opts.get(b'parent'):
426 if opts.get(b'parent'):
427 parent = source.lookup(opts[b'parent'])
427 parent = source.lookup(opts[b'parent'])
428 if parent not in parents:
428 if parent not in parents:
429 raise error.Abort(
429 raise error.Abort(
430 _(b'%s is not a parent of %s')
430 _(b'%s is not a parent of %s')
431 % (nodemod.short(parent), nodemod.short(node))
431 % (nodemod.short(parent), nodemod.short(node))
432 )
432 )
433 else:
433 else:
434 merge = True
434 merge = True
435
435
436 extra = {b'transplant_source': node}
436 extra = {b'transplant_source': node}
437 try:
437 try:
438 p1 = repo.dirstate.p1()
438 p1 = repo.dirstate.p1()
439 if p1 != parent:
439 if p1 != parent:
440 raise error.Abort(
440 raise error.Abort(
441 _(b'working directory not at transplant parent %s')
441 _(b'working directory not at transplant parent %s')
442 % nodemod.hex(parent)
442 % nodemod.hex(parent)
443 )
443 )
444 if merge:
444 if merge:
445 repo.setparents(p1, parents[1])
445 repo.setparents(p1, parents[1])
446 st = repo.status()
446 st = repo.status()
447 modified, added, removed, deleted = (
447 modified, added, removed, deleted = (
448 st.modified,
448 st.modified,
449 st.added,
449 st.added,
450 st.removed,
450 st.removed,
451 st.deleted,
451 st.deleted,
452 )
452 )
453 if merge or modified or added or removed or deleted:
453 if merge or modified or added or removed or deleted:
454 n = repo.commit(
454 n = repo.commit(
455 message,
455 message,
456 user,
456 user,
457 date,
457 date,
458 extra=extra,
458 extra=extra,
459 editor=self.getcommiteditor(),
459 editor=self.getcommiteditor(),
460 )
460 )
461 if not n:
461 if not n:
462 raise error.Abort(_(b'commit failed'))
462 raise error.Abort(_(b'commit failed'))
463 if not merge:
463 if not merge:
464 self.transplants.set(n, node)
464 self.transplants.set(n, node)
465 else:
465 else:
466 n = None
466 n = None
467 self.unlog()
467 self.unlog()
468
468
469 return n, node
469 return n, node
470 finally:
470 finally:
471 # TODO: get rid of this meaningless try/finally enclosing.
471 # TODO: get rid of this meaningless try/finally enclosing.
472 # this is kept only to reduce changes in a patch.
472 # this is kept only to reduce changes in a patch.
473 pass
473 pass
474
474
475 def stop(self, ui, repo):
475 def stop(self, ui, repo):
476 """logic to stop an interrupted transplant"""
476 """logic to stop an interrupted transplant"""
477 if self.canresume():
477 if self.canresume():
478 startctx = repo[b'.']
478 startctx = repo[b'.']
479 hg.updaterepo(repo, startctx.node(), overwrite=True)
479 hg.updaterepo(repo, startctx.node(), overwrite=True)
480 ui.status(_(b"stopped the interrupted transplant\n"))
480 ui.status(_(b"stopped the interrupted transplant\n"))
481 ui.status(
481 ui.status(
482 _(b"working directory is now at %s\n") % startctx.hex()[:12]
482 _(b"working directory is now at %s\n") % startctx.hex()[:12]
483 )
483 )
484 self.unlog()
484 self.unlog()
485 return 0
485 return 0
486
486
487 def readseries(self):
487 def readseries(self):
488 nodes = []
488 nodes = []
489 merges = []
489 merges = []
490 cur = nodes
490 cur = nodes
491 for line in self.opener.read(b'series').splitlines():
491 for line in self.opener.read(b'series').splitlines():
492 if line.startswith(b'# Merges'):
492 if line.startswith(b'# Merges'):
493 cur = merges
493 cur = merges
494 continue
494 continue
495 cur.append(revlog.bin(line))
495 cur.append(revlog.bin(line))
496
496
497 return (nodes, merges)
497 return (nodes, merges)
498
498
499 def saveseries(self, revmap, merges):
499 def saveseries(self, revmap, merges):
500 if not revmap:
500 if not revmap:
501 return
501 return
502
502
503 if not os.path.isdir(self.path):
503 if not os.path.isdir(self.path):
504 os.mkdir(self.path)
504 os.mkdir(self.path)
505 series = self.opener(b'series', b'w')
505 series = self.opener(b'series', b'w')
506 for rev in sorted(revmap):
506 for rev in sorted(revmap):
507 series.write(nodemod.hex(revmap[rev]) + b'\n')
507 series.write(nodemod.hex(revmap[rev]) + b'\n')
508 if merges:
508 if merges:
509 series.write(b'# Merges\n')
509 series.write(b'# Merges\n')
510 for m in merges:
510 for m in merges:
511 series.write(nodemod.hex(m) + b'\n')
511 series.write(nodemod.hex(m) + b'\n')
512 series.close()
512 series.close()
513
513
514 def parselog(self, fp):
514 def parselog(self, fp):
515 parents = []
515 parents = []
516 message = []
516 message = []
517 node = revlog.nullid
517 node = revlog.nullid
518 inmsg = False
518 inmsg = False
519 user = None
519 user = None
520 date = None
520 date = None
521 for line in fp.read().splitlines():
521 for line in fp.read().splitlines():
522 if inmsg:
522 if inmsg:
523 message.append(line)
523 message.append(line)
524 elif line.startswith(b'# User '):
524 elif line.startswith(b'# User '):
525 user = line[7:]
525 user = line[7:]
526 elif line.startswith(b'# Date '):
526 elif line.startswith(b'# Date '):
527 date = line[7:]
527 date = line[7:]
528 elif line.startswith(b'# Node ID '):
528 elif line.startswith(b'# Node ID '):
529 node = revlog.bin(line[10:])
529 node = revlog.bin(line[10:])
530 elif line.startswith(b'# Parent '):
530 elif line.startswith(b'# Parent '):
531 parents.append(revlog.bin(line[9:]))
531 parents.append(revlog.bin(line[9:]))
532 elif not line.startswith(b'# '):
532 elif not line.startswith(b'# '):
533 inmsg = True
533 inmsg = True
534 message.append(line)
534 message.append(line)
535 if None in (user, date):
535 if None in (user, date):
536 raise error.Abort(
536 raise error.Abort(
537 _(b"filter corrupted changeset (no user or date)")
537 _(b"filter corrupted changeset (no user or date)")
538 )
538 )
539 return (node, user, date, b'\n'.join(message), parents)
539 return (node, user, date, b'\n'.join(message), parents)
540
540
541 def log(self, user, date, message, p1, p2, merge=False):
541 def log(self, user, date, message, p1, p2, merge=False):
542 '''journal changelog metadata for later recover'''
542 '''journal changelog metadata for later recover'''
543
543
544 if not os.path.isdir(self.path):
544 if not os.path.isdir(self.path):
545 os.mkdir(self.path)
545 os.mkdir(self.path)
546 fp = self.opener(b'journal', b'w')
546 fp = self.opener(b'journal', b'w')
547 fp.write(b'# User %s\n' % user)
547 fp.write(b'# User %s\n' % user)
548 fp.write(b'# Date %s\n' % date)
548 fp.write(b'# Date %s\n' % date)
549 fp.write(b'# Node ID %s\n' % nodemod.hex(p2))
549 fp.write(b'# Node ID %s\n' % nodemod.hex(p2))
550 fp.write(b'# Parent ' + nodemod.hex(p1) + b'\n')
550 fp.write(b'# Parent ' + nodemod.hex(p1) + b'\n')
551 if merge:
551 if merge:
552 fp.write(b'# Parent ' + nodemod.hex(p2) + b'\n')
552 fp.write(b'# Parent ' + nodemod.hex(p2) + b'\n')
553 fp.write(message.rstrip() + b'\n')
553 fp.write(message.rstrip() + b'\n')
554 fp.close()
554 fp.close()
555
555
556 def readlog(self):
556 def readlog(self):
557 return self.parselog(self.opener(b'journal'))
557 return self.parselog(self.opener(b'journal'))
558
558
559 def unlog(self):
559 def unlog(self):
560 '''remove changelog journal'''
560 '''remove changelog journal'''
561 absdst = os.path.join(self.path, b'journal')
561 absdst = os.path.join(self.path, b'journal')
562 if os.path.exists(absdst):
562 if os.path.exists(absdst):
563 os.unlink(absdst)
563 os.unlink(absdst)
564
564
565 def transplantfilter(self, repo, source, root):
565 def transplantfilter(self, repo, source, root):
566 def matchfn(node):
566 def matchfn(node):
567 if self.applied(repo, node, root):
567 if self.applied(repo, node, root):
568 return False
568 return False
569 if source.changelog.parents(node)[1] != revlog.nullid:
569 if source.changelog.parents(node)[1] != revlog.nullid:
570 return False
570 return False
571 extra = source.changelog.read(node)[5]
571 extra = source.changelog.read(node)[5]
572 cnode = extra.get(b'transplant_source')
572 cnode = extra.get(b'transplant_source')
573 if cnode and self.applied(repo, cnode, root):
573 if cnode and self.applied(repo, cnode, root):
574 return False
574 return False
575 return True
575 return True
576
576
577 return matchfn
577 return matchfn
578
578
579
579
580 def hasnode(repo, node):
580 def hasnode(repo, node):
581 try:
581 try:
582 return repo.changelog.rev(node) is not None
582 return repo.changelog.rev(node) is not None
583 except error.StorageError:
583 except error.StorageError:
584 return False
584 return False
585
585
586
586
587 def browserevs(ui, repo, nodes, opts):
587 def browserevs(ui, repo, nodes, opts):
588 '''interactively transplant changesets'''
588 '''interactively transplant changesets'''
589 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
589 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
590 transplants = []
590 transplants = []
591 merges = []
591 merges = []
592 prompt = _(
592 prompt = _(
593 b'apply changeset? [ynmpcq?]:'
593 b'apply changeset? [ynmpcq?]:'
594 b'$$ &yes, transplant this changeset'
594 b'$$ &yes, transplant this changeset'
595 b'$$ &no, skip this changeset'
595 b'$$ &no, skip this changeset'
596 b'$$ &merge at this changeset'
596 b'$$ &merge at this changeset'
597 b'$$ show &patch'
597 b'$$ show &patch'
598 b'$$ &commit selected changesets'
598 b'$$ &commit selected changesets'
599 b'$$ &quit and cancel transplant'
599 b'$$ &quit and cancel transplant'
600 b'$$ &? (show this help)'
600 b'$$ &? (show this help)'
601 )
601 )
602 for node in nodes:
602 for node in nodes:
603 displayer.show(repo[node])
603 displayer.show(repo[node])
604 action = None
604 action = None
605 while not action:
605 while not action:
606 choice = ui.promptchoice(prompt)
606 choice = ui.promptchoice(prompt)
607 action = b'ynmpcq?'[choice : choice + 1]
607 action = b'ynmpcq?'[choice : choice + 1]
608 if action == b'?':
608 if action == b'?':
609 for c, t in ui.extractchoices(prompt)[1]:
609 for c, t in ui.extractchoices(prompt)[1]:
610 ui.write(b'%s: %s\n' % (c, t))
610 ui.write(b'%s: %s\n' % (c, t))
611 action = None
611 action = None
612 elif action == b'p':
612 elif action == b'p':
613 parent = repo.changelog.parents(node)[0]
613 parent = repo.changelog.parents(node)[0]
614 for chunk in patch.diff(repo, parent, node):
614 for chunk in patch.diff(repo, parent, node):
615 ui.write(chunk)
615 ui.write(chunk)
616 action = None
616 action = None
617 if action == b'y':
617 if action == b'y':
618 transplants.append(node)
618 transplants.append(node)
619 elif action == b'm':
619 elif action == b'm':
620 merges.append(node)
620 merges.append(node)
621 elif action == b'c':
621 elif action == b'c':
622 break
622 break
623 elif action == b'q':
623 elif action == b'q':
624 transplants = ()
624 transplants = ()
625 merges = ()
625 merges = ()
626 break
626 break
627 displayer.close()
627 displayer.close()
628 return (transplants, merges)
628 return (transplants, merges)
629
629
630
630
631 @command(
631 @command(
632 b'transplant',
632 b'transplant',
633 [
633 [
634 (
634 (
635 b's',
635 b's',
636 b'source',
636 b'source',
637 b'',
637 b'',
638 _(b'transplant changesets from REPO'),
638 _(b'transplant changesets from REPO'),
639 _(b'REPO'),
639 _(b'REPO'),
640 ),
640 ),
641 (
641 (
642 b'b',
642 b'b',
643 b'branch',
643 b'branch',
644 [],
644 [],
645 _(b'use this source changeset as head'),
645 _(b'use this source changeset as head'),
646 _(b'REV'),
646 _(b'REV'),
647 ),
647 ),
648 (
648 (
649 b'a',
649 b'a',
650 b'all',
650 b'all',
651 None,
651 None,
652 _(b'pull all changesets up to the --branch revisions'),
652 _(b'pull all changesets up to the --branch revisions'),
653 ),
653 ),
654 (b'p', b'prune', [], _(b'skip over REV'), _(b'REV')),
654 (b'p', b'prune', [], _(b'skip over REV'), _(b'REV')),
655 (b'm', b'merge', [], _(b'merge at REV'), _(b'REV')),
655 (b'm', b'merge', [], _(b'merge at REV'), _(b'REV')),
656 (
656 (
657 b'',
657 b'',
658 b'parent',
658 b'parent',
659 b'',
659 b'',
660 _(b'parent to choose when transplanting merge'),
660 _(b'parent to choose when transplanting merge'),
661 _(b'REV'),
661 _(b'REV'),
662 ),
662 ),
663 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
663 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
664 (b'', b'log', None, _(b'append transplant info to log message')),
664 (b'', b'log', None, _(b'append transplant info to log message')),
665 (b'', b'stop', False, _(b'stop interrupted transplant')),
665 (b'', b'stop', False, _(b'stop interrupted transplant')),
666 (
666 (
667 b'c',
667 b'c',
668 b'continue',
668 b'continue',
669 None,
669 None,
670 _(b'continue last transplant session after fixing conflicts'),
670 _(b'continue last transplant session after fixing conflicts'),
671 ),
671 ),
672 (
672 (
673 b'',
673 b'',
674 b'filter',
674 b'filter',
675 b'',
675 b'',
676 _(b'filter changesets through command'),
676 _(b'filter changesets through command'),
677 _(b'CMD'),
677 _(b'CMD'),
678 ),
678 ),
679 ],
679 ],
680 _(
680 _(
681 b'hg transplant [-s REPO] [-b BRANCH [-a]] [-p REV] '
681 b'hg transplant [-s REPO] [-b BRANCH [-a]] [-p REV] '
682 b'[-m REV] [REV]...'
682 b'[-m REV] [REV]...'
683 ),
683 ),
684 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
684 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
685 )
685 )
686 def transplant(ui, repo, *revs, **opts):
686 def transplant(ui, repo, *revs, **opts):
687 '''transplant changesets from another branch
687 '''transplant changesets from another branch
688
688
689 Selected changesets will be applied on top of the current working
689 Selected changesets will be applied on top of the current working
690 directory with the log of the original changeset. The changesets
690 directory with the log of the original changeset. The changesets
691 are copied and will thus appear twice in the history with different
691 are copied and will thus appear twice in the history with different
692 identities.
692 identities.
693
693
694 Consider using the graft command if everything is inside the same
694 Consider using the graft command if everything is inside the same
695 repository - it will use merges and will usually give a better result.
695 repository - it will use merges and will usually give a better result.
696 Use the rebase extension if the changesets are unpublished and you want
696 Use the rebase extension if the changesets are unpublished and you want
697 to move them instead of copying them.
697 to move them instead of copying them.
698
698
699 If --log is specified, log messages will have a comment appended
699 If --log is specified, log messages will have a comment appended
700 of the form::
700 of the form::
701
701
702 (transplanted from CHANGESETHASH)
702 (transplanted from CHANGESETHASH)
703
703
704 You can rewrite the changelog message with the --filter option.
704 You can rewrite the changelog message with the --filter option.
705 Its argument will be invoked with the current changelog message as
705 Its argument will be invoked with the current changelog message as
706 $1 and the patch as $2.
706 $1 and the patch as $2.
707
707
708 --source/-s specifies another repository to use for selecting changesets,
708 --source/-s specifies another repository to use for selecting changesets,
709 just as if it temporarily had been pulled.
709 just as if it temporarily had been pulled.
710 If --branch/-b is specified, these revisions will be used as
710 If --branch/-b is specified, these revisions will be used as
711 heads when deciding which changesets to transplant, just as if only
711 heads when deciding which changesets to transplant, just as if only
712 these revisions had been pulled.
712 these revisions had been pulled.
713 If --all/-a is specified, all the revisions up to the heads specified
713 If --all/-a is specified, all the revisions up to the heads specified
714 with --branch will be transplanted.
714 with --branch will be transplanted.
715
715
716 Example:
716 Example:
717
717
718 - transplant all changes up to REV on top of your current revision::
718 - transplant all changes up to REV on top of your current revision::
719
719
720 hg transplant --branch REV --all
720 hg transplant --branch REV --all
721
721
722 You can optionally mark selected transplanted changesets as merge
722 You can optionally mark selected transplanted changesets as merge
723 changesets. You will not be prompted to transplant any ancestors
723 changesets. You will not be prompted to transplant any ancestors
724 of a merged transplant, and you can merge descendants of them
724 of a merged transplant, and you can merge descendants of them
725 normally instead of transplanting them.
725 normally instead of transplanting them.
726
726
727 Merge changesets may be transplanted directly by specifying the
727 Merge changesets may be transplanted directly by specifying the
728 proper parent changeset by calling :hg:`transplant --parent`.
728 proper parent changeset by calling :hg:`transplant --parent`.
729
729
730 If no merges or revisions are provided, :hg:`transplant` will
730 If no merges or revisions are provided, :hg:`transplant` will
731 start an interactive changeset browser.
731 start an interactive changeset browser.
732
732
733 If a changeset application fails, you can fix the merge by hand
733 If a changeset application fails, you can fix the merge by hand
734 and then resume where you left off by calling :hg:`transplant
734 and then resume where you left off by calling :hg:`transplant
735 --continue/-c`.
735 --continue/-c`.
736 '''
736 '''
737 with repo.wlock():
737 with repo.wlock():
738 return _dotransplant(ui, repo, *revs, **opts)
738 return _dotransplant(ui, repo, *revs, **opts)
739
739
740
740
741 def _dotransplant(ui, repo, *revs, **opts):
741 def _dotransplant(ui, repo, *revs, **opts):
742 def incwalk(repo, csets, match=util.always):
742 def incwalk(repo, csets, match=util.always):
743 for node in csets:
743 for node in csets:
744 if match(node):
744 if match(node):
745 yield node
745 yield node
746
746
747 def transplantwalk(repo, dest, heads, match=util.always):
747 def transplantwalk(repo, dest, heads, match=util.always):
748 '''Yield all nodes that are ancestors of a head but not ancestors
748 '''Yield all nodes that are ancestors of a head but not ancestors
749 of dest.
749 of dest.
750 If no heads are specified, the heads of repo will be used.'''
750 If no heads are specified, the heads of repo will be used.'''
751 if not heads:
751 if not heads:
752 heads = repo.heads()
752 heads = repo.heads()
753 ancestors = []
753 ancestors = []
754 ctx = repo[dest]
754 ctx = repo[dest]
755 for head in heads:
755 for head in heads:
756 ancestors.append(ctx.ancestor(repo[head]).node())
756 ancestors.append(ctx.ancestor(repo[head]).node())
757 for node in repo.changelog.nodesbetween(ancestors, heads)[0]:
757 for node in repo.changelog.nodesbetween(ancestors, heads)[0]:
758 if match(node):
758 if match(node):
759 yield node
759 yield node
760
760
761 def checkopts(opts, revs):
761 def checkopts(opts, revs):
762 if opts.get(b'continue'):
762 if opts.get(b'continue'):
763 if opts.get(b'branch') or opts.get(b'all') or opts.get(b'merge'):
763 cmdutil.check_incompatible_arguments(
764 raise error.Abort(
764 opts, b'continue', b'branch', b'all', b'merge'
765 _(
765 )
766 b'--continue is incompatible with '
767 b'--branch, --all and --merge'
768 )
769 )
770 return
766 return
771 if opts.get(b'stop'):
767 if opts.get(b'stop'):
772 if opts.get(b'branch') or opts.get(b'all') or opts.get(b'merge'):
768 cmdutil.check_incompatible_arguments(
773 raise error.Abort(
769 opts, b'stop', b'branch', b'all', b'merge'
774 _(
770 )
775 b'--stop is incompatible with '
776 b'--branch, --all and --merge'
777 )
778 )
779 return
771 return
780 if not (
772 if not (
781 opts.get(b'source')
773 opts.get(b'source')
782 or revs
774 or revs
783 or opts.get(b'merge')
775 or opts.get(b'merge')
784 or opts.get(b'branch')
776 or opts.get(b'branch')
785 ):
777 ):
786 raise error.Abort(
778 raise error.Abort(
787 _(
779 _(
788 b'no source URL, branch revision, or revision '
780 b'no source URL, branch revision, or revision '
789 b'list provided'
781 b'list provided'
790 )
782 )
791 )
783 )
792 if opts.get(b'all'):
784 if opts.get(b'all'):
793 if not opts.get(b'branch'):
785 if not opts.get(b'branch'):
794 raise error.Abort(_(b'--all requires a branch revision'))
786 raise error.Abort(_(b'--all requires a branch revision'))
795 if revs:
787 if revs:
796 raise error.Abort(
788 raise error.Abort(
797 _(b'--all is incompatible with a revision list')
789 _(b'--all is incompatible with a revision list')
798 )
790 )
799
791
800 opts = pycompat.byteskwargs(opts)
792 opts = pycompat.byteskwargs(opts)
801 checkopts(opts, revs)
793 checkopts(opts, revs)
802
794
803 if not opts.get(b'log'):
795 if not opts.get(b'log'):
804 # deprecated config: transplant.log
796 # deprecated config: transplant.log
805 opts[b'log'] = ui.config(b'transplant', b'log')
797 opts[b'log'] = ui.config(b'transplant', b'log')
806 if not opts.get(b'filter'):
798 if not opts.get(b'filter'):
807 # deprecated config: transplant.filter
799 # deprecated config: transplant.filter
808 opts[b'filter'] = ui.config(b'transplant', b'filter')
800 opts[b'filter'] = ui.config(b'transplant', b'filter')
809
801
810 tp = transplanter(ui, repo, opts)
802 tp = transplanter(ui, repo, opts)
811
803
812 p1 = repo.dirstate.p1()
804 p1 = repo.dirstate.p1()
813 if len(repo) > 0 and p1 == revlog.nullid:
805 if len(repo) > 0 and p1 == revlog.nullid:
814 raise error.Abort(_(b'no revision checked out'))
806 raise error.Abort(_(b'no revision checked out'))
815 if opts.get(b'continue'):
807 if opts.get(b'continue'):
816 if not tp.canresume():
808 if not tp.canresume():
817 raise error.Abort(_(b'no transplant to continue'))
809 raise error.Abort(_(b'no transplant to continue'))
818 elif opts.get(b'stop'):
810 elif opts.get(b'stop'):
819 if not tp.canresume():
811 if not tp.canresume():
820 raise error.Abort(_(b'no interrupted transplant found'))
812 raise error.Abort(_(b'no interrupted transplant found'))
821 return tp.stop(ui, repo)
813 return tp.stop(ui, repo)
822 else:
814 else:
823 cmdutil.checkunfinished(repo)
815 cmdutil.checkunfinished(repo)
824 cmdutil.bailifchanged(repo)
816 cmdutil.bailifchanged(repo)
825
817
826 sourcerepo = opts.get(b'source')
818 sourcerepo = opts.get(b'source')
827 if sourcerepo:
819 if sourcerepo:
828 peer = hg.peer(repo, opts, ui.expandpath(sourcerepo))
820 peer = hg.peer(repo, opts, ui.expandpath(sourcerepo))
829 heads = pycompat.maplist(peer.lookup, opts.get(b'branch', ()))
821 heads = pycompat.maplist(peer.lookup, opts.get(b'branch', ()))
830 target = set(heads)
822 target = set(heads)
831 for r in revs:
823 for r in revs:
832 try:
824 try:
833 target.add(peer.lookup(r))
825 target.add(peer.lookup(r))
834 except error.RepoError:
826 except error.RepoError:
835 pass
827 pass
836 source, csets, cleanupfn = bundlerepo.getremotechanges(
828 source, csets, cleanupfn = bundlerepo.getremotechanges(
837 ui, repo, peer, onlyheads=sorted(target), force=True
829 ui, repo, peer, onlyheads=sorted(target), force=True
838 )
830 )
839 else:
831 else:
840 source = repo
832 source = repo
841 heads = pycompat.maplist(source.lookup, opts.get(b'branch', ()))
833 heads = pycompat.maplist(source.lookup, opts.get(b'branch', ()))
842 cleanupfn = None
834 cleanupfn = None
843
835
844 try:
836 try:
845 if opts.get(b'continue'):
837 if opts.get(b'continue'):
846 tp.resume(repo, source, opts)
838 tp.resume(repo, source, opts)
847 return
839 return
848
840
849 tf = tp.transplantfilter(repo, source, p1)
841 tf = tp.transplantfilter(repo, source, p1)
850 if opts.get(b'prune'):
842 if opts.get(b'prune'):
851 prune = set(
843 prune = set(
852 source[r].node()
844 source[r].node()
853 for r in scmutil.revrange(source, opts.get(b'prune'))
845 for r in scmutil.revrange(source, opts.get(b'prune'))
854 )
846 )
855 matchfn = lambda x: tf(x) and x not in prune
847 matchfn = lambda x: tf(x) and x not in prune
856 else:
848 else:
857 matchfn = tf
849 matchfn = tf
858 merges = pycompat.maplist(source.lookup, opts.get(b'merge', ()))
850 merges = pycompat.maplist(source.lookup, opts.get(b'merge', ()))
859 revmap = {}
851 revmap = {}
860 if revs:
852 if revs:
861 for r in scmutil.revrange(source, revs):
853 for r in scmutil.revrange(source, revs):
862 revmap[int(r)] = source[r].node()
854 revmap[int(r)] = source[r].node()
863 elif opts.get(b'all') or not merges:
855 elif opts.get(b'all') or not merges:
864 if source != repo:
856 if source != repo:
865 alltransplants = incwalk(source, csets, match=matchfn)
857 alltransplants = incwalk(source, csets, match=matchfn)
866 else:
858 else:
867 alltransplants = transplantwalk(
859 alltransplants = transplantwalk(
868 source, p1, heads, match=matchfn
860 source, p1, heads, match=matchfn
869 )
861 )
870 if opts.get(b'all'):
862 if opts.get(b'all'):
871 revs = alltransplants
863 revs = alltransplants
872 else:
864 else:
873 revs, newmerges = browserevs(ui, source, alltransplants, opts)
865 revs, newmerges = browserevs(ui, source, alltransplants, opts)
874 merges.extend(newmerges)
866 merges.extend(newmerges)
875 for r in revs:
867 for r in revs:
876 revmap[source.changelog.rev(r)] = r
868 revmap[source.changelog.rev(r)] = r
877 for r in merges:
869 for r in merges:
878 revmap[source.changelog.rev(r)] = r
870 revmap[source.changelog.rev(r)] = r
879
871
880 tp.apply(repo, source, revmap, merges, opts)
872 tp.apply(repo, source, revmap, merges, opts)
881 finally:
873 finally:
882 if cleanupfn:
874 if cleanupfn:
883 cleanupfn()
875 cleanupfn()
884
876
885
877
886 def continuecmd(ui, repo):
878 def continuecmd(ui, repo):
887 """logic to resume an interrupted transplant using
879 """logic to resume an interrupted transplant using
888 'hg continue'"""
880 'hg continue'"""
889 with repo.wlock():
881 with repo.wlock():
890 tp = transplanter(ui, repo, {})
882 tp = transplanter(ui, repo, {})
891 return tp.resume(repo, repo, {})
883 return tp.resume(repo, repo, {})
892
884
893
885
894 revsetpredicate = registrar.revsetpredicate()
886 revsetpredicate = registrar.revsetpredicate()
895
887
896
888
897 @revsetpredicate(b'transplanted([set])')
889 @revsetpredicate(b'transplanted([set])')
898 def revsettransplanted(repo, subset, x):
890 def revsettransplanted(repo, subset, x):
899 """Transplanted changesets in set, or all transplanted changesets.
891 """Transplanted changesets in set, or all transplanted changesets.
900 """
892 """
901 if x:
893 if x:
902 s = revset.getset(repo, subset, x)
894 s = revset.getset(repo, subset, x)
903 else:
895 else:
904 s = subset
896 s = subset
905 return smartset.baseset(
897 return smartset.baseset(
906 [r for r in s if repo[r].extra().get(b'transplant_source')]
898 [r for r in s if repo[r].extra().get(b'transplant_source')]
907 )
899 )
908
900
909
901
910 templatekeyword = registrar.templatekeyword()
902 templatekeyword = registrar.templatekeyword()
911
903
912
904
913 @templatekeyword(b'transplanted', requires={b'ctx'})
905 @templatekeyword(b'transplanted', requires={b'ctx'})
914 def kwtransplanted(context, mapping):
906 def kwtransplanted(context, mapping):
915 """String. The node identifier of the transplanted
907 """String. The node identifier of the transplanted
916 changeset if any."""
908 changeset if any."""
917 ctx = context.resource(mapping, b'ctx')
909 ctx = context.resource(mapping, b'ctx')
918 n = ctx.extra().get(b'transplant_source')
910 n = ctx.extra().get(b'transplant_source')
919 return n and nodemod.hex(n) or b''
911 return n and nodemod.hex(n) or b''
920
912
921
913
922 def extsetup(ui):
914 def extsetup(ui):
923 statemod.addunfinished(
915 statemod.addunfinished(
924 b'transplant',
916 b'transplant',
925 fname=b'transplant/journal',
917 fname=b'transplant/journal',
926 clearable=True,
918 clearable=True,
927 continuefunc=continuecmd,
919 continuefunc=continuecmd,
928 statushint=_(
920 statushint=_(
929 b'To continue: hg transplant --continue\n'
921 b'To continue: hg transplant --continue\n'
930 b'To stop: hg transplant --stop'
922 b'To stop: hg transplant --stop'
931 ),
923 ),
932 cmdhint=_(b"use 'hg transplant --continue' or 'hg transplant --stop'"),
924 cmdhint=_(b"use 'hg transplant --continue' or 'hg transplant --stop'"),
933 )
925 )
934
926
935
927
936 # tell hggettext to extract docstrings from these functions:
928 # tell hggettext to extract docstrings from these functions:
937 i18nfunctions = [revsettransplanted, kwtransplanted]
929 i18nfunctions = [revsettransplanted, kwtransplanted]
@@ -1,1107 +1,1107 b''
1 #testcases commandmode continueflag
1 #testcases commandmode continueflag
2 $ cat <<EOF >> $HGRCPATH
2 $ cat <<EOF >> $HGRCPATH
3 > [extensions]
3 > [extensions]
4 > transplant=
4 > transplant=
5 > graphlog=
5 > graphlog=
6 > EOF
6 > EOF
7
7
8 #if continueflag
8 #if continueflag
9 $ cat >> $HGRCPATH <<EOF
9 $ cat >> $HGRCPATH <<EOF
10 > [alias]
10 > [alias]
11 > continue = transplant --continue
11 > continue = transplant --continue
12 > EOF
12 > EOF
13 #endif
13 #endif
14
14
15 $ hg init t
15 $ hg init t
16 $ cd t
16 $ cd t
17 $ hg transplant
17 $ hg transplant
18 abort: no source URL, branch revision, or revision list provided
18 abort: no source URL, branch revision, or revision list provided
19 [255]
19 [255]
20 $ hg transplant --continue --all
20 $ hg transplant --continue --all
21 abort: --continue is incompatible with --branch, --all and --merge
21 abort: cannot specify both --continue and --all
22 [255]
22 [255]
23 $ hg transplant --stop --all
23 $ hg transplant --stop --all
24 abort: --stop is incompatible with --branch, --all and --merge
24 abort: cannot specify both --stop and --all
25 [255]
25 [255]
26 $ hg transplant --all tip
26 $ hg transplant --all tip
27 abort: --all requires a branch revision
27 abort: --all requires a branch revision
28 [255]
28 [255]
29 $ hg transplant --all --branch default tip
29 $ hg transplant --all --branch default tip
30 abort: --all is incompatible with a revision list
30 abort: --all is incompatible with a revision list
31 [255]
31 [255]
32 $ echo r1 > r1
32 $ echo r1 > r1
33 $ hg ci -Amr1 -d'0 0'
33 $ hg ci -Amr1 -d'0 0'
34 adding r1
34 adding r1
35 $ hg co -q null
35 $ hg co -q null
36 $ hg transplant tip
36 $ hg transplant tip
37 abort: no revision checked out
37 abort: no revision checked out
38 [255]
38 [255]
39 $ hg up -q
39 $ hg up -q
40 $ echo r2 > r2
40 $ echo r2 > r2
41 $ hg ci -Amr2 -d'1 0'
41 $ hg ci -Amr2 -d'1 0'
42 adding r2
42 adding r2
43 $ hg up 0
43 $ hg up 0
44 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
44 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
45
45
46 $ echo b1 > b1
46 $ echo b1 > b1
47 $ hg ci -Amb1 -d '0 0'
47 $ hg ci -Amb1 -d '0 0'
48 adding b1
48 adding b1
49 created new head
49 created new head
50 $ hg merge 1
50 $ hg merge 1
51 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 (branch merge, don't forget to commit)
52 (branch merge, don't forget to commit)
53 $ hg transplant 1
53 $ hg transplant 1
54 abort: outstanding uncommitted merge
54 abort: outstanding uncommitted merge
55 (use 'hg commit' or 'hg merge --abort')
55 (use 'hg commit' or 'hg merge --abort')
56 [255]
56 [255]
57 $ hg up -qC tip
57 $ hg up -qC tip
58 $ echo b0 > b1
58 $ echo b0 > b1
59 $ hg transplant 1
59 $ hg transplant 1
60 abort: uncommitted changes
60 abort: uncommitted changes
61 [255]
61 [255]
62 $ hg up -qC tip
62 $ hg up -qC tip
63 $ echo b2 > b2
63 $ echo b2 > b2
64 $ hg ci -Amb2 -d '1 0'
64 $ hg ci -Amb2 -d '1 0'
65 adding b2
65 adding b2
66 $ echo b3 > b3
66 $ echo b3 > b3
67 $ hg ci -Amb3 -d '2 0'
67 $ hg ci -Amb3 -d '2 0'
68 adding b3
68 adding b3
69
69
70 $ hg log --template '{rev} {parents} {desc}\n'
70 $ hg log --template '{rev} {parents} {desc}\n'
71 4 b3
71 4 b3
72 3 b2
72 3 b2
73 2 0:17ab29e464c6 b1
73 2 0:17ab29e464c6 b1
74 1 r2
74 1 r2
75 0 r1
75 0 r1
76
76
77 $ hg clone . ../rebase
77 $ hg clone . ../rebase
78 updating to branch default
78 updating to branch default
79 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 $ hg init ../emptydest
80 $ hg init ../emptydest
81 $ cd ../emptydest
81 $ cd ../emptydest
82 $ hg transplant --source=../t > /dev/null
82 $ hg transplant --source=../t > /dev/null
83 $ cd ../rebase
83 $ cd ../rebase
84
84
85 $ hg up -C 1
85 $ hg up -C 1
86 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
86 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
87
87
88 rebase b onto r1
88 rebase b onto r1
89 (this also tests that editor is not invoked if '--edit' is not specified)
89 (this also tests that editor is not invoked if '--edit' is not specified)
90
90
91 $ HGEDITOR=cat hg transplant -a -b tip
91 $ HGEDITOR=cat hg transplant -a -b tip
92 applying 37a1297eb21b
92 applying 37a1297eb21b
93 37a1297eb21b transplanted to e234d668f844
93 37a1297eb21b transplanted to e234d668f844
94 applying 722f4667af76
94 applying 722f4667af76
95 722f4667af76 transplanted to 539f377d78df
95 722f4667af76 transplanted to 539f377d78df
96 applying a53251cdf717
96 applying a53251cdf717
97 a53251cdf717 transplanted to ffd6818a3975
97 a53251cdf717 transplanted to ffd6818a3975
98 $ hg log --template '{rev} {parents} {desc}\n'
98 $ hg log --template '{rev} {parents} {desc}\n'
99 7 b3
99 7 b3
100 6 b2
100 6 b2
101 5 1:d11e3596cc1a b1
101 5 1:d11e3596cc1a b1
102 4 b3
102 4 b3
103 3 b2
103 3 b2
104 2 0:17ab29e464c6 b1
104 2 0:17ab29e464c6 b1
105 1 r2
105 1 r2
106 0 r1
106 0 r1
107
107
108 test format of transplant_source
108 test format of transplant_source
109
109
110 $ hg log -r7 --debug | grep transplant_source
110 $ hg log -r7 --debug | grep transplant_source
111 extra: transplant_source=\xa52Q\xcd\xf7\x17g\x9d\x19\x07\xb2\x89\xf9\x91SK\xe0\\\x99z
111 extra: transplant_source=\xa52Q\xcd\xf7\x17g\x9d\x19\x07\xb2\x89\xf9\x91SK\xe0\\\x99z
112 $ hg log -r7 -T '{extras}\n'
112 $ hg log -r7 -T '{extras}\n'
113 branch=defaulttransplant_source=\xa52Q\xcd\xf7\x17g\x9d\x19\x07\xb2\x89\xf9\x91SK\xe0\\\x99z
113 branch=defaulttransplant_source=\xa52Q\xcd\xf7\x17g\x9d\x19\x07\xb2\x89\xf9\x91SK\xe0\\\x99z
114 $ hg log -r7 -T '{join(extras, " ")}\n'
114 $ hg log -r7 -T '{join(extras, " ")}\n'
115 branch=default transplant_source=\xa52Q\xcd\xf7\x17g\x9d\x19\x07\xb2\x89\xf9\x91SK\xe0\\\x99z
115 branch=default transplant_source=\xa52Q\xcd\xf7\x17g\x9d\x19\x07\xb2\x89\xf9\x91SK\xe0\\\x99z
116
116
117 test transplanted revset
117 test transplanted revset
118
118
119 $ hg log -r 'transplanted()' --template '{rev} {parents} {desc}\n'
119 $ hg log -r 'transplanted()' --template '{rev} {parents} {desc}\n'
120 5 1:d11e3596cc1a b1
120 5 1:d11e3596cc1a b1
121 6 b2
121 6 b2
122 7 b3
122 7 b3
123 $ hg log -r 'transplanted(head())' --template '{rev} {parents} {desc}\n'
123 $ hg log -r 'transplanted(head())' --template '{rev} {parents} {desc}\n'
124 7 b3
124 7 b3
125 $ hg help revisions.transplanted
125 $ hg help revisions.transplanted
126 "transplanted([set])"
126 "transplanted([set])"
127 Transplanted changesets in set, or all transplanted changesets.
127 Transplanted changesets in set, or all transplanted changesets.
128
128
129
129
130 test transplanted keyword
130 test transplanted keyword
131
131
132 $ hg log --template '{rev} {transplanted}\n'
132 $ hg log --template '{rev} {transplanted}\n'
133 7 a53251cdf717679d1907b289f991534be05c997a
133 7 a53251cdf717679d1907b289f991534be05c997a
134 6 722f4667af767100cb15b6a79324bf8abbfe1ef4
134 6 722f4667af767100cb15b6a79324bf8abbfe1ef4
135 5 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21
135 5 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21
136 4
136 4
137 3
137 3
138 2
138 2
139 1
139 1
140 0
140 0
141
141
142 test destination() revset predicate with a transplant of a transplant; new
142 test destination() revset predicate with a transplant of a transplant; new
143 clone so subsequent rollback isn't affected
143 clone so subsequent rollback isn't affected
144 (this also tests that editor is invoked if '--edit' is specified)
144 (this also tests that editor is invoked if '--edit' is specified)
145
145
146 $ hg clone -q . ../destination
146 $ hg clone -q . ../destination
147 $ cd ../destination
147 $ cd ../destination
148 $ hg up -Cq 0
148 $ hg up -Cq 0
149 $ hg branch -q b4
149 $ hg branch -q b4
150 $ hg ci -qm "b4"
150 $ hg ci -qm "b4"
151 $ hg status --rev "7^1" --rev 7
151 $ hg status --rev "7^1" --rev 7
152 A b3
152 A b3
153 $ cat > $TESTTMP/checkeditform.sh <<EOF
153 $ cat > $TESTTMP/checkeditform.sh <<EOF
154 > env | grep HGEDITFORM
154 > env | grep HGEDITFORM
155 > true
155 > true
156 > EOF
156 > EOF
157 $ cat > $TESTTMP/checkeditform-n-cat.sh <<EOF
157 $ cat > $TESTTMP/checkeditform-n-cat.sh <<EOF
158 > env | grep HGEDITFORM
158 > env | grep HGEDITFORM
159 > cat \$*
159 > cat \$*
160 > EOF
160 > EOF
161 $ HGEDITOR="sh $TESTTMP/checkeditform-n-cat.sh" hg transplant --edit 7
161 $ HGEDITOR="sh $TESTTMP/checkeditform-n-cat.sh" hg transplant --edit 7
162 applying ffd6818a3975
162 applying ffd6818a3975
163 HGEDITFORM=transplant.normal
163 HGEDITFORM=transplant.normal
164 b3
164 b3
165
165
166
166
167 HG: Enter commit message. Lines beginning with 'HG:' are removed.
167 HG: Enter commit message. Lines beginning with 'HG:' are removed.
168 HG: Leave message empty to abort commit.
168 HG: Leave message empty to abort commit.
169 HG: --
169 HG: --
170 HG: user: test
170 HG: user: test
171 HG: branch 'b4'
171 HG: branch 'b4'
172 HG: added b3
172 HG: added b3
173 ffd6818a3975 transplanted to 502236fa76bb
173 ffd6818a3975 transplanted to 502236fa76bb
174
174
175
175
176 $ hg log -r 'destination()'
176 $ hg log -r 'destination()'
177 changeset: 5:e234d668f844
177 changeset: 5:e234d668f844
178 parent: 1:d11e3596cc1a
178 parent: 1:d11e3596cc1a
179 user: test
179 user: test
180 date: Thu Jan 01 00:00:00 1970 +0000
180 date: Thu Jan 01 00:00:00 1970 +0000
181 summary: b1
181 summary: b1
182
182
183 changeset: 6:539f377d78df
183 changeset: 6:539f377d78df
184 user: test
184 user: test
185 date: Thu Jan 01 00:00:01 1970 +0000
185 date: Thu Jan 01 00:00:01 1970 +0000
186 summary: b2
186 summary: b2
187
187
188 changeset: 7:ffd6818a3975
188 changeset: 7:ffd6818a3975
189 user: test
189 user: test
190 date: Thu Jan 01 00:00:02 1970 +0000
190 date: Thu Jan 01 00:00:02 1970 +0000
191 summary: b3
191 summary: b3
192
192
193 changeset: 9:502236fa76bb
193 changeset: 9:502236fa76bb
194 branch: b4
194 branch: b4
195 tag: tip
195 tag: tip
196 user: test
196 user: test
197 date: Thu Jan 01 00:00:02 1970 +0000
197 date: Thu Jan 01 00:00:02 1970 +0000
198 summary: b3
198 summary: b3
199
199
200 $ hg log -r 'destination(a53251cdf717)'
200 $ hg log -r 'destination(a53251cdf717)'
201 changeset: 7:ffd6818a3975
201 changeset: 7:ffd6818a3975
202 user: test
202 user: test
203 date: Thu Jan 01 00:00:02 1970 +0000
203 date: Thu Jan 01 00:00:02 1970 +0000
204 summary: b3
204 summary: b3
205
205
206 changeset: 9:502236fa76bb
206 changeset: 9:502236fa76bb
207 branch: b4
207 branch: b4
208 tag: tip
208 tag: tip
209 user: test
209 user: test
210 date: Thu Jan 01 00:00:02 1970 +0000
210 date: Thu Jan 01 00:00:02 1970 +0000
211 summary: b3
211 summary: b3
212
212
213
213
214 test subset parameter in reverse order
214 test subset parameter in reverse order
215 $ hg log -r 'reverse(all()) and destination(a53251cdf717)'
215 $ hg log -r 'reverse(all()) and destination(a53251cdf717)'
216 changeset: 9:502236fa76bb
216 changeset: 9:502236fa76bb
217 branch: b4
217 branch: b4
218 tag: tip
218 tag: tip
219 user: test
219 user: test
220 date: Thu Jan 01 00:00:02 1970 +0000
220 date: Thu Jan 01 00:00:02 1970 +0000
221 summary: b3
221 summary: b3
222
222
223 changeset: 7:ffd6818a3975
223 changeset: 7:ffd6818a3975
224 user: test
224 user: test
225 date: Thu Jan 01 00:00:02 1970 +0000
225 date: Thu Jan 01 00:00:02 1970 +0000
226 summary: b3
226 summary: b3
227
227
228
228
229 back to the original dir
229 back to the original dir
230 $ cd ../rebase
230 $ cd ../rebase
231
231
232 rollback the transplant
232 rollback the transplant
233 $ hg rollback
233 $ hg rollback
234 repository tip rolled back to revision 4 (undo transplant)
234 repository tip rolled back to revision 4 (undo transplant)
235 working directory now based on revision 1
235 working directory now based on revision 1
236 $ hg tip -q
236 $ hg tip -q
237 4:a53251cdf717
237 4:a53251cdf717
238 $ hg parents -q
238 $ hg parents -q
239 1:d11e3596cc1a
239 1:d11e3596cc1a
240 $ hg status
240 $ hg status
241 ? b1
241 ? b1
242 ? b2
242 ? b2
243 ? b3
243 ? b3
244
244
245 $ hg clone ../t ../prune
245 $ hg clone ../t ../prune
246 updating to branch default
246 updating to branch default
247 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
248 $ cd ../prune
248 $ cd ../prune
249
249
250 $ hg up -C 1
250 $ hg up -C 1
251 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
251 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
252
252
253 rebase b onto r1, skipping b2
253 rebase b onto r1, skipping b2
254
254
255 $ hg transplant -a -b tip -p 3
255 $ hg transplant -a -b tip -p 3
256 applying 37a1297eb21b
256 applying 37a1297eb21b
257 37a1297eb21b transplanted to e234d668f844
257 37a1297eb21b transplanted to e234d668f844
258 applying a53251cdf717
258 applying a53251cdf717
259 a53251cdf717 transplanted to 7275fda4d04f
259 a53251cdf717 transplanted to 7275fda4d04f
260 $ hg log --template '{rev} {parents} {desc}\n'
260 $ hg log --template '{rev} {parents} {desc}\n'
261 6 b3
261 6 b3
262 5 1:d11e3596cc1a b1
262 5 1:d11e3596cc1a b1
263 4 b3
263 4 b3
264 3 b2
264 3 b2
265 2 0:17ab29e464c6 b1
265 2 0:17ab29e464c6 b1
266 1 r2
266 1 r2
267 0 r1
267 0 r1
268
268
269 test same-parent transplant with --log
269 test same-parent transplant with --log
270
270
271 $ hg clone -r 1 ../t ../sameparent
271 $ hg clone -r 1 ../t ../sameparent
272 adding changesets
272 adding changesets
273 adding manifests
273 adding manifests
274 adding file changes
274 adding file changes
275 added 2 changesets with 2 changes to 2 files
275 added 2 changesets with 2 changes to 2 files
276 new changesets 17ab29e464c6:d11e3596cc1a
276 new changesets 17ab29e464c6:d11e3596cc1a
277 updating to branch default
277 updating to branch default
278 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
278 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
279 $ cd ../sameparent
279 $ cd ../sameparent
280 $ hg transplant --log -s ../prune 5
280 $ hg transplant --log -s ../prune 5
281 searching for changes
281 searching for changes
282 applying e234d668f844
282 applying e234d668f844
283 e234d668f844 transplanted to e07aea8ecf9c
283 e234d668f844 transplanted to e07aea8ecf9c
284 $ hg log --template '{rev} {parents} {desc}\n'
284 $ hg log --template '{rev} {parents} {desc}\n'
285 2 b1
285 2 b1
286 (transplanted from e234d668f844e1b1a765f01db83a32c0c7bfa170)
286 (transplanted from e234d668f844e1b1a765f01db83a32c0c7bfa170)
287 1 r2
287 1 r2
288 0 r1
288 0 r1
289 remote transplant, and also test that transplant doesn't break with
289 remote transplant, and also test that transplant doesn't break with
290 format-breaking diffopts
290 format-breaking diffopts
291
291
292 $ hg clone -r 1 ../t ../remote
292 $ hg clone -r 1 ../t ../remote
293 adding changesets
293 adding changesets
294 adding manifests
294 adding manifests
295 adding file changes
295 adding file changes
296 added 2 changesets with 2 changes to 2 files
296 added 2 changesets with 2 changes to 2 files
297 new changesets 17ab29e464c6:d11e3596cc1a
297 new changesets 17ab29e464c6:d11e3596cc1a
298 updating to branch default
298 updating to branch default
299 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 $ cd ../remote
300 $ cd ../remote
301 $ hg --config diff.noprefix=True transplant --log -s ../t 2 4
301 $ hg --config diff.noprefix=True transplant --log -s ../t 2 4
302 searching for changes
302 searching for changes
303 applying 37a1297eb21b
303 applying 37a1297eb21b
304 37a1297eb21b transplanted to c19cf0ccb069
304 37a1297eb21b transplanted to c19cf0ccb069
305 applying a53251cdf717
305 applying a53251cdf717
306 a53251cdf717 transplanted to f7fe5bf98525
306 a53251cdf717 transplanted to f7fe5bf98525
307 $ hg log --template '{rev} {parents} {desc}\n'
307 $ hg log --template '{rev} {parents} {desc}\n'
308 3 b3
308 3 b3
309 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
309 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
310 2 b1
310 2 b1
311 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
311 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
312 1 r2
312 1 r2
313 0 r1
313 0 r1
314
314
315 skip previous transplants
315 skip previous transplants
316
316
317 $ hg transplant -s ../t -a -b 4
317 $ hg transplant -s ../t -a -b 4
318 searching for changes
318 searching for changes
319 applying 722f4667af76
319 applying 722f4667af76
320 722f4667af76 transplanted to 47156cd86c0b
320 722f4667af76 transplanted to 47156cd86c0b
321 $ hg log --template '{rev} {parents} {desc}\n'
321 $ hg log --template '{rev} {parents} {desc}\n'
322 4 b2
322 4 b2
323 3 b3
323 3 b3
324 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
324 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
325 2 b1
325 2 b1
326 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
326 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
327 1 r2
327 1 r2
328 0 r1
328 0 r1
329
329
330 skip local changes transplanted to the source
330 skip local changes transplanted to the source
331
331
332 $ echo b4 > b4
332 $ echo b4 > b4
333 $ hg ci -Amb4 -d '3 0'
333 $ hg ci -Amb4 -d '3 0'
334 adding b4
334 adding b4
335 $ hg clone ../t ../pullback
335 $ hg clone ../t ../pullback
336 updating to branch default
336 updating to branch default
337 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
337 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
338 $ cd ../pullback
338 $ cd ../pullback
339 $ hg transplant -s ../remote -a -b tip
339 $ hg transplant -s ../remote -a -b tip
340 searching for changes
340 searching for changes
341 applying 4333daefcb15
341 applying 4333daefcb15
342 4333daefcb15 transplanted to 5f42c04e07cc
342 4333daefcb15 transplanted to 5f42c04e07cc
343
343
344
344
345 remote transplant with pull
345 remote transplant with pull
346
346
347 $ hg serve -R ../t -p $HGPORT -d --pid-file=../t.pid
347 $ hg serve -R ../t -p $HGPORT -d --pid-file=../t.pid
348 $ cat ../t.pid >> $DAEMON_PIDS
348 $ cat ../t.pid >> $DAEMON_PIDS
349
349
350 $ hg clone -r 0 ../t ../rp
350 $ hg clone -r 0 ../t ../rp
351 adding changesets
351 adding changesets
352 adding manifests
352 adding manifests
353 adding file changes
353 adding file changes
354 added 1 changesets with 1 changes to 1 files
354 added 1 changesets with 1 changes to 1 files
355 new changesets 17ab29e464c6
355 new changesets 17ab29e464c6
356 updating to branch default
356 updating to branch default
357 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
357 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
358 $ cd ../rp
358 $ cd ../rp
359 $ hg transplant -s http://localhost:$HGPORT/ 37a1297eb21b a53251cdf717
359 $ hg transplant -s http://localhost:$HGPORT/ 37a1297eb21b a53251cdf717
360 searching for changes
360 searching for changes
361 searching for changes
361 searching for changes
362 adding changesets
362 adding changesets
363 adding manifests
363 adding manifests
364 adding file changes
364 adding file changes
365 applying a53251cdf717
365 applying a53251cdf717
366 a53251cdf717 transplanted to 8d9279348abb
366 a53251cdf717 transplanted to 8d9279348abb
367 added 1 changesets with 1 changes to 1 files
367 added 1 changesets with 1 changes to 1 files
368 $ hg log --template '{rev} {parents} {desc}\n'
368 $ hg log --template '{rev} {parents} {desc}\n'
369 2 b3
369 2 b3
370 1 b1
370 1 b1
371 0 r1
371 0 r1
372
372
373 remote transplant without pull
373 remote transplant without pull
374 (It was using "2" and "4" (as the previous transplant used to) which referenced
374 (It was using "2" and "4" (as the previous transplant used to) which referenced
375 revision different from one run to another)
375 revision different from one run to another)
376
376
377 $ hg pull -q http://localhost:$HGPORT/
377 $ hg pull -q http://localhost:$HGPORT/
378 $ hg transplant -s http://localhost:$HGPORT/ 8d9279348abb 722f4667af76
378 $ hg transplant -s http://localhost:$HGPORT/ 8d9279348abb 722f4667af76
379 skipping already applied revision 2:8d9279348abb
379 skipping already applied revision 2:8d9279348abb
380 applying 722f4667af76
380 applying 722f4667af76
381 722f4667af76 transplanted to 76e321915884
381 722f4667af76 transplanted to 76e321915884
382
382
383
383
384 transplant --continue and --stop behaviour
384 transplant --continue and --stop behaviour
385
385
386 $ hg init ../tc
386 $ hg init ../tc
387 $ cd ../tc
387 $ cd ../tc
388 $ cat <<EOF > foo
388 $ cat <<EOF > foo
389 > foo
389 > foo
390 > bar
390 > bar
391 > baz
391 > baz
392 > EOF
392 > EOF
393 $ echo toremove > toremove
393 $ echo toremove > toremove
394 $ echo baz > baz
394 $ echo baz > baz
395 $ hg ci -Amfoo
395 $ hg ci -Amfoo
396 adding baz
396 adding baz
397 adding foo
397 adding foo
398 adding toremove
398 adding toremove
399 $ cat <<EOF > foo
399 $ cat <<EOF > foo
400 > foo2
400 > foo2
401 > bar2
401 > bar2
402 > baz2
402 > baz2
403 > EOF
403 > EOF
404 $ rm toremove
404 $ rm toremove
405 $ echo added > added
405 $ echo added > added
406 $ hg ci -Amfoo2
406 $ hg ci -Amfoo2
407 adding added
407 adding added
408 removing toremove
408 removing toremove
409 $ echo bar > bar
409 $ echo bar > bar
410 $ cat > baz <<EOF
410 $ cat > baz <<EOF
411 > before baz
411 > before baz
412 > baz
412 > baz
413 > after baz
413 > after baz
414 > EOF
414 > EOF
415 $ hg ci -Ambar
415 $ hg ci -Ambar
416 adding bar
416 adding bar
417 $ echo bar2 >> bar
417 $ echo bar2 >> bar
418 $ hg ci -mbar2
418 $ hg ci -mbar2
419 $ hg up 0
419 $ hg up 0
420 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
420 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
421 $ echo foobar > foo
421 $ echo foobar > foo
422 $ hg ci -mfoobar
422 $ hg ci -mfoobar
423 created new head
423 created new head
424
424
425 Repo log before transplant
425 Repo log before transplant
426 $ hg glog
426 $ hg glog
427 @ changeset: 4:e8643552fde5
427 @ changeset: 4:e8643552fde5
428 | tag: tip
428 | tag: tip
429 | parent: 0:493149fa1541
429 | parent: 0:493149fa1541
430 | user: test
430 | user: test
431 | date: Thu Jan 01 00:00:00 1970 +0000
431 | date: Thu Jan 01 00:00:00 1970 +0000
432 | summary: foobar
432 | summary: foobar
433 |
433 |
434 | o changeset: 3:1dab759070cf
434 | o changeset: 3:1dab759070cf
435 | | user: test
435 | | user: test
436 | | date: Thu Jan 01 00:00:00 1970 +0000
436 | | date: Thu Jan 01 00:00:00 1970 +0000
437 | | summary: bar2
437 | | summary: bar2
438 | |
438 | |
439 | o changeset: 2:9d6d6b5a8275
439 | o changeset: 2:9d6d6b5a8275
440 | | user: test
440 | | user: test
441 | | date: Thu Jan 01 00:00:00 1970 +0000
441 | | date: Thu Jan 01 00:00:00 1970 +0000
442 | | summary: bar
442 | | summary: bar
443 | |
443 | |
444 | o changeset: 1:46ae92138f3c
444 | o changeset: 1:46ae92138f3c
445 |/ user: test
445 |/ user: test
446 | date: Thu Jan 01 00:00:00 1970 +0000
446 | date: Thu Jan 01 00:00:00 1970 +0000
447 | summary: foo2
447 | summary: foo2
448 |
448 |
449 o changeset: 0:493149fa1541
449 o changeset: 0:493149fa1541
450 user: test
450 user: test
451 date: Thu Jan 01 00:00:00 1970 +0000
451 date: Thu Jan 01 00:00:00 1970 +0000
452 summary: foo
452 summary: foo
453
453
454 $ hg transplant 1:3
454 $ hg transplant 1:3
455 applying 46ae92138f3c
455 applying 46ae92138f3c
456 patching file foo
456 patching file foo
457 Hunk #1 FAILED at 0
457 Hunk #1 FAILED at 0
458 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
458 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
459 patch failed to apply
459 patch failed to apply
460 abort: fix up the working directory and run hg transplant --continue
460 abort: fix up the working directory and run hg transplant --continue
461 [255]
461 [255]
462
462
463 $ hg transplant --stop
463 $ hg transplant --stop
464 stopped the interrupted transplant
464 stopped the interrupted transplant
465 working directory is now at e8643552fde5
465 working directory is now at e8643552fde5
466 Repo log after abort
466 Repo log after abort
467 $ hg glog
467 $ hg glog
468 @ changeset: 4:e8643552fde5
468 @ changeset: 4:e8643552fde5
469 | tag: tip
469 | tag: tip
470 | parent: 0:493149fa1541
470 | parent: 0:493149fa1541
471 | user: test
471 | user: test
472 | date: Thu Jan 01 00:00:00 1970 +0000
472 | date: Thu Jan 01 00:00:00 1970 +0000
473 | summary: foobar
473 | summary: foobar
474 |
474 |
475 | o changeset: 3:1dab759070cf
475 | o changeset: 3:1dab759070cf
476 | | user: test
476 | | user: test
477 | | date: Thu Jan 01 00:00:00 1970 +0000
477 | | date: Thu Jan 01 00:00:00 1970 +0000
478 | | summary: bar2
478 | | summary: bar2
479 | |
479 | |
480 | o changeset: 2:9d6d6b5a8275
480 | o changeset: 2:9d6d6b5a8275
481 | | user: test
481 | | user: test
482 | | date: Thu Jan 01 00:00:00 1970 +0000
482 | | date: Thu Jan 01 00:00:00 1970 +0000
483 | | summary: bar
483 | | summary: bar
484 | |
484 | |
485 | o changeset: 1:46ae92138f3c
485 | o changeset: 1:46ae92138f3c
486 |/ user: test
486 |/ user: test
487 | date: Thu Jan 01 00:00:00 1970 +0000
487 | date: Thu Jan 01 00:00:00 1970 +0000
488 | summary: foo2
488 | summary: foo2
489 |
489 |
490 o changeset: 0:493149fa1541
490 o changeset: 0:493149fa1541
491 user: test
491 user: test
492 date: Thu Jan 01 00:00:00 1970 +0000
492 date: Thu Jan 01 00:00:00 1970 +0000
493 summary: foo
493 summary: foo
494
494
495 $ hg transplant 1:3
495 $ hg transplant 1:3
496 applying 46ae92138f3c
496 applying 46ae92138f3c
497 file added already exists
497 file added already exists
498 1 out of 1 hunks FAILED -- saving rejects to file added.rej
498 1 out of 1 hunks FAILED -- saving rejects to file added.rej
499 patching file foo
499 patching file foo
500 Hunk #1 FAILED at 0
500 Hunk #1 FAILED at 0
501 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
501 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
502 patch failed to apply
502 patch failed to apply
503 abort: fix up the working directory and run hg transplant --continue
503 abort: fix up the working directory and run hg transplant --continue
504 [255]
504 [255]
505
505
506 transplant -c shouldn't use an old changeset
506 transplant -c shouldn't use an old changeset
507
507
508 $ hg up -C
508 $ hg up -C
509 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
509 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 updated to "e8643552fde5: foobar"
510 updated to "e8643552fde5: foobar"
511 1 other heads for branch "default"
511 1 other heads for branch "default"
512 $ rm added
512 $ rm added
513 $ hg continue
513 $ hg continue
514 abort: no transplant to continue (continueflag !)
514 abort: no transplant to continue (continueflag !)
515 abort: no operation in progress (no-continueflag !)
515 abort: no operation in progress (no-continueflag !)
516 [255]
516 [255]
517 $ hg transplant --stop
517 $ hg transplant --stop
518 abort: no interrupted transplant found
518 abort: no interrupted transplant found
519 [255]
519 [255]
520 $ hg transplant 1
520 $ hg transplant 1
521 applying 46ae92138f3c
521 applying 46ae92138f3c
522 patching file foo
522 patching file foo
523 Hunk #1 FAILED at 0
523 Hunk #1 FAILED at 0
524 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
524 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
525 patch failed to apply
525 patch failed to apply
526 abort: fix up the working directory and run hg transplant --continue
526 abort: fix up the working directory and run hg transplant --continue
527 [255]
527 [255]
528 $ cp .hg/transplant/journal .hg/transplant/journal.orig
528 $ cp .hg/transplant/journal .hg/transplant/journal.orig
529 $ cat .hg/transplant/journal
529 $ cat .hg/transplant/journal
530 # User test
530 # User test
531 # Date 0 0
531 # Date 0 0
532 # Node ID 46ae92138f3ce0249f6789650403286ead052b6d
532 # Node ID 46ae92138f3ce0249f6789650403286ead052b6d
533 # Parent e8643552fde58f57515e19c4b373a57c96e62af3
533 # Parent e8643552fde58f57515e19c4b373a57c96e62af3
534 foo2
534 foo2
535 $ grep -v 'Date' .hg/transplant/journal.orig > .hg/transplant/journal
535 $ grep -v 'Date' .hg/transplant/journal.orig > .hg/transplant/journal
536 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e
536 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e
537 abort: filter corrupted changeset (no user or date)
537 abort: filter corrupted changeset (no user or date)
538 [255]
538 [255]
539 $ cp .hg/transplant/journal.orig .hg/transplant/journal
539 $ cp .hg/transplant/journal.orig .hg/transplant/journal
540 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e
540 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e
541 HGEDITFORM=transplant.normal
541 HGEDITFORM=transplant.normal
542 46ae92138f3c transplanted as 9159dada197d
542 46ae92138f3c transplanted as 9159dada197d
543 $ hg transplant 1:3
543 $ hg transplant 1:3
544 skipping already applied revision 1:46ae92138f3c
544 skipping already applied revision 1:46ae92138f3c
545 applying 9d6d6b5a8275
545 applying 9d6d6b5a8275
546 9d6d6b5a8275 transplanted to 2d17a10c922f
546 9d6d6b5a8275 transplanted to 2d17a10c922f
547 applying 1dab759070cf
547 applying 1dab759070cf
548 1dab759070cf transplanted to e06a69927eb0
548 1dab759070cf transplanted to e06a69927eb0
549 $ hg locate
549 $ hg locate
550 added
550 added
551 bar
551 bar
552 baz
552 baz
553 foo
553 foo
554
554
555 test multiple revisions, --continue and hg status --verbose
555 test multiple revisions, --continue and hg status --verbose
556
556
557 $ hg up -qC 0
557 $ hg up -qC 0
558 $ echo bazbaz > baz
558 $ echo bazbaz > baz
559 $ hg ci -Am anotherbaz baz
559 $ hg ci -Am anotherbaz baz
560 created new head
560 created new head
561 $ hg transplant 1:3
561 $ hg transplant 1:3
562 applying 46ae92138f3c
562 applying 46ae92138f3c
563 46ae92138f3c transplanted to 1024233ea0ba
563 46ae92138f3c transplanted to 1024233ea0ba
564 applying 9d6d6b5a8275
564 applying 9d6d6b5a8275
565 patching file baz
565 patching file baz
566 Hunk #1 FAILED at 0
566 Hunk #1 FAILED at 0
567 1 out of 1 hunks FAILED -- saving rejects to file baz.rej
567 1 out of 1 hunks FAILED -- saving rejects to file baz.rej
568 patch failed to apply
568 patch failed to apply
569 abort: fix up the working directory and run hg transplant --continue
569 abort: fix up the working directory and run hg transplant --continue
570 [255]
570 [255]
571 $ hg transplant 1:3
571 $ hg transplant 1:3
572 abort: transplant in progress
572 abort: transplant in progress
573 (use 'hg transplant --continue' or 'hg transplant --stop')
573 (use 'hg transplant --continue' or 'hg transplant --stop')
574 [255]
574 [255]
575 $ hg status -v
575 $ hg status -v
576 A bar
576 A bar
577 ? added.rej
577 ? added.rej
578 ? baz.rej
578 ? baz.rej
579 ? foo.rej
579 ? foo.rej
580 # The repository is in an unfinished *transplant* state.
580 # The repository is in an unfinished *transplant* state.
581
581
582 # To continue: hg transplant --continue
582 # To continue: hg transplant --continue
583 # To stop: hg transplant --stop
583 # To stop: hg transplant --stop
584
584
585 $ echo fixed > baz
585 $ echo fixed > baz
586 $ hg continue
586 $ hg continue
587 9d6d6b5a8275 transplanted as d80c49962290
587 9d6d6b5a8275 transplanted as d80c49962290
588 applying 1dab759070cf
588 applying 1dab759070cf
589 1dab759070cf transplanted to aa0ffe6bd5ae
589 1dab759070cf transplanted to aa0ffe6bd5ae
590 $ cd ..
590 $ cd ..
591
591
592 Issue1111: Test transplant --merge
592 Issue1111: Test transplant --merge
593
593
594 $ hg init t1111
594 $ hg init t1111
595 $ cd t1111
595 $ cd t1111
596 $ echo a > a
596 $ echo a > a
597 $ hg ci -Am adda
597 $ hg ci -Am adda
598 adding a
598 adding a
599 $ echo b >> a
599 $ echo b >> a
600 $ hg ci -m appendb
600 $ hg ci -m appendb
601 $ echo c >> a
601 $ echo c >> a
602 $ hg ci -m appendc
602 $ hg ci -m appendc
603 $ hg up -C 0
603 $ hg up -C 0
604 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
604 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
605 $ echo d >> a
605 $ echo d >> a
606 $ hg ci -m appendd
606 $ hg ci -m appendd
607 created new head
607 created new head
608
608
609 transplant
609 transplant
610
610
611 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant -m 1 -e
611 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant -m 1 -e
612 applying 42dc4432fd35
612 applying 42dc4432fd35
613 HGEDITFORM=transplant.merge
613 HGEDITFORM=transplant.merge
614 1:42dc4432fd35 merged at a9f4acbac129
614 1:42dc4432fd35 merged at a9f4acbac129
615 $ hg update -q -C 2
615 $ hg update -q -C 2
616 $ cat > a <<EOF
616 $ cat > a <<EOF
617 > x
617 > x
618 > y
618 > y
619 > z
619 > z
620 > EOF
620 > EOF
621 $ hg commit -m replace
621 $ hg commit -m replace
622 $ hg update -q -C 4
622 $ hg update -q -C 4
623 $ hg transplant -m 5
623 $ hg transplant -m 5
624 applying 600a3cdcb41d
624 applying 600a3cdcb41d
625 patching file a
625 patching file a
626 Hunk #1 FAILED at 0
626 Hunk #1 FAILED at 0
627 1 out of 1 hunks FAILED -- saving rejects to file a.rej
627 1 out of 1 hunks FAILED -- saving rejects to file a.rej
628 patch failed to apply
628 patch failed to apply
629 abort: fix up the working directory and run hg transplant --continue
629 abort: fix up the working directory and run hg transplant --continue
630 [255]
630 [255]
631 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e
631 $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e
632 HGEDITFORM=transplant.merge
632 HGEDITFORM=transplant.merge
633 600a3cdcb41d transplanted as a3f88be652e0
633 600a3cdcb41d transplanted as a3f88be652e0
634
634
635 $ cd ..
635 $ cd ..
636
636
637 test transplant into empty repository
637 test transplant into empty repository
638
638
639 $ hg init empty
639 $ hg init empty
640 $ cd empty
640 $ cd empty
641 $ hg transplant -s ../t -b tip -a
641 $ hg transplant -s ../t -b tip -a
642 adding changesets
642 adding changesets
643 adding manifests
643 adding manifests
644 adding file changes
644 adding file changes
645 added 4 changesets with 4 changes to 4 files
645 added 4 changesets with 4 changes to 4 files
646 new changesets 17ab29e464c6:a53251cdf717
646 new changesets 17ab29e464c6:a53251cdf717
647
647
648 test "--merge" causing pull from source repository on local host
648 test "--merge" causing pull from source repository on local host
649
649
650 $ hg --config extensions.mq= -q strip 2
650 $ hg --config extensions.mq= -q strip 2
651 $ hg transplant -s ../t --merge tip
651 $ hg transplant -s ../t --merge tip
652 searching for changes
652 searching for changes
653 searching for changes
653 searching for changes
654 adding changesets
654 adding changesets
655 adding manifests
655 adding manifests
656 adding file changes
656 adding file changes
657 applying a53251cdf717
657 applying a53251cdf717
658 4:a53251cdf717 merged at 4831f4dc831a
658 4:a53251cdf717 merged at 4831f4dc831a
659 added 2 changesets with 2 changes to 2 files
659 added 2 changesets with 2 changes to 2 files
660
660
661 test interactive transplant
661 test interactive transplant
662
662
663 $ hg --config extensions.strip= -q strip 0
663 $ hg --config extensions.strip= -q strip 0
664 $ hg -R ../t log -G --template "{rev}:{node|short}"
664 $ hg -R ../t log -G --template "{rev}:{node|short}"
665 @ 4:a53251cdf717
665 @ 4:a53251cdf717
666 |
666 |
667 o 3:722f4667af76
667 o 3:722f4667af76
668 |
668 |
669 o 2:37a1297eb21b
669 o 2:37a1297eb21b
670 |
670 |
671 | o 1:d11e3596cc1a
671 | o 1:d11e3596cc1a
672 |/
672 |/
673 o 0:17ab29e464c6
673 o 0:17ab29e464c6
674
674
675 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
675 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
676 > ?
676 > ?
677 > x
677 > x
678 > q
678 > q
679 > EOF
679 > EOF
680 0:17ab29e464c6
680 0:17ab29e464c6
681 apply changeset? [ynmpcq?]: ?
681 apply changeset? [ynmpcq?]: ?
682 y: yes, transplant this changeset
682 y: yes, transplant this changeset
683 n: no, skip this changeset
683 n: no, skip this changeset
684 m: merge at this changeset
684 m: merge at this changeset
685 p: show patch
685 p: show patch
686 c: commit selected changesets
686 c: commit selected changesets
687 q: quit and cancel transplant
687 q: quit and cancel transplant
688 ?: ? (show this help)
688 ?: ? (show this help)
689 apply changeset? [ynmpcq?]: x
689 apply changeset? [ynmpcq?]: x
690 unrecognized response
690 unrecognized response
691 apply changeset? [ynmpcq?]: q
691 apply changeset? [ynmpcq?]: q
692 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
692 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
693 > p
693 > p
694 > y
694 > y
695 > n
695 > n
696 > n
696 > n
697 > m
697 > m
698 > c
698 > c
699 > EOF
699 > EOF
700 0:17ab29e464c6
700 0:17ab29e464c6
701 apply changeset? [ynmpcq?]: p
701 apply changeset? [ynmpcq?]: p
702 diff -r 000000000000 -r 17ab29e464c6 r1
702 diff -r 000000000000 -r 17ab29e464c6 r1
703 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
703 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
704 +++ b/r1 Thu Jan 01 00:00:00 1970 +0000
704 +++ b/r1 Thu Jan 01 00:00:00 1970 +0000
705 @@ -0,0 +1,1 @@
705 @@ -0,0 +1,1 @@
706 +r1
706 +r1
707 apply changeset? [ynmpcq?]: y
707 apply changeset? [ynmpcq?]: y
708 1:d11e3596cc1a
708 1:d11e3596cc1a
709 apply changeset? [ynmpcq?]: n
709 apply changeset? [ynmpcq?]: n
710 2:37a1297eb21b
710 2:37a1297eb21b
711 apply changeset? [ynmpcq?]: n
711 apply changeset? [ynmpcq?]: n
712 3:722f4667af76
712 3:722f4667af76
713 apply changeset? [ynmpcq?]: m
713 apply changeset? [ynmpcq?]: m
714 4:a53251cdf717
714 4:a53251cdf717
715 apply changeset? [ynmpcq?]: c
715 apply changeset? [ynmpcq?]: c
716 $ hg log -G --template "{node|short}"
716 $ hg log -G --template "{node|short}"
717 @ 88be5dde5260
717 @ 88be5dde5260
718 |\
718 |\
719 | o 722f4667af76
719 | o 722f4667af76
720 | |
720 | |
721 | o 37a1297eb21b
721 | o 37a1297eb21b
722 |/
722 |/
723 o 17ab29e464c6
723 o 17ab29e464c6
724
724
725 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
725 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
726 > x
726 > x
727 > ?
727 > ?
728 > y
728 > y
729 > q
729 > q
730 > EOF
730 > EOF
731 1:d11e3596cc1a
731 1:d11e3596cc1a
732 apply changeset? [ynmpcq?]: x
732 apply changeset? [ynmpcq?]: x
733 unrecognized response
733 unrecognized response
734 apply changeset? [ynmpcq?]: ?
734 apply changeset? [ynmpcq?]: ?
735 y: yes, transplant this changeset
735 y: yes, transplant this changeset
736 n: no, skip this changeset
736 n: no, skip this changeset
737 m: merge at this changeset
737 m: merge at this changeset
738 p: show patch
738 p: show patch
739 c: commit selected changesets
739 c: commit selected changesets
740 q: quit and cancel transplant
740 q: quit and cancel transplant
741 ?: ? (show this help)
741 ?: ? (show this help)
742 apply changeset? [ynmpcq?]: y
742 apply changeset? [ynmpcq?]: y
743 4:a53251cdf717
743 4:a53251cdf717
744 apply changeset? [ynmpcq?]: q
744 apply changeset? [ynmpcq?]: q
745 $ hg heads --template "{node|short}\n"
745 $ hg heads --template "{node|short}\n"
746 88be5dde5260
746 88be5dde5260
747
747
748 $ cd ..
748 $ cd ..
749
749
750
750
751 #if unix-permissions system-sh
751 #if unix-permissions system-sh
752
752
753 test filter
753 test filter
754
754
755 $ hg init filter
755 $ hg init filter
756 $ cd filter
756 $ cd filter
757 $ cat <<'EOF' >test-filter
757 $ cat <<'EOF' >test-filter
758 > #!/bin/sh
758 > #!/bin/sh
759 > sed 's/r1/r2/' $1 > $1.new
759 > sed 's/r1/r2/' $1 > $1.new
760 > mv $1.new $1
760 > mv $1.new $1
761 > EOF
761 > EOF
762 $ chmod +x test-filter
762 $ chmod +x test-filter
763 $ hg transplant -s ../t -b tip -a --filter ./test-filter
763 $ hg transplant -s ../t -b tip -a --filter ./test-filter
764 filtering * (glob)
764 filtering * (glob)
765 applying 17ab29e464c6
765 applying 17ab29e464c6
766 17ab29e464c6 transplanted to e9ffc54ea104
766 17ab29e464c6 transplanted to e9ffc54ea104
767 filtering * (glob)
767 filtering * (glob)
768 applying 37a1297eb21b
768 applying 37a1297eb21b
769 37a1297eb21b transplanted to 348b36d0b6a5
769 37a1297eb21b transplanted to 348b36d0b6a5
770 filtering * (glob)
770 filtering * (glob)
771 applying 722f4667af76
771 applying 722f4667af76
772 722f4667af76 transplanted to 0aa6979afb95
772 722f4667af76 transplanted to 0aa6979afb95
773 filtering * (glob)
773 filtering * (glob)
774 applying a53251cdf717
774 applying a53251cdf717
775 a53251cdf717 transplanted to 14f8512272b5
775 a53251cdf717 transplanted to 14f8512272b5
776 $ hg log --template '{rev} {parents} {desc}\n'
776 $ hg log --template '{rev} {parents} {desc}\n'
777 3 b3
777 3 b3
778 2 b2
778 2 b2
779 1 b1
779 1 b1
780 0 r2
780 0 r2
781 $ cd ..
781 $ cd ..
782
782
783
783
784 test filter with failed patch
784 test filter with failed patch
785
785
786 $ cd filter
786 $ cd filter
787 $ hg up 0
787 $ hg up 0
788 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
788 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
789 $ echo foo > b1
789 $ echo foo > b1
790 $ hg ci -Am foo
790 $ hg ci -Am foo
791 adding b1
791 adding b1
792 adding test-filter
792 adding test-filter
793 created new head
793 created new head
794 $ hg transplant 1 --filter ./test-filter
794 $ hg transplant 1 --filter ./test-filter
795 filtering * (glob)
795 filtering * (glob)
796 applying 348b36d0b6a5
796 applying 348b36d0b6a5
797 file b1 already exists
797 file b1 already exists
798 1 out of 1 hunks FAILED -- saving rejects to file b1.rej
798 1 out of 1 hunks FAILED -- saving rejects to file b1.rej
799 patch failed to apply
799 patch failed to apply
800 abort: fix up the working directory and run hg transplant --continue
800 abort: fix up the working directory and run hg transplant --continue
801 [255]
801 [255]
802 $ cd ..
802 $ cd ..
803
803
804 test environment passed to filter
804 test environment passed to filter
805
805
806 $ hg init filter-environment
806 $ hg init filter-environment
807 $ cd filter-environment
807 $ cd filter-environment
808 $ cat <<'EOF' >test-filter-environment
808 $ cat <<'EOF' >test-filter-environment
809 > #!/bin/sh
809 > #!/bin/sh
810 > echo "Transplant by $HGUSER" >> $1
810 > echo "Transplant by $HGUSER" >> $1
811 > echo "Transplant from rev $HGREVISION" >> $1
811 > echo "Transplant from rev $HGREVISION" >> $1
812 > EOF
812 > EOF
813 $ chmod +x test-filter-environment
813 $ chmod +x test-filter-environment
814 $ hg transplant -s ../t --filter ./test-filter-environment 0
814 $ hg transplant -s ../t --filter ./test-filter-environment 0
815 filtering * (glob)
815 filtering * (glob)
816 applying 17ab29e464c6
816 applying 17ab29e464c6
817 17ab29e464c6 transplanted to 5190e68026a0
817 17ab29e464c6 transplanted to 5190e68026a0
818
818
819 $ hg log --template '{rev} {parents} {desc}\n'
819 $ hg log --template '{rev} {parents} {desc}\n'
820 0 r1
820 0 r1
821 Transplant by test
821 Transplant by test
822 Transplant from rev 17ab29e464c6ca53e329470efe2a9918ac617a6f
822 Transplant from rev 17ab29e464c6ca53e329470efe2a9918ac617a6f
823 $ cd ..
823 $ cd ..
824
824
825 test transplant with filter handles invalid changelog
825 test transplant with filter handles invalid changelog
826
826
827 $ hg init filter-invalid-log
827 $ hg init filter-invalid-log
828 $ cd filter-invalid-log
828 $ cd filter-invalid-log
829 $ cat <<'EOF' >test-filter-invalid-log
829 $ cat <<'EOF' >test-filter-invalid-log
830 > #!/bin/sh
830 > #!/bin/sh
831 > echo "" > $1
831 > echo "" > $1
832 > EOF
832 > EOF
833 $ chmod +x test-filter-invalid-log
833 $ chmod +x test-filter-invalid-log
834 $ hg transplant -s ../t --filter ./test-filter-invalid-log 0
834 $ hg transplant -s ../t --filter ./test-filter-invalid-log 0
835 filtering * (glob)
835 filtering * (glob)
836 abort: filter corrupted changeset (no user or date)
836 abort: filter corrupted changeset (no user or date)
837 [255]
837 [255]
838 $ cd ..
838 $ cd ..
839
839
840 #endif
840 #endif
841
841
842
842
843 test with a win32ext like setup (differing EOLs)
843 test with a win32ext like setup (differing EOLs)
844
844
845 $ hg init twin1
845 $ hg init twin1
846 $ cd twin1
846 $ cd twin1
847 $ echo a > a
847 $ echo a > a
848 $ echo b > b
848 $ echo b > b
849 $ echo b >> b
849 $ echo b >> b
850 $ hg ci -Am t
850 $ hg ci -Am t
851 adding a
851 adding a
852 adding b
852 adding b
853 $ echo a > b
853 $ echo a > b
854 $ echo b >> b
854 $ echo b >> b
855 $ hg ci -m changeb
855 $ hg ci -m changeb
856 $ cd ..
856 $ cd ..
857
857
858 $ hg init twin2
858 $ hg init twin2
859 $ cd twin2
859 $ cd twin2
860 $ echo '[patch]' >> .hg/hgrc
860 $ echo '[patch]' >> .hg/hgrc
861 $ echo 'eol = crlf' >> .hg/hgrc
861 $ echo 'eol = crlf' >> .hg/hgrc
862 $ "$PYTHON" -c "open('b', 'wb').write(b'b\r\nb\r\n')"
862 $ "$PYTHON" -c "open('b', 'wb').write(b'b\r\nb\r\n')"
863 $ hg ci -Am addb
863 $ hg ci -Am addb
864 adding b
864 adding b
865 $ hg transplant -s ../twin1 tip
865 $ hg transplant -s ../twin1 tip
866 searching for changes
866 searching for changes
867 warning: repository is unrelated
867 warning: repository is unrelated
868 applying 2e849d776c17
868 applying 2e849d776c17
869 2e849d776c17 transplanted to 8e65bebc063e
869 2e849d776c17 transplanted to 8e65bebc063e
870 $ cat b
870 $ cat b
871 a\r (esc)
871 a\r (esc)
872 b\r (esc)
872 b\r (esc)
873 $ cd ..
873 $ cd ..
874
874
875 test transplant with merge changeset is skipped
875 test transplant with merge changeset is skipped
876
876
877 $ hg init merge1a
877 $ hg init merge1a
878 $ cd merge1a
878 $ cd merge1a
879 $ echo a > a
879 $ echo a > a
880 $ hg ci -Am a
880 $ hg ci -Am a
881 adding a
881 adding a
882 $ hg branch b
882 $ hg branch b
883 marked working directory as branch b
883 marked working directory as branch b
884 (branches are permanent and global, did you want a bookmark?)
884 (branches are permanent and global, did you want a bookmark?)
885 $ hg ci -m branchb
885 $ hg ci -m branchb
886 $ echo b > b
886 $ echo b > b
887 $ hg ci -Am b
887 $ hg ci -Am b
888 adding b
888 adding b
889 $ hg update default
889 $ hg update default
890 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
890 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
891 $ hg merge b
891 $ hg merge b
892 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
892 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
893 (branch merge, don't forget to commit)
893 (branch merge, don't forget to commit)
894 $ hg ci -m mergeb
894 $ hg ci -m mergeb
895 $ cd ..
895 $ cd ..
896
896
897 $ hg init merge1b
897 $ hg init merge1b
898 $ cd merge1b
898 $ cd merge1b
899 $ hg transplant -s ../merge1a tip
899 $ hg transplant -s ../merge1a tip
900 $ cd ..
900 $ cd ..
901
901
902 test transplant with merge changeset accepts --parent
902 test transplant with merge changeset accepts --parent
903
903
904 $ hg init merge2a
904 $ hg init merge2a
905 $ cd merge2a
905 $ cd merge2a
906 $ echo a > a
906 $ echo a > a
907 $ hg ci -Am a
907 $ hg ci -Am a
908 adding a
908 adding a
909 $ hg branch b
909 $ hg branch b
910 marked working directory as branch b
910 marked working directory as branch b
911 (branches are permanent and global, did you want a bookmark?)
911 (branches are permanent and global, did you want a bookmark?)
912 $ hg ci -m branchb
912 $ hg ci -m branchb
913 $ echo b > b
913 $ echo b > b
914 $ hg ci -Am b
914 $ hg ci -Am b
915 adding b
915 adding b
916 $ hg update default
916 $ hg update default
917 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
917 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
918 $ hg merge b
918 $ hg merge b
919 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
919 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
920 (branch merge, don't forget to commit)
920 (branch merge, don't forget to commit)
921 $ hg ci -m mergeb
921 $ hg ci -m mergeb
922 $ cd ..
922 $ cd ..
923
923
924 $ hg init merge2b
924 $ hg init merge2b
925 $ cd merge2b
925 $ cd merge2b
926 $ hg transplant -s ../merge2a --parent tip tip
926 $ hg transplant -s ../merge2a --parent tip tip
927 abort: be9f9b39483f is not a parent of be9f9b39483f
927 abort: be9f9b39483f is not a parent of be9f9b39483f
928 [255]
928 [255]
929 $ hg transplant -s ../merge2a --parent 0 tip
929 $ hg transplant -s ../merge2a --parent 0 tip
930 applying be9f9b39483f
930 applying be9f9b39483f
931 be9f9b39483f transplanted to 9959e51f94d1
931 be9f9b39483f transplanted to 9959e51f94d1
932 $ cd ..
932 $ cd ..
933
933
934 test transplanting a patch turning into a no-op
934 test transplanting a patch turning into a no-op
935
935
936 $ hg init binarysource
936 $ hg init binarysource
937 $ cd binarysource
937 $ cd binarysource
938 $ echo a > a
938 $ echo a > a
939 $ hg ci -Am adda a
939 $ hg ci -Am adda a
940 >>> open('b', 'wb').write(b'\0b1') and None
940 >>> open('b', 'wb').write(b'\0b1') and None
941 $ hg ci -Am addb b
941 $ hg ci -Am addb b
942 >>> open('b', 'wb').write(b'\0b2') and None
942 >>> open('b', 'wb').write(b'\0b2') and None
943 $ hg ci -m changeb b
943 $ hg ci -m changeb b
944 $ cd ..
944 $ cd ..
945
945
946 $ hg clone -r0 binarysource binarydest
946 $ hg clone -r0 binarysource binarydest
947 adding changesets
947 adding changesets
948 adding manifests
948 adding manifests
949 adding file changes
949 adding file changes
950 added 1 changesets with 1 changes to 1 files
950 added 1 changesets with 1 changes to 1 files
951 new changesets 07f494440405
951 new changesets 07f494440405
952 updating to branch default
952 updating to branch default
953 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
953 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
954 $ cd binarydest
954 $ cd binarydest
955 $ cp ../binarysource/b b
955 $ cp ../binarysource/b b
956 $ hg ci -Am addb2 b
956 $ hg ci -Am addb2 b
957 $ hg transplant -s ../binarysource 2
957 $ hg transplant -s ../binarysource 2
958 searching for changes
958 searching for changes
959 applying 7a7d57e15850
959 applying 7a7d57e15850
960 skipping emptied changeset 7a7d57e15850
960 skipping emptied changeset 7a7d57e15850
961
961
962 Test empty result in --continue
962 Test empty result in --continue
963
963
964 $ hg transplant -s ../binarysource 1
964 $ hg transplant -s ../binarysource 1
965 searching for changes
965 searching for changes
966 applying 645035761929
966 applying 645035761929
967 file b already exists
967 file b already exists
968 1 out of 1 hunks FAILED -- saving rejects to file b.rej
968 1 out of 1 hunks FAILED -- saving rejects to file b.rej
969 patch failed to apply
969 patch failed to apply
970 abort: fix up the working directory and run hg transplant --continue
970 abort: fix up the working directory and run hg transplant --continue
971 [255]
971 [255]
972 $ hg status
972 $ hg status
973 ? b.rej
973 ? b.rej
974 $ hg continue
974 $ hg continue
975 645035761929 skipped due to empty diff
975 645035761929 skipped due to empty diff
976
976
977 $ cd ..
977 $ cd ..
978
978
979 Explicitly kill daemons to let the test exit on Windows
979 Explicitly kill daemons to let the test exit on Windows
980
980
981 $ killdaemons.py
981 $ killdaemons.py
982
982
983 Test that patch-ed files are treated as "modified", when transplant is
983 Test that patch-ed files are treated as "modified", when transplant is
984 aborted by failure of patching, even if none of mode, size and
984 aborted by failure of patching, even if none of mode, size and
985 timestamp of them isn't changed on the filesystem (see also issue4583)
985 timestamp of them isn't changed on the filesystem (see also issue4583)
986
986
987 $ cd t
987 $ cd t
988
988
989 $ cat > $TESTTMP/abort.py <<EOF
989 $ cat > $TESTTMP/abort.py <<EOF
990 > # emulate that patch.patch() is aborted at patching on "abort" file
990 > # emulate that patch.patch() is aborted at patching on "abort" file
991 > from mercurial import error, extensions, patch as patchmod
991 > from mercurial import error, extensions, patch as patchmod
992 > def patch(orig, ui, repo, patchname,
992 > def patch(orig, ui, repo, patchname,
993 > strip=1, prefix=b'', files=None,
993 > strip=1, prefix=b'', files=None,
994 > eolmode=b'strict', similarity=0):
994 > eolmode=b'strict', similarity=0):
995 > if files is None:
995 > if files is None:
996 > files = set()
996 > files = set()
997 > r = orig(ui, repo, patchname,
997 > r = orig(ui, repo, patchname,
998 > strip=strip, prefix=prefix, files=files,
998 > strip=strip, prefix=prefix, files=files,
999 > eolmode=eolmode, similarity=similarity)
999 > eolmode=eolmode, similarity=similarity)
1000 > if b'abort' in files:
1000 > if b'abort' in files:
1001 > raise error.PatchError('intentional error while patching')
1001 > raise error.PatchError('intentional error while patching')
1002 > return r
1002 > return r
1003 > def extsetup(ui):
1003 > def extsetup(ui):
1004 > extensions.wrapfunction(patchmod, 'patch', patch)
1004 > extensions.wrapfunction(patchmod, 'patch', patch)
1005 > EOF
1005 > EOF
1006
1006
1007 $ echo X1 > r1
1007 $ echo X1 > r1
1008 $ hg diff --nodates r1
1008 $ hg diff --nodates r1
1009 diff -r a53251cdf717 r1
1009 diff -r a53251cdf717 r1
1010 --- a/r1
1010 --- a/r1
1011 +++ b/r1
1011 +++ b/r1
1012 @@ -1,1 +1,1 @@
1012 @@ -1,1 +1,1 @@
1013 -r1
1013 -r1
1014 +X1
1014 +X1
1015 $ hg commit -m "X1 as r1"
1015 $ hg commit -m "X1 as r1"
1016
1016
1017 $ echo 'marking to abort patching' > abort
1017 $ echo 'marking to abort patching' > abort
1018 $ hg add abort
1018 $ hg add abort
1019 $ echo Y1 > r1
1019 $ echo Y1 > r1
1020 $ hg diff --nodates r1
1020 $ hg diff --nodates r1
1021 diff -r 22c515968f13 r1
1021 diff -r 22c515968f13 r1
1022 --- a/r1
1022 --- a/r1
1023 +++ b/r1
1023 +++ b/r1
1024 @@ -1,1 +1,1 @@
1024 @@ -1,1 +1,1 @@
1025 -X1
1025 -X1
1026 +Y1
1026 +Y1
1027 $ hg commit -m "Y1 as r1"
1027 $ hg commit -m "Y1 as r1"
1028
1028
1029 $ hg update -q -C d11e3596cc1a
1029 $ hg update -q -C d11e3596cc1a
1030 $ cat r1
1030 $ cat r1
1031 r1
1031 r1
1032
1032
1033 $ cat >> .hg/hgrc <<EOF
1033 $ cat >> .hg/hgrc <<EOF
1034 > [fakedirstatewritetime]
1034 > [fakedirstatewritetime]
1035 > # emulate invoking dirstate.write() via repo.status() or markcommitted()
1035 > # emulate invoking dirstate.write() via repo.status() or markcommitted()
1036 > # at 2000-01-01 00:00
1036 > # at 2000-01-01 00:00
1037 > fakenow = 200001010000
1037 > fakenow = 200001010000
1038 >
1038 >
1039 > # emulate invoking patch.internalpatch() at 2000-01-01 00:00
1039 > # emulate invoking patch.internalpatch() at 2000-01-01 00:00
1040 > [fakepatchtime]
1040 > [fakepatchtime]
1041 > fakenow = 200001010000
1041 > fakenow = 200001010000
1042 >
1042 >
1043 > [extensions]
1043 > [extensions]
1044 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
1044 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
1045 > fakepatchtime = $TESTDIR/fakepatchtime.py
1045 > fakepatchtime = $TESTDIR/fakepatchtime.py
1046 > abort = $TESTTMP/abort.py
1046 > abort = $TESTTMP/abort.py
1047 > EOF
1047 > EOF
1048 $ hg transplant "22c515968f13::"
1048 $ hg transplant "22c515968f13::"
1049 applying 22c515968f13
1049 applying 22c515968f13
1050 22c515968f13 transplanted to * (glob)
1050 22c515968f13 transplanted to * (glob)
1051 applying e38700ba9dd3
1051 applying e38700ba9dd3
1052 intentional error while patching
1052 intentional error while patching
1053 abort: fix up the working directory and run hg transplant --continue
1053 abort: fix up the working directory and run hg transplant --continue
1054 [255]
1054 [255]
1055 $ cat >> .hg/hgrc <<EOF
1055 $ cat >> .hg/hgrc <<EOF
1056 > [hooks]
1056 > [hooks]
1057 > fakedirstatewritetime = !
1057 > fakedirstatewritetime = !
1058 > fakepatchtime = !
1058 > fakepatchtime = !
1059 > [extensions]
1059 > [extensions]
1060 > abort = !
1060 > abort = !
1061 > EOF
1061 > EOF
1062
1062
1063 $ cat r1
1063 $ cat r1
1064 Y1
1064 Y1
1065 $ hg debugstate | grep ' r1$'
1065 $ hg debugstate | grep ' r1$'
1066 n 644 3 unset r1
1066 n 644 3 unset r1
1067 $ hg status -A r1
1067 $ hg status -A r1
1068 M r1
1068 M r1
1069
1069
1070 Test that rollback by unexpected failure after transplanting the first
1070 Test that rollback by unexpected failure after transplanting the first
1071 revision restores dirstate correctly.
1071 revision restores dirstate correctly.
1072
1072
1073 $ hg rollback -q
1073 $ hg rollback -q
1074 $ rm -f abort
1074 $ rm -f abort
1075 $ hg update -q -C d11e3596cc1a
1075 $ hg update -q -C d11e3596cc1a
1076 $ hg parents -T "{node|short}\n"
1076 $ hg parents -T "{node|short}\n"
1077 d11e3596cc1a
1077 d11e3596cc1a
1078 $ hg status -A
1078 $ hg status -A
1079 C r1
1079 C r1
1080 C r2
1080 C r2
1081
1081
1082 $ cat >> .hg/hgrc <<EOF
1082 $ cat >> .hg/hgrc <<EOF
1083 > [hooks]
1083 > [hooks]
1084 > # emulate failure at transplanting the 2nd revision
1084 > # emulate failure at transplanting the 2nd revision
1085 > pretxncommit.abort = test ! -f abort
1085 > pretxncommit.abort = test ! -f abort
1086 > EOF
1086 > EOF
1087 $ hg transplant "22c515968f13::"
1087 $ hg transplant "22c515968f13::"
1088 applying 22c515968f13
1088 applying 22c515968f13
1089 22c515968f13 transplanted to * (glob)
1089 22c515968f13 transplanted to * (glob)
1090 applying e38700ba9dd3
1090 applying e38700ba9dd3
1091 transaction abort!
1091 transaction abort!
1092 rollback completed
1092 rollback completed
1093 abort: pretxncommit.abort hook exited with status 1
1093 abort: pretxncommit.abort hook exited with status 1
1094 [255]
1094 [255]
1095 $ cat >> .hg/hgrc <<EOF
1095 $ cat >> .hg/hgrc <<EOF
1096 > [hooks]
1096 > [hooks]
1097 > pretxncommit.abort = !
1097 > pretxncommit.abort = !
1098 > EOF
1098 > EOF
1099
1099
1100 $ hg parents -T "{node|short}\n"
1100 $ hg parents -T "{node|short}\n"
1101 d11e3596cc1a
1101 d11e3596cc1a
1102 $ hg status -A
1102 $ hg status -A
1103 M r1
1103 M r1
1104 ? abort
1104 ? abort
1105 C r2
1105 C r2
1106
1106
1107 $ cd ..
1107 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now