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