Mercurial > hg > mercurial-crew
annotate hgext/transplant.py @ 11638:79231258503b stable
transplant: crash if repo.commit() finds nothing to commit
(makes issue2135, issue2264 more obvious, but does nothing to fix
either one)
This seems to happen in two distinct cases:
* patch.patch() claims success but changes nothing (e.g.
the transplanted changeset adds an empty file that already
exists)
* patch.patch() makes changes, but repo.status() fails to report them
Both of these seem like bugs in other parts of Mercurial, so arguably
it's not transplant's job to detect the failure to commit. However:
* detecting the problem as soon as possible is desirable
* it prevents a more obscure crash later, in transplants.write()
* there might be other lurking (or future) bugs that cause
repo.commit() to do nothing
Also, in the case of issue2264 (source changesets silently dropped by
transplant), the only way to spot the problem currently is the crash
in transplants.write(). Failure to transplant a patch should abort
immediately, whether it's user error (patch does not apply) or a
Mercurial bug (e.g. repo.status() failing to report changes).
author | Greg Ward <greg-hg@gerg.ca> |
---|---|
date | Sun, 18 Jul 2010 21:29:29 -0400 |
parents | 5834e79b24f7 |
children | a4fbbe0fbc38 |
rev | line source |
---|---|
3714 | 1 # Patch transplanting extension for Mercurial |
2 # | |
4635
63b9d2deed48
Updated copyright notices and add "and others" to "hg version"
Thomas Arendsen Hein <thomas@intevation.de>
parents:
4516
diff
changeset
|
3 # Copyright 2006, 2007 Brendan Cully <brendan@kublai.com> |
3714 | 4 # |
8225
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
8209
diff
changeset
|
5 # This software may be used and distributed according to the terms of the |
10263 | 6 # GNU General Public License version 2 or any later version. |
3714 | 7 |
8934
9dda4c73fc3b
extensions: change descriptions for extensions providing a few commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
8894
diff
changeset
|
8 '''command to transplant changesets from another branch |
3714 | 9 |
10 This extension allows you to transplant patches from another branch. | |
11 | |
8000
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
12 Transplanted patches are recorded in .hg/transplant/transplants, as a |
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
13 map from a changeset hash to its hash in the source repository. |
3714 | 14 ''' |
15 | |
7629
97253bcb44a8
transplant: move docstrings before imports (see issue1466)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7415
diff
changeset
|
16 from mercurial.i18n import _ |
97253bcb44a8
transplant: move docstrings before imports (see issue1466)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7415
diff
changeset
|
17 import os, tempfile |
8703
8676dd819444
transplant: use match object rather than files for commit
Matt Mackall <mpm@selenic.com>
parents:
8615
diff
changeset
|
18 from mercurial import bundlerepo, changegroup, cmdutil, hg, merge, match |
11301
3d0591a66118
move discovery methods from localrepo into new discovery module
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
11193
diff
changeset
|
19 from mercurial import patch, revlog, util, error, discovery |
7629
97253bcb44a8
transplant: move docstrings before imports (see issue1466)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7415
diff
changeset
|
20 |
8778
c5f36402daad
use new style classes
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
8706
diff
changeset
|
21 class transplantentry(object): |
3714 | 22 def __init__(self, lnode, rnode): |
23 self.lnode = lnode | |
24 self.rnode = rnode | |
25 | |
8778
c5f36402daad
use new style classes
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
8706
diff
changeset
|
26 class transplants(object): |
3714 | 27 def __init__(self, path=None, transplantfile=None, opener=None): |
28 self.path = path | |
29 self.transplantfile = transplantfile | |
30 self.opener = opener | |
31 | |
32 if not opener: | |
33 self.opener = util.opener(self.path) | |
34 self.transplants = [] | |
35 self.dirty = False | |
36 self.read() | |
37 | |
38 def read(self): | |
39 abspath = os.path.join(self.path, self.transplantfile) | |
40 if self.transplantfile and os.path.exists(abspath): | |
41 for line in self.opener(self.transplantfile).read().splitlines(): | |
42 lnode, rnode = map(revlog.bin, line.split(':')) | |
43 self.transplants.append(transplantentry(lnode, rnode)) | |
44 | |
45 def write(self): | |
46 if self.dirty and self.transplantfile: | |
47 if not os.path.isdir(self.path): | |
48 os.mkdir(self.path) | |
49 fp = self.opener(self.transplantfile, 'w') | |
50 for c in self.transplants: | |
51 l, r = map(revlog.hex, (c.lnode, c.rnode)) | |
52 fp.write(l + ':' + r + '\n') | |
53 fp.close() | |
54 self.dirty = False | |
55 | |
56 def get(self, rnode): | |
57 return [t for t in self.transplants if t.rnode == rnode] | |
58 | |
59 def set(self, lnode, rnode): | |
60 self.transplants.append(transplantentry(lnode, rnode)) | |
61 self.dirty = True | |
62 | |
63 def remove(self, transplant): | |
64 del self.transplants[self.transplants.index(transplant)] | |
65 self.dirty = True | |
66 | |
8778
c5f36402daad
use new style classes
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
8706
diff
changeset
|
67 class transplanter(object): |
3714 | 68 def __init__(self, ui, repo): |
69 self.ui = ui | |
70 self.path = repo.join('transplant') | |
71 self.opener = util.opener(self.path) | |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
72 self.transplants = transplants(self.path, 'transplants', |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
73 opener=self.opener) |
3714 | 74 |
75 def applied(self, repo, node, parent): | |
76 '''returns True if a node is already an ancestor of parent | |
77 or has already been transplanted''' | |
78 if hasnode(repo, node): | |
79 if node in repo.changelog.reachable(parent, stop=node): | |
80 return True | |
81 for t in self.transplants.get(node): | |
82 # it might have been stripped | |
83 if not hasnode(repo, t.lnode): | |
84 self.transplants.remove(t) | |
85 return False | |
86 if t.lnode in repo.changelog.reachable(parent, stop=t.lnode): | |
87 return True | |
88 return False | |
89 | |
90 def apply(self, repo, source, revmap, merges, opts={}): | |
91 '''apply the revisions in revmap one by one in revision order''' | |
8209
a1a5a57efe90
replace util.sort with sorted built-in
Matt Mackall <mpm@selenic.com>
parents:
8176
diff
changeset
|
92 revs = sorted(revmap) |
3714 | 93 p1, p2 = repo.dirstate.parents() |
94 pulls = [] | |
95 diffopts = patch.diffopts(self.ui, opts) | |
96 diffopts.git = True | |
97 | |
4959
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
98 lock = wlock = None |
3714 | 99 try: |
4959
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
100 wlock = repo.wlock() |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
101 lock = repo.lock() |
3714 | 102 for rev in revs: |
103 node = revmap[rev] | |
104 revstr = '%s:%s' % (rev, revlog.short(node)) | |
105 | |
106 if self.applied(repo, node, p1): | |
107 self.ui.warn(_('skipping already applied revision %s\n') % | |
108 revstr) | |
109 continue | |
110 | |
111 parents = source.changelog.parents(node) | |
112 if not opts.get('filter'): | |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
113 # If the changeset parent is the same as the |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
114 # wdir's parent, just pull it. |
3714 | 115 if parents[0] == p1: |
116 pulls.append(node) | |
117 p1 = node | |
118 continue | |
119 if pulls: | |
120 if source != repo: | |
4961
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
121 repo.pull(source, heads=pulls) |
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
122 merge.update(repo, pulls[-1], False, False, None) |
3714 | 123 p1, p2 = repo.dirstate.parents() |
124 pulls = [] | |
125 | |
126 domerge = False | |
127 if node in merges: | |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
128 # pulling all the merge revs at once would mean we |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
129 # couldn't transplant after the latest even if |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
130 # transplants before them fail. |
3714 | 131 domerge = True |
132 if not hasnode(repo, node): | |
4961
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
133 repo.pull(source, heads=[node]) |
3714 | 134 |
135 if parents[1] != revlog.nullid: | |
136 self.ui.note(_('skipping merge changeset %s:%s\n') | |
137 % (rev, revlog.short(node))) | |
138 patchfile = None | |
139 else: | |
140 fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-') | |
141 fp = os.fdopen(fd, 'w') | |
7308
b6f5490effbf
patch: turn patch.diff() into a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7278
diff
changeset
|
142 gen = patch.diff(source, parents[0], node, opts=diffopts) |
b6f5490effbf
patch: turn patch.diff() into a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7278
diff
changeset
|
143 for chunk in gen: |
b6f5490effbf
patch: turn patch.diff() into a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7278
diff
changeset
|
144 fp.write(chunk) |
3714 | 145 fp.close() |
146 | |
147 del revmap[rev] | |
148 if patchfile or domerge: | |
149 try: | |
4961
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
150 n = self.applyone(repo, node, |
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
151 source.changelog.read(node), |
3714 | 152 patchfile, merge=domerge, |
153 log=opts.get('log'), | |
4961
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
154 filter=opts.get('filter')) |
4251
e76e52145c3d
transplant: fix ignoring empty changesets (eg after filter)
Brendan Cully <brendan@kublai.com>
parents:
4072
diff
changeset
|
155 if n and domerge: |
3714 | 156 self.ui.status(_('%s merged at %s\n') % (revstr, |
157 revlog.short(n))) | |
4251
e76e52145c3d
transplant: fix ignoring empty changesets (eg after filter)
Brendan Cully <brendan@kublai.com>
parents:
4072
diff
changeset
|
158 elif n: |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
159 self.ui.status(_('%s transplanted to %s\n') |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
160 % (revlog.short(node), |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
161 revlog.short(n))) |
3714 | 162 finally: |
163 if patchfile: | |
164 os.unlink(patchfile) | |
165 if pulls: | |
4961
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
166 repo.pull(source, heads=pulls) |
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
167 merge.update(repo, pulls[-1], False, False, None) |
3714 | 168 finally: |
169 self.saveseries(revmap, merges) | |
170 self.transplants.write() | |
8107
6ee71f78497c
switch lock releasing in the extensions from gc to explicit
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8075
diff
changeset
|
171 lock.release() |
6ee71f78497c
switch lock releasing in the extensions from gc to explicit
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8075
diff
changeset
|
172 wlock.release() |
3714 | 173 |
174 def filter(self, filter, changelog, patchfile): | |
175 '''arbitrarily rewrite changeset before applying it''' | |
176 | |
6966
057ced2b8543
i18n: mark strings for translation in transplant extension
Martin Geisler <mg@daimi.au.dk>
parents:
6764
diff
changeset
|
177 self.ui.status(_('filtering %s\n') % patchfile) |
3759
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
178 user, date, msg = (changelog[1], changelog[2], changelog[4]) |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
179 |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
180 fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-') |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
181 fp = os.fdopen(fd, 'w') |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
182 fp.write("# HG changeset patch\n") |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
183 fp.write("# User %s\n" % user) |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
184 fp.write("# Date %d %d\n" % date) |
9433
f01a22096f1f
transplant: Add trailing LF in tmp file for filtering
Mads Kiilerich <mads@kiilerich.com>
parents:
9186
diff
changeset
|
185 fp.write(msg + '\n') |
3759
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
186 fp.close() |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
187 |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
188 try: |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
189 util.system('%s %s %s' % (filter, util.shellquote(headerfile), |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
190 util.shellquote(patchfile)), |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
191 environ={'HGUSER': changelog[1]}, |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
192 onerr=util.Abort, errprefix=_('filter failed')) |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
193 user, date, msg = self.parselog(file(headerfile))[1:4] |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
194 finally: |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
195 os.unlink(headerfile) |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
196 |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
197 return (user, date, msg) |
3714 | 198 |
199 def applyone(self, repo, node, cl, patchfile, merge=False, log=False, | |
4961
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
200 filter=None): |
3714 | 201 '''apply the patch in patchfile to the repository as a transplant''' |
202 (manifest, user, (time, timezone), files, message) = cl[:5] | |
203 date = "%d %d" % (time, timezone) | |
204 extra = {'transplant_source': node} | |
205 if filter: | |
3759
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
206 (user, date, message) = self.filter(filter, cl, patchfile) |
3714 | 207 |
208 if log: | |
9186
d0225fa2f6c4
do not translate commit messages
Martin Geisler <mg@lazybytes.net>
parents:
8934
diff
changeset
|
209 # we don't translate messages inserted into commits |
3714 | 210 message += '\n(transplanted from %s)' % revlog.hex(node) |
211 | |
212 self.ui.status(_('applying %s\n') % revlog.short(node)) | |
213 self.ui.note('%s %s\n%s\n' % (user, date, message)) | |
214 | |
215 if not patchfile and not merge: | |
216 raise util.Abort(_('can only omit patchfile if merging')) | |
217 if patchfile: | |
218 try: | |
219 files = {} | |
3726
752884db5037
transplant: recover added/removed files after failed application
Brendan Cully <brendan@kublai.com>
parents:
3725
diff
changeset
|
220 try: |
7873
d812029cda85
cleanup: drop variables for unused return values
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents:
7744
diff
changeset
|
221 patch.patch(patchfile, self.ui, cwd=repo.root, |
8811
8b35b08724eb
Make mq, record and transplant honor patch.eol
Patrick Mezard <pmezard@gmail.com>
parents:
8778
diff
changeset
|
222 files=files, eolmode=None) |
3726
752884db5037
transplant: recover added/removed files after failed application
Brendan Cully <brendan@kublai.com>
parents:
3725
diff
changeset
|
223 if not files: |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
224 self.ui.warn(_('%s: empty changeset') |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
225 % revlog.hex(node)) |
4251
e76e52145c3d
transplant: fix ignoring empty changesets (eg after filter)
Brendan Cully <brendan@kublai.com>
parents:
4072
diff
changeset
|
226 return None |
3726
752884db5037
transplant: recover added/removed files after failed application
Brendan Cully <brendan@kublai.com>
parents:
3725
diff
changeset
|
227 finally: |
4961
126f527b3ba3
Make repo locks recursive, eliminate all passing of lock/wlock
Matt Mackall <mpm@selenic.com>
parents:
4959
diff
changeset
|
228 files = patch.updatedir(self.ui, repo, files) |
3714 | 229 except Exception, inst: |
3757
faed44bab17b
transplant: clobber old series when transplant fails
Brendan Cully <brendan@kublai.com>
parents:
3752
diff
changeset
|
230 seriespath = os.path.join(self.path, 'series') |
faed44bab17b
transplant: clobber old series when transplant fails
Brendan Cully <brendan@kublai.com>
parents:
3752
diff
changeset
|
231 if os.path.exists(seriespath): |
faed44bab17b
transplant: clobber old series when transplant fails
Brendan Cully <brendan@kublai.com>
parents:
3752
diff
changeset
|
232 os.unlink(seriespath) |
3714 | 233 p1 = repo.dirstate.parents()[0] |
234 p2 = node | |
3725
ccc7a9eb0e5e
transplant: preserve filter changes in --continue log
Brendan Cully <brendan@kublai.com>
parents:
3724
diff
changeset
|
235 self.log(user, date, message, p1, p2, merge=merge) |
3714 | 236 self.ui.write(str(inst) + '\n') |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
237 raise util.Abort(_('Fix up the merge and run ' |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
238 'hg transplant --continue')) |
3714 | 239 else: |
240 files = None | |
241 if merge: | |
242 p1, p2 = repo.dirstate.parents() | |
243 repo.dirstate.setparents(p1, node) | |
8703
8676dd819444
transplant: use match object rather than files for commit
Matt Mackall <mpm@selenic.com>
parents:
8615
diff
changeset
|
244 m = match.always(repo.root, '') |
8676dd819444
transplant: use match object rather than files for commit
Matt Mackall <mpm@selenic.com>
parents:
8615
diff
changeset
|
245 else: |
8676dd819444
transplant: use match object rather than files for commit
Matt Mackall <mpm@selenic.com>
parents:
8615
diff
changeset
|
246 m = match.exact(repo.root, '', files) |
3714 | 247 |
8706
25e9c71b89de
commit: drop the now-unused files parameter
Matt Mackall <mpm@selenic.com>
parents:
8703
diff
changeset
|
248 n = repo.commit(message, user, date, extra=extra, match=m) |
11638
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
249 if not n: |
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
250 # Crash here to prevent an unclear crash later, in |
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
251 # transplants.write(). This can happen if patch.patch() |
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
252 # does nothing but claims success or if repo.status() fails |
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
253 # to report changes done by patch.patch(). These both |
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
254 # appear to be bugs in other parts of Mercurial, but dying |
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
255 # here, as soon as we can detect the problem, is preferable |
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
256 # to silently dropping changesets on the floor. |
79231258503b
transplant: crash if repo.commit() finds nothing to commit
Greg Ward <greg-hg@gerg.ca>
parents:
11411
diff
changeset
|
257 raise RuntimeError('nothing committed after transplant') |
3714 | 258 if not merge: |
259 self.transplants.set(n, node) | |
260 | |
261 return n | |
262 | |
263 def resume(self, repo, source, opts=None): | |
264 '''recover last transaction and apply remaining changesets''' | |
265 if os.path.exists(os.path.join(self.path, 'journal')): | |
266 n, node = self.recover(repo) | |
3724
ea523d6f5f1a
transplant: fix --continue; add --continue test
Brendan Cully <brendan@kublai.com>
parents:
3723
diff
changeset
|
267 self.ui.status(_('%s transplanted as %s\n') % (revlog.short(node), |
ea523d6f5f1a
transplant: fix --continue; add --continue test
Brendan Cully <brendan@kublai.com>
parents:
3723
diff
changeset
|
268 revlog.short(n))) |
3714 | 269 seriespath = os.path.join(self.path, 'series') |
270 if not os.path.exists(seriespath): | |
3758
889f7e74a0d9
transplant: log source node when recovering too.
Brendan Cully <brendan@kublai.com>
parents:
3757
diff
changeset
|
271 self.transplants.write() |
3714 | 272 return |
273 nodes, merges = self.readseries() | |
274 revmap = {} | |
275 for n in nodes: | |
276 revmap[source.changelog.rev(n)] = n | |
277 os.unlink(seriespath) | |
278 | |
279 self.apply(repo, source, revmap, merges, opts) | |
280 | |
281 def recover(self, repo): | |
282 '''commit working directory using journal metadata''' | |
283 node, user, date, message, parents = self.readlog() | |
284 merge = len(parents) == 2 | |
285 | |
286 if not user or not date or not message or not parents[0]: | |
287 raise util.Abort(_('transplant log file is corrupt')) | |
288 | |
3758
889f7e74a0d9
transplant: log source node when recovering too.
Brendan Cully <brendan@kublai.com>
parents:
3757
diff
changeset
|
289 extra = {'transplant_source': node} |
3714 | 290 wlock = repo.wlock() |
4959
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
291 try: |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
292 p1, p2 = repo.dirstate.parents() |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
293 if p1 != parents[0]: |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
294 raise util.Abort( |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
295 _('working dir not at transplant parent %s') % |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
296 revlog.hex(parents[0])) |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
297 if merge: |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
298 repo.dirstate.setparents(p1, parents[1]) |
8706
25e9c71b89de
commit: drop the now-unused files parameter
Matt Mackall <mpm@selenic.com>
parents:
8703
diff
changeset
|
299 n = repo.commit(message, user, date, extra=extra) |
4959
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
300 if not n: |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
301 raise util.Abort(_('commit failed')) |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
302 if not merge: |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
303 self.transplants.set(n, node) |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
304 self.unlog() |
3714 | 305 |
4959
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
306 return n, node |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4680
diff
changeset
|
307 finally: |
8107
6ee71f78497c
switch lock releasing in the extensions from gc to explicit
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8075
diff
changeset
|
308 wlock.release() |
3714 | 309 |
310 def readseries(self): | |
311 nodes = [] | |
312 merges = [] | |
313 cur = nodes | |
314 for line in self.opener('series').read().splitlines(): | |
315 if line.startswith('# Merges'): | |
316 cur = merges | |
317 continue | |
318 cur.append(revlog.bin(line)) | |
319 | |
320 return (nodes, merges) | |
321 | |
322 def saveseries(self, revmap, merges): | |
323 if not revmap: | |
324 return | |
325 | |
326 if not os.path.isdir(self.path): | |
327 os.mkdir(self.path) | |
328 series = self.opener('series', 'w') | |
8209
a1a5a57efe90
replace util.sort with sorted built-in
Matt Mackall <mpm@selenic.com>
parents:
8176
diff
changeset
|
329 for rev in sorted(revmap): |
3714 | 330 series.write(revlog.hex(revmap[rev]) + '\n') |
331 if merges: | |
332 series.write('# Merges\n') | |
333 for m in merges: | |
334 series.write(revlog.hex(m) + '\n') | |
335 series.close() | |
336 | |
3759
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
337 def parselog(self, fp): |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
338 parents = [] |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
339 message = [] |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
340 node = revlog.nullid |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
341 inmsg = False |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
342 for line in fp.read().splitlines(): |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
343 if inmsg: |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
344 message.append(line) |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
345 elif line.startswith('# User '): |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
346 user = line[7:] |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
347 elif line.startswith('# Date '): |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
348 date = line[7:] |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
349 elif line.startswith('# Node ID '): |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
350 node = revlog.bin(line[10:]) |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
351 elif line.startswith('# Parent '): |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
352 parents.append(revlog.bin(line[9:])) |
11411
5834e79b24f7
transplant: when reading journal, treat only lines starting with "# " special like patch.extract() does
Georg Brandl <georg@python.org>
parents:
11321
diff
changeset
|
353 elif not line.startswith('# '): |
3759
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
354 inmsg = True |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
355 message.append(line) |
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
356 return (node, user, date, '\n'.join(message), parents) |
4516
96d8a56d4ef9
Removed trailing whitespace and tabs from python files
Thomas Arendsen Hein <thomas@intevation.de>
parents:
4251
diff
changeset
|
357 |
3725
ccc7a9eb0e5e
transplant: preserve filter changes in --continue log
Brendan Cully <brendan@kublai.com>
parents:
3724
diff
changeset
|
358 def log(self, user, date, message, p1, p2, merge=False): |
3714 | 359 '''journal changelog metadata for later recover''' |
360 | |
361 if not os.path.isdir(self.path): | |
362 os.mkdir(self.path) | |
363 fp = self.opener('journal', 'w') | |
3725
ccc7a9eb0e5e
transplant: preserve filter changes in --continue log
Brendan Cully <brendan@kublai.com>
parents:
3724
diff
changeset
|
364 fp.write('# User %s\n' % user) |
ccc7a9eb0e5e
transplant: preserve filter changes in --continue log
Brendan Cully <brendan@kublai.com>
parents:
3724
diff
changeset
|
365 fp.write('# Date %s\n' % date) |
3714 | 366 fp.write('# Node ID %s\n' % revlog.hex(p2)) |
367 fp.write('# Parent ' + revlog.hex(p1) + '\n') | |
368 if merge: | |
369 fp.write('# Parent ' + revlog.hex(p2) + '\n') | |
3725
ccc7a9eb0e5e
transplant: preserve filter changes in --continue log
Brendan Cully <brendan@kublai.com>
parents:
3724
diff
changeset
|
370 fp.write(message.rstrip() + '\n') |
3714 | 371 fp.close() |
372 | |
373 def readlog(self): | |
3759
e96f97ca0358
transplant: split filter args into changelog entry and patch
Brendan Cully <brendan@kublai.com>
parents:
3758
diff
changeset
|
374 return self.parselog(self.opener('journal')) |
3714 | 375 |
376 def unlog(self): | |
377 '''remove changelog journal''' | |
378 absdst = os.path.join(self.path, 'journal') | |
379 if os.path.exists(absdst): | |
380 os.unlink(absdst) | |
381 | |
382 def transplantfilter(self, repo, source, root): | |
383 def matchfn(node): | |
384 if self.applied(repo, node, root): | |
385 return False | |
386 if source.changelog.parents(node)[1] != revlog.nullid: | |
387 return False | |
388 extra = source.changelog.read(node)[5] | |
389 cnode = extra.get('transplant_source') | |
390 if cnode and self.applied(repo, cnode, root): | |
391 return False | |
392 return True | |
393 | |
394 return matchfn | |
395 | |
396 def hasnode(repo, node): | |
397 try: | |
398 return repo.changelog.rev(node) != None | |
7633 | 399 except error.RevlogError: |
3714 | 400 return False |
401 | |
402 def browserevs(ui, repo, nodes, opts): | |
403 '''interactively transplant changesets''' | |
404 def browsehelp(ui): | |
10510
f77f3383c666
i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10394
diff
changeset
|
405 ui.write(_('y: transplant this changeset\n' |
f77f3383c666
i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10394
diff
changeset
|
406 'n: skip this changeset\n' |
f77f3383c666
i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10394
diff
changeset
|
407 'm: merge at this changeset\n' |
f77f3383c666
i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10394
diff
changeset
|
408 'p: show patch\n' |
f77f3383c666
i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10394
diff
changeset
|
409 'c: commit selected changesets\n' |
f77f3383c666
i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10394
diff
changeset
|
410 'q: cancel transplant\n' |
f77f3383c666
i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10394
diff
changeset
|
411 '?: show this help\n')) |
3714 | 412 |
3723
c828fca6f38a
transplant: show_changeset moved to cmdutil
Brendan Cully <brendan@kublai.com>
parents:
3714
diff
changeset
|
413 displayer = cmdutil.show_changeset(ui, repo, opts) |
3714 | 414 transplants = [] |
415 merges = [] | |
416 for node in nodes: | |
7369
87158be081b8
cmdutil: use change contexts for cset-printer and cset-templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7308
diff
changeset
|
417 displayer.show(repo[node]) |
3714 | 418 action = None |
419 while not action: | |
420 action = ui.prompt(_('apply changeset? [ynmpcq?]:')) | |
421 if action == '?': | |
422 browsehelp(ui) | |
423 action = None | |
424 elif action == 'p': | |
425 parent = repo.changelog.parents(node)[0] | |
7308
b6f5490effbf
patch: turn patch.diff() into a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7278
diff
changeset
|
426 for chunk in patch.diff(repo, parent, node): |
8615
94ca38e63576
use ui instead of repo.ui when the former is in scope
Martin Geisler <mg@lazybytes.net>
parents:
8225
diff
changeset
|
427 ui.write(chunk) |
3714 | 428 action = None |
429 elif action not in ('y', 'n', 'm', 'c', 'q'): | |
10510
f77f3383c666
i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10394
diff
changeset
|
430 ui.write(_('no such option\n')) |
3714 | 431 action = None |
432 if action == 'y': | |
433 transplants.append(node) | |
434 elif action == 'm': | |
435 merges.append(node) | |
436 elif action == 'c': | |
437 break | |
438 elif action == 'q': | |
439 transplants = () | |
440 merges = () | |
441 break | |
10152
56284451a22c
Added support for templatevar "footer" to cmdutil.py
Robert Bachmann <rbachm@gmail.com>
parents:
9995
diff
changeset
|
442 displayer.close() |
3714 | 443 return (transplants, merges) |
444 | |
445 def transplant(ui, repo, *revs, **opts): | |
446 '''transplant changesets from another branch | |
447 | |
448 Selected changesets will be applied on top of the current working | |
449 directory with the log of the original changeset. If --log is | |
9262
4e61abab5f4b
transplant: wrap docstrings at 70 characters
Martin Geisler <mg@lazybytes.net>
parents:
9192
diff
changeset
|
450 specified, log messages will have a comment appended of the form:: |
3714 | 451 |
9192
6b4c527c3d22
transplant: better reST formatting
Martin Geisler <mg@lazybytes.net>
parents:
9187
diff
changeset
|
452 (transplanted from CHANGESETHASH) |
3714 | 453 |
454 You can rewrite the changelog message with the --filter option. | |
8000
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
455 Its argument will be invoked with the current changelog message as |
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
456 $1 and the patch as $2. |
3714 | 457 |
8075
5ec526c1a32f
help texts: write command line switches as -a/--abc
Martin Geisler <mg@lazybytes.net>
parents:
8000
diff
changeset
|
458 If --source/-s is specified, selects changesets from the named |
5ec526c1a32f
help texts: write command line switches as -a/--abc
Martin Geisler <mg@lazybytes.net>
parents:
8000
diff
changeset
|
459 repository. If --branch/-b is specified, selects changesets from |
5ec526c1a32f
help texts: write command line switches as -a/--abc
Martin Geisler <mg@lazybytes.net>
parents:
8000
diff
changeset
|
460 the branch holding the named revision, up to that revision. If |
5ec526c1a32f
help texts: write command line switches as -a/--abc
Martin Geisler <mg@lazybytes.net>
parents:
8000
diff
changeset
|
461 --all/-a is specified, all changesets on the branch will be |
5ec526c1a32f
help texts: write command line switches as -a/--abc
Martin Geisler <mg@lazybytes.net>
parents:
8000
diff
changeset
|
462 transplanted, otherwise you will be prompted to select the |
5ec526c1a32f
help texts: write command line switches as -a/--abc
Martin Geisler <mg@lazybytes.net>
parents:
8000
diff
changeset
|
463 changesets you want. |
3714 | 464 |
11193
687c7d395f20
Use our custom hg reStructuredText role some more
Martin Geisler <mg@aragost.com>
parents:
10510
diff
changeset
|
465 :hg:`transplant --branch REVISION --all` will rebase the selected |
8000
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
466 branch (up to the named revision) onto your current working |
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
467 directory. |
3714 | 468 |
8000
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
469 You can optionally mark selected transplanted changesets as merge |
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
470 changesets. You will not be prompted to transplant any ancestors |
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
471 of a merged transplant, and you can merge descendants of them |
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
472 normally instead of transplanting them. |
3714 | 473 |
11193
687c7d395f20
Use our custom hg reStructuredText role some more
Martin Geisler <mg@aragost.com>
parents:
10510
diff
changeset
|
474 If no merges or revisions are provided, :hg:`transplant` will |
687c7d395f20
Use our custom hg reStructuredText role some more
Martin Geisler <mg@aragost.com>
parents:
10510
diff
changeset
|
475 start an interactive changeset browser. |
3714 | 476 |
8000
83d7c9cfb065
transplant: word-wrap help texts at 70 characters
Martin Geisler <mg@daimi.au.dk>
parents:
7873
diff
changeset
|
477 If a changeset application fails, you can fix the merge by hand |
11193
687c7d395f20
Use our custom hg reStructuredText role some more
Martin Geisler <mg@aragost.com>
parents:
10510
diff
changeset
|
478 and then resume where you left off by calling :hg:`transplant |
687c7d395f20
Use our custom hg reStructuredText role some more
Martin Geisler <mg@aragost.com>
parents:
10510
diff
changeset
|
479 --continue/-c`. |
3714 | 480 ''' |
481 def getremotechanges(repo, url): | |
482 sourcerepo = ui.expandpath(url) | |
483 source = hg.repository(ui, sourcerepo) | |
11301
3d0591a66118
move discovery methods from localrepo into new discovery module
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
11193
diff
changeset
|
484 tmp = discovery.findcommonincoming(repo, source, force=True) |
3d0591a66118
move discovery methods from localrepo into new discovery module
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
11193
diff
changeset
|
485 common, incoming, rheads = tmp |
3714 | 486 if not incoming: |
487 return (source, None, None) | |
488 | |
489 bundle = None | |
490 if not source.local(): | |
7415
6163ef936a00
protocol: use changegroupsubset() if possible (issue1389)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7369
diff
changeset
|
491 if source.capable('changegroupsubset'): |
6163ef936a00
protocol: use changegroupsubset() if possible (issue1389)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7369
diff
changeset
|
492 cg = source.changegroupsubset(incoming, rheads, 'incoming') |
6163ef936a00
protocol: use changegroupsubset() if possible (issue1389)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7369
diff
changeset
|
493 else: |
6163ef936a00
protocol: use changegroupsubset() if possible (issue1389)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7369
diff
changeset
|
494 cg = source.changegroup(incoming, 'incoming') |
4049
863465381028
transplant: update to current writebundle API
Brendan Cully <brendan@kublai.com>
parents:
4035
diff
changeset
|
495 bundle = changegroup.writebundle(cg, None, 'HG10UN') |
3714 | 496 source = bundlerepo.bundlerepository(ui, repo.root, bundle) |
497 | |
498 return (source, incoming, bundle) | |
499 | |
500 def incwalk(repo, incoming, branches, match=util.always): | |
501 if not branches: | |
10282
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
10264
diff
changeset
|
502 branches = None |
3714 | 503 for node in repo.changelog.nodesbetween(incoming, branches)[0]: |
504 if match(node): | |
505 yield node | |
506 | |
507 def transplantwalk(repo, root, branches, match=util.always): | |
508 if not branches: | |
509 branches = repo.heads() | |
510 ancestors = [] | |
511 for branch in branches: | |
512 ancestors.append(repo.changelog.ancestor(root, branch)) | |
513 for node in repo.changelog.nodesbetween(ancestors, branches)[0]: | |
514 if match(node): | |
515 yield node | |
516 | |
517 def checkopts(opts, revs): | |
518 if opts.get('continue'): | |
10282
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
10264
diff
changeset
|
519 if opts.get('branch') or opts.get('all') or opts.get('merge'): |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
520 raise util.Abort(_('--continue is incompatible with ' |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
521 'branch, all or merge')) |
3714 | 522 return |
523 if not (opts.get('source') or revs or | |
524 opts.get('merge') or opts.get('branch')): | |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
525 raise util.Abort(_('no source URL, branch tag or revision ' |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
526 'list provided')) |
3714 | 527 if opts.get('all'): |
528 if not opts.get('branch'): | |
529 raise util.Abort(_('--all requires a branch revision')) | |
530 if revs: | |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
531 raise util.Abort(_('--all is incompatible with a ' |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
532 'revision list')) |
3714 | 533 |
534 checkopts(opts, revs) | |
535 | |
536 if not opts.get('log'): | |
537 opts['log'] = ui.config('transplant', 'log') | |
538 if not opts.get('filter'): | |
539 opts['filter'] = ui.config('transplant', 'filter') | |
540 | |
541 tp = transplanter(ui, repo) | |
542 | |
543 p1, p2 = repo.dirstate.parents() | |
8176
2660e7002413
transplant: forbid transplant to nonempty repositories with no working directory.
Brendan Cully <brendan@kublai.com>
parents:
8173
diff
changeset
|
544 if len(repo) > 0 and p1 == revlog.nullid: |
2660e7002413
transplant: forbid transplant to nonempty repositories with no working directory.
Brendan Cully <brendan@kublai.com>
parents:
8173
diff
changeset
|
545 raise util.Abort(_('no revision checked out')) |
3714 | 546 if not opts.get('continue'): |
547 if p2 != revlog.nullid: | |
548 raise util.Abort(_('outstanding uncommitted merges')) | |
549 m, a, r, d = repo.status()[:4] | |
550 if m or a or r or d: | |
551 raise util.Abort(_('outstanding local changes')) | |
552 | |
553 bundle = None | |
554 source = opts.get('source') | |
555 if source: | |
556 (source, incoming, bundle) = getremotechanges(repo, source) | |
557 else: | |
558 source = repo | |
559 | |
560 try: | |
561 if opts.get('continue'): | |
3724
ea523d6f5f1a
transplant: fix --continue; add --continue test
Brendan Cully <brendan@kublai.com>
parents:
3723
diff
changeset
|
562 tp.resume(repo, source, opts) |
3714 | 563 return |
564 | |
10394
4612cded5176
fix coding style (reported by pylint)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10282
diff
changeset
|
565 tf = tp.transplantfilter(repo, source, p1) |
3714 | 566 if opts.get('prune'): |
567 prune = [source.lookup(r) | |
568 for r in cmdutil.revrange(source, opts.get('prune'))] | |
569 matchfn = lambda x: tf(x) and x not in prune | |
570 else: | |
571 matchfn = tf | |
572 branches = map(source.lookup, opts.get('branch', ())) | |
573 merges = map(source.lookup, opts.get('merge', ())) | |
574 revmap = {} | |
575 if revs: | |
576 for r in cmdutil.revrange(source, revs): | |
577 revmap[int(r)] = source.lookup(r) | |
578 elif opts.get('all') or not merges: | |
579 if source != repo: | |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
580 alltransplants = incwalk(source, incoming, branches, |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
581 match=matchfn) |
3714 | 582 else: |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
583 alltransplants = transplantwalk(source, p1, branches, |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
584 match=matchfn) |
3714 | 585 if opts.get('all'): |
586 revs = alltransplants | |
587 else: | |
588 revs, newmerges = browserevs(ui, source, alltransplants, opts) | |
589 merges.extend(newmerges) | |
590 for r in revs: | |
591 revmap[source.changelog.rev(r)] = r | |
592 for r in merges: | |
593 revmap[source.changelog.rev(r)] = r | |
594 | |
595 tp.apply(repo, source, revmap, merges, opts) | |
596 finally: | |
597 if bundle: | |
4072
e916bc0dfdd6
transplant: remote bundle source was not closed before deleting the fetched bundle.
Patrick Mezard <pmezard@gmail.com>
parents:
4049
diff
changeset
|
598 source.close() |
3714 | 599 os.unlink(bundle) |
600 | |
601 cmdtable = { | |
602 "transplant": | |
603 (transplant, | |
11321
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
604 [('s', 'source', '', |
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
605 _('pull patches from REPO'), _('REPO')), |
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
606 ('b', 'branch', [], |
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
607 _('pull patches from branch BRANCH'), _('BRANCH')), |
3714 | 608 ('a', 'all', None, _('pull all changesets up to BRANCH')), |
11321
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
609 ('p', 'prune', [], |
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
610 _('skip over REV'), _('REV')), |
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
611 ('m', 'merge', [], |
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
612 _('merge at REV'), _('REV')), |
3714 | 613 ('', 'log', None, _('append transplant info to log message')), |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
614 ('c', 'continue', None, _('continue last transplant session ' |
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
615 'after repair')), |
11321
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
616 ('', 'filter', '', |
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
617 _('filter changesets through command'), _('CMD'))], |
40c06bbf58be
help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
11301
diff
changeset
|
618 _('hg transplant [-s REPO] [-b BRANCH [-a]] [-p REV] ' |
7744
b44dbb95f07f
transplant: wrapped long lines
Martin Geisler <mg@daimi.au.dk>
parents:
7633
diff
changeset
|
619 '[-m REV] [REV]...')) |
3714 | 620 } |