##// END OF EJS Templates
transplant: use "ui.extractchoices()" to show the list of available responses...
FUJIWARA Katsunori -
r20269:acb6ccea default
parent child Browse files
Show More
@@ -1,697 +1,689
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
16
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18 import os, tempfile
18 import os, tempfile
19 from mercurial.node import short
19 from mercurial.node import short
20 from mercurial import bundlerepo, hg, merge, match
20 from mercurial import bundlerepo, hg, merge, match
21 from mercurial import patch, revlog, scmutil, util, error, cmdutil
21 from mercurial import patch, revlog, scmutil, util, error, cmdutil
22 from mercurial import revset, templatekw
22 from mercurial import revset, templatekw
23
23
24 class TransplantError(error.Abort):
24 class TransplantError(error.Abort):
25 pass
25 pass
26
26
27 cmdtable = {}
27 cmdtable = {}
28 command = cmdutil.command(cmdtable)
28 command = cmdutil.command(cmdtable)
29 testedwith = 'internal'
29 testedwith = 'internal'
30
30
31 class transplantentry(object):
31 class transplantentry(object):
32 def __init__(self, lnode, rnode):
32 def __init__(self, lnode, rnode):
33 self.lnode = lnode
33 self.lnode = lnode
34 self.rnode = rnode
34 self.rnode = rnode
35
35
36 class transplants(object):
36 class transplants(object):
37 def __init__(self, path=None, transplantfile=None, opener=None):
37 def __init__(self, path=None, transplantfile=None, opener=None):
38 self.path = path
38 self.path = path
39 self.transplantfile = transplantfile
39 self.transplantfile = transplantfile
40 self.opener = opener
40 self.opener = opener
41
41
42 if not opener:
42 if not opener:
43 self.opener = scmutil.opener(self.path)
43 self.opener = scmutil.opener(self.path)
44 self.transplants = {}
44 self.transplants = {}
45 self.dirty = False
45 self.dirty = False
46 self.read()
46 self.read()
47
47
48 def read(self):
48 def read(self):
49 abspath = os.path.join(self.path, self.transplantfile)
49 abspath = os.path.join(self.path, self.transplantfile)
50 if self.transplantfile and os.path.exists(abspath):
50 if self.transplantfile and os.path.exists(abspath):
51 for line in self.opener.read(self.transplantfile).splitlines():
51 for line in self.opener.read(self.transplantfile).splitlines():
52 lnode, rnode = map(revlog.bin, line.split(':'))
52 lnode, rnode = map(revlog.bin, line.split(':'))
53 list = self.transplants.setdefault(rnode, [])
53 list = self.transplants.setdefault(rnode, [])
54 list.append(transplantentry(lnode, rnode))
54 list.append(transplantentry(lnode, rnode))
55
55
56 def write(self):
56 def write(self):
57 if self.dirty and self.transplantfile:
57 if self.dirty and self.transplantfile:
58 if not os.path.isdir(self.path):
58 if not os.path.isdir(self.path):
59 os.mkdir(self.path)
59 os.mkdir(self.path)
60 fp = self.opener(self.transplantfile, 'w')
60 fp = self.opener(self.transplantfile, 'w')
61 for list in self.transplants.itervalues():
61 for list in self.transplants.itervalues():
62 for t in list:
62 for t in list:
63 l, r = map(revlog.hex, (t.lnode, t.rnode))
63 l, r = map(revlog.hex, (t.lnode, t.rnode))
64 fp.write(l + ':' + r + '\n')
64 fp.write(l + ':' + r + '\n')
65 fp.close()
65 fp.close()
66 self.dirty = False
66 self.dirty = False
67
67
68 def get(self, rnode):
68 def get(self, rnode):
69 return self.transplants.get(rnode) or []
69 return self.transplants.get(rnode) or []
70
70
71 def set(self, lnode, rnode):
71 def set(self, lnode, rnode):
72 list = self.transplants.setdefault(rnode, [])
72 list = self.transplants.setdefault(rnode, [])
73 list.append(transplantentry(lnode, rnode))
73 list.append(transplantentry(lnode, rnode))
74 self.dirty = True
74 self.dirty = True
75
75
76 def remove(self, transplant):
76 def remove(self, transplant):
77 list = self.transplants.get(transplant.rnode)
77 list = self.transplants.get(transplant.rnode)
78 if list:
78 if list:
79 del list[list.index(transplant)]
79 del list[list.index(transplant)]
80 self.dirty = True
80 self.dirty = True
81
81
82 class transplanter(object):
82 class transplanter(object):
83 def __init__(self, ui, repo):
83 def __init__(self, ui, repo):
84 self.ui = ui
84 self.ui = ui
85 self.path = repo.join('transplant')
85 self.path = repo.join('transplant')
86 self.opener = scmutil.opener(self.path)
86 self.opener = scmutil.opener(self.path)
87 self.transplants = transplants(self.path, 'transplants',
87 self.transplants = transplants(self.path, 'transplants',
88 opener=self.opener)
88 opener=self.opener)
89 self.editor = None
89 self.editor = None
90
90
91 def applied(self, repo, node, parent):
91 def applied(self, repo, node, parent):
92 '''returns True if a node is already an ancestor of parent
92 '''returns True if a node is already an ancestor of parent
93 or is parent or has already been transplanted'''
93 or is parent or has already been transplanted'''
94 if hasnode(repo, parent):
94 if hasnode(repo, parent):
95 parentrev = repo.changelog.rev(parent)
95 parentrev = repo.changelog.rev(parent)
96 if hasnode(repo, node):
96 if hasnode(repo, node):
97 rev = repo.changelog.rev(node)
97 rev = repo.changelog.rev(node)
98 reachable = repo.changelog.ancestors([parentrev], rev,
98 reachable = repo.changelog.ancestors([parentrev], rev,
99 inclusive=True)
99 inclusive=True)
100 if rev in reachable:
100 if rev in reachable:
101 return True
101 return True
102 for t in self.transplants.get(node):
102 for t in self.transplants.get(node):
103 # it might have been stripped
103 # it might have been stripped
104 if not hasnode(repo, t.lnode):
104 if not hasnode(repo, t.lnode):
105 self.transplants.remove(t)
105 self.transplants.remove(t)
106 return False
106 return False
107 lnoderev = repo.changelog.rev(t.lnode)
107 lnoderev = repo.changelog.rev(t.lnode)
108 if lnoderev in repo.changelog.ancestors([parentrev], lnoderev,
108 if lnoderev in repo.changelog.ancestors([parentrev], lnoderev,
109 inclusive=True):
109 inclusive=True):
110 return True
110 return True
111 return False
111 return False
112
112
113 def apply(self, repo, source, revmap, merges, opts={}):
113 def apply(self, repo, source, revmap, merges, opts={}):
114 '''apply the revisions in revmap one by one in revision order'''
114 '''apply the revisions in revmap one by one in revision order'''
115 revs = sorted(revmap)
115 revs = sorted(revmap)
116 p1, p2 = repo.dirstate.parents()
116 p1, p2 = repo.dirstate.parents()
117 pulls = []
117 pulls = []
118 diffopts = patch.diffopts(self.ui, opts)
118 diffopts = patch.diffopts(self.ui, opts)
119 diffopts.git = True
119 diffopts.git = True
120
120
121 lock = wlock = tr = None
121 lock = wlock = tr = None
122 try:
122 try:
123 wlock = repo.wlock()
123 wlock = repo.wlock()
124 lock = repo.lock()
124 lock = repo.lock()
125 tr = repo.transaction('transplant')
125 tr = repo.transaction('transplant')
126 for rev in revs:
126 for rev in revs:
127 node = revmap[rev]
127 node = revmap[rev]
128 revstr = '%s:%s' % (rev, short(node))
128 revstr = '%s:%s' % (rev, short(node))
129
129
130 if self.applied(repo, node, p1):
130 if self.applied(repo, node, p1):
131 self.ui.warn(_('skipping already applied revision %s\n') %
131 self.ui.warn(_('skipping already applied revision %s\n') %
132 revstr)
132 revstr)
133 continue
133 continue
134
134
135 parents = source.changelog.parents(node)
135 parents = source.changelog.parents(node)
136 if not (opts.get('filter') or opts.get('log')):
136 if not (opts.get('filter') or opts.get('log')):
137 # If the changeset parent is the same as the
137 # If the changeset parent is the same as the
138 # wdir's parent, just pull it.
138 # wdir's parent, just pull it.
139 if parents[0] == p1:
139 if parents[0] == p1:
140 pulls.append(node)
140 pulls.append(node)
141 p1 = node
141 p1 = node
142 continue
142 continue
143 if pulls:
143 if pulls:
144 if source != repo:
144 if source != repo:
145 repo.pull(source.peer(), heads=pulls)
145 repo.pull(source.peer(), heads=pulls)
146 merge.update(repo, pulls[-1], False, False, None)
146 merge.update(repo, pulls[-1], False, False, None)
147 p1, p2 = repo.dirstate.parents()
147 p1, p2 = repo.dirstate.parents()
148 pulls = []
148 pulls = []
149
149
150 domerge = False
150 domerge = False
151 if node in merges:
151 if node in merges:
152 # pulling all the merge revs at once would mean we
152 # pulling all the merge revs at once would mean we
153 # couldn't transplant after the latest even if
153 # couldn't transplant after the latest even if
154 # transplants before them fail.
154 # transplants before them fail.
155 domerge = True
155 domerge = True
156 if not hasnode(repo, node):
156 if not hasnode(repo, node):
157 repo.pull(source.peer(), heads=[node])
157 repo.pull(source.peer(), heads=[node])
158
158
159 skipmerge = False
159 skipmerge = False
160 if parents[1] != revlog.nullid:
160 if parents[1] != revlog.nullid:
161 if not opts.get('parent'):
161 if not opts.get('parent'):
162 self.ui.note(_('skipping merge changeset %s:%s\n')
162 self.ui.note(_('skipping merge changeset %s:%s\n')
163 % (rev, short(node)))
163 % (rev, short(node)))
164 skipmerge = True
164 skipmerge = True
165 else:
165 else:
166 parent = source.lookup(opts['parent'])
166 parent = source.lookup(opts['parent'])
167 if parent not in parents:
167 if parent not in parents:
168 raise util.Abort(_('%s is not a parent of %s') %
168 raise util.Abort(_('%s is not a parent of %s') %
169 (short(parent), short(node)))
169 (short(parent), short(node)))
170 else:
170 else:
171 parent = parents[0]
171 parent = parents[0]
172
172
173 if skipmerge:
173 if skipmerge:
174 patchfile = None
174 patchfile = None
175 else:
175 else:
176 fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
176 fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
177 fp = os.fdopen(fd, 'w')
177 fp = os.fdopen(fd, 'w')
178 gen = patch.diff(source, parent, node, opts=diffopts)
178 gen = patch.diff(source, parent, node, opts=diffopts)
179 for chunk in gen:
179 for chunk in gen:
180 fp.write(chunk)
180 fp.write(chunk)
181 fp.close()
181 fp.close()
182
182
183 del revmap[rev]
183 del revmap[rev]
184 if patchfile or domerge:
184 if patchfile or domerge:
185 try:
185 try:
186 try:
186 try:
187 n = self.applyone(repo, node,
187 n = self.applyone(repo, node,
188 source.changelog.read(node),
188 source.changelog.read(node),
189 patchfile, merge=domerge,
189 patchfile, merge=domerge,
190 log=opts.get('log'),
190 log=opts.get('log'),
191 filter=opts.get('filter'))
191 filter=opts.get('filter'))
192 except TransplantError:
192 except TransplantError:
193 # Do not rollback, it is up to the user to
193 # Do not rollback, it is up to the user to
194 # fix the merge or cancel everything
194 # fix the merge or cancel everything
195 tr.close()
195 tr.close()
196 raise
196 raise
197 if n and domerge:
197 if n and domerge:
198 self.ui.status(_('%s merged at %s\n') % (revstr,
198 self.ui.status(_('%s merged at %s\n') % (revstr,
199 short(n)))
199 short(n)))
200 elif n:
200 elif n:
201 self.ui.status(_('%s transplanted to %s\n')
201 self.ui.status(_('%s transplanted to %s\n')
202 % (short(node),
202 % (short(node),
203 short(n)))
203 short(n)))
204 finally:
204 finally:
205 if patchfile:
205 if patchfile:
206 os.unlink(patchfile)
206 os.unlink(patchfile)
207 tr.close()
207 tr.close()
208 if pulls:
208 if pulls:
209 repo.pull(source.peer(), heads=pulls)
209 repo.pull(source.peer(), heads=pulls)
210 merge.update(repo, pulls[-1], False, False, None)
210 merge.update(repo, pulls[-1], False, False, None)
211 finally:
211 finally:
212 self.saveseries(revmap, merges)
212 self.saveseries(revmap, merges)
213 self.transplants.write()
213 self.transplants.write()
214 if tr:
214 if tr:
215 tr.release()
215 tr.release()
216 lock.release()
216 lock.release()
217 wlock.release()
217 wlock.release()
218
218
219 def filter(self, filter, node, changelog, patchfile):
219 def filter(self, filter, node, changelog, patchfile):
220 '''arbitrarily rewrite changeset before applying it'''
220 '''arbitrarily rewrite changeset before applying it'''
221
221
222 self.ui.status(_('filtering %s\n') % patchfile)
222 self.ui.status(_('filtering %s\n') % patchfile)
223 user, date, msg = (changelog[1], changelog[2], changelog[4])
223 user, date, msg = (changelog[1], changelog[2], changelog[4])
224 fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-')
224 fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-')
225 fp = os.fdopen(fd, 'w')
225 fp = os.fdopen(fd, 'w')
226 fp.write("# HG changeset patch\n")
226 fp.write("# HG changeset patch\n")
227 fp.write("# User %s\n" % user)
227 fp.write("# User %s\n" % user)
228 fp.write("# Date %d %d\n" % date)
228 fp.write("# Date %d %d\n" % date)
229 fp.write(msg + '\n')
229 fp.write(msg + '\n')
230 fp.close()
230 fp.close()
231
231
232 try:
232 try:
233 util.system('%s %s %s' % (filter, util.shellquote(headerfile),
233 util.system('%s %s %s' % (filter, util.shellquote(headerfile),
234 util.shellquote(patchfile)),
234 util.shellquote(patchfile)),
235 environ={'HGUSER': changelog[1],
235 environ={'HGUSER': changelog[1],
236 'HGREVISION': revlog.hex(node),
236 'HGREVISION': revlog.hex(node),
237 },
237 },
238 onerr=util.Abort, errprefix=_('filter failed'),
238 onerr=util.Abort, errprefix=_('filter failed'),
239 out=self.ui.fout)
239 out=self.ui.fout)
240 user, date, msg = self.parselog(file(headerfile))[1:4]
240 user, date, msg = self.parselog(file(headerfile))[1:4]
241 finally:
241 finally:
242 os.unlink(headerfile)
242 os.unlink(headerfile)
243
243
244 return (user, date, msg)
244 return (user, date, msg)
245
245
246 def applyone(self, repo, node, cl, patchfile, merge=False, log=False,
246 def applyone(self, repo, node, cl, patchfile, merge=False, log=False,
247 filter=None):
247 filter=None):
248 '''apply the patch in patchfile to the repository as a transplant'''
248 '''apply the patch in patchfile to the repository as a transplant'''
249 (manifest, user, (time, timezone), files, message) = cl[:5]
249 (manifest, user, (time, timezone), files, message) = cl[:5]
250 date = "%d %d" % (time, timezone)
250 date = "%d %d" % (time, timezone)
251 extra = {'transplant_source': node}
251 extra = {'transplant_source': node}
252 if filter:
252 if filter:
253 (user, date, message) = self.filter(filter, node, cl, patchfile)
253 (user, date, message) = self.filter(filter, node, cl, patchfile)
254
254
255 if log:
255 if log:
256 # we don't translate messages inserted into commits
256 # we don't translate messages inserted into commits
257 message += '\n(transplanted from %s)' % revlog.hex(node)
257 message += '\n(transplanted from %s)' % revlog.hex(node)
258
258
259 self.ui.status(_('applying %s\n') % short(node))
259 self.ui.status(_('applying %s\n') % short(node))
260 self.ui.note('%s %s\n%s\n' % (user, date, message))
260 self.ui.note('%s %s\n%s\n' % (user, date, message))
261
261
262 if not patchfile and not merge:
262 if not patchfile and not merge:
263 raise util.Abort(_('can only omit patchfile if merging'))
263 raise util.Abort(_('can only omit patchfile if merging'))
264 if patchfile:
264 if patchfile:
265 try:
265 try:
266 files = set()
266 files = set()
267 patch.patch(self.ui, repo, patchfile, files=files, eolmode=None)
267 patch.patch(self.ui, repo, patchfile, files=files, eolmode=None)
268 files = list(files)
268 files = list(files)
269 except Exception, inst:
269 except Exception, inst:
270 seriespath = os.path.join(self.path, 'series')
270 seriespath = os.path.join(self.path, 'series')
271 if os.path.exists(seriespath):
271 if os.path.exists(seriespath):
272 os.unlink(seriespath)
272 os.unlink(seriespath)
273 p1 = repo.dirstate.p1()
273 p1 = repo.dirstate.p1()
274 p2 = node
274 p2 = node
275 self.log(user, date, message, p1, p2, merge=merge)
275 self.log(user, date, message, p1, p2, merge=merge)
276 self.ui.write(str(inst) + '\n')
276 self.ui.write(str(inst) + '\n')
277 raise TransplantError(_('fix up the merge and run '
277 raise TransplantError(_('fix up the merge and run '
278 'hg transplant --continue'))
278 'hg transplant --continue'))
279 else:
279 else:
280 files = None
280 files = None
281 if merge:
281 if merge:
282 p1, p2 = repo.dirstate.parents()
282 p1, p2 = repo.dirstate.parents()
283 repo.setparents(p1, node)
283 repo.setparents(p1, node)
284 m = match.always(repo.root, '')
284 m = match.always(repo.root, '')
285 else:
285 else:
286 m = match.exact(repo.root, '', files)
286 m = match.exact(repo.root, '', files)
287
287
288 n = repo.commit(message, user, date, extra=extra, match=m,
288 n = repo.commit(message, user, date, extra=extra, match=m,
289 editor=self.editor)
289 editor=self.editor)
290 if not n:
290 if not n:
291 self.ui.warn(_('skipping emptied changeset %s\n') % short(node))
291 self.ui.warn(_('skipping emptied changeset %s\n') % short(node))
292 return None
292 return None
293 if not merge:
293 if not merge:
294 self.transplants.set(n, node)
294 self.transplants.set(n, node)
295
295
296 return n
296 return n
297
297
298 def resume(self, repo, source, opts):
298 def resume(self, repo, source, opts):
299 '''recover last transaction and apply remaining changesets'''
299 '''recover last transaction and apply remaining changesets'''
300 if os.path.exists(os.path.join(self.path, 'journal')):
300 if os.path.exists(os.path.join(self.path, 'journal')):
301 n, node = self.recover(repo, source, opts)
301 n, node = self.recover(repo, source, opts)
302 self.ui.status(_('%s transplanted as %s\n') % (short(node),
302 self.ui.status(_('%s transplanted as %s\n') % (short(node),
303 short(n)))
303 short(n)))
304 seriespath = os.path.join(self.path, 'series')
304 seriespath = os.path.join(self.path, 'series')
305 if not os.path.exists(seriespath):
305 if not os.path.exists(seriespath):
306 self.transplants.write()
306 self.transplants.write()
307 return
307 return
308 nodes, merges = self.readseries()
308 nodes, merges = self.readseries()
309 revmap = {}
309 revmap = {}
310 for n in nodes:
310 for n in nodes:
311 revmap[source.changelog.rev(n)] = n
311 revmap[source.changelog.rev(n)] = n
312 os.unlink(seriespath)
312 os.unlink(seriespath)
313
313
314 self.apply(repo, source, revmap, merges, opts)
314 self.apply(repo, source, revmap, merges, opts)
315
315
316 def recover(self, repo, source, opts):
316 def recover(self, repo, source, opts):
317 '''commit working directory using journal metadata'''
317 '''commit working directory using journal metadata'''
318 node, user, date, message, parents = self.readlog()
318 node, user, date, message, parents = self.readlog()
319 merge = False
319 merge = False
320
320
321 if not user or not date or not message or not parents[0]:
321 if not user or not date or not message or not parents[0]:
322 raise util.Abort(_('transplant log file is corrupt'))
322 raise util.Abort(_('transplant log file is corrupt'))
323
323
324 parent = parents[0]
324 parent = parents[0]
325 if len(parents) > 1:
325 if len(parents) > 1:
326 if opts.get('parent'):
326 if opts.get('parent'):
327 parent = source.lookup(opts['parent'])
327 parent = source.lookup(opts['parent'])
328 if parent not in parents:
328 if parent not in parents:
329 raise util.Abort(_('%s is not a parent of %s') %
329 raise util.Abort(_('%s is not a parent of %s') %
330 (short(parent), short(node)))
330 (short(parent), short(node)))
331 else:
331 else:
332 merge = True
332 merge = True
333
333
334 extra = {'transplant_source': node}
334 extra = {'transplant_source': node}
335 wlock = repo.wlock()
335 wlock = repo.wlock()
336 try:
336 try:
337 p1, p2 = repo.dirstate.parents()
337 p1, p2 = repo.dirstate.parents()
338 if p1 != parent:
338 if p1 != parent:
339 raise util.Abort(
339 raise util.Abort(
340 _('working dir not at transplant parent %s') %
340 _('working dir not at transplant parent %s') %
341 revlog.hex(parent))
341 revlog.hex(parent))
342 if merge:
342 if merge:
343 repo.setparents(p1, parents[1])
343 repo.setparents(p1, parents[1])
344 n = repo.commit(message, user, date, extra=extra,
344 n = repo.commit(message, user, date, extra=extra,
345 editor=self.editor)
345 editor=self.editor)
346 if not n:
346 if not n:
347 raise util.Abort(_('commit failed'))
347 raise util.Abort(_('commit failed'))
348 if not merge:
348 if not merge:
349 self.transplants.set(n, node)
349 self.transplants.set(n, node)
350 self.unlog()
350 self.unlog()
351
351
352 return n, node
352 return n, node
353 finally:
353 finally:
354 wlock.release()
354 wlock.release()
355
355
356 def readseries(self):
356 def readseries(self):
357 nodes = []
357 nodes = []
358 merges = []
358 merges = []
359 cur = nodes
359 cur = nodes
360 for line in self.opener.read('series').splitlines():
360 for line in self.opener.read('series').splitlines():
361 if line.startswith('# Merges'):
361 if line.startswith('# Merges'):
362 cur = merges
362 cur = merges
363 continue
363 continue
364 cur.append(revlog.bin(line))
364 cur.append(revlog.bin(line))
365
365
366 return (nodes, merges)
366 return (nodes, merges)
367
367
368 def saveseries(self, revmap, merges):
368 def saveseries(self, revmap, merges):
369 if not revmap:
369 if not revmap:
370 return
370 return
371
371
372 if not os.path.isdir(self.path):
372 if not os.path.isdir(self.path):
373 os.mkdir(self.path)
373 os.mkdir(self.path)
374 series = self.opener('series', 'w')
374 series = self.opener('series', 'w')
375 for rev in sorted(revmap):
375 for rev in sorted(revmap):
376 series.write(revlog.hex(revmap[rev]) + '\n')
376 series.write(revlog.hex(revmap[rev]) + '\n')
377 if merges:
377 if merges:
378 series.write('# Merges\n')
378 series.write('# Merges\n')
379 for m in merges:
379 for m in merges:
380 series.write(revlog.hex(m) + '\n')
380 series.write(revlog.hex(m) + '\n')
381 series.close()
381 series.close()
382
382
383 def parselog(self, fp):
383 def parselog(self, fp):
384 parents = []
384 parents = []
385 message = []
385 message = []
386 node = revlog.nullid
386 node = revlog.nullid
387 inmsg = False
387 inmsg = False
388 user = None
388 user = None
389 date = None
389 date = None
390 for line in fp.read().splitlines():
390 for line in fp.read().splitlines():
391 if inmsg:
391 if inmsg:
392 message.append(line)
392 message.append(line)
393 elif line.startswith('# User '):
393 elif line.startswith('# User '):
394 user = line[7:]
394 user = line[7:]
395 elif line.startswith('# Date '):
395 elif line.startswith('# Date '):
396 date = line[7:]
396 date = line[7:]
397 elif line.startswith('# Node ID '):
397 elif line.startswith('# Node ID '):
398 node = revlog.bin(line[10:])
398 node = revlog.bin(line[10:])
399 elif line.startswith('# Parent '):
399 elif line.startswith('# Parent '):
400 parents.append(revlog.bin(line[9:]))
400 parents.append(revlog.bin(line[9:]))
401 elif not line.startswith('# '):
401 elif not line.startswith('# '):
402 inmsg = True
402 inmsg = True
403 message.append(line)
403 message.append(line)
404 if None in (user, date):
404 if None in (user, date):
405 raise util.Abort(_("filter corrupted changeset (no user or date)"))
405 raise util.Abort(_("filter corrupted changeset (no user or date)"))
406 return (node, user, date, '\n'.join(message), parents)
406 return (node, user, date, '\n'.join(message), parents)
407
407
408 def log(self, user, date, message, p1, p2, merge=False):
408 def log(self, user, date, message, p1, p2, merge=False):
409 '''journal changelog metadata for later recover'''
409 '''journal changelog metadata for later recover'''
410
410
411 if not os.path.isdir(self.path):
411 if not os.path.isdir(self.path):
412 os.mkdir(self.path)
412 os.mkdir(self.path)
413 fp = self.opener('journal', 'w')
413 fp = self.opener('journal', 'w')
414 fp.write('# User %s\n' % user)
414 fp.write('# User %s\n' % user)
415 fp.write('# Date %s\n' % date)
415 fp.write('# Date %s\n' % date)
416 fp.write('# Node ID %s\n' % revlog.hex(p2))
416 fp.write('# Node ID %s\n' % revlog.hex(p2))
417 fp.write('# Parent ' + revlog.hex(p1) + '\n')
417 fp.write('# Parent ' + revlog.hex(p1) + '\n')
418 if merge:
418 if merge:
419 fp.write('# Parent ' + revlog.hex(p2) + '\n')
419 fp.write('# Parent ' + revlog.hex(p2) + '\n')
420 fp.write(message.rstrip() + '\n')
420 fp.write(message.rstrip() + '\n')
421 fp.close()
421 fp.close()
422
422
423 def readlog(self):
423 def readlog(self):
424 return self.parselog(self.opener('journal'))
424 return self.parselog(self.opener('journal'))
425
425
426 def unlog(self):
426 def unlog(self):
427 '''remove changelog journal'''
427 '''remove changelog journal'''
428 absdst = os.path.join(self.path, 'journal')
428 absdst = os.path.join(self.path, 'journal')
429 if os.path.exists(absdst):
429 if os.path.exists(absdst):
430 os.unlink(absdst)
430 os.unlink(absdst)
431
431
432 def transplantfilter(self, repo, source, root):
432 def transplantfilter(self, repo, source, root):
433 def matchfn(node):
433 def matchfn(node):
434 if self.applied(repo, node, root):
434 if self.applied(repo, node, root):
435 return False
435 return False
436 if source.changelog.parents(node)[1] != revlog.nullid:
436 if source.changelog.parents(node)[1] != revlog.nullid:
437 return False
437 return False
438 extra = source.changelog.read(node)[5]
438 extra = source.changelog.read(node)[5]
439 cnode = extra.get('transplant_source')
439 cnode = extra.get('transplant_source')
440 if cnode and self.applied(repo, cnode, root):
440 if cnode and self.applied(repo, cnode, root):
441 return False
441 return False
442 return True
442 return True
443
443
444 return matchfn
444 return matchfn
445
445
446 def hasnode(repo, node):
446 def hasnode(repo, node):
447 try:
447 try:
448 return repo.changelog.rev(node) is not None
448 return repo.changelog.rev(node) is not None
449 except error.RevlogError:
449 except error.RevlogError:
450 return False
450 return False
451
451
452 def browserevs(ui, repo, nodes, opts):
452 def browserevs(ui, repo, nodes, opts):
453 '''interactively transplant changesets'''
453 '''interactively transplant changesets'''
454 def browsehelp(ui):
455 ui.write(_('y: transplant this changeset\n'
456 'n: skip this changeset\n'
457 'm: merge at this changeset\n'
458 'p: show patch\n'
459 'c: commit selected changesets\n'
460 'q: cancel transplant\n'
461 '?: show this help\n'))
462
463 displayer = cmdutil.show_changeset(ui, repo, opts)
454 displayer = cmdutil.show_changeset(ui, repo, opts)
464 transplants = []
455 transplants = []
465 merges = []
456 merges = []
466 prompt = _('apply changeset? [ynmpcq?]:'
457 prompt = _('apply changeset? [ynmpcq?]:'
467 '$$ &yes, transplant this changeset'
458 '$$ &yes, transplant this changeset'
468 '$$ &no, skip this changeset'
459 '$$ &no, skip this changeset'
469 '$$ &merge at this changeset'
460 '$$ &merge at this changeset'
470 '$$ show &patch'
461 '$$ show &patch'
471 '$$ &commit selected changesets'
462 '$$ &commit selected changesets'
472 '$$ &quit and cancel transplant'
463 '$$ &quit and cancel transplant'
473 '$$ &? (show this help)')
464 '$$ &? (show this help)')
474 for node in nodes:
465 for node in nodes:
475 displayer.show(repo[node])
466 displayer.show(repo[node])
476 action = None
467 action = None
477 while not action:
468 while not action:
478 action = 'ynmpcq?'[ui.promptchoice(prompt)]
469 action = 'ynmpcq?'[ui.promptchoice(prompt)]
479 if action == '?':
470 if action == '?':
480 browsehelp(ui)
471 for c, t in ui.extractchoices(prompt)[1]:
472 ui.write('%s: %s\n' % (c, t))
481 action = None
473 action = None
482 elif action == 'p':
474 elif action == 'p':
483 parent = repo.changelog.parents(node)[0]
475 parent = repo.changelog.parents(node)[0]
484 for chunk in patch.diff(repo, parent, node):
476 for chunk in patch.diff(repo, parent, node):
485 ui.write(chunk)
477 ui.write(chunk)
486 action = None
478 action = None
487 if action == 'y':
479 if action == 'y':
488 transplants.append(node)
480 transplants.append(node)
489 elif action == 'm':
481 elif action == 'm':
490 merges.append(node)
482 merges.append(node)
491 elif action == 'c':
483 elif action == 'c':
492 break
484 break
493 elif action == 'q':
485 elif action == 'q':
494 transplants = ()
486 transplants = ()
495 merges = ()
487 merges = ()
496 break
488 break
497 displayer.close()
489 displayer.close()
498 return (transplants, merges)
490 return (transplants, merges)
499
491
500 @command('transplant',
492 @command('transplant',
501 [('s', 'source', '', _('transplant changesets from REPO'), _('REPO')),
493 [('s', 'source', '', _('transplant changesets from REPO'), _('REPO')),
502 ('b', 'branch', [], _('use this source changeset as head'), _('REV')),
494 ('b', 'branch', [], _('use this source changeset as head'), _('REV')),
503 ('a', 'all', None, _('pull all changesets up to the --branch revisions')),
495 ('a', 'all', None, _('pull all changesets up to the --branch revisions')),
504 ('p', 'prune', [], _('skip over REV'), _('REV')),
496 ('p', 'prune', [], _('skip over REV'), _('REV')),
505 ('m', 'merge', [], _('merge at REV'), _('REV')),
497 ('m', 'merge', [], _('merge at REV'), _('REV')),
506 ('', 'parent', '',
498 ('', 'parent', '',
507 _('parent to choose when transplanting merge'), _('REV')),
499 _('parent to choose when transplanting merge'), _('REV')),
508 ('e', 'edit', False, _('invoke editor on commit messages')),
500 ('e', 'edit', False, _('invoke editor on commit messages')),
509 ('', 'log', None, _('append transplant info to log message')),
501 ('', 'log', None, _('append transplant info to log message')),
510 ('c', 'continue', None, _('continue last transplant session '
502 ('c', 'continue', None, _('continue last transplant session '
511 'after fixing conflicts')),
503 'after fixing conflicts')),
512 ('', 'filter', '',
504 ('', 'filter', '',
513 _('filter changesets through command'), _('CMD'))],
505 _('filter changesets through command'), _('CMD'))],
514 _('hg transplant [-s REPO] [-b BRANCH [-a]] [-p REV] '
506 _('hg transplant [-s REPO] [-b BRANCH [-a]] [-p REV] '
515 '[-m REV] [REV]...'))
507 '[-m REV] [REV]...'))
516 def transplant(ui, repo, *revs, **opts):
508 def transplant(ui, repo, *revs, **opts):
517 '''transplant changesets from another branch
509 '''transplant changesets from another branch
518
510
519 Selected changesets will be applied on top of the current working
511 Selected changesets will be applied on top of the current working
520 directory with the log of the original changeset. The changesets
512 directory with the log of the original changeset. The changesets
521 are copied and will thus appear twice in the history with different
513 are copied and will thus appear twice in the history with different
522 identities.
514 identities.
523
515
524 Consider using the graft command if everything is inside the same
516 Consider using the graft command if everything is inside the same
525 repository - it will use merges and will usually give a better result.
517 repository - it will use merges and will usually give a better result.
526 Use the rebase extension if the changesets are unpublished and you want
518 Use the rebase extension if the changesets are unpublished and you want
527 to move them instead of copying them.
519 to move them instead of copying them.
528
520
529 If --log is specified, log messages will have a comment appended
521 If --log is specified, log messages will have a comment appended
530 of the form::
522 of the form::
531
523
532 (transplanted from CHANGESETHASH)
524 (transplanted from CHANGESETHASH)
533
525
534 You can rewrite the changelog message with the --filter option.
526 You can rewrite the changelog message with the --filter option.
535 Its argument will be invoked with the current changelog message as
527 Its argument will be invoked with the current changelog message as
536 $1 and the patch as $2.
528 $1 and the patch as $2.
537
529
538 --source/-s specifies another repository to use for selecting changesets,
530 --source/-s specifies another repository to use for selecting changesets,
539 just as if it temporarily had been pulled.
531 just as if it temporarily had been pulled.
540 If --branch/-b is specified, these revisions will be used as
532 If --branch/-b is specified, these revisions will be used as
541 heads when deciding which changesets to transplant, just as if only
533 heads when deciding which changesets to transplant, just as if only
542 these revisions had been pulled.
534 these revisions had been pulled.
543 If --all/-a is specified, all the revisions up to the heads specified
535 If --all/-a is specified, all the revisions up to the heads specified
544 with --branch will be transplanted.
536 with --branch will be transplanted.
545
537
546 Example:
538 Example:
547
539
548 - transplant all changes up to REV on top of your current revision::
540 - transplant all changes up to REV on top of your current revision::
549
541
550 hg transplant --branch REV --all
542 hg transplant --branch REV --all
551
543
552 You can optionally mark selected transplanted changesets as merge
544 You can optionally mark selected transplanted changesets as merge
553 changesets. You will not be prompted to transplant any ancestors
545 changesets. You will not be prompted to transplant any ancestors
554 of a merged transplant, and you can merge descendants of them
546 of a merged transplant, and you can merge descendants of them
555 normally instead of transplanting them.
547 normally instead of transplanting them.
556
548
557 Merge changesets may be transplanted directly by specifying the
549 Merge changesets may be transplanted directly by specifying the
558 proper parent changeset by calling :hg:`transplant --parent`.
550 proper parent changeset by calling :hg:`transplant --parent`.
559
551
560 If no merges or revisions are provided, :hg:`transplant` will
552 If no merges or revisions are provided, :hg:`transplant` will
561 start an interactive changeset browser.
553 start an interactive changeset browser.
562
554
563 If a changeset application fails, you can fix the merge by hand
555 If a changeset application fails, you can fix the merge by hand
564 and then resume where you left off by calling :hg:`transplant
556 and then resume where you left off by calling :hg:`transplant
565 --continue/-c`.
557 --continue/-c`.
566 '''
558 '''
567 def incwalk(repo, csets, match=util.always):
559 def incwalk(repo, csets, match=util.always):
568 for node in csets:
560 for node in csets:
569 if match(node):
561 if match(node):
570 yield node
562 yield node
571
563
572 def transplantwalk(repo, dest, heads, match=util.always):
564 def transplantwalk(repo, dest, heads, match=util.always):
573 '''Yield all nodes that are ancestors of a head but not ancestors
565 '''Yield all nodes that are ancestors of a head but not ancestors
574 of dest.
566 of dest.
575 If no heads are specified, the heads of repo will be used.'''
567 If no heads are specified, the heads of repo will be used.'''
576 if not heads:
568 if not heads:
577 heads = repo.heads()
569 heads = repo.heads()
578 ancestors = []
570 ancestors = []
579 for head in heads:
571 for head in heads:
580 ancestors.append(repo.changelog.ancestor(dest, head))
572 ancestors.append(repo.changelog.ancestor(dest, head))
581 for node in repo.changelog.nodesbetween(ancestors, heads)[0]:
573 for node in repo.changelog.nodesbetween(ancestors, heads)[0]:
582 if match(node):
574 if match(node):
583 yield node
575 yield node
584
576
585 def checkopts(opts, revs):
577 def checkopts(opts, revs):
586 if opts.get('continue'):
578 if opts.get('continue'):
587 if opts.get('branch') or opts.get('all') or opts.get('merge'):
579 if opts.get('branch') or opts.get('all') or opts.get('merge'):
588 raise util.Abort(_('--continue is incompatible with '
580 raise util.Abort(_('--continue is incompatible with '
589 '--branch, --all and --merge'))
581 '--branch, --all and --merge'))
590 return
582 return
591 if not (opts.get('source') or revs or
583 if not (opts.get('source') or revs or
592 opts.get('merge') or opts.get('branch')):
584 opts.get('merge') or opts.get('branch')):
593 raise util.Abort(_('no source URL, branch revision or revision '
585 raise util.Abort(_('no source URL, branch revision or revision '
594 'list provided'))
586 'list provided'))
595 if opts.get('all'):
587 if opts.get('all'):
596 if not opts.get('branch'):
588 if not opts.get('branch'):
597 raise util.Abort(_('--all requires a branch revision'))
589 raise util.Abort(_('--all requires a branch revision'))
598 if revs:
590 if revs:
599 raise util.Abort(_('--all is incompatible with a '
591 raise util.Abort(_('--all is incompatible with a '
600 'revision list'))
592 'revision list'))
601
593
602 checkopts(opts, revs)
594 checkopts(opts, revs)
603
595
604 if not opts.get('log'):
596 if not opts.get('log'):
605 opts['log'] = ui.config('transplant', 'log')
597 opts['log'] = ui.config('transplant', 'log')
606 if not opts.get('filter'):
598 if not opts.get('filter'):
607 opts['filter'] = ui.config('transplant', 'filter')
599 opts['filter'] = ui.config('transplant', 'filter')
608
600
609 tp = transplanter(ui, repo)
601 tp = transplanter(ui, repo)
610 if opts.get('edit'):
602 if opts.get('edit'):
611 tp.editor = cmdutil.commitforceeditor
603 tp.editor = cmdutil.commitforceeditor
612
604
613 cmdutil.checkunfinished(repo)
605 cmdutil.checkunfinished(repo)
614 p1, p2 = repo.dirstate.parents()
606 p1, p2 = repo.dirstate.parents()
615 if len(repo) > 0 and p1 == revlog.nullid:
607 if len(repo) > 0 and p1 == revlog.nullid:
616 raise util.Abort(_('no revision checked out'))
608 raise util.Abort(_('no revision checked out'))
617 if not opts.get('continue'):
609 if not opts.get('continue'):
618 if p2 != revlog.nullid:
610 if p2 != revlog.nullid:
619 raise util.Abort(_('outstanding uncommitted merges'))
611 raise util.Abort(_('outstanding uncommitted merges'))
620 m, a, r, d = repo.status()[:4]
612 m, a, r, d = repo.status()[:4]
621 if m or a or r or d:
613 if m or a or r or d:
622 raise util.Abort(_('outstanding local changes'))
614 raise util.Abort(_('outstanding local changes'))
623
615
624 sourcerepo = opts.get('source')
616 sourcerepo = opts.get('source')
625 if sourcerepo:
617 if sourcerepo:
626 peer = hg.peer(repo, opts, ui.expandpath(sourcerepo))
618 peer = hg.peer(repo, opts, ui.expandpath(sourcerepo))
627 heads = map(peer.lookup, opts.get('branch', ()))
619 heads = map(peer.lookup, opts.get('branch', ()))
628 source, csets, cleanupfn = bundlerepo.getremotechanges(ui, repo, peer,
620 source, csets, cleanupfn = bundlerepo.getremotechanges(ui, repo, peer,
629 onlyheads=heads, force=True)
621 onlyheads=heads, force=True)
630 else:
622 else:
631 source = repo
623 source = repo
632 heads = map(source.lookup, opts.get('branch', ()))
624 heads = map(source.lookup, opts.get('branch', ()))
633 cleanupfn = None
625 cleanupfn = None
634
626
635 try:
627 try:
636 if opts.get('continue'):
628 if opts.get('continue'):
637 tp.resume(repo, source, opts)
629 tp.resume(repo, source, opts)
638 return
630 return
639
631
640 tf = tp.transplantfilter(repo, source, p1)
632 tf = tp.transplantfilter(repo, source, p1)
641 if opts.get('prune'):
633 if opts.get('prune'):
642 prune = set(source.lookup(r)
634 prune = set(source.lookup(r)
643 for r in scmutil.revrange(source, opts.get('prune')))
635 for r in scmutil.revrange(source, opts.get('prune')))
644 matchfn = lambda x: tf(x) and x not in prune
636 matchfn = lambda x: tf(x) and x not in prune
645 else:
637 else:
646 matchfn = tf
638 matchfn = tf
647 merges = map(source.lookup, opts.get('merge', ()))
639 merges = map(source.lookup, opts.get('merge', ()))
648 revmap = {}
640 revmap = {}
649 if revs:
641 if revs:
650 for r in scmutil.revrange(source, revs):
642 for r in scmutil.revrange(source, revs):
651 revmap[int(r)] = source.lookup(r)
643 revmap[int(r)] = source.lookup(r)
652 elif opts.get('all') or not merges:
644 elif opts.get('all') or not merges:
653 if source != repo:
645 if source != repo:
654 alltransplants = incwalk(source, csets, match=matchfn)
646 alltransplants = incwalk(source, csets, match=matchfn)
655 else:
647 else:
656 alltransplants = transplantwalk(source, p1, heads,
648 alltransplants = transplantwalk(source, p1, heads,
657 match=matchfn)
649 match=matchfn)
658 if opts.get('all'):
650 if opts.get('all'):
659 revs = alltransplants
651 revs = alltransplants
660 else:
652 else:
661 revs, newmerges = browserevs(ui, source, alltransplants, opts)
653 revs, newmerges = browserevs(ui, source, alltransplants, opts)
662 merges.extend(newmerges)
654 merges.extend(newmerges)
663 for r in revs:
655 for r in revs:
664 revmap[source.changelog.rev(r)] = r
656 revmap[source.changelog.rev(r)] = r
665 for r in merges:
657 for r in merges:
666 revmap[source.changelog.rev(r)] = r
658 revmap[source.changelog.rev(r)] = r
667
659
668 tp.apply(repo, source, revmap, merges, opts)
660 tp.apply(repo, source, revmap, merges, opts)
669 finally:
661 finally:
670 if cleanupfn:
662 if cleanupfn:
671 cleanupfn()
663 cleanupfn()
672
664
673 def revsettransplanted(repo, subset, x):
665 def revsettransplanted(repo, subset, x):
674 """``transplanted([set])``
666 """``transplanted([set])``
675 Transplanted changesets in set, or all transplanted changesets.
667 Transplanted changesets in set, or all transplanted changesets.
676 """
668 """
677 if x:
669 if x:
678 s = revset.getset(repo, subset, x)
670 s = revset.getset(repo, subset, x)
679 else:
671 else:
680 s = subset
672 s = subset
681 return [r for r in s if repo[r].extra().get('transplant_source')]
673 return [r for r in s if repo[r].extra().get('transplant_source')]
682
674
683 def kwtransplanted(repo, ctx, **args):
675 def kwtransplanted(repo, ctx, **args):
684 """:transplanted: String. The node identifier of the transplanted
676 """:transplanted: String. The node identifier of the transplanted
685 changeset if any."""
677 changeset if any."""
686 n = ctx.extra().get('transplant_source')
678 n = ctx.extra().get('transplant_source')
687 return n and revlog.hex(n) or ''
679 return n and revlog.hex(n) or ''
688
680
689 def extsetup(ui):
681 def extsetup(ui):
690 revset.symbols['transplanted'] = revsettransplanted
682 revset.symbols['transplanted'] = revsettransplanted
691 templatekw.keywords['transplanted'] = kwtransplanted
683 templatekw.keywords['transplanted'] = kwtransplanted
692 cmdutil.unfinishedstates.append(
684 cmdutil.unfinishedstates.append(
693 ['series', True, False, _('transplant in progress'),
685 ['series', True, False, _('transplant in progress'),
694 _("use 'hg transplant --continue' or 'hg update' to abort")])
686 _("use 'hg transplant --continue' or 'hg update' to abort")])
695
687
696 # tell hggettext to extract docstrings from these functions:
688 # tell hggettext to extract docstrings from these functions:
697 i18nfunctions = [revsettransplanted, kwtransplanted]
689 i18nfunctions = [revsettransplanted, kwtransplanted]
@@ -1,722 +1,722
1 $ "$TESTDIR/hghave" killdaemons || exit 80
1 $ "$TESTDIR/hghave" killdaemons || exit 80
2
2
3 $ cat <<EOF >> $HGRCPATH
3 $ cat <<EOF >> $HGRCPATH
4 > [extensions]
4 > [extensions]
5 > transplant=
5 > transplant=
6 > EOF
6 > EOF
7
7
8 $ hg init t
8 $ hg init t
9 $ cd t
9 $ cd t
10 $ echo r1 > r1
10 $ echo r1 > r1
11 $ hg ci -Amr1 -d'0 0'
11 $ hg ci -Amr1 -d'0 0'
12 adding r1
12 adding r1
13 $ echo r2 > r2
13 $ echo r2 > r2
14 $ hg ci -Amr2 -d'1 0'
14 $ hg ci -Amr2 -d'1 0'
15 adding r2
15 adding r2
16 $ hg up 0
16 $ hg up 0
17 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
17 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
18
18
19 $ echo b1 > b1
19 $ echo b1 > b1
20 $ hg ci -Amb1 -d '0 0'
20 $ hg ci -Amb1 -d '0 0'
21 adding b1
21 adding b1
22 created new head
22 created new head
23 $ echo b2 > b2
23 $ echo b2 > b2
24 $ hg ci -Amb2 -d '1 0'
24 $ hg ci -Amb2 -d '1 0'
25 adding b2
25 adding b2
26 $ echo b3 > b3
26 $ echo b3 > b3
27 $ hg ci -Amb3 -d '2 0'
27 $ hg ci -Amb3 -d '2 0'
28 adding b3
28 adding b3
29
29
30 $ hg log --template '{rev} {parents} {desc}\n'
30 $ hg log --template '{rev} {parents} {desc}\n'
31 4 b3
31 4 b3
32 3 b2
32 3 b2
33 2 0:17ab29e464c6 b1
33 2 0:17ab29e464c6 b1
34 1 r2
34 1 r2
35 0 r1
35 0 r1
36
36
37 $ hg clone . ../rebase
37 $ hg clone . ../rebase
38 updating to branch default
38 updating to branch default
39 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
39 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
40 $ cd ../rebase
40 $ cd ../rebase
41
41
42 $ hg up -C 1
42 $ hg up -C 1
43 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
43 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
44
44
45 rebase b onto r1
45 rebase b onto r1
46
46
47 $ hg transplant -a -b tip
47 $ hg transplant -a -b tip
48 applying 37a1297eb21b
48 applying 37a1297eb21b
49 37a1297eb21b transplanted to e234d668f844
49 37a1297eb21b transplanted to e234d668f844
50 applying 722f4667af76
50 applying 722f4667af76
51 722f4667af76 transplanted to 539f377d78df
51 722f4667af76 transplanted to 539f377d78df
52 applying a53251cdf717
52 applying a53251cdf717
53 a53251cdf717 transplanted to ffd6818a3975
53 a53251cdf717 transplanted to ffd6818a3975
54 $ hg log --template '{rev} {parents} {desc}\n'
54 $ hg log --template '{rev} {parents} {desc}\n'
55 7 b3
55 7 b3
56 6 b2
56 6 b2
57 5 1:d11e3596cc1a b1
57 5 1:d11e3596cc1a b1
58 4 b3
58 4 b3
59 3 b2
59 3 b2
60 2 0:17ab29e464c6 b1
60 2 0:17ab29e464c6 b1
61 1 r2
61 1 r2
62 0 r1
62 0 r1
63
63
64 test transplanted revset
64 test transplanted revset
65
65
66 $ hg log -r 'transplanted()' --template '{rev} {parents} {desc}\n'
66 $ hg log -r 'transplanted()' --template '{rev} {parents} {desc}\n'
67 5 1:d11e3596cc1a b1
67 5 1:d11e3596cc1a b1
68 6 b2
68 6 b2
69 7 b3
69 7 b3
70 $ hg help revsets | grep transplanted
70 $ hg help revsets | grep transplanted
71 "transplanted([set])"
71 "transplanted([set])"
72 Transplanted changesets in set, or all transplanted changesets.
72 Transplanted changesets in set, or all transplanted changesets.
73
73
74 test tranplanted keyword
74 test tranplanted keyword
75
75
76 $ hg log --template '{rev} {transplanted}\n'
76 $ hg log --template '{rev} {transplanted}\n'
77 7 a53251cdf717679d1907b289f991534be05c997a
77 7 a53251cdf717679d1907b289f991534be05c997a
78 6 722f4667af767100cb15b6a79324bf8abbfe1ef4
78 6 722f4667af767100cb15b6a79324bf8abbfe1ef4
79 5 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21
79 5 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21
80 4
80 4
81 3
81 3
82 2
82 2
83 1
83 1
84 0
84 0
85
85
86 test destination() revset predicate with a transplant of a transplant; new
86 test destination() revset predicate with a transplant of a transplant; new
87 clone so subsequent rollback isn't affected
87 clone so subsequent rollback isn't affected
88 $ hg clone -q . ../destination
88 $ hg clone -q . ../destination
89 $ cd ../destination
89 $ cd ../destination
90 $ hg up -Cq 0
90 $ hg up -Cq 0
91 $ hg branch -q b4
91 $ hg branch -q b4
92 $ hg ci -qm "b4"
92 $ hg ci -qm "b4"
93 $ hg transplant 7
93 $ hg transplant 7
94 applying ffd6818a3975
94 applying ffd6818a3975
95 ffd6818a3975 transplanted to 502236fa76bb
95 ffd6818a3975 transplanted to 502236fa76bb
96
96
97
97
98 $ hg log -r 'destination()'
98 $ hg log -r 'destination()'
99 changeset: 5:e234d668f844
99 changeset: 5:e234d668f844
100 parent: 1:d11e3596cc1a
100 parent: 1:d11e3596cc1a
101 user: test
101 user: test
102 date: Thu Jan 01 00:00:00 1970 +0000
102 date: Thu Jan 01 00:00:00 1970 +0000
103 summary: b1
103 summary: b1
104
104
105 changeset: 6:539f377d78df
105 changeset: 6:539f377d78df
106 user: test
106 user: test
107 date: Thu Jan 01 00:00:01 1970 +0000
107 date: Thu Jan 01 00:00:01 1970 +0000
108 summary: b2
108 summary: b2
109
109
110 changeset: 7:ffd6818a3975
110 changeset: 7:ffd6818a3975
111 user: test
111 user: test
112 date: Thu Jan 01 00:00:02 1970 +0000
112 date: Thu Jan 01 00:00:02 1970 +0000
113 summary: b3
113 summary: b3
114
114
115 changeset: 9:502236fa76bb
115 changeset: 9:502236fa76bb
116 branch: b4
116 branch: b4
117 tag: tip
117 tag: tip
118 user: test
118 user: test
119 date: Thu Jan 01 00:00:02 1970 +0000
119 date: Thu Jan 01 00:00:02 1970 +0000
120 summary: b3
120 summary: b3
121
121
122 $ hg log -r 'destination(a53251cdf717)'
122 $ hg log -r 'destination(a53251cdf717)'
123 changeset: 7:ffd6818a3975
123 changeset: 7:ffd6818a3975
124 user: test
124 user: test
125 date: Thu Jan 01 00:00:02 1970 +0000
125 date: Thu Jan 01 00:00:02 1970 +0000
126 summary: b3
126 summary: b3
127
127
128 changeset: 9:502236fa76bb
128 changeset: 9:502236fa76bb
129 branch: b4
129 branch: b4
130 tag: tip
130 tag: tip
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:02 1970 +0000
132 date: Thu Jan 01 00:00:02 1970 +0000
133 summary: b3
133 summary: b3
134
134
135
135
136 test subset parameter in reverse order
136 test subset parameter in reverse order
137 $ hg log -r 'reverse(all()) and destination(a53251cdf717)'
137 $ hg log -r 'reverse(all()) and destination(a53251cdf717)'
138 changeset: 9:502236fa76bb
138 changeset: 9:502236fa76bb
139 branch: b4
139 branch: b4
140 tag: tip
140 tag: tip
141 user: test
141 user: test
142 date: Thu Jan 01 00:00:02 1970 +0000
142 date: Thu Jan 01 00:00:02 1970 +0000
143 summary: b3
143 summary: b3
144
144
145 changeset: 7:ffd6818a3975
145 changeset: 7:ffd6818a3975
146 user: test
146 user: test
147 date: Thu Jan 01 00:00:02 1970 +0000
147 date: Thu Jan 01 00:00:02 1970 +0000
148 summary: b3
148 summary: b3
149
149
150
150
151 back to the original dir
151 back to the original dir
152 $ cd ../rebase
152 $ cd ../rebase
153
153
154 rollback the transplant
154 rollback the transplant
155 $ hg rollback
155 $ hg rollback
156 repository tip rolled back to revision 4 (undo transplant)
156 repository tip rolled back to revision 4 (undo transplant)
157 working directory now based on revision 1
157 working directory now based on revision 1
158 $ hg tip -q
158 $ hg tip -q
159 4:a53251cdf717
159 4:a53251cdf717
160 $ hg parents -q
160 $ hg parents -q
161 1:d11e3596cc1a
161 1:d11e3596cc1a
162 $ hg status
162 $ hg status
163 ? b1
163 ? b1
164 ? b2
164 ? b2
165 ? b3
165 ? b3
166
166
167 $ hg clone ../t ../prune
167 $ hg clone ../t ../prune
168 updating to branch default
168 updating to branch default
169 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 $ cd ../prune
170 $ cd ../prune
171
171
172 $ hg up -C 1
172 $ hg up -C 1
173 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
173 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
174
174
175 rebase b onto r1, skipping b2
175 rebase b onto r1, skipping b2
176
176
177 $ hg transplant -a -b tip -p 3
177 $ hg transplant -a -b tip -p 3
178 applying 37a1297eb21b
178 applying 37a1297eb21b
179 37a1297eb21b transplanted to e234d668f844
179 37a1297eb21b transplanted to e234d668f844
180 applying a53251cdf717
180 applying a53251cdf717
181 a53251cdf717 transplanted to 7275fda4d04f
181 a53251cdf717 transplanted to 7275fda4d04f
182 $ hg log --template '{rev} {parents} {desc}\n'
182 $ hg log --template '{rev} {parents} {desc}\n'
183 6 b3
183 6 b3
184 5 1:d11e3596cc1a b1
184 5 1:d11e3596cc1a b1
185 4 b3
185 4 b3
186 3 b2
186 3 b2
187 2 0:17ab29e464c6 b1
187 2 0:17ab29e464c6 b1
188 1 r2
188 1 r2
189 0 r1
189 0 r1
190
190
191 test same-parent transplant with --log
191 test same-parent transplant with --log
192
192
193 $ hg clone -r 1 ../t ../sameparent
193 $ hg clone -r 1 ../t ../sameparent
194 adding changesets
194 adding changesets
195 adding manifests
195 adding manifests
196 adding file changes
196 adding file changes
197 added 2 changesets with 2 changes to 2 files
197 added 2 changesets with 2 changes to 2 files
198 updating to branch default
198 updating to branch default
199 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 $ cd ../sameparent
200 $ cd ../sameparent
201 $ hg transplant --log -s ../prune 5
201 $ hg transplant --log -s ../prune 5
202 searching for changes
202 searching for changes
203 applying e234d668f844
203 applying e234d668f844
204 e234d668f844 transplanted to e07aea8ecf9c
204 e234d668f844 transplanted to e07aea8ecf9c
205 $ hg log --template '{rev} {parents} {desc}\n'
205 $ hg log --template '{rev} {parents} {desc}\n'
206 2 b1
206 2 b1
207 (transplanted from e234d668f844e1b1a765f01db83a32c0c7bfa170)
207 (transplanted from e234d668f844e1b1a765f01db83a32c0c7bfa170)
208 1 r2
208 1 r2
209 0 r1
209 0 r1
210 remote transplant
210 remote transplant
211
211
212 $ hg clone -r 1 ../t ../remote
212 $ hg clone -r 1 ../t ../remote
213 adding changesets
213 adding changesets
214 adding manifests
214 adding manifests
215 adding file changes
215 adding file changes
216 added 2 changesets with 2 changes to 2 files
216 added 2 changesets with 2 changes to 2 files
217 updating to branch default
217 updating to branch default
218 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
218 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 $ cd ../remote
219 $ cd ../remote
220 $ hg transplant --log -s ../t 2 4
220 $ hg transplant --log -s ../t 2 4
221 searching for changes
221 searching for changes
222 applying 37a1297eb21b
222 applying 37a1297eb21b
223 37a1297eb21b transplanted to c19cf0ccb069
223 37a1297eb21b transplanted to c19cf0ccb069
224 applying a53251cdf717
224 applying a53251cdf717
225 a53251cdf717 transplanted to f7fe5bf98525
225 a53251cdf717 transplanted to f7fe5bf98525
226 $ hg log --template '{rev} {parents} {desc}\n'
226 $ hg log --template '{rev} {parents} {desc}\n'
227 3 b3
227 3 b3
228 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
228 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
229 2 b1
229 2 b1
230 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
230 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
231 1 r2
231 1 r2
232 0 r1
232 0 r1
233
233
234 skip previous transplants
234 skip previous transplants
235
235
236 $ hg transplant -s ../t -a -b 4
236 $ hg transplant -s ../t -a -b 4
237 searching for changes
237 searching for changes
238 applying 722f4667af76
238 applying 722f4667af76
239 722f4667af76 transplanted to 47156cd86c0b
239 722f4667af76 transplanted to 47156cd86c0b
240 $ hg log --template '{rev} {parents} {desc}\n'
240 $ hg log --template '{rev} {parents} {desc}\n'
241 4 b2
241 4 b2
242 3 b3
242 3 b3
243 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
243 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
244 2 b1
244 2 b1
245 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
245 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
246 1 r2
246 1 r2
247 0 r1
247 0 r1
248
248
249 skip local changes transplanted to the source
249 skip local changes transplanted to the source
250
250
251 $ echo b4 > b4
251 $ echo b4 > b4
252 $ hg ci -Amb4 -d '3 0'
252 $ hg ci -Amb4 -d '3 0'
253 adding b4
253 adding b4
254 $ hg clone ../t ../pullback
254 $ hg clone ../t ../pullback
255 updating to branch default
255 updating to branch default
256 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
256 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
257 $ cd ../pullback
257 $ cd ../pullback
258 $ hg transplant -s ../remote -a -b tip
258 $ hg transplant -s ../remote -a -b tip
259 searching for changes
259 searching for changes
260 applying 4333daefcb15
260 applying 4333daefcb15
261 4333daefcb15 transplanted to 5f42c04e07cc
261 4333daefcb15 transplanted to 5f42c04e07cc
262
262
263
263
264 remote transplant with pull
264 remote transplant with pull
265
265
266 $ hg -R ../t serve -p $HGPORT -d --pid-file=../t.pid
266 $ hg -R ../t serve -p $HGPORT -d --pid-file=../t.pid
267 $ cat ../t.pid >> $DAEMON_PIDS
267 $ cat ../t.pid >> $DAEMON_PIDS
268
268
269 $ hg clone -r 0 ../t ../rp
269 $ hg clone -r 0 ../t ../rp
270 adding changesets
270 adding changesets
271 adding manifests
271 adding manifests
272 adding file changes
272 adding file changes
273 added 1 changesets with 1 changes to 1 files
273 added 1 changesets with 1 changes to 1 files
274 updating to branch default
274 updating to branch default
275 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
276 $ cd ../rp
276 $ cd ../rp
277 $ hg transplant -s http://localhost:$HGPORT/ 2 4
277 $ hg transplant -s http://localhost:$HGPORT/ 2 4
278 searching for changes
278 searching for changes
279 searching for changes
279 searching for changes
280 adding changesets
280 adding changesets
281 adding manifests
281 adding manifests
282 adding file changes
282 adding file changes
283 added 1 changesets with 1 changes to 1 files
283 added 1 changesets with 1 changes to 1 files
284 applying a53251cdf717
284 applying a53251cdf717
285 a53251cdf717 transplanted to 8d9279348abb
285 a53251cdf717 transplanted to 8d9279348abb
286 $ hg log --template '{rev} {parents} {desc}\n'
286 $ hg log --template '{rev} {parents} {desc}\n'
287 2 b3
287 2 b3
288 1 b1
288 1 b1
289 0 r1
289 0 r1
290
290
291 remote transplant without pull
291 remote transplant without pull
292
292
293 $ hg pull -q http://localhost:$HGPORT/
293 $ hg pull -q http://localhost:$HGPORT/
294 $ hg transplant -s http://localhost:$HGPORT/ 2 4
294 $ hg transplant -s http://localhost:$HGPORT/ 2 4
295 searching for changes
295 searching for changes
296 skipping already applied revision 2:8d9279348abb
296 skipping already applied revision 2:8d9279348abb
297 applying 722f4667af76
297 applying 722f4667af76
298 722f4667af76 transplanted to 76e321915884
298 722f4667af76 transplanted to 76e321915884
299
299
300 transplant --continue
300 transplant --continue
301
301
302 $ hg init ../tc
302 $ hg init ../tc
303 $ cd ../tc
303 $ cd ../tc
304 $ cat <<EOF > foo
304 $ cat <<EOF > foo
305 > foo
305 > foo
306 > bar
306 > bar
307 > baz
307 > baz
308 > EOF
308 > EOF
309 $ echo toremove > toremove
309 $ echo toremove > toremove
310 $ echo baz > baz
310 $ echo baz > baz
311 $ hg ci -Amfoo
311 $ hg ci -Amfoo
312 adding baz
312 adding baz
313 adding foo
313 adding foo
314 adding toremove
314 adding toremove
315 $ cat <<EOF > foo
315 $ cat <<EOF > foo
316 > foo2
316 > foo2
317 > bar2
317 > bar2
318 > baz2
318 > baz2
319 > EOF
319 > EOF
320 $ rm toremove
320 $ rm toremove
321 $ echo added > added
321 $ echo added > added
322 $ hg ci -Amfoo2
322 $ hg ci -Amfoo2
323 adding added
323 adding added
324 removing toremove
324 removing toremove
325 $ echo bar > bar
325 $ echo bar > bar
326 $ cat > baz <<EOF
326 $ cat > baz <<EOF
327 > before baz
327 > before baz
328 > baz
328 > baz
329 > after baz
329 > after baz
330 > EOF
330 > EOF
331 $ hg ci -Ambar
331 $ hg ci -Ambar
332 adding bar
332 adding bar
333 $ echo bar2 >> bar
333 $ echo bar2 >> bar
334 $ hg ci -mbar2
334 $ hg ci -mbar2
335 $ hg up 0
335 $ hg up 0
336 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
336 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
337 $ echo foobar > foo
337 $ echo foobar > foo
338 $ hg ci -mfoobar
338 $ hg ci -mfoobar
339 created new head
339 created new head
340 $ hg transplant 1:3
340 $ hg transplant 1:3
341 applying 46ae92138f3c
341 applying 46ae92138f3c
342 patching file foo
342 patching file foo
343 Hunk #1 FAILED at 0
343 Hunk #1 FAILED at 0
344 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
344 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
345 patch failed to apply
345 patch failed to apply
346 abort: fix up the merge and run hg transplant --continue
346 abort: fix up the merge and run hg transplant --continue
347 [255]
347 [255]
348
348
349 transplant -c shouldn't use an old changeset
349 transplant -c shouldn't use an old changeset
350
350
351 $ hg up -C
351 $ hg up -C
352 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
352 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 $ rm added
353 $ rm added
354 $ hg transplant 1
354 $ hg transplant 1
355 applying 46ae92138f3c
355 applying 46ae92138f3c
356 patching file foo
356 patching file foo
357 Hunk #1 FAILED at 0
357 Hunk #1 FAILED at 0
358 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
358 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
359 patch failed to apply
359 patch failed to apply
360 abort: fix up the merge and run hg transplant --continue
360 abort: fix up the merge and run hg transplant --continue
361 [255]
361 [255]
362 $ hg transplant --continue
362 $ hg transplant --continue
363 46ae92138f3c transplanted as 9159dada197d
363 46ae92138f3c transplanted as 9159dada197d
364 $ hg transplant 1:3
364 $ hg transplant 1:3
365 skipping already applied revision 1:46ae92138f3c
365 skipping already applied revision 1:46ae92138f3c
366 applying 9d6d6b5a8275
366 applying 9d6d6b5a8275
367 9d6d6b5a8275 transplanted to 2d17a10c922f
367 9d6d6b5a8275 transplanted to 2d17a10c922f
368 applying 1dab759070cf
368 applying 1dab759070cf
369 1dab759070cf transplanted to e06a69927eb0
369 1dab759070cf transplanted to e06a69927eb0
370 $ hg locate
370 $ hg locate
371 added
371 added
372 bar
372 bar
373 baz
373 baz
374 foo
374 foo
375
375
376 test multiple revisions and --continue
376 test multiple revisions and --continue
377
377
378 $ hg up -qC 0
378 $ hg up -qC 0
379 $ echo bazbaz > baz
379 $ echo bazbaz > baz
380 $ hg ci -Am anotherbaz baz
380 $ hg ci -Am anotherbaz baz
381 created new head
381 created new head
382 $ hg transplant 1:3
382 $ hg transplant 1:3
383 applying 46ae92138f3c
383 applying 46ae92138f3c
384 46ae92138f3c transplanted to 1024233ea0ba
384 46ae92138f3c transplanted to 1024233ea0ba
385 applying 9d6d6b5a8275
385 applying 9d6d6b5a8275
386 patching file baz
386 patching file baz
387 Hunk #1 FAILED at 0
387 Hunk #1 FAILED at 0
388 1 out of 1 hunks FAILED -- saving rejects to file baz.rej
388 1 out of 1 hunks FAILED -- saving rejects to file baz.rej
389 patch failed to apply
389 patch failed to apply
390 abort: fix up the merge and run hg transplant --continue
390 abort: fix up the merge and run hg transplant --continue
391 [255]
391 [255]
392 $ echo fixed > baz
392 $ echo fixed > baz
393 $ hg transplant --continue
393 $ hg transplant --continue
394 9d6d6b5a8275 transplanted as d80c49962290
394 9d6d6b5a8275 transplanted as d80c49962290
395 applying 1dab759070cf
395 applying 1dab759070cf
396 1dab759070cf transplanted to aa0ffe6bd5ae
396 1dab759070cf transplanted to aa0ffe6bd5ae
397
397
398 $ cd ..
398 $ cd ..
399
399
400 Issue1111: Test transplant --merge
400 Issue1111: Test transplant --merge
401
401
402 $ hg init t1111
402 $ hg init t1111
403 $ cd t1111
403 $ cd t1111
404 $ echo a > a
404 $ echo a > a
405 $ hg ci -Am adda
405 $ hg ci -Am adda
406 adding a
406 adding a
407 $ echo b >> a
407 $ echo b >> a
408 $ hg ci -m appendb
408 $ hg ci -m appendb
409 $ echo c >> a
409 $ echo c >> a
410 $ hg ci -m appendc
410 $ hg ci -m appendc
411 $ hg up -C 0
411 $ hg up -C 0
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 $ echo d >> a
413 $ echo d >> a
414 $ hg ci -m appendd
414 $ hg ci -m appendd
415 created new head
415 created new head
416
416
417 tranplant
417 tranplant
418
418
419 $ hg transplant -m 1
419 $ hg transplant -m 1
420 applying 42dc4432fd35
420 applying 42dc4432fd35
421 1:42dc4432fd35 merged at a9f4acbac129
421 1:42dc4432fd35 merged at a9f4acbac129
422 $ cd ..
422 $ cd ..
423
423
424 test transplant into empty repository
424 test transplant into empty repository
425
425
426 $ hg init empty
426 $ hg init empty
427 $ cd empty
427 $ cd empty
428 $ hg transplant -s ../t -b tip -a
428 $ hg transplant -s ../t -b tip -a
429 adding changesets
429 adding changesets
430 adding manifests
430 adding manifests
431 adding file changes
431 adding file changes
432 added 4 changesets with 4 changes to 4 files
432 added 4 changesets with 4 changes to 4 files
433
433
434 test "--merge" causing pull from source repository on local host
434 test "--merge" causing pull from source repository on local host
435
435
436 $ hg --config extensions.mq= -q strip 2
436 $ hg --config extensions.mq= -q strip 2
437 $ hg transplant -s ../t --merge tip
437 $ hg transplant -s ../t --merge tip
438 searching for changes
438 searching for changes
439 searching for changes
439 searching for changes
440 adding changesets
440 adding changesets
441 adding manifests
441 adding manifests
442 adding file changes
442 adding file changes
443 added 2 changesets with 2 changes to 2 files
443 added 2 changesets with 2 changes to 2 files
444 applying a53251cdf717
444 applying a53251cdf717
445 4:a53251cdf717 merged at 4831f4dc831a
445 4:a53251cdf717 merged at 4831f4dc831a
446
446
447 test interactive transplant
447 test interactive transplant
448
448
449 $ hg --config extensions.strip= -q strip 0
449 $ hg --config extensions.strip= -q strip 0
450 $ hg -R ../t log -G --template "{rev}:{node|short}"
450 $ hg -R ../t log -G --template "{rev}:{node|short}"
451 @ 4:a53251cdf717
451 @ 4:a53251cdf717
452 |
452 |
453 o 3:722f4667af76
453 o 3:722f4667af76
454 |
454 |
455 o 2:37a1297eb21b
455 o 2:37a1297eb21b
456 |
456 |
457 | o 1:d11e3596cc1a
457 | o 1:d11e3596cc1a
458 |/
458 |/
459 o 0:17ab29e464c6
459 o 0:17ab29e464c6
460
460
461 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
461 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
462 > p
462 > p
463 > y
463 > y
464 > n
464 > n
465 > n
465 > n
466 > m
466 > m
467 > c
467 > c
468 > EOF
468 > EOF
469 0:17ab29e464c6
469 0:17ab29e464c6
470 apply changeset? [ynmpcq?]: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
470 apply changeset? [ynmpcq?]: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
471 +++ b/r1 Thu Jan 01 00:00:00 1970 +0000
471 +++ b/r1 Thu Jan 01 00:00:00 1970 +0000
472 @@ -0,0 +1,1 @@
472 @@ -0,0 +1,1 @@
473 +r1
473 +r1
474 apply changeset? [ynmpcq?]: 1:d11e3596cc1a
474 apply changeset? [ynmpcq?]: 1:d11e3596cc1a
475 apply changeset? [ynmpcq?]: 2:37a1297eb21b
475 apply changeset? [ynmpcq?]: 2:37a1297eb21b
476 apply changeset? [ynmpcq?]: 3:722f4667af76
476 apply changeset? [ynmpcq?]: 3:722f4667af76
477 apply changeset? [ynmpcq?]: 4:a53251cdf717
477 apply changeset? [ynmpcq?]: 4:a53251cdf717
478 apply changeset? [ynmpcq?]: (no-eol)
478 apply changeset? [ynmpcq?]: (no-eol)
479 $ hg log -G --template "{node|short}"
479 $ hg log -G --template "{node|short}"
480 @ 88be5dde5260
480 @ 88be5dde5260
481 |\
481 |\
482 | o 722f4667af76
482 | o 722f4667af76
483 | |
483 | |
484 | o 37a1297eb21b
484 | o 37a1297eb21b
485 |/
485 |/
486 o 17ab29e464c6
486 o 17ab29e464c6
487
487
488 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
488 $ hg transplant -q --config ui.interactive=true -s ../t <<EOF
489 > x
489 > x
490 > ?
490 > ?
491 > y
491 > y
492 > q
492 > q
493 > EOF
493 > EOF
494 1:d11e3596cc1a
494 1:d11e3596cc1a
495 apply changeset? [ynmpcq?]: unrecognized response
495 apply changeset? [ynmpcq?]: unrecognized response
496 apply changeset? [ynmpcq?]: y: transplant this changeset
496 apply changeset? [ynmpcq?]: y: yes, transplant this changeset
497 n: skip this changeset
497 n: no, skip this changeset
498 m: merge at this changeset
498 m: merge at this changeset
499 p: show patch
499 p: show patch
500 c: commit selected changesets
500 c: commit selected changesets
501 q: cancel transplant
501 q: quit and cancel transplant
502 ?: show this help
502 ?: ? (show this help)
503 apply changeset? [ynmpcq?]: 4:a53251cdf717
503 apply changeset? [ynmpcq?]: 4:a53251cdf717
504 apply changeset? [ynmpcq?]: (no-eol)
504 apply changeset? [ynmpcq?]: (no-eol)
505 $ hg heads --template "{node|short}\n"
505 $ hg heads --template "{node|short}\n"
506 88be5dde5260
506 88be5dde5260
507
507
508 $ cd ..
508 $ cd ..
509
509
510
510
511 #if unix-permissions system-sh
511 #if unix-permissions system-sh
512
512
513 test filter
513 test filter
514
514
515 $ hg init filter
515 $ hg init filter
516 $ cd filter
516 $ cd filter
517 $ cat <<'EOF' >test-filter
517 $ cat <<'EOF' >test-filter
518 > #!/bin/sh
518 > #!/bin/sh
519 > sed 's/r1/r2/' $1 > $1.new
519 > sed 's/r1/r2/' $1 > $1.new
520 > mv $1.new $1
520 > mv $1.new $1
521 > EOF
521 > EOF
522 $ chmod +x test-filter
522 $ chmod +x test-filter
523 $ hg transplant -s ../t -b tip -a --filter ./test-filter
523 $ hg transplant -s ../t -b tip -a --filter ./test-filter
524 filtering * (glob)
524 filtering * (glob)
525 applying 17ab29e464c6
525 applying 17ab29e464c6
526 17ab29e464c6 transplanted to e9ffc54ea104
526 17ab29e464c6 transplanted to e9ffc54ea104
527 filtering * (glob)
527 filtering * (glob)
528 applying 37a1297eb21b
528 applying 37a1297eb21b
529 37a1297eb21b transplanted to 348b36d0b6a5
529 37a1297eb21b transplanted to 348b36d0b6a5
530 filtering * (glob)
530 filtering * (glob)
531 applying 722f4667af76
531 applying 722f4667af76
532 722f4667af76 transplanted to 0aa6979afb95
532 722f4667af76 transplanted to 0aa6979afb95
533 filtering * (glob)
533 filtering * (glob)
534 applying a53251cdf717
534 applying a53251cdf717
535 a53251cdf717 transplanted to 14f8512272b5
535 a53251cdf717 transplanted to 14f8512272b5
536 $ hg log --template '{rev} {parents} {desc}\n'
536 $ hg log --template '{rev} {parents} {desc}\n'
537 3 b3
537 3 b3
538 2 b2
538 2 b2
539 1 b1
539 1 b1
540 0 r2
540 0 r2
541 $ cd ..
541 $ cd ..
542
542
543
543
544 test filter with failed patch
544 test filter with failed patch
545
545
546 $ cd filter
546 $ cd filter
547 $ hg up 0
547 $ hg up 0
548 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
548 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
549 $ echo foo > b1
549 $ echo foo > b1
550 $ hg ci -Am foo
550 $ hg ci -Am foo
551 adding b1
551 adding b1
552 adding test-filter
552 adding test-filter
553 created new head
553 created new head
554 $ hg transplant 1 --filter ./test-filter
554 $ hg transplant 1 --filter ./test-filter
555 filtering * (glob)
555 filtering * (glob)
556 applying 348b36d0b6a5
556 applying 348b36d0b6a5
557 file b1 already exists
557 file b1 already exists
558 1 out of 1 hunks FAILED -- saving rejects to file b1.rej
558 1 out of 1 hunks FAILED -- saving rejects to file b1.rej
559 patch failed to apply
559 patch failed to apply
560 abort: fix up the merge and run hg transplant --continue
560 abort: fix up the merge and run hg transplant --continue
561 [255]
561 [255]
562 $ cd ..
562 $ cd ..
563
563
564 test environment passed to filter
564 test environment passed to filter
565
565
566 $ hg init filter-environment
566 $ hg init filter-environment
567 $ cd filter-environment
567 $ cd filter-environment
568 $ cat <<'EOF' >test-filter-environment
568 $ cat <<'EOF' >test-filter-environment
569 > #!/bin/sh
569 > #!/bin/sh
570 > echo "Transplant by $HGUSER" >> $1
570 > echo "Transplant by $HGUSER" >> $1
571 > echo "Transplant from rev $HGREVISION" >> $1
571 > echo "Transplant from rev $HGREVISION" >> $1
572 > EOF
572 > EOF
573 $ chmod +x test-filter-environment
573 $ chmod +x test-filter-environment
574 $ hg transplant -s ../t --filter ./test-filter-environment 0
574 $ hg transplant -s ../t --filter ./test-filter-environment 0
575 filtering * (glob)
575 filtering * (glob)
576 applying 17ab29e464c6
576 applying 17ab29e464c6
577 17ab29e464c6 transplanted to 5190e68026a0
577 17ab29e464c6 transplanted to 5190e68026a0
578
578
579 $ hg log --template '{rev} {parents} {desc}\n'
579 $ hg log --template '{rev} {parents} {desc}\n'
580 0 r1
580 0 r1
581 Transplant by test
581 Transplant by test
582 Transplant from rev 17ab29e464c6ca53e329470efe2a9918ac617a6f
582 Transplant from rev 17ab29e464c6ca53e329470efe2a9918ac617a6f
583 $ cd ..
583 $ cd ..
584
584
585 test transplant with filter handles invalid changelog
585 test transplant with filter handles invalid changelog
586
586
587 $ hg init filter-invalid-log
587 $ hg init filter-invalid-log
588 $ cd filter-invalid-log
588 $ cd filter-invalid-log
589 $ cat <<'EOF' >test-filter-invalid-log
589 $ cat <<'EOF' >test-filter-invalid-log
590 > #!/bin/sh
590 > #!/bin/sh
591 > echo "" > $1
591 > echo "" > $1
592 > EOF
592 > EOF
593 $ chmod +x test-filter-invalid-log
593 $ chmod +x test-filter-invalid-log
594 $ hg transplant -s ../t --filter ./test-filter-invalid-log 0
594 $ hg transplant -s ../t --filter ./test-filter-invalid-log 0
595 filtering * (glob)
595 filtering * (glob)
596 abort: filter corrupted changeset (no user or date)
596 abort: filter corrupted changeset (no user or date)
597 [255]
597 [255]
598 $ cd ..
598 $ cd ..
599
599
600 #endif
600 #endif
601
601
602
602
603 test with a win32ext like setup (differing EOLs)
603 test with a win32ext like setup (differing EOLs)
604
604
605 $ hg init twin1
605 $ hg init twin1
606 $ cd twin1
606 $ cd twin1
607 $ echo a > a
607 $ echo a > a
608 $ echo b > b
608 $ echo b > b
609 $ echo b >> b
609 $ echo b >> b
610 $ hg ci -Am t
610 $ hg ci -Am t
611 adding a
611 adding a
612 adding b
612 adding b
613 $ echo a > b
613 $ echo a > b
614 $ echo b >> b
614 $ echo b >> b
615 $ hg ci -m changeb
615 $ hg ci -m changeb
616 $ cd ..
616 $ cd ..
617
617
618 $ hg init twin2
618 $ hg init twin2
619 $ cd twin2
619 $ cd twin2
620 $ echo '[patch]' >> .hg/hgrc
620 $ echo '[patch]' >> .hg/hgrc
621 $ echo 'eol = crlf' >> .hg/hgrc
621 $ echo 'eol = crlf' >> .hg/hgrc
622 $ python -c "file('b', 'wb').write('b\r\nb\r\n')"
622 $ python -c "file('b', 'wb').write('b\r\nb\r\n')"
623 $ hg ci -Am addb
623 $ hg ci -Am addb
624 adding b
624 adding b
625 $ hg transplant -s ../twin1 tip
625 $ hg transplant -s ../twin1 tip
626 searching for changes
626 searching for changes
627 warning: repository is unrelated
627 warning: repository is unrelated
628 applying 2e849d776c17
628 applying 2e849d776c17
629 2e849d776c17 transplanted to 8e65bebc063e
629 2e849d776c17 transplanted to 8e65bebc063e
630 $ cat b
630 $ cat b
631 a\r (esc)
631 a\r (esc)
632 b\r (esc)
632 b\r (esc)
633 $ cd ..
633 $ cd ..
634
634
635 test transplant with merge changeset is skipped
635 test transplant with merge changeset is skipped
636
636
637 $ hg init merge1a
637 $ hg init merge1a
638 $ cd merge1a
638 $ cd merge1a
639 $ echo a > a
639 $ echo a > a
640 $ hg ci -Am a
640 $ hg ci -Am a
641 adding a
641 adding a
642 $ hg branch b
642 $ hg branch b
643 marked working directory as branch b
643 marked working directory as branch b
644 (branches are permanent and global, did you want a bookmark?)
644 (branches are permanent and global, did you want a bookmark?)
645 $ hg ci -m branchb
645 $ hg ci -m branchb
646 $ echo b > b
646 $ echo b > b
647 $ hg ci -Am b
647 $ hg ci -Am b
648 adding b
648 adding b
649 $ hg update default
649 $ hg update default
650 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
650 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
651 $ hg merge b
651 $ hg merge b
652 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
652 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
653 (branch merge, don't forget to commit)
653 (branch merge, don't forget to commit)
654 $ hg ci -m mergeb
654 $ hg ci -m mergeb
655 $ cd ..
655 $ cd ..
656
656
657 $ hg init merge1b
657 $ hg init merge1b
658 $ cd merge1b
658 $ cd merge1b
659 $ hg transplant -s ../merge1a tip
659 $ hg transplant -s ../merge1a tip
660 $ cd ..
660 $ cd ..
661
661
662 test transplant with merge changeset accepts --parent
662 test transplant with merge changeset accepts --parent
663
663
664 $ hg init merge2a
664 $ hg init merge2a
665 $ cd merge2a
665 $ cd merge2a
666 $ echo a > a
666 $ echo a > a
667 $ hg ci -Am a
667 $ hg ci -Am a
668 adding a
668 adding a
669 $ hg branch b
669 $ hg branch b
670 marked working directory as branch b
670 marked working directory as branch b
671 (branches are permanent and global, did you want a bookmark?)
671 (branches are permanent and global, did you want a bookmark?)
672 $ hg ci -m branchb
672 $ hg ci -m branchb
673 $ echo b > b
673 $ echo b > b
674 $ hg ci -Am b
674 $ hg ci -Am b
675 adding b
675 adding b
676 $ hg update default
676 $ hg update default
677 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
677 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
678 $ hg merge b
678 $ hg merge b
679 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
679 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
680 (branch merge, don't forget to commit)
680 (branch merge, don't forget to commit)
681 $ hg ci -m mergeb
681 $ hg ci -m mergeb
682 $ cd ..
682 $ cd ..
683
683
684 $ hg init merge2b
684 $ hg init merge2b
685 $ cd merge2b
685 $ cd merge2b
686 $ hg transplant -s ../merge2a --parent 0 tip
686 $ hg transplant -s ../merge2a --parent 0 tip
687 applying be9f9b39483f
687 applying be9f9b39483f
688 be9f9b39483f transplanted to 9959e51f94d1
688 be9f9b39483f transplanted to 9959e51f94d1
689 $ cd ..
689 $ cd ..
690
690
691 test transplanting a patch turning into a no-op
691 test transplanting a patch turning into a no-op
692
692
693 $ hg init binarysource
693 $ hg init binarysource
694 $ cd binarysource
694 $ cd binarysource
695 $ echo a > a
695 $ echo a > a
696 $ hg ci -Am adda a
696 $ hg ci -Am adda a
697 >>> file('b', 'wb').write('\0b1')
697 >>> file('b', 'wb').write('\0b1')
698 $ hg ci -Am addb b
698 $ hg ci -Am addb b
699 >>> file('b', 'wb').write('\0b2')
699 >>> file('b', 'wb').write('\0b2')
700 $ hg ci -m changeb b
700 $ hg ci -m changeb b
701 $ cd ..
701 $ cd ..
702
702
703 $ hg clone -r0 binarysource binarydest
703 $ hg clone -r0 binarysource binarydest
704 adding changesets
704 adding changesets
705 adding manifests
705 adding manifests
706 adding file changes
706 adding file changes
707 added 1 changesets with 1 changes to 1 files
707 added 1 changesets with 1 changes to 1 files
708 updating to branch default
708 updating to branch default
709 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
709 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
710 $ cd binarydest
710 $ cd binarydest
711 $ cp ../binarysource/b b
711 $ cp ../binarysource/b b
712 $ hg ci -Am addb2 b
712 $ hg ci -Am addb2 b
713 $ hg transplant -s ../binarysource 2
713 $ hg transplant -s ../binarysource 2
714 searching for changes
714 searching for changes
715 applying 7a7d57e15850
715 applying 7a7d57e15850
716 skipping emptied changeset 7a7d57e15850
716 skipping emptied changeset 7a7d57e15850
717 $ cd ..
717 $ cd ..
718
718
719 Explicitly kill daemons to let the test exit on Windows
719 Explicitly kill daemons to let the test exit on Windows
720
720
721 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
721 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
722
722
General Comments 0
You need to be logged in to leave comments. Login now