##// END OF EJS Templates
convert: update the transplant, rebase and graft references in 'extra'...
Matt Harbison -
r21765:44255f7c default
parent child Browse files
Show More
@@ -1,452 +1,470
1 # hg.py - hg backend for convert extension
1 # hg.py - hg backend for convert extension
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
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 # Notes for hg->hg conversion:
8 # Notes for hg->hg conversion:
9 #
9 #
10 # * Old versions of Mercurial didn't trim the whitespace from the ends
10 # * Old versions of Mercurial didn't trim the whitespace from the ends
11 # of commit messages, but new versions do. Changesets created by
11 # of commit messages, but new versions do. Changesets created by
12 # those older versions, then converted, may thus have different
12 # those older versions, then converted, may thus have different
13 # hashes for changesets that are otherwise identical.
13 # hashes for changesets that are otherwise identical.
14 #
14 #
15 # * Using "--config convert.hg.saverev=true" will make the source
15 # * Using "--config convert.hg.saverev=true" will make the source
16 # identifier to be stored in the converted revision. This will cause
16 # identifier to be stored in the converted revision. This will cause
17 # the converted revision to have a different identity than the
17 # the converted revision to have a different identity than the
18 # source.
18 # source.
19
19
20
20
21 import os, time, cStringIO
21 import os, time, cStringIO
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23 from mercurial.node import bin, hex, nullid
23 from mercurial.node import bin, hex, nullid
24 from mercurial import hg, util, context, bookmarks, error, scmutil
24 from mercurial import hg, util, context, bookmarks, error, scmutil
25
25
26 from common import NoRepo, commit, converter_source, converter_sink
26 from common import NoRepo, commit, converter_source, converter_sink
27
27
28 import re
28 import re
29 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
29 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
30
30
31 class mercurial_sink(converter_sink):
31 class mercurial_sink(converter_sink):
32 def __init__(self, ui, path):
32 def __init__(self, ui, path):
33 converter_sink.__init__(self, ui, path)
33 converter_sink.__init__(self, ui, path)
34 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
34 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
35 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
35 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
36 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
36 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
37 self.lastbranch = None
37 self.lastbranch = None
38 if os.path.isdir(path) and len(os.listdir(path)) > 0:
38 if os.path.isdir(path) and len(os.listdir(path)) > 0:
39 try:
39 try:
40 self.repo = hg.repository(self.ui, path)
40 self.repo = hg.repository(self.ui, path)
41 if not self.repo.local():
41 if not self.repo.local():
42 raise NoRepo(_('%s is not a local Mercurial repository')
42 raise NoRepo(_('%s is not a local Mercurial repository')
43 % path)
43 % path)
44 except error.RepoError, err:
44 except error.RepoError, err:
45 ui.traceback()
45 ui.traceback()
46 raise NoRepo(err.args[0])
46 raise NoRepo(err.args[0])
47 else:
47 else:
48 try:
48 try:
49 ui.status(_('initializing destination %s repository\n') % path)
49 ui.status(_('initializing destination %s repository\n') % path)
50 self.repo = hg.repository(self.ui, path, create=True)
50 self.repo = hg.repository(self.ui, path, create=True)
51 if not self.repo.local():
51 if not self.repo.local():
52 raise NoRepo(_('%s is not a local Mercurial repository')
52 raise NoRepo(_('%s is not a local Mercurial repository')
53 % path)
53 % path)
54 self.created.append(path)
54 self.created.append(path)
55 except error.RepoError:
55 except error.RepoError:
56 ui.traceback()
56 ui.traceback()
57 raise NoRepo(_("could not create hg repository %s as sink")
57 raise NoRepo(_("could not create hg repository %s as sink")
58 % path)
58 % path)
59 self.lock = None
59 self.lock = None
60 self.wlock = None
60 self.wlock = None
61 self.filemapmode = False
61 self.filemapmode = False
62
62
63 def before(self):
63 def before(self):
64 self.ui.debug('run hg sink pre-conversion action\n')
64 self.ui.debug('run hg sink pre-conversion action\n')
65 self.wlock = self.repo.wlock()
65 self.wlock = self.repo.wlock()
66 self.lock = self.repo.lock()
66 self.lock = self.repo.lock()
67
67
68 def after(self):
68 def after(self):
69 self.ui.debug('run hg sink post-conversion action\n')
69 self.ui.debug('run hg sink post-conversion action\n')
70 if self.lock:
70 if self.lock:
71 self.lock.release()
71 self.lock.release()
72 if self.wlock:
72 if self.wlock:
73 self.wlock.release()
73 self.wlock.release()
74
74
75 def revmapfile(self):
75 def revmapfile(self):
76 return self.repo.join("shamap")
76 return self.repo.join("shamap")
77
77
78 def authorfile(self):
78 def authorfile(self):
79 return self.repo.join("authormap")
79 return self.repo.join("authormap")
80
80
81 def setbranch(self, branch, pbranches):
81 def setbranch(self, branch, pbranches):
82 if not self.clonebranches:
82 if not self.clonebranches:
83 return
83 return
84
84
85 setbranch = (branch != self.lastbranch)
85 setbranch = (branch != self.lastbranch)
86 self.lastbranch = branch
86 self.lastbranch = branch
87 if not branch:
87 if not branch:
88 branch = 'default'
88 branch = 'default'
89 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
89 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
90 pbranch = pbranches and pbranches[0][1] or 'default'
90 pbranch = pbranches and pbranches[0][1] or 'default'
91
91
92 branchpath = os.path.join(self.path, branch)
92 branchpath = os.path.join(self.path, branch)
93 if setbranch:
93 if setbranch:
94 self.after()
94 self.after()
95 try:
95 try:
96 self.repo = hg.repository(self.ui, branchpath)
96 self.repo = hg.repository(self.ui, branchpath)
97 except Exception:
97 except Exception:
98 self.repo = hg.repository(self.ui, branchpath, create=True)
98 self.repo = hg.repository(self.ui, branchpath, create=True)
99 self.before()
99 self.before()
100
100
101 # pbranches may bring revisions from other branches (merge parents)
101 # pbranches may bring revisions from other branches (merge parents)
102 # Make sure we have them, or pull them.
102 # Make sure we have them, or pull them.
103 missings = {}
103 missings = {}
104 for b in pbranches:
104 for b in pbranches:
105 try:
105 try:
106 self.repo.lookup(b[0])
106 self.repo.lookup(b[0])
107 except Exception:
107 except Exception:
108 missings.setdefault(b[1], []).append(b[0])
108 missings.setdefault(b[1], []).append(b[0])
109
109
110 if missings:
110 if missings:
111 self.after()
111 self.after()
112 for pbranch, heads in sorted(missings.iteritems()):
112 for pbranch, heads in sorted(missings.iteritems()):
113 pbranchpath = os.path.join(self.path, pbranch)
113 pbranchpath = os.path.join(self.path, pbranch)
114 prepo = hg.peer(self.ui, {}, pbranchpath)
114 prepo = hg.peer(self.ui, {}, pbranchpath)
115 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
115 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
116 self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
116 self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
117 self.before()
117 self.before()
118
118
119 def _rewritetags(self, source, revmap, data):
119 def _rewritetags(self, source, revmap, data):
120 fp = cStringIO.StringIO()
120 fp = cStringIO.StringIO()
121 for line in data.splitlines():
121 for line in data.splitlines():
122 s = line.split(' ', 1)
122 s = line.split(' ', 1)
123 if len(s) != 2:
123 if len(s) != 2:
124 continue
124 continue
125 revid = revmap.get(source.lookuprev(s[0]))
125 revid = revmap.get(source.lookuprev(s[0]))
126 if not revid:
126 if not revid:
127 continue
127 continue
128 fp.write('%s %s\n' % (revid, s[1]))
128 fp.write('%s %s\n' % (revid, s[1]))
129 return fp.getvalue()
129 return fp.getvalue()
130
130
131 def putcommit(self, files, copies, parents, commit, source, revmap):
131 def putcommit(self, files, copies, parents, commit, source, revmap):
132
132
133 files = dict(files)
133 files = dict(files)
134 def getfilectx(repo, memctx, f):
134 def getfilectx(repo, memctx, f):
135 v = files[f]
135 v = files[f]
136 data, mode = source.getfile(f, v)
136 data, mode = source.getfile(f, v)
137 if f == '.hgtags':
137 if f == '.hgtags':
138 data = self._rewritetags(source, revmap, data)
138 data = self._rewritetags(source, revmap, data)
139 return context.memfilectx(self.repo, f, data, 'l' in mode,
139 return context.memfilectx(self.repo, f, data, 'l' in mode,
140 'x' in mode, copies.get(f))
140 'x' in mode, copies.get(f))
141
141
142 pl = []
142 pl = []
143 for p in parents:
143 for p in parents:
144 if p not in pl:
144 if p not in pl:
145 pl.append(p)
145 pl.append(p)
146 parents = pl
146 parents = pl
147 nparents = len(parents)
147 nparents = len(parents)
148 if self.filemapmode and nparents == 1:
148 if self.filemapmode and nparents == 1:
149 m1node = self.repo.changelog.read(bin(parents[0]))[0]
149 m1node = self.repo.changelog.read(bin(parents[0]))[0]
150 parent = parents[0]
150 parent = parents[0]
151
151
152 if len(parents) < 2:
152 if len(parents) < 2:
153 parents.append(nullid)
153 parents.append(nullid)
154 if len(parents) < 2:
154 if len(parents) < 2:
155 parents.append(nullid)
155 parents.append(nullid)
156 p2 = parents.pop(0)
156 p2 = parents.pop(0)
157
157
158 text = commit.desc
158 text = commit.desc
159
159
160 sha1s = re.findall(sha1re, text)
160 sha1s = re.findall(sha1re, text)
161 for sha1 in sha1s:
161 for sha1 in sha1s:
162 oldrev = source.lookuprev(sha1)
162 oldrev = source.lookuprev(sha1)
163 newrev = revmap.get(oldrev)
163 newrev = revmap.get(oldrev)
164 if newrev is not None:
164 if newrev is not None:
165 text = text.replace(sha1, newrev[:len(sha1)])
165 text = text.replace(sha1, newrev[:len(sha1)])
166
166
167 extra = commit.extra.copy()
167 extra = commit.extra.copy()
168
169 for label in ('source', 'transplant_source', 'rebase_source'):
170 node = extra.get(label)
171
172 if node is None:
173 continue
174
175 # Only transplant stores its reference in binary
176 if label == 'transplant_source':
177 node = hex(node)
178
179 newrev = revmap.get(node)
180 if newrev is not None:
181 if label == 'transplant_source':
182 newrev = bin(newrev)
183
184 extra[label] = newrev
185
168 if self.branchnames and commit.branch:
186 if self.branchnames and commit.branch:
169 extra['branch'] = commit.branch
187 extra['branch'] = commit.branch
170 if commit.rev:
188 if commit.rev:
171 extra['convert_revision'] = commit.rev
189 extra['convert_revision'] = commit.rev
172
190
173 while parents:
191 while parents:
174 p1 = p2
192 p1 = p2
175 p2 = parents.pop(0)
193 p2 = parents.pop(0)
176 ctx = context.memctx(self.repo, (p1, p2), text, files.keys(),
194 ctx = context.memctx(self.repo, (p1, p2), text, files.keys(),
177 getfilectx, commit.author, commit.date, extra)
195 getfilectx, commit.author, commit.date, extra)
178 self.repo.commitctx(ctx)
196 self.repo.commitctx(ctx)
179 text = "(octopus merge fixup)\n"
197 text = "(octopus merge fixup)\n"
180 p2 = hex(self.repo.changelog.tip())
198 p2 = hex(self.repo.changelog.tip())
181
199
182 if self.filemapmode and nparents == 1:
200 if self.filemapmode and nparents == 1:
183 man = self.repo.manifest
201 man = self.repo.manifest
184 mnode = self.repo.changelog.read(bin(p2))[0]
202 mnode = self.repo.changelog.read(bin(p2))[0]
185 closed = 'close' in commit.extra
203 closed = 'close' in commit.extra
186 if not closed and not man.cmp(m1node, man.revision(mnode)):
204 if not closed and not man.cmp(m1node, man.revision(mnode)):
187 self.ui.status(_("filtering out empty revision\n"))
205 self.ui.status(_("filtering out empty revision\n"))
188 self.repo.rollback(force=True)
206 self.repo.rollback(force=True)
189 return parent
207 return parent
190 return p2
208 return p2
191
209
192 def puttags(self, tags):
210 def puttags(self, tags):
193 try:
211 try:
194 parentctx = self.repo[self.tagsbranch]
212 parentctx = self.repo[self.tagsbranch]
195 tagparent = parentctx.node()
213 tagparent = parentctx.node()
196 except error.RepoError:
214 except error.RepoError:
197 parentctx = None
215 parentctx = None
198 tagparent = nullid
216 tagparent = nullid
199
217
200 oldlines = set()
218 oldlines = set()
201 for branch, heads in self.repo.branchmap().iteritems():
219 for branch, heads in self.repo.branchmap().iteritems():
202 for h in heads:
220 for h in heads:
203 if '.hgtags' in self.repo[h]:
221 if '.hgtags' in self.repo[h]:
204 oldlines.update(
222 oldlines.update(
205 set(self.repo[h]['.hgtags'].data().splitlines(True)))
223 set(self.repo[h]['.hgtags'].data().splitlines(True)))
206 oldlines = sorted(list(oldlines))
224 oldlines = sorted(list(oldlines))
207
225
208 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
226 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
209 if newlines == oldlines:
227 if newlines == oldlines:
210 return None, None
228 return None, None
211
229
212 # if the old and new tags match, then there is nothing to update
230 # if the old and new tags match, then there is nothing to update
213 oldtags = set()
231 oldtags = set()
214 newtags = set()
232 newtags = set()
215 for line in oldlines:
233 for line in oldlines:
216 s = line.strip().split(' ', 1)
234 s = line.strip().split(' ', 1)
217 if len(s) != 2:
235 if len(s) != 2:
218 continue
236 continue
219 oldtags.add(s[1])
237 oldtags.add(s[1])
220 for line in newlines:
238 for line in newlines:
221 s = line.strip().split(' ', 1)
239 s = line.strip().split(' ', 1)
222 if len(s) != 2:
240 if len(s) != 2:
223 continue
241 continue
224 if s[1] not in oldtags:
242 if s[1] not in oldtags:
225 newtags.add(s[1].strip())
243 newtags.add(s[1].strip())
226
244
227 if not newtags:
245 if not newtags:
228 return None, None
246 return None, None
229
247
230 data = "".join(newlines)
248 data = "".join(newlines)
231 def getfilectx(repo, memctx, f):
249 def getfilectx(repo, memctx, f):
232 return context.memfilectx(repo, f, data, False, False, None)
250 return context.memfilectx(repo, f, data, False, False, None)
233
251
234 self.ui.status(_("updating tags\n"))
252 self.ui.status(_("updating tags\n"))
235 date = "%s 0" % int(time.mktime(time.gmtime()))
253 date = "%s 0" % int(time.mktime(time.gmtime()))
236 extra = {'branch': self.tagsbranch}
254 extra = {'branch': self.tagsbranch}
237 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
255 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
238 [".hgtags"], getfilectx, "convert-repo", date,
256 [".hgtags"], getfilectx, "convert-repo", date,
239 extra)
257 extra)
240 self.repo.commitctx(ctx)
258 self.repo.commitctx(ctx)
241 return hex(self.repo.changelog.tip()), hex(tagparent)
259 return hex(self.repo.changelog.tip()), hex(tagparent)
242
260
243 def setfilemapmode(self, active):
261 def setfilemapmode(self, active):
244 self.filemapmode = active
262 self.filemapmode = active
245
263
246 def putbookmarks(self, updatedbookmark):
264 def putbookmarks(self, updatedbookmark):
247 if not len(updatedbookmark):
265 if not len(updatedbookmark):
248 return
266 return
249
267
250 self.ui.status(_("updating bookmarks\n"))
268 self.ui.status(_("updating bookmarks\n"))
251 destmarks = self.repo._bookmarks
269 destmarks = self.repo._bookmarks
252 for bookmark in updatedbookmark:
270 for bookmark in updatedbookmark:
253 destmarks[bookmark] = bin(updatedbookmark[bookmark])
271 destmarks[bookmark] = bin(updatedbookmark[bookmark])
254 destmarks.write()
272 destmarks.write()
255
273
256 def hascommitfrommap(self, rev):
274 def hascommitfrommap(self, rev):
257 # the exact semantics of clonebranches is unclear so we can't say no
275 # the exact semantics of clonebranches is unclear so we can't say no
258 return rev in self.repo or self.clonebranches
276 return rev in self.repo or self.clonebranches
259
277
260 def hascommitforsplicemap(self, rev):
278 def hascommitforsplicemap(self, rev):
261 if rev not in self.repo and self.clonebranches:
279 if rev not in self.repo and self.clonebranches:
262 raise util.Abort(_('revision %s not found in destination '
280 raise util.Abort(_('revision %s not found in destination '
263 'repository (lookups with clonebranches=true '
281 'repository (lookups with clonebranches=true '
264 'are not implemented)') % rev)
282 'are not implemented)') % rev)
265 return rev in self.repo
283 return rev in self.repo
266
284
267 class mercurial_source(converter_source):
285 class mercurial_source(converter_source):
268 def __init__(self, ui, path, rev=None):
286 def __init__(self, ui, path, rev=None):
269 converter_source.__init__(self, ui, path, rev)
287 converter_source.__init__(self, ui, path, rev)
270 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
288 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
271 self.ignored = set()
289 self.ignored = set()
272 self.saverev = ui.configbool('convert', 'hg.saverev', False)
290 self.saverev = ui.configbool('convert', 'hg.saverev', False)
273 try:
291 try:
274 self.repo = hg.repository(self.ui, path)
292 self.repo = hg.repository(self.ui, path)
275 # try to provoke an exception if this isn't really a hg
293 # try to provoke an exception if this isn't really a hg
276 # repo, but some other bogus compatible-looking url
294 # repo, but some other bogus compatible-looking url
277 if not self.repo.local():
295 if not self.repo.local():
278 raise error.RepoError
296 raise error.RepoError
279 except error.RepoError:
297 except error.RepoError:
280 ui.traceback()
298 ui.traceback()
281 raise NoRepo(_("%s is not a local Mercurial repository") % path)
299 raise NoRepo(_("%s is not a local Mercurial repository") % path)
282 self.lastrev = None
300 self.lastrev = None
283 self.lastctx = None
301 self.lastctx = None
284 self._changescache = None
302 self._changescache = None
285 self.convertfp = None
303 self.convertfp = None
286 # Restrict converted revisions to startrev descendants
304 # Restrict converted revisions to startrev descendants
287 startnode = ui.config('convert', 'hg.startrev')
305 startnode = ui.config('convert', 'hg.startrev')
288 hgrevs = ui.config('convert', 'hg.revs')
306 hgrevs = ui.config('convert', 'hg.revs')
289 if hgrevs is None:
307 if hgrevs is None:
290 if startnode is not None:
308 if startnode is not None:
291 try:
309 try:
292 startnode = self.repo.lookup(startnode)
310 startnode = self.repo.lookup(startnode)
293 except error.RepoError:
311 except error.RepoError:
294 raise util.Abort(_('%s is not a valid start revision')
312 raise util.Abort(_('%s is not a valid start revision')
295 % startnode)
313 % startnode)
296 startrev = self.repo.changelog.rev(startnode)
314 startrev = self.repo.changelog.rev(startnode)
297 children = {startnode: 1}
315 children = {startnode: 1}
298 for r in self.repo.changelog.descendants([startrev]):
316 for r in self.repo.changelog.descendants([startrev]):
299 children[self.repo.changelog.node(r)] = 1
317 children[self.repo.changelog.node(r)] = 1
300 self.keep = children.__contains__
318 self.keep = children.__contains__
301 else:
319 else:
302 self.keep = util.always
320 self.keep = util.always
303 if rev:
321 if rev:
304 self._heads = [self.repo[rev].node()]
322 self._heads = [self.repo[rev].node()]
305 else:
323 else:
306 self._heads = self.repo.heads()
324 self._heads = self.repo.heads()
307 else:
325 else:
308 if rev or startnode is not None:
326 if rev or startnode is not None:
309 raise util.Abort(_('hg.revs cannot be combined with '
327 raise util.Abort(_('hg.revs cannot be combined with '
310 'hg.startrev or --rev'))
328 'hg.startrev or --rev'))
311 nodes = set()
329 nodes = set()
312 parents = set()
330 parents = set()
313 for r in scmutil.revrange(self.repo, [hgrevs]):
331 for r in scmutil.revrange(self.repo, [hgrevs]):
314 ctx = self.repo[r]
332 ctx = self.repo[r]
315 nodes.add(ctx.node())
333 nodes.add(ctx.node())
316 parents.update(p.node() for p in ctx.parents())
334 parents.update(p.node() for p in ctx.parents())
317 self.keep = nodes.__contains__
335 self.keep = nodes.__contains__
318 self._heads = nodes - parents
336 self._heads = nodes - parents
319
337
320 def changectx(self, rev):
338 def changectx(self, rev):
321 if self.lastrev != rev:
339 if self.lastrev != rev:
322 self.lastctx = self.repo[rev]
340 self.lastctx = self.repo[rev]
323 self.lastrev = rev
341 self.lastrev = rev
324 return self.lastctx
342 return self.lastctx
325
343
326 def parents(self, ctx):
344 def parents(self, ctx):
327 return [p for p in ctx.parents() if p and self.keep(p.node())]
345 return [p for p in ctx.parents() if p and self.keep(p.node())]
328
346
329 def getheads(self):
347 def getheads(self):
330 return [hex(h) for h in self._heads if self.keep(h)]
348 return [hex(h) for h in self._heads if self.keep(h)]
331
349
332 def getfile(self, name, rev):
350 def getfile(self, name, rev):
333 try:
351 try:
334 fctx = self.changectx(rev)[name]
352 fctx = self.changectx(rev)[name]
335 return fctx.data(), fctx.flags()
353 return fctx.data(), fctx.flags()
336 except error.LookupError, err:
354 except error.LookupError, err:
337 raise IOError(err)
355 raise IOError(err)
338
356
339 def getchanges(self, rev):
357 def getchanges(self, rev):
340 ctx = self.changectx(rev)
358 ctx = self.changectx(rev)
341 parents = self.parents(ctx)
359 parents = self.parents(ctx)
342 if not parents:
360 if not parents:
343 files = sorted(ctx.manifest())
361 files = sorted(ctx.manifest())
344 # getcopies() is not needed for roots, but it is a simple way to
362 # getcopies() is not needed for roots, but it is a simple way to
345 # detect missing revlogs and abort on errors or populate
363 # detect missing revlogs and abort on errors or populate
346 # self.ignored
364 # self.ignored
347 self.getcopies(ctx, parents, files)
365 self.getcopies(ctx, parents, files)
348 return [(f, rev) for f in files if f not in self.ignored], {}
366 return [(f, rev) for f in files if f not in self.ignored], {}
349 if self._changescache and self._changescache[0] == rev:
367 if self._changescache and self._changescache[0] == rev:
350 m, a, r = self._changescache[1]
368 m, a, r = self._changescache[1]
351 else:
369 else:
352 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
370 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
353 # getcopies() detects missing revlogs early, run it before
371 # getcopies() detects missing revlogs early, run it before
354 # filtering the changes.
372 # filtering the changes.
355 copies = self.getcopies(ctx, parents, m + a)
373 copies = self.getcopies(ctx, parents, m + a)
356 changes = [(name, rev) for name in m + a + r
374 changes = [(name, rev) for name in m + a + r
357 if name not in self.ignored]
375 if name not in self.ignored]
358 return sorted(changes), copies
376 return sorted(changes), copies
359
377
360 def getcopies(self, ctx, parents, files):
378 def getcopies(self, ctx, parents, files):
361 copies = {}
379 copies = {}
362 for name in files:
380 for name in files:
363 if name in self.ignored:
381 if name in self.ignored:
364 continue
382 continue
365 try:
383 try:
366 copysource, _copynode = ctx.filectx(name).renamed()
384 copysource, _copynode = ctx.filectx(name).renamed()
367 if copysource in self.ignored:
385 if copysource in self.ignored:
368 continue
386 continue
369 # Ignore copy sources not in parent revisions
387 # Ignore copy sources not in parent revisions
370 found = False
388 found = False
371 for p in parents:
389 for p in parents:
372 if copysource in p:
390 if copysource in p:
373 found = True
391 found = True
374 break
392 break
375 if not found:
393 if not found:
376 continue
394 continue
377 copies[name] = copysource
395 copies[name] = copysource
378 except TypeError:
396 except TypeError:
379 pass
397 pass
380 except error.LookupError, e:
398 except error.LookupError, e:
381 if not self.ignoreerrors:
399 if not self.ignoreerrors:
382 raise
400 raise
383 self.ignored.add(name)
401 self.ignored.add(name)
384 self.ui.warn(_('ignoring: %s\n') % e)
402 self.ui.warn(_('ignoring: %s\n') % e)
385 return copies
403 return copies
386
404
387 def getcommit(self, rev):
405 def getcommit(self, rev):
388 ctx = self.changectx(rev)
406 ctx = self.changectx(rev)
389 parents = [p.hex() for p in self.parents(ctx)]
407 parents = [p.hex() for p in self.parents(ctx)]
390 if self.saverev:
408 if self.saverev:
391 crev = rev
409 crev = rev
392 else:
410 else:
393 crev = None
411 crev = None
394 return commit(author=ctx.user(),
412 return commit(author=ctx.user(),
395 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
413 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
396 desc=ctx.description(), rev=crev, parents=parents,
414 desc=ctx.description(), rev=crev, parents=parents,
397 branch=ctx.branch(), extra=ctx.extra(),
415 branch=ctx.branch(), extra=ctx.extra(),
398 sortkey=ctx.rev())
416 sortkey=ctx.rev())
399
417
400 def gettags(self):
418 def gettags(self):
401 # This will get written to .hgtags, filter non global tags out.
419 # This will get written to .hgtags, filter non global tags out.
402 tags = [t for t in self.repo.tagslist()
420 tags = [t for t in self.repo.tagslist()
403 if self.repo.tagtype(t[0]) == 'global']
421 if self.repo.tagtype(t[0]) == 'global']
404 return dict([(name, hex(node)) for name, node in tags
422 return dict([(name, hex(node)) for name, node in tags
405 if self.keep(node)])
423 if self.keep(node)])
406
424
407 def getchangedfiles(self, rev, i):
425 def getchangedfiles(self, rev, i):
408 ctx = self.changectx(rev)
426 ctx = self.changectx(rev)
409 parents = self.parents(ctx)
427 parents = self.parents(ctx)
410 if not parents and i is None:
428 if not parents and i is None:
411 i = 0
429 i = 0
412 changes = [], ctx.manifest().keys(), []
430 changes = [], ctx.manifest().keys(), []
413 else:
431 else:
414 i = i or 0
432 i = i or 0
415 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
433 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
416 changes = [[f for f in l if f not in self.ignored] for l in changes]
434 changes = [[f for f in l if f not in self.ignored] for l in changes]
417
435
418 if i == 0:
436 if i == 0:
419 self._changescache = (rev, changes)
437 self._changescache = (rev, changes)
420
438
421 return changes[0] + changes[1] + changes[2]
439 return changes[0] + changes[1] + changes[2]
422
440
423 def converted(self, rev, destrev):
441 def converted(self, rev, destrev):
424 if self.convertfp is None:
442 if self.convertfp is None:
425 self.convertfp = open(self.repo.join('shamap'), 'a')
443 self.convertfp = open(self.repo.join('shamap'), 'a')
426 self.convertfp.write('%s %s\n' % (destrev, rev))
444 self.convertfp.write('%s %s\n' % (destrev, rev))
427 self.convertfp.flush()
445 self.convertfp.flush()
428
446
429 def before(self):
447 def before(self):
430 self.ui.debug('run hg source pre-conversion action\n')
448 self.ui.debug('run hg source pre-conversion action\n')
431
449
432 def after(self):
450 def after(self):
433 self.ui.debug('run hg source post-conversion action\n')
451 self.ui.debug('run hg source post-conversion action\n')
434
452
435 def hasnativeorder(self):
453 def hasnativeorder(self):
436 return True
454 return True
437
455
438 def hasnativeclose(self):
456 def hasnativeclose(self):
439 return True
457 return True
440
458
441 def lookuprev(self, rev):
459 def lookuprev(self, rev):
442 try:
460 try:
443 return hex(self.repo.lookup(rev))
461 return hex(self.repo.lookup(rev))
444 except error.RepoError:
462 except error.RepoError:
445 return None
463 return None
446
464
447 def getbookmarks(self):
465 def getbookmarks(self):
448 return bookmarks.listbookmarks(self.repo)
466 return bookmarks.listbookmarks(self.repo)
449
467
450 def checkrevformat(self, revstr, mapname='splicemap'):
468 def checkrevformat(self, revstr, mapname='splicemap'):
451 """ Mercurial, revision string is a 40 byte hex """
469 """ Mercurial, revision string is a 40 byte hex """
452 self.checkhexformat(revstr, mapname)
470 self.checkhexformat(revstr, mapname)
@@ -1,602 +1,633
1 Create a repo with some stuff in it:
1 Create a repo with some stuff in it:
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ echo a > a
5 $ echo a > a
6 $ echo a > d
6 $ echo a > d
7 $ echo a > e
7 $ echo a > e
8 $ hg ci -qAm0
8 $ hg ci -qAm0
9 $ echo b > a
9 $ echo b > a
10 $ hg ci -m1 -u bar
10 $ hg ci -m1 -u bar
11 $ hg mv a b
11 $ hg mv a b
12 $ hg ci -m2
12 $ hg ci -m2
13 $ hg cp b c
13 $ hg cp b c
14 $ hg ci -m3 -u baz
14 $ hg ci -m3 -u baz
15 $ echo b > d
15 $ echo b > d
16 $ echo f > e
16 $ echo f > e
17 $ hg ci -m4
17 $ hg ci -m4
18 $ hg up -q 3
18 $ hg up -q 3
19 $ echo b > e
19 $ echo b > e
20 $ hg branch -q stable
20 $ hg branch -q stable
21 $ hg ci -m5
21 $ hg ci -m5
22 $ hg merge -q default --tool internal:local
22 $ hg merge -q default --tool internal:local
23 $ hg branch -q default
23 $ hg branch -q default
24 $ hg ci -m6
24 $ hg ci -m6
25 $ hg phase --public 3
25 $ hg phase --public 3
26 $ hg phase --force --secret 6
26 $ hg phase --force --secret 6
27
27
28 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
28 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
29 @ test@6.secret: 6
29 @ test@6.secret: 6
30 |\
30 |\
31 | o test@5.draft: 5
31 | o test@5.draft: 5
32 | |
32 | |
33 o | test@4.draft: 4
33 o | test@4.draft: 4
34 |/
34 |/
35 o baz@3.public: 3
35 o baz@3.public: 3
36 |
36 |
37 o test@2.public: 2
37 o test@2.public: 2
38 |
38 |
39 o bar@1.public: 1
39 o bar@1.public: 1
40 |
40 |
41 o test@0.public: 0
41 o test@0.public: 0
42
42
43
43
44 Need to specify a rev:
44 Need to specify a rev:
45
45
46 $ hg graft
46 $ hg graft
47 abort: no revisions specified
47 abort: no revisions specified
48 [255]
48 [255]
49
49
50 Can't graft ancestor:
50 Can't graft ancestor:
51
51
52 $ hg graft 1 2
52 $ hg graft 1 2
53 skipping ancestor revision 1
53 skipping ancestor revision 1
54 skipping ancestor revision 2
54 skipping ancestor revision 2
55 [255]
55 [255]
56
56
57 Specify revisions with -r:
57 Specify revisions with -r:
58
58
59 $ hg graft -r 1 -r 2
59 $ hg graft -r 1 -r 2
60 skipping ancestor revision 1
60 skipping ancestor revision 1
61 skipping ancestor revision 2
61 skipping ancestor revision 2
62 [255]
62 [255]
63
63
64 $ hg graft -r 1 2
64 $ hg graft -r 1 2
65 skipping ancestor revision 2
65 skipping ancestor revision 2
66 skipping ancestor revision 1
66 skipping ancestor revision 1
67 [255]
67 [255]
68
68
69 Can't graft with dirty wd:
69 Can't graft with dirty wd:
70
70
71 $ hg up -q 0
71 $ hg up -q 0
72 $ echo foo > a
72 $ echo foo > a
73 $ hg graft 1
73 $ hg graft 1
74 abort: uncommitted changes
74 abort: uncommitted changes
75 [255]
75 [255]
76 $ hg revert a
76 $ hg revert a
77
77
78 Graft a rename:
78 Graft a rename:
79 (this also tests that editor is invoked if '--edit' is specified)
79 (this also tests that editor is invoked if '--edit' is specified)
80
80
81 $ hg status --rev "2^1" --rev 2
81 $ hg status --rev "2^1" --rev 2
82 A b
82 A b
83 R a
83 R a
84 $ HGEDITOR=cat hg graft 2 -u foo --edit
84 $ HGEDITOR=cat hg graft 2 -u foo --edit
85 grafting revision 2
85 grafting revision 2
86 merging a and b to b
86 merging a and b to b
87 2
87 2
88
88
89
89
90 HG: Enter commit message. Lines beginning with 'HG:' are removed.
90 HG: Enter commit message. Lines beginning with 'HG:' are removed.
91 HG: Leave message empty to abort commit.
91 HG: Leave message empty to abort commit.
92 HG: --
92 HG: --
93 HG: user: foo
93 HG: user: foo
94 HG: branch 'default'
94 HG: branch 'default'
95 HG: changed b
95 HG: changed b
96 HG: removed a
96 HG: removed a
97 $ hg export tip --git
97 $ hg export tip --git
98 # HG changeset patch
98 # HG changeset patch
99 # User foo
99 # User foo
100 # Date 0 0
100 # Date 0 0
101 # Thu Jan 01 00:00:00 1970 +0000
101 # Thu Jan 01 00:00:00 1970 +0000
102 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
102 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
103 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
103 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
104 2
104 2
105
105
106 diff --git a/a b/b
106 diff --git a/a b/b
107 rename from a
107 rename from a
108 rename to b
108 rename to b
109
109
110 Look for extra:source
110 Look for extra:source
111
111
112 $ hg log --debug -r tip
112 $ hg log --debug -r tip
113 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
113 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
114 tag: tip
114 tag: tip
115 phase: draft
115 phase: draft
116 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
116 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
117 parent: -1:0000000000000000000000000000000000000000
117 parent: -1:0000000000000000000000000000000000000000
118 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
118 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
119 user: foo
119 user: foo
120 date: Thu Jan 01 00:00:00 1970 +0000
120 date: Thu Jan 01 00:00:00 1970 +0000
121 files+: b
121 files+: b
122 files-: a
122 files-: a
123 extra: branch=default
123 extra: branch=default
124 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
124 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
125 description:
125 description:
126 2
126 2
127
127
128
128
129
129
130 Graft out of order, skipping a merge and a duplicate
130 Graft out of order, skipping a merge and a duplicate
131 (this also tests that editor is not invoked if '--edit' is not specified)
131 (this also tests that editor is not invoked if '--edit' is not specified)
132
132
133 $ hg graft 1 5 4 3 'merge()' 2 -n
133 $ hg graft 1 5 4 3 'merge()' 2 -n
134 skipping ungraftable merge revision 6
134 skipping ungraftable merge revision 6
135 skipping revision 2 (already grafted to 7)
135 skipping revision 2 (already grafted to 7)
136 grafting revision 1
136 grafting revision 1
137 grafting revision 5
137 grafting revision 5
138 grafting revision 4
138 grafting revision 4
139 grafting revision 3
139 grafting revision 3
140
140
141 $ HGEDITOR=cat hg graft 1 5 4 3 'merge()' 2 --debug
141 $ HGEDITOR=cat hg graft 1 5 4 3 'merge()' 2 --debug
142 skipping ungraftable merge revision 6
142 skipping ungraftable merge revision 6
143 scanning for duplicate grafts
143 scanning for duplicate grafts
144 skipping revision 2 (already grafted to 7)
144 skipping revision 2 (already grafted to 7)
145 grafting revision 1
145 grafting revision 1
146 searching for copies back to rev 1
146 searching for copies back to rev 1
147 unmatched files in local:
147 unmatched files in local:
148 b
148 b
149 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
149 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
150 src: 'a' -> dst: 'b' *
150 src: 'a' -> dst: 'b' *
151 checking for directory renames
151 checking for directory renames
152 resolving manifests
152 resolving manifests
153 branchmerge: True, force: True, partial: False
153 branchmerge: True, force: True, partial: False
154 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
154 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
155 preserving b for resolve of b
155 preserving b for resolve of b
156 b: local copied/moved from a -> m
156 b: local copied/moved from a -> m
157 updating: b 1/1 files (100.00%)
157 updating: b 1/1 files (100.00%)
158 picked tool 'internal:merge' for b (binary False symlink False)
158 picked tool 'internal:merge' for b (binary False symlink False)
159 merging b and a to b
159 merging b and a to b
160 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
160 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
161 premerge successful
161 premerge successful
162 b
162 b
163 grafting revision 5
163 grafting revision 5
164 searching for copies back to rev 1
164 searching for copies back to rev 1
165 resolving manifests
165 resolving manifests
166 branchmerge: True, force: True, partial: False
166 branchmerge: True, force: True, partial: False
167 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
167 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
168 e: remote is newer -> g
168 e: remote is newer -> g
169 getting e
169 getting e
170 updating: e 1/1 files (100.00%)
170 updating: e 1/1 files (100.00%)
171 b: keep -> k
171 b: keep -> k
172 e
172 e
173 grafting revision 4
173 grafting revision 4
174 searching for copies back to rev 1
174 searching for copies back to rev 1
175 resolving manifests
175 resolving manifests
176 branchmerge: True, force: True, partial: False
176 branchmerge: True, force: True, partial: False
177 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
177 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
178 preserving e for resolve of e
178 preserving e for resolve of e
179 d: remote is newer -> g
179 d: remote is newer -> g
180 getting d
180 getting d
181 updating: d 1/2 files (50.00%)
181 updating: d 1/2 files (50.00%)
182 b: keep -> k
182 b: keep -> k
183 e: versions differ -> m
183 e: versions differ -> m
184 updating: e 2/2 files (100.00%)
184 updating: e 2/2 files (100.00%)
185 picked tool 'internal:merge' for e (binary False symlink False)
185 picked tool 'internal:merge' for e (binary False symlink False)
186 merging e
186 merging e
187 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
187 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
188 warning: conflicts during merge.
188 warning: conflicts during merge.
189 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
189 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
190 abort: unresolved conflicts, can't continue
190 abort: unresolved conflicts, can't continue
191 (use hg resolve and hg graft --continue)
191 (use hg resolve and hg graft --continue)
192 [255]
192 [255]
193
193
194 Commit while interrupted should fail:
194 Commit while interrupted should fail:
195
195
196 $ hg ci -m 'commit interrupted graft'
196 $ hg ci -m 'commit interrupted graft'
197 abort: graft in progress
197 abort: graft in progress
198 (use 'hg graft --continue' or 'hg update' to abort)
198 (use 'hg graft --continue' or 'hg update' to abort)
199 [255]
199 [255]
200
200
201 Abort the graft and try committing:
201 Abort the graft and try committing:
202
202
203 $ hg up -C .
203 $ hg up -C .
204 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
204 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 $ echo c >> e
205 $ echo c >> e
206 $ hg ci -mtest
206 $ hg ci -mtest
207
207
208 $ hg strip . --config extensions.mq=
208 $ hg strip . --config extensions.mq=
209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
210 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
211
211
212 Graft again:
212 Graft again:
213
213
214 $ hg graft 1 5 4 3 'merge()' 2
214 $ hg graft 1 5 4 3 'merge()' 2
215 skipping ungraftable merge revision 6
215 skipping ungraftable merge revision 6
216 skipping revision 2 (already grafted to 7)
216 skipping revision 2 (already grafted to 7)
217 skipping revision 1 (already grafted to 8)
217 skipping revision 1 (already grafted to 8)
218 skipping revision 5 (already grafted to 9)
218 skipping revision 5 (already grafted to 9)
219 grafting revision 4
219 grafting revision 4
220 merging e
220 merging e
221 warning: conflicts during merge.
221 warning: conflicts during merge.
222 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
222 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
223 abort: unresolved conflicts, can't continue
223 abort: unresolved conflicts, can't continue
224 (use hg resolve and hg graft --continue)
224 (use hg resolve and hg graft --continue)
225 [255]
225 [255]
226
226
227 Continue without resolve should fail:
227 Continue without resolve should fail:
228
228
229 $ hg graft -c
229 $ hg graft -c
230 grafting revision 4
230 grafting revision 4
231 abort: unresolved merge conflicts (see hg help resolve)
231 abort: unresolved merge conflicts (see hg help resolve)
232 [255]
232 [255]
233
233
234 Fix up:
234 Fix up:
235
235
236 $ echo b > e
236 $ echo b > e
237 $ hg resolve -m e
237 $ hg resolve -m e
238 no more unresolved files
238 no more unresolved files
239
239
240 Continue with a revision should fail:
240 Continue with a revision should fail:
241
241
242 $ hg graft -c 6
242 $ hg graft -c 6
243 abort: can't specify --continue and revisions
243 abort: can't specify --continue and revisions
244 [255]
244 [255]
245
245
246 $ hg graft -c -r 6
246 $ hg graft -c -r 6
247 abort: can't specify --continue and revisions
247 abort: can't specify --continue and revisions
248 [255]
248 [255]
249
249
250 Continue for real, clobber usernames
250 Continue for real, clobber usernames
251
251
252 $ hg graft -c -U
252 $ hg graft -c -U
253 grafting revision 4
253 grafting revision 4
254 grafting revision 3
254 grafting revision 3
255
255
256 Compare with original:
256 Compare with original:
257
257
258 $ hg diff -r 6
258 $ hg diff -r 6
259 $ hg status --rev 0:. -C
259 $ hg status --rev 0:. -C
260 M d
260 M d
261 M e
261 M e
262 A b
262 A b
263 a
263 a
264 A c
264 A c
265 a
265 a
266 R a
266 R a
267
267
268 View graph:
268 View graph:
269
269
270 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
270 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
271 @ test@11.draft: 3
271 @ test@11.draft: 3
272 |
272 |
273 o test@10.draft: 4
273 o test@10.draft: 4
274 |
274 |
275 o test@9.draft: 5
275 o test@9.draft: 5
276 |
276 |
277 o bar@8.draft: 1
277 o bar@8.draft: 1
278 |
278 |
279 o foo@7.draft: 2
279 o foo@7.draft: 2
280 |
280 |
281 | o test@6.secret: 6
281 | o test@6.secret: 6
282 | |\
282 | |\
283 | | o test@5.draft: 5
283 | | o test@5.draft: 5
284 | | |
284 | | |
285 | o | test@4.draft: 4
285 | o | test@4.draft: 4
286 | |/
286 | |/
287 | o baz@3.public: 3
287 | o baz@3.public: 3
288 | |
288 | |
289 | o test@2.public: 2
289 | o test@2.public: 2
290 | |
290 | |
291 | o bar@1.public: 1
291 | o bar@1.public: 1
292 |/
292 |/
293 o test@0.public: 0
293 o test@0.public: 0
294
294
295 Graft again onto another branch should preserve the original source
295 Graft again onto another branch should preserve the original source
296 $ hg up -q 0
296 $ hg up -q 0
297 $ echo 'g'>g
297 $ echo 'g'>g
298 $ hg add g
298 $ hg add g
299 $ hg ci -m 7
299 $ hg ci -m 7
300 created new head
300 created new head
301 $ hg graft 7
301 $ hg graft 7
302 grafting revision 7
302 grafting revision 7
303
303
304 $ hg log -r 7 --template '{rev}:{node}\n'
304 $ hg log -r 7 --template '{rev}:{node}\n'
305 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
305 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
306 $ hg log -r 2 --template '{rev}:{node}\n'
306 $ hg log -r 2 --template '{rev}:{node}\n'
307 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
307 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
308
308
309 $ hg log --debug -r tip
309 $ hg log --debug -r tip
310 changeset: 13:9db0f28fd3747e92c57d015f53b5593aeec53c2d
310 changeset: 13:9db0f28fd3747e92c57d015f53b5593aeec53c2d
311 tag: tip
311 tag: tip
312 phase: draft
312 phase: draft
313 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
313 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
314 parent: -1:0000000000000000000000000000000000000000
314 parent: -1:0000000000000000000000000000000000000000
315 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
315 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
316 user: foo
316 user: foo
317 date: Thu Jan 01 00:00:00 1970 +0000
317 date: Thu Jan 01 00:00:00 1970 +0000
318 files+: b
318 files+: b
319 files-: a
319 files-: a
320 extra: branch=default
320 extra: branch=default
321 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
321 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
322 description:
322 description:
323 2
323 2
324
324
325
325
326 Disallow grafting an already grafted cset onto its original branch
326 Disallow grafting an already grafted cset onto its original branch
327 $ hg up -q 6
327 $ hg up -q 6
328 $ hg graft 7
328 $ hg graft 7
329 skipping already grafted revision 7 (was grafted from 2)
329 skipping already grafted revision 7 (was grafted from 2)
330 [255]
330 [255]
331
331
332 Disallow grafting already grafted csets with the same origin onto each other
332 Disallow grafting already grafted csets with the same origin onto each other
333 $ hg up -q 13
333 $ hg up -q 13
334 $ hg graft 2
334 $ hg graft 2
335 skipping revision 2 (already grafted to 13)
335 skipping revision 2 (already grafted to 13)
336 [255]
336 [255]
337 $ hg graft 7
337 $ hg graft 7
338 skipping already grafted revision 7 (13 also has origin 2)
338 skipping already grafted revision 7 (13 also has origin 2)
339 [255]
339 [255]
340
340
341 $ hg up -q 7
341 $ hg up -q 7
342 $ hg graft 2
342 $ hg graft 2
343 skipping revision 2 (already grafted to 7)
343 skipping revision 2 (already grafted to 7)
344 [255]
344 [255]
345 $ hg graft tip
345 $ hg graft tip
346 skipping already grafted revision 13 (7 also has origin 2)
346 skipping already grafted revision 13 (7 also has origin 2)
347 [255]
347 [255]
348
348
349 Graft with --log
349 Graft with --log
350
350
351 $ hg up -Cq 1
351 $ hg up -Cq 1
352 $ hg graft 3 --log -u foo
352 $ hg graft 3 --log -u foo
353 grafting revision 3
353 grafting revision 3
354 warning: can't find ancestor for 'c' copied from 'b'!
354 warning: can't find ancestor for 'c' copied from 'b'!
355 $ hg log --template '{rev} {parents} {desc}\n' -r tip
355 $ hg log --template '{rev} {parents} {desc}\n' -r tip
356 14 1:5d205f8b35b6 3
356 14 1:5d205f8b35b6 3
357 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
357 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
358
358
359 Resolve conflicted graft
359 Resolve conflicted graft
360 $ hg up -q 0
360 $ hg up -q 0
361 $ echo b > a
361 $ echo b > a
362 $ hg ci -m 8
362 $ hg ci -m 8
363 created new head
363 created new head
364 $ echo a > a
364 $ echo a > a
365 $ hg ci -m 9
365 $ hg ci -m 9
366 $ hg graft 1 --tool internal:fail
366 $ hg graft 1 --tool internal:fail
367 grafting revision 1
367 grafting revision 1
368 abort: unresolved conflicts, can't continue
368 abort: unresolved conflicts, can't continue
369 (use hg resolve and hg graft --continue)
369 (use hg resolve and hg graft --continue)
370 [255]
370 [255]
371 $ hg resolve --all
371 $ hg resolve --all
372 merging a
372 merging a
373 no more unresolved files
373 no more unresolved files
374 $ hg graft -c
374 $ hg graft -c
375 grafting revision 1
375 grafting revision 1
376 $ hg export tip --git
376 $ hg export tip --git
377 # HG changeset patch
377 # HG changeset patch
378 # User bar
378 # User bar
379 # Date 0 0
379 # Date 0 0
380 # Thu Jan 01 00:00:00 1970 +0000
380 # Thu Jan 01 00:00:00 1970 +0000
381 # Node ID 64ecd9071ce83c6e62f538d8ce7709d53f32ebf7
381 # Node ID 64ecd9071ce83c6e62f538d8ce7709d53f32ebf7
382 # Parent 4bdb9a9d0b84ffee1d30f0dfc7744cade17aa19c
382 # Parent 4bdb9a9d0b84ffee1d30f0dfc7744cade17aa19c
383 1
383 1
384
384
385 diff --git a/a b/a
385 diff --git a/a b/a
386 --- a/a
386 --- a/a
387 +++ b/a
387 +++ b/a
388 @@ -1,1 +1,1 @@
388 @@ -1,1 +1,1 @@
389 -a
389 -a
390 +b
390 +b
391
391
392 Resolve conflicted graft with rename
392 Resolve conflicted graft with rename
393 $ echo c > a
393 $ echo c > a
394 $ hg ci -m 10
394 $ hg ci -m 10
395 $ hg graft 2 --tool internal:fail
395 $ hg graft 2 --tool internal:fail
396 grafting revision 2
396 grafting revision 2
397 abort: unresolved conflicts, can't continue
397 abort: unresolved conflicts, can't continue
398 (use hg resolve and hg graft --continue)
398 (use hg resolve and hg graft --continue)
399 [255]
399 [255]
400 $ hg resolve --all
400 $ hg resolve --all
401 merging a and b to b
401 merging a and b to b
402 no more unresolved files
402 no more unresolved files
403 $ hg graft -c
403 $ hg graft -c
404 grafting revision 2
404 grafting revision 2
405 $ hg export tip --git
405 $ hg export tip --git
406 # HG changeset patch
406 # HG changeset patch
407 # User test
407 # User test
408 # Date 0 0
408 # Date 0 0
409 # Thu Jan 01 00:00:00 1970 +0000
409 # Thu Jan 01 00:00:00 1970 +0000
410 # Node ID 2e80e1351d6ed50302fe1e05f8bd1d4d412b6e11
410 # Node ID 2e80e1351d6ed50302fe1e05f8bd1d4d412b6e11
411 # Parent e5a51ae854a8bbaaf25cc5c6a57ff46042dadbb4
411 # Parent e5a51ae854a8bbaaf25cc5c6a57ff46042dadbb4
412 2
412 2
413
413
414 diff --git a/a b/b
414 diff --git a/a b/b
415 rename from a
415 rename from a
416 rename to b
416 rename to b
417
417
418 Test simple origin(), with and without args
418 Test simple origin(), with and without args
419 $ hg log -r 'origin()'
419 $ hg log -r 'origin()'
420 changeset: 1:5d205f8b35b6
420 changeset: 1:5d205f8b35b6
421 user: bar
421 user: bar
422 date: Thu Jan 01 00:00:00 1970 +0000
422 date: Thu Jan 01 00:00:00 1970 +0000
423 summary: 1
423 summary: 1
424
424
425 changeset: 2:5c095ad7e90f
425 changeset: 2:5c095ad7e90f
426 user: test
426 user: test
427 date: Thu Jan 01 00:00:00 1970 +0000
427 date: Thu Jan 01 00:00:00 1970 +0000
428 summary: 2
428 summary: 2
429
429
430 changeset: 3:4c60f11aa304
430 changeset: 3:4c60f11aa304
431 user: baz
431 user: baz
432 date: Thu Jan 01 00:00:00 1970 +0000
432 date: Thu Jan 01 00:00:00 1970 +0000
433 summary: 3
433 summary: 3
434
434
435 changeset: 4:9c233e8e184d
435 changeset: 4:9c233e8e184d
436 user: test
436 user: test
437 date: Thu Jan 01 00:00:00 1970 +0000
437 date: Thu Jan 01 00:00:00 1970 +0000
438 summary: 4
438 summary: 4
439
439
440 changeset: 5:97f8bfe72746
440 changeset: 5:97f8bfe72746
441 branch: stable
441 branch: stable
442 parent: 3:4c60f11aa304
442 parent: 3:4c60f11aa304
443 user: test
443 user: test
444 date: Thu Jan 01 00:00:00 1970 +0000
444 date: Thu Jan 01 00:00:00 1970 +0000
445 summary: 5
445 summary: 5
446
446
447 $ hg log -r 'origin(7)'
447 $ hg log -r 'origin(7)'
448 changeset: 2:5c095ad7e90f
448 changeset: 2:5c095ad7e90f
449 user: test
449 user: test
450 date: Thu Jan 01 00:00:00 1970 +0000
450 date: Thu Jan 01 00:00:00 1970 +0000
451 summary: 2
451 summary: 2
452
452
453 Now transplant a graft to test following through copies
453 Now transplant a graft to test following through copies
454 $ hg up -q 0
454 $ hg up -q 0
455 $ hg branch -q dev
455 $ hg branch -q dev
456 $ hg ci -qm "dev branch"
456 $ hg ci -qm "dev branch"
457 $ hg --config extensions.transplant= transplant -q 7
457 $ hg --config extensions.transplant= transplant -q 7
458 $ hg log -r 'origin(.)'
458 $ hg log -r 'origin(.)'
459 changeset: 2:5c095ad7e90f
459 changeset: 2:5c095ad7e90f
460 user: test
460 user: test
461 date: Thu Jan 01 00:00:00 1970 +0000
461 date: Thu Jan 01 00:00:00 1970 +0000
462 summary: 2
462 summary: 2
463
463
464 Test that the graft and transplant markers in extra are converted, allowing
465 origin() to still work. Note that these recheck the immediately preceeding two
466 tests.
467 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
468
469 The graft case
470 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
471 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
472 branch=default
473 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
474 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
475 $ hg -R ../converted log -r 'origin(7)'
476 changeset: 2:e0213322b2c1
477 user: test
478 date: Thu Jan 01 00:00:00 1970 +0000
479 summary: 2
480
481 The transplant case
482 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
483 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
484 branch=dev
485 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
486 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
487 `h\x9b (esc)
488 $ hg -R ../converted log -r 'origin(tip)'
489 changeset: 2:e0213322b2c1
490 user: test
491 date: Thu Jan 01 00:00:00 1970 +0000
492 summary: 2
493
494
464 Test simple destination
495 Test simple destination
465 $ hg log -r 'destination()'
496 $ hg log -r 'destination()'
466 changeset: 7:ef0ef43d49e7
497 changeset: 7:ef0ef43d49e7
467 parent: 0:68795b066622
498 parent: 0:68795b066622
468 user: foo
499 user: foo
469 date: Thu Jan 01 00:00:00 1970 +0000
500 date: Thu Jan 01 00:00:00 1970 +0000
470 summary: 2
501 summary: 2
471
502
472 changeset: 8:6b9e5368ca4e
503 changeset: 8:6b9e5368ca4e
473 user: bar
504 user: bar
474 date: Thu Jan 01 00:00:00 1970 +0000
505 date: Thu Jan 01 00:00:00 1970 +0000
475 summary: 1
506 summary: 1
476
507
477 changeset: 9:1905859650ec
508 changeset: 9:1905859650ec
478 user: test
509 user: test
479 date: Thu Jan 01 00:00:00 1970 +0000
510 date: Thu Jan 01 00:00:00 1970 +0000
480 summary: 5
511 summary: 5
481
512
482 changeset: 10:52dc0b4c6907
513 changeset: 10:52dc0b4c6907
483 user: test
514 user: test
484 date: Thu Jan 01 00:00:00 1970 +0000
515 date: Thu Jan 01 00:00:00 1970 +0000
485 summary: 4
516 summary: 4
486
517
487 changeset: 11:882b35362a6b
518 changeset: 11:882b35362a6b
488 user: test
519 user: test
489 date: Thu Jan 01 00:00:00 1970 +0000
520 date: Thu Jan 01 00:00:00 1970 +0000
490 summary: 3
521 summary: 3
491
522
492 changeset: 13:9db0f28fd374
523 changeset: 13:9db0f28fd374
493 user: foo
524 user: foo
494 date: Thu Jan 01 00:00:00 1970 +0000
525 date: Thu Jan 01 00:00:00 1970 +0000
495 summary: 2
526 summary: 2
496
527
497 changeset: 14:f64defefacee
528 changeset: 14:f64defefacee
498 parent: 1:5d205f8b35b6
529 parent: 1:5d205f8b35b6
499 user: foo
530 user: foo
500 date: Thu Jan 01 00:00:00 1970 +0000
531 date: Thu Jan 01 00:00:00 1970 +0000
501 summary: 3
532 summary: 3
502
533
503 changeset: 17:64ecd9071ce8
534 changeset: 17:64ecd9071ce8
504 user: bar
535 user: bar
505 date: Thu Jan 01 00:00:00 1970 +0000
536 date: Thu Jan 01 00:00:00 1970 +0000
506 summary: 1
537 summary: 1
507
538
508 changeset: 19:2e80e1351d6e
539 changeset: 19:2e80e1351d6e
509 user: test
540 user: test
510 date: Thu Jan 01 00:00:00 1970 +0000
541 date: Thu Jan 01 00:00:00 1970 +0000
511 summary: 2
542 summary: 2
512
543
513 changeset: 21:7e61b508e709
544 changeset: 21:7e61b508e709
514 branch: dev
545 branch: dev
515 tag: tip
546 tag: tip
516 user: foo
547 user: foo
517 date: Thu Jan 01 00:00:00 1970 +0000
548 date: Thu Jan 01 00:00:00 1970 +0000
518 summary: 2
549 summary: 2
519
550
520 $ hg log -r 'destination(2)'
551 $ hg log -r 'destination(2)'
521 changeset: 7:ef0ef43d49e7
552 changeset: 7:ef0ef43d49e7
522 parent: 0:68795b066622
553 parent: 0:68795b066622
523 user: foo
554 user: foo
524 date: Thu Jan 01 00:00:00 1970 +0000
555 date: Thu Jan 01 00:00:00 1970 +0000
525 summary: 2
556 summary: 2
526
557
527 changeset: 13:9db0f28fd374
558 changeset: 13:9db0f28fd374
528 user: foo
559 user: foo
529 date: Thu Jan 01 00:00:00 1970 +0000
560 date: Thu Jan 01 00:00:00 1970 +0000
530 summary: 2
561 summary: 2
531
562
532 changeset: 19:2e80e1351d6e
563 changeset: 19:2e80e1351d6e
533 user: test
564 user: test
534 date: Thu Jan 01 00:00:00 1970 +0000
565 date: Thu Jan 01 00:00:00 1970 +0000
535 summary: 2
566 summary: 2
536
567
537 changeset: 21:7e61b508e709
568 changeset: 21:7e61b508e709
538 branch: dev
569 branch: dev
539 tag: tip
570 tag: tip
540 user: foo
571 user: foo
541 date: Thu Jan 01 00:00:00 1970 +0000
572 date: Thu Jan 01 00:00:00 1970 +0000
542 summary: 2
573 summary: 2
543
574
544 Transplants of grafts can find a destination...
575 Transplants of grafts can find a destination...
545 $ hg log -r 'destination(7)'
576 $ hg log -r 'destination(7)'
546 changeset: 21:7e61b508e709
577 changeset: 21:7e61b508e709
547 branch: dev
578 branch: dev
548 tag: tip
579 tag: tip
549 user: foo
580 user: foo
550 date: Thu Jan 01 00:00:00 1970 +0000
581 date: Thu Jan 01 00:00:00 1970 +0000
551 summary: 2
582 summary: 2
552
583
553 ... grafts of grafts unfortunately can't
584 ... grafts of grafts unfortunately can't
554 $ hg graft -q 13
585 $ hg graft -q 13
555 $ hg log -r 'destination(13)'
586 $ hg log -r 'destination(13)'
556 All copies of a cset
587 All copies of a cset
557 $ hg log -r 'origin(13) or destination(origin(13))'
588 $ hg log -r 'origin(13) or destination(origin(13))'
558 changeset: 2:5c095ad7e90f
589 changeset: 2:5c095ad7e90f
559 user: test
590 user: test
560 date: Thu Jan 01 00:00:00 1970 +0000
591 date: Thu Jan 01 00:00:00 1970 +0000
561 summary: 2
592 summary: 2
562
593
563 changeset: 7:ef0ef43d49e7
594 changeset: 7:ef0ef43d49e7
564 parent: 0:68795b066622
595 parent: 0:68795b066622
565 user: foo
596 user: foo
566 date: Thu Jan 01 00:00:00 1970 +0000
597 date: Thu Jan 01 00:00:00 1970 +0000
567 summary: 2
598 summary: 2
568
599
569 changeset: 13:9db0f28fd374
600 changeset: 13:9db0f28fd374
570 user: foo
601 user: foo
571 date: Thu Jan 01 00:00:00 1970 +0000
602 date: Thu Jan 01 00:00:00 1970 +0000
572 summary: 2
603 summary: 2
573
604
574 changeset: 19:2e80e1351d6e
605 changeset: 19:2e80e1351d6e
575 user: test
606 user: test
576 date: Thu Jan 01 00:00:00 1970 +0000
607 date: Thu Jan 01 00:00:00 1970 +0000
577 summary: 2
608 summary: 2
578
609
579 changeset: 21:7e61b508e709
610 changeset: 21:7e61b508e709
580 branch: dev
611 branch: dev
581 user: foo
612 user: foo
582 date: Thu Jan 01 00:00:00 1970 +0000
613 date: Thu Jan 01 00:00:00 1970 +0000
583 summary: 2
614 summary: 2
584
615
585 changeset: 22:1313d0a825e2
616 changeset: 22:1313d0a825e2
586 branch: dev
617 branch: dev
587 tag: tip
618 tag: tip
588 user: foo
619 user: foo
589 date: Thu Jan 01 00:00:00 1970 +0000
620 date: Thu Jan 01 00:00:00 1970 +0000
590 summary: 2
621 summary: 2
591
622
592
623
593 graft works on complex revset
624 graft works on complex revset
594
625
595 $ hg graft 'origin(13) or destination(origin(13))'
626 $ hg graft 'origin(13) or destination(origin(13))'
596 skipping ancestor revision 21
627 skipping ancestor revision 21
597 skipping ancestor revision 22
628 skipping ancestor revision 22
598 skipping revision 2 (already grafted to 22)
629 skipping revision 2 (already grafted to 22)
599 grafting revision 7
630 grafting revision 7
600 grafting revision 13
631 grafting revision 13
601 grafting revision 19
632 grafting revision 19
602 merging b
633 merging b
General Comments 0
You need to be logged in to leave comments. Login now