##// END OF EJS Templates
localrepo: use single quotes in use warning
timeless -
r29975:c15f0610 default
parent child Browse files
Show More
@@ -1,1996 +1,1996 b''
1 # localrepo.py - read/write repository class for mercurial
1 # localrepo.py - read/write repository class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import hashlib
11 import hashlib
12 import inspect
12 import inspect
13 import os
13 import os
14 import random
14 import random
15 import time
15 import time
16 import weakref
16 import weakref
17
17
18 from .i18n import _
18 from .i18n import _
19 from .node import (
19 from .node import (
20 hex,
20 hex,
21 nullid,
21 nullid,
22 short,
22 short,
23 wdirrev,
23 wdirrev,
24 )
24 )
25 from . import (
25 from . import (
26 bookmarks,
26 bookmarks,
27 branchmap,
27 branchmap,
28 bundle2,
28 bundle2,
29 changegroup,
29 changegroup,
30 changelog,
30 changelog,
31 cmdutil,
31 cmdutil,
32 context,
32 context,
33 dirstate,
33 dirstate,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 filelog,
38 filelog,
39 hook,
39 hook,
40 lock as lockmod,
40 lock as lockmod,
41 manifest,
41 manifest,
42 match as matchmod,
42 match as matchmod,
43 merge as mergemod,
43 merge as mergemod,
44 namespaces,
44 namespaces,
45 obsolete,
45 obsolete,
46 pathutil,
46 pathutil,
47 peer,
47 peer,
48 phases,
48 phases,
49 pushkey,
49 pushkey,
50 repoview,
50 repoview,
51 revset,
51 revset,
52 scmutil,
52 scmutil,
53 store,
53 store,
54 subrepo,
54 subrepo,
55 tags as tagsmod,
55 tags as tagsmod,
56 transaction,
56 transaction,
57 util,
57 util,
58 )
58 )
59
59
60 release = lockmod.release
60 release = lockmod.release
61 urlerr = util.urlerr
61 urlerr = util.urlerr
62 urlreq = util.urlreq
62 urlreq = util.urlreq
63
63
64 class repofilecache(scmutil.filecache):
64 class repofilecache(scmutil.filecache):
65 """All filecache usage on repo are done for logic that should be unfiltered
65 """All filecache usage on repo are done for logic that should be unfiltered
66 """
66 """
67
67
68 def __get__(self, repo, type=None):
68 def __get__(self, repo, type=None):
69 if repo is None:
69 if repo is None:
70 return self
70 return self
71 return super(repofilecache, self).__get__(repo.unfiltered(), type)
71 return super(repofilecache, self).__get__(repo.unfiltered(), type)
72 def __set__(self, repo, value):
72 def __set__(self, repo, value):
73 return super(repofilecache, self).__set__(repo.unfiltered(), value)
73 return super(repofilecache, self).__set__(repo.unfiltered(), value)
74 def __delete__(self, repo):
74 def __delete__(self, repo):
75 return super(repofilecache, self).__delete__(repo.unfiltered())
75 return super(repofilecache, self).__delete__(repo.unfiltered())
76
76
77 class storecache(repofilecache):
77 class storecache(repofilecache):
78 """filecache for files in the store"""
78 """filecache for files in the store"""
79 def join(self, obj, fname):
79 def join(self, obj, fname):
80 return obj.sjoin(fname)
80 return obj.sjoin(fname)
81
81
82 class unfilteredpropertycache(util.propertycache):
82 class unfilteredpropertycache(util.propertycache):
83 """propertycache that apply to unfiltered repo only"""
83 """propertycache that apply to unfiltered repo only"""
84
84
85 def __get__(self, repo, type=None):
85 def __get__(self, repo, type=None):
86 unfi = repo.unfiltered()
86 unfi = repo.unfiltered()
87 if unfi is repo:
87 if unfi is repo:
88 return super(unfilteredpropertycache, self).__get__(unfi)
88 return super(unfilteredpropertycache, self).__get__(unfi)
89 return getattr(unfi, self.name)
89 return getattr(unfi, self.name)
90
90
91 class filteredpropertycache(util.propertycache):
91 class filteredpropertycache(util.propertycache):
92 """propertycache that must take filtering in account"""
92 """propertycache that must take filtering in account"""
93
93
94 def cachevalue(self, obj, value):
94 def cachevalue(self, obj, value):
95 object.__setattr__(obj, self.name, value)
95 object.__setattr__(obj, self.name, value)
96
96
97
97
98 def hasunfilteredcache(repo, name):
98 def hasunfilteredcache(repo, name):
99 """check if a repo has an unfilteredpropertycache value for <name>"""
99 """check if a repo has an unfilteredpropertycache value for <name>"""
100 return name in vars(repo.unfiltered())
100 return name in vars(repo.unfiltered())
101
101
102 def unfilteredmethod(orig):
102 def unfilteredmethod(orig):
103 """decorate method that always need to be run on unfiltered version"""
103 """decorate method that always need to be run on unfiltered version"""
104 def wrapper(repo, *args, **kwargs):
104 def wrapper(repo, *args, **kwargs):
105 return orig(repo.unfiltered(), *args, **kwargs)
105 return orig(repo.unfiltered(), *args, **kwargs)
106 return wrapper
106 return wrapper
107
107
108 moderncaps = set(('lookup', 'branchmap', 'pushkey', 'known', 'getbundle',
108 moderncaps = set(('lookup', 'branchmap', 'pushkey', 'known', 'getbundle',
109 'unbundle'))
109 'unbundle'))
110 legacycaps = moderncaps.union(set(['changegroupsubset']))
110 legacycaps = moderncaps.union(set(['changegroupsubset']))
111
111
112 class localpeer(peer.peerrepository):
112 class localpeer(peer.peerrepository):
113 '''peer for a local repo; reflects only the most recent API'''
113 '''peer for a local repo; reflects only the most recent API'''
114
114
115 def __init__(self, repo, caps=moderncaps):
115 def __init__(self, repo, caps=moderncaps):
116 peer.peerrepository.__init__(self)
116 peer.peerrepository.__init__(self)
117 self._repo = repo.filtered('served')
117 self._repo = repo.filtered('served')
118 self.ui = repo.ui
118 self.ui = repo.ui
119 self._caps = repo._restrictcapabilities(caps)
119 self._caps = repo._restrictcapabilities(caps)
120 self.requirements = repo.requirements
120 self.requirements = repo.requirements
121 self.supportedformats = repo.supportedformats
121 self.supportedformats = repo.supportedformats
122
122
123 def close(self):
123 def close(self):
124 self._repo.close()
124 self._repo.close()
125
125
126 def _capabilities(self):
126 def _capabilities(self):
127 return self._caps
127 return self._caps
128
128
129 def local(self):
129 def local(self):
130 return self._repo
130 return self._repo
131
131
132 def canpush(self):
132 def canpush(self):
133 return True
133 return True
134
134
135 def url(self):
135 def url(self):
136 return self._repo.url()
136 return self._repo.url()
137
137
138 def lookup(self, key):
138 def lookup(self, key):
139 return self._repo.lookup(key)
139 return self._repo.lookup(key)
140
140
141 def branchmap(self):
141 def branchmap(self):
142 return self._repo.branchmap()
142 return self._repo.branchmap()
143
143
144 def heads(self):
144 def heads(self):
145 return self._repo.heads()
145 return self._repo.heads()
146
146
147 def known(self, nodes):
147 def known(self, nodes):
148 return self._repo.known(nodes)
148 return self._repo.known(nodes)
149
149
150 def getbundle(self, source, heads=None, common=None, bundlecaps=None,
150 def getbundle(self, source, heads=None, common=None, bundlecaps=None,
151 **kwargs):
151 **kwargs):
152 cg = exchange.getbundle(self._repo, source, heads=heads,
152 cg = exchange.getbundle(self._repo, source, heads=heads,
153 common=common, bundlecaps=bundlecaps, **kwargs)
153 common=common, bundlecaps=bundlecaps, **kwargs)
154 if bundlecaps is not None and 'HG20' in bundlecaps:
154 if bundlecaps is not None and 'HG20' in bundlecaps:
155 # When requesting a bundle2, getbundle returns a stream to make the
155 # When requesting a bundle2, getbundle returns a stream to make the
156 # wire level function happier. We need to build a proper object
156 # wire level function happier. We need to build a proper object
157 # from it in local peer.
157 # from it in local peer.
158 cg = bundle2.getunbundler(self.ui, cg)
158 cg = bundle2.getunbundler(self.ui, cg)
159 return cg
159 return cg
160
160
161 # TODO We might want to move the next two calls into legacypeer and add
161 # TODO We might want to move the next two calls into legacypeer and add
162 # unbundle instead.
162 # unbundle instead.
163
163
164 def unbundle(self, cg, heads, url):
164 def unbundle(self, cg, heads, url):
165 """apply a bundle on a repo
165 """apply a bundle on a repo
166
166
167 This function handles the repo locking itself."""
167 This function handles the repo locking itself."""
168 try:
168 try:
169 try:
169 try:
170 cg = exchange.readbundle(self.ui, cg, None)
170 cg = exchange.readbundle(self.ui, cg, None)
171 ret = exchange.unbundle(self._repo, cg, heads, 'push', url)
171 ret = exchange.unbundle(self._repo, cg, heads, 'push', url)
172 if util.safehasattr(ret, 'getchunks'):
172 if util.safehasattr(ret, 'getchunks'):
173 # This is a bundle20 object, turn it into an unbundler.
173 # This is a bundle20 object, turn it into an unbundler.
174 # This little dance should be dropped eventually when the
174 # This little dance should be dropped eventually when the
175 # API is finally improved.
175 # API is finally improved.
176 stream = util.chunkbuffer(ret.getchunks())
176 stream = util.chunkbuffer(ret.getchunks())
177 ret = bundle2.getunbundler(self.ui, stream)
177 ret = bundle2.getunbundler(self.ui, stream)
178 return ret
178 return ret
179 except Exception as exc:
179 except Exception as exc:
180 # If the exception contains output salvaged from a bundle2
180 # If the exception contains output salvaged from a bundle2
181 # reply, we need to make sure it is printed before continuing
181 # reply, we need to make sure it is printed before continuing
182 # to fail. So we build a bundle2 with such output and consume
182 # to fail. So we build a bundle2 with such output and consume
183 # it directly.
183 # it directly.
184 #
184 #
185 # This is not very elegant but allows a "simple" solution for
185 # This is not very elegant but allows a "simple" solution for
186 # issue4594
186 # issue4594
187 output = getattr(exc, '_bundle2salvagedoutput', ())
187 output = getattr(exc, '_bundle2salvagedoutput', ())
188 if output:
188 if output:
189 bundler = bundle2.bundle20(self._repo.ui)
189 bundler = bundle2.bundle20(self._repo.ui)
190 for out in output:
190 for out in output:
191 bundler.addpart(out)
191 bundler.addpart(out)
192 stream = util.chunkbuffer(bundler.getchunks())
192 stream = util.chunkbuffer(bundler.getchunks())
193 b = bundle2.getunbundler(self.ui, stream)
193 b = bundle2.getunbundler(self.ui, stream)
194 bundle2.processbundle(self._repo, b)
194 bundle2.processbundle(self._repo, b)
195 raise
195 raise
196 except error.PushRaced as exc:
196 except error.PushRaced as exc:
197 raise error.ResponseError(_('push failed:'), str(exc))
197 raise error.ResponseError(_('push failed:'), str(exc))
198
198
199 def lock(self):
199 def lock(self):
200 return self._repo.lock()
200 return self._repo.lock()
201
201
202 def addchangegroup(self, cg, source, url):
202 def addchangegroup(self, cg, source, url):
203 return cg.apply(self._repo, source, url)
203 return cg.apply(self._repo, source, url)
204
204
205 def pushkey(self, namespace, key, old, new):
205 def pushkey(self, namespace, key, old, new):
206 return self._repo.pushkey(namespace, key, old, new)
206 return self._repo.pushkey(namespace, key, old, new)
207
207
208 def listkeys(self, namespace):
208 def listkeys(self, namespace):
209 return self._repo.listkeys(namespace)
209 return self._repo.listkeys(namespace)
210
210
211 def debugwireargs(self, one, two, three=None, four=None, five=None):
211 def debugwireargs(self, one, two, three=None, four=None, five=None):
212 '''used to test argument passing over the wire'''
212 '''used to test argument passing over the wire'''
213 return "%s %s %s %s %s" % (one, two, three, four, five)
213 return "%s %s %s %s %s" % (one, two, three, four, five)
214
214
215 class locallegacypeer(localpeer):
215 class locallegacypeer(localpeer):
216 '''peer extension which implements legacy methods too; used for tests with
216 '''peer extension which implements legacy methods too; used for tests with
217 restricted capabilities'''
217 restricted capabilities'''
218
218
219 def __init__(self, repo):
219 def __init__(self, repo):
220 localpeer.__init__(self, repo, caps=legacycaps)
220 localpeer.__init__(self, repo, caps=legacycaps)
221
221
222 def branches(self, nodes):
222 def branches(self, nodes):
223 return self._repo.branches(nodes)
223 return self._repo.branches(nodes)
224
224
225 def between(self, pairs):
225 def between(self, pairs):
226 return self._repo.between(pairs)
226 return self._repo.between(pairs)
227
227
228 def changegroup(self, basenodes, source):
228 def changegroup(self, basenodes, source):
229 return changegroup.changegroup(self._repo, basenodes, source)
229 return changegroup.changegroup(self._repo, basenodes, source)
230
230
231 def changegroupsubset(self, bases, heads, source):
231 def changegroupsubset(self, bases, heads, source):
232 return changegroup.changegroupsubset(self._repo, bases, heads, source)
232 return changegroup.changegroupsubset(self._repo, bases, heads, source)
233
233
234 class localrepository(object):
234 class localrepository(object):
235
235
236 supportedformats = set(('revlogv1', 'generaldelta', 'treemanifest',
236 supportedformats = set(('revlogv1', 'generaldelta', 'treemanifest',
237 'manifestv2'))
237 'manifestv2'))
238 _basesupported = supportedformats | set(('store', 'fncache', 'shared',
238 _basesupported = supportedformats | set(('store', 'fncache', 'shared',
239 'dotencode'))
239 'dotencode'))
240 openerreqs = set(('revlogv1', 'generaldelta', 'treemanifest', 'manifestv2'))
240 openerreqs = set(('revlogv1', 'generaldelta', 'treemanifest', 'manifestv2'))
241 filtername = None
241 filtername = None
242
242
243 # a list of (ui, featureset) functions.
243 # a list of (ui, featureset) functions.
244 # only functions defined in module of enabled extensions are invoked
244 # only functions defined in module of enabled extensions are invoked
245 featuresetupfuncs = set()
245 featuresetupfuncs = set()
246
246
247 def __init__(self, baseui, path=None, create=False):
247 def __init__(self, baseui, path=None, create=False):
248 self.requirements = set()
248 self.requirements = set()
249 self.wvfs = scmutil.vfs(path, expandpath=True, realpath=True)
249 self.wvfs = scmutil.vfs(path, expandpath=True, realpath=True)
250 self.wopener = self.wvfs
250 self.wopener = self.wvfs
251 self.root = self.wvfs.base
251 self.root = self.wvfs.base
252 self.path = self.wvfs.join(".hg")
252 self.path = self.wvfs.join(".hg")
253 self.origroot = path
253 self.origroot = path
254 self.auditor = pathutil.pathauditor(self.root, self._checknested)
254 self.auditor = pathutil.pathauditor(self.root, self._checknested)
255 self.nofsauditor = pathutil.pathauditor(self.root, self._checknested,
255 self.nofsauditor = pathutil.pathauditor(self.root, self._checknested,
256 realfs=False)
256 realfs=False)
257 self.vfs = scmutil.vfs(self.path)
257 self.vfs = scmutil.vfs(self.path)
258 self.opener = self.vfs
258 self.opener = self.vfs
259 self.baseui = baseui
259 self.baseui = baseui
260 self.ui = baseui.copy()
260 self.ui = baseui.copy()
261 self.ui.copy = baseui.copy # prevent copying repo configuration
261 self.ui.copy = baseui.copy # prevent copying repo configuration
262 # A list of callback to shape the phase if no data were found.
262 # A list of callback to shape the phase if no data were found.
263 # Callback are in the form: func(repo, roots) --> processed root.
263 # Callback are in the form: func(repo, roots) --> processed root.
264 # This list it to be filled by extension during repo setup
264 # This list it to be filled by extension during repo setup
265 self._phasedefaults = []
265 self._phasedefaults = []
266 try:
266 try:
267 self.ui.readconfig(self.join("hgrc"), self.root)
267 self.ui.readconfig(self.join("hgrc"), self.root)
268 extensions.loadall(self.ui)
268 extensions.loadall(self.ui)
269 except IOError:
269 except IOError:
270 pass
270 pass
271
271
272 if self.featuresetupfuncs:
272 if self.featuresetupfuncs:
273 self.supported = set(self._basesupported) # use private copy
273 self.supported = set(self._basesupported) # use private copy
274 extmods = set(m.__name__ for n, m
274 extmods = set(m.__name__ for n, m
275 in extensions.extensions(self.ui))
275 in extensions.extensions(self.ui))
276 for setupfunc in self.featuresetupfuncs:
276 for setupfunc in self.featuresetupfuncs:
277 if setupfunc.__module__ in extmods:
277 if setupfunc.__module__ in extmods:
278 setupfunc(self.ui, self.supported)
278 setupfunc(self.ui, self.supported)
279 else:
279 else:
280 self.supported = self._basesupported
280 self.supported = self._basesupported
281
281
282 if not self.vfs.isdir():
282 if not self.vfs.isdir():
283 if create:
283 if create:
284 self.requirements = newreporequirements(self)
284 self.requirements = newreporequirements(self)
285
285
286 if not self.wvfs.exists():
286 if not self.wvfs.exists():
287 self.wvfs.makedirs()
287 self.wvfs.makedirs()
288 self.vfs.makedir(notindexed=True)
288 self.vfs.makedir(notindexed=True)
289
289
290 if 'store' in self.requirements:
290 if 'store' in self.requirements:
291 self.vfs.mkdir("store")
291 self.vfs.mkdir("store")
292
292
293 # create an invalid changelog
293 # create an invalid changelog
294 self.vfs.append(
294 self.vfs.append(
295 "00changelog.i",
295 "00changelog.i",
296 '\0\0\0\2' # represents revlogv2
296 '\0\0\0\2' # represents revlogv2
297 ' dummy changelog to prevent using the old repo layout'
297 ' dummy changelog to prevent using the old repo layout'
298 )
298 )
299 else:
299 else:
300 raise error.RepoError(_("repository %s not found") % path)
300 raise error.RepoError(_("repository %s not found") % path)
301 elif create:
301 elif create:
302 raise error.RepoError(_("repository %s already exists") % path)
302 raise error.RepoError(_("repository %s already exists") % path)
303 else:
303 else:
304 try:
304 try:
305 self.requirements = scmutil.readrequires(
305 self.requirements = scmutil.readrequires(
306 self.vfs, self.supported)
306 self.vfs, self.supported)
307 except IOError as inst:
307 except IOError as inst:
308 if inst.errno != errno.ENOENT:
308 if inst.errno != errno.ENOENT:
309 raise
309 raise
310
310
311 self.sharedpath = self.path
311 self.sharedpath = self.path
312 try:
312 try:
313 vfs = scmutil.vfs(self.vfs.read("sharedpath").rstrip('\n'),
313 vfs = scmutil.vfs(self.vfs.read("sharedpath").rstrip('\n'),
314 realpath=True)
314 realpath=True)
315 s = vfs.base
315 s = vfs.base
316 if not vfs.exists():
316 if not vfs.exists():
317 raise error.RepoError(
317 raise error.RepoError(
318 _('.hg/sharedpath points to nonexistent directory %s') % s)
318 _('.hg/sharedpath points to nonexistent directory %s') % s)
319 self.sharedpath = s
319 self.sharedpath = s
320 except IOError as inst:
320 except IOError as inst:
321 if inst.errno != errno.ENOENT:
321 if inst.errno != errno.ENOENT:
322 raise
322 raise
323
323
324 self.store = store.store(
324 self.store = store.store(
325 self.requirements, self.sharedpath, scmutil.vfs)
325 self.requirements, self.sharedpath, scmutil.vfs)
326 self.spath = self.store.path
326 self.spath = self.store.path
327 self.svfs = self.store.vfs
327 self.svfs = self.store.vfs
328 self.sjoin = self.store.join
328 self.sjoin = self.store.join
329 self.vfs.createmode = self.store.createmode
329 self.vfs.createmode = self.store.createmode
330 self._applyopenerreqs()
330 self._applyopenerreqs()
331 if create:
331 if create:
332 self._writerequirements()
332 self._writerequirements()
333
333
334 self._dirstatevalidatewarned = False
334 self._dirstatevalidatewarned = False
335
335
336 self._branchcaches = {}
336 self._branchcaches = {}
337 self._revbranchcache = None
337 self._revbranchcache = None
338 self.filterpats = {}
338 self.filterpats = {}
339 self._datafilters = {}
339 self._datafilters = {}
340 self._transref = self._lockref = self._wlockref = None
340 self._transref = self._lockref = self._wlockref = None
341
341
342 # A cache for various files under .hg/ that tracks file changes,
342 # A cache for various files under .hg/ that tracks file changes,
343 # (used by the filecache decorator)
343 # (used by the filecache decorator)
344 #
344 #
345 # Maps a property name to its util.filecacheentry
345 # Maps a property name to its util.filecacheentry
346 self._filecache = {}
346 self._filecache = {}
347
347
348 # hold sets of revision to be filtered
348 # hold sets of revision to be filtered
349 # should be cleared when something might have changed the filter value:
349 # should be cleared when something might have changed the filter value:
350 # - new changesets,
350 # - new changesets,
351 # - phase change,
351 # - phase change,
352 # - new obsolescence marker,
352 # - new obsolescence marker,
353 # - working directory parent change,
353 # - working directory parent change,
354 # - bookmark changes
354 # - bookmark changes
355 self.filteredrevcache = {}
355 self.filteredrevcache = {}
356
356
357 # generic mapping between names and nodes
357 # generic mapping between names and nodes
358 self.names = namespaces.namespaces()
358 self.names = namespaces.namespaces()
359
359
360 def close(self):
360 def close(self):
361 self._writecaches()
361 self._writecaches()
362
362
363 def _writecaches(self):
363 def _writecaches(self):
364 if self._revbranchcache:
364 if self._revbranchcache:
365 self._revbranchcache.write()
365 self._revbranchcache.write()
366
366
367 def _restrictcapabilities(self, caps):
367 def _restrictcapabilities(self, caps):
368 if self.ui.configbool('experimental', 'bundle2-advertise', True):
368 if self.ui.configbool('experimental', 'bundle2-advertise', True):
369 caps = set(caps)
369 caps = set(caps)
370 capsblob = bundle2.encodecaps(bundle2.getrepocaps(self))
370 capsblob = bundle2.encodecaps(bundle2.getrepocaps(self))
371 caps.add('bundle2=' + urlreq.quote(capsblob))
371 caps.add('bundle2=' + urlreq.quote(capsblob))
372 return caps
372 return caps
373
373
374 def _applyopenerreqs(self):
374 def _applyopenerreqs(self):
375 self.svfs.options = dict((r, 1) for r in self.requirements
375 self.svfs.options = dict((r, 1) for r in self.requirements
376 if r in self.openerreqs)
376 if r in self.openerreqs)
377 # experimental config: format.chunkcachesize
377 # experimental config: format.chunkcachesize
378 chunkcachesize = self.ui.configint('format', 'chunkcachesize')
378 chunkcachesize = self.ui.configint('format', 'chunkcachesize')
379 if chunkcachesize is not None:
379 if chunkcachesize is not None:
380 self.svfs.options['chunkcachesize'] = chunkcachesize
380 self.svfs.options['chunkcachesize'] = chunkcachesize
381 # experimental config: format.maxchainlen
381 # experimental config: format.maxchainlen
382 maxchainlen = self.ui.configint('format', 'maxchainlen')
382 maxchainlen = self.ui.configint('format', 'maxchainlen')
383 if maxchainlen is not None:
383 if maxchainlen is not None:
384 self.svfs.options['maxchainlen'] = maxchainlen
384 self.svfs.options['maxchainlen'] = maxchainlen
385 # experimental config: format.manifestcachesize
385 # experimental config: format.manifestcachesize
386 manifestcachesize = self.ui.configint('format', 'manifestcachesize')
386 manifestcachesize = self.ui.configint('format', 'manifestcachesize')
387 if manifestcachesize is not None:
387 if manifestcachesize is not None:
388 self.svfs.options['manifestcachesize'] = manifestcachesize
388 self.svfs.options['manifestcachesize'] = manifestcachesize
389 # experimental config: format.aggressivemergedeltas
389 # experimental config: format.aggressivemergedeltas
390 aggressivemergedeltas = self.ui.configbool('format',
390 aggressivemergedeltas = self.ui.configbool('format',
391 'aggressivemergedeltas', False)
391 'aggressivemergedeltas', False)
392 self.svfs.options['aggressivemergedeltas'] = aggressivemergedeltas
392 self.svfs.options['aggressivemergedeltas'] = aggressivemergedeltas
393 self.svfs.options['lazydeltabase'] = not scmutil.gddeltaconfig(self.ui)
393 self.svfs.options['lazydeltabase'] = not scmutil.gddeltaconfig(self.ui)
394
394
395 def _writerequirements(self):
395 def _writerequirements(self):
396 scmutil.writerequires(self.vfs, self.requirements)
396 scmutil.writerequires(self.vfs, self.requirements)
397
397
398 def _checknested(self, path):
398 def _checknested(self, path):
399 """Determine if path is a legal nested repository."""
399 """Determine if path is a legal nested repository."""
400 if not path.startswith(self.root):
400 if not path.startswith(self.root):
401 return False
401 return False
402 subpath = path[len(self.root) + 1:]
402 subpath = path[len(self.root) + 1:]
403 normsubpath = util.pconvert(subpath)
403 normsubpath = util.pconvert(subpath)
404
404
405 # XXX: Checking against the current working copy is wrong in
405 # XXX: Checking against the current working copy is wrong in
406 # the sense that it can reject things like
406 # the sense that it can reject things like
407 #
407 #
408 # $ hg cat -r 10 sub/x.txt
408 # $ hg cat -r 10 sub/x.txt
409 #
409 #
410 # if sub/ is no longer a subrepository in the working copy
410 # if sub/ is no longer a subrepository in the working copy
411 # parent revision.
411 # parent revision.
412 #
412 #
413 # However, it can of course also allow things that would have
413 # However, it can of course also allow things that would have
414 # been rejected before, such as the above cat command if sub/
414 # been rejected before, such as the above cat command if sub/
415 # is a subrepository now, but was a normal directory before.
415 # is a subrepository now, but was a normal directory before.
416 # The old path auditor would have rejected by mistake since it
416 # The old path auditor would have rejected by mistake since it
417 # panics when it sees sub/.hg/.
417 # panics when it sees sub/.hg/.
418 #
418 #
419 # All in all, checking against the working copy seems sensible
419 # All in all, checking against the working copy seems sensible
420 # since we want to prevent access to nested repositories on
420 # since we want to prevent access to nested repositories on
421 # the filesystem *now*.
421 # the filesystem *now*.
422 ctx = self[None]
422 ctx = self[None]
423 parts = util.splitpath(subpath)
423 parts = util.splitpath(subpath)
424 while parts:
424 while parts:
425 prefix = '/'.join(parts)
425 prefix = '/'.join(parts)
426 if prefix in ctx.substate:
426 if prefix in ctx.substate:
427 if prefix == normsubpath:
427 if prefix == normsubpath:
428 return True
428 return True
429 else:
429 else:
430 sub = ctx.sub(prefix)
430 sub = ctx.sub(prefix)
431 return sub.checknested(subpath[len(prefix) + 1:])
431 return sub.checknested(subpath[len(prefix) + 1:])
432 else:
432 else:
433 parts.pop()
433 parts.pop()
434 return False
434 return False
435
435
436 def peer(self):
436 def peer(self):
437 return localpeer(self) # not cached to avoid reference cycle
437 return localpeer(self) # not cached to avoid reference cycle
438
438
439 def unfiltered(self):
439 def unfiltered(self):
440 """Return unfiltered version of the repository
440 """Return unfiltered version of the repository
441
441
442 Intended to be overwritten by filtered repo."""
442 Intended to be overwritten by filtered repo."""
443 return self
443 return self
444
444
445 def filtered(self, name):
445 def filtered(self, name):
446 """Return a filtered version of a repository"""
446 """Return a filtered version of a repository"""
447 # build a new class with the mixin and the current class
447 # build a new class with the mixin and the current class
448 # (possibly subclass of the repo)
448 # (possibly subclass of the repo)
449 class proxycls(repoview.repoview, self.unfiltered().__class__):
449 class proxycls(repoview.repoview, self.unfiltered().__class__):
450 pass
450 pass
451 return proxycls(self, name)
451 return proxycls(self, name)
452
452
453 @repofilecache('bookmarks', 'bookmarks.current')
453 @repofilecache('bookmarks', 'bookmarks.current')
454 def _bookmarks(self):
454 def _bookmarks(self):
455 return bookmarks.bmstore(self)
455 return bookmarks.bmstore(self)
456
456
457 @property
457 @property
458 def _activebookmark(self):
458 def _activebookmark(self):
459 return self._bookmarks.active
459 return self._bookmarks.active
460
460
461 def bookmarkheads(self, bookmark):
461 def bookmarkheads(self, bookmark):
462 name = bookmark.split('@', 1)[0]
462 name = bookmark.split('@', 1)[0]
463 heads = []
463 heads = []
464 for mark, n in self._bookmarks.iteritems():
464 for mark, n in self._bookmarks.iteritems():
465 if mark.split('@', 1)[0] == name:
465 if mark.split('@', 1)[0] == name:
466 heads.append(n)
466 heads.append(n)
467 return heads
467 return heads
468
468
469 # _phaserevs and _phasesets depend on changelog. what we need is to
469 # _phaserevs and _phasesets depend on changelog. what we need is to
470 # call _phasecache.invalidate() if '00changelog.i' was changed, but it
470 # call _phasecache.invalidate() if '00changelog.i' was changed, but it
471 # can't be easily expressed in filecache mechanism.
471 # can't be easily expressed in filecache mechanism.
472 @storecache('phaseroots', '00changelog.i')
472 @storecache('phaseroots', '00changelog.i')
473 def _phasecache(self):
473 def _phasecache(self):
474 return phases.phasecache(self, self._phasedefaults)
474 return phases.phasecache(self, self._phasedefaults)
475
475
476 @storecache('obsstore')
476 @storecache('obsstore')
477 def obsstore(self):
477 def obsstore(self):
478 # read default format for new obsstore.
478 # read default format for new obsstore.
479 # developer config: format.obsstore-version
479 # developer config: format.obsstore-version
480 defaultformat = self.ui.configint('format', 'obsstore-version', None)
480 defaultformat = self.ui.configint('format', 'obsstore-version', None)
481 # rely on obsstore class default when possible.
481 # rely on obsstore class default when possible.
482 kwargs = {}
482 kwargs = {}
483 if defaultformat is not None:
483 if defaultformat is not None:
484 kwargs['defaultformat'] = defaultformat
484 kwargs['defaultformat'] = defaultformat
485 readonly = not obsolete.isenabled(self, obsolete.createmarkersopt)
485 readonly = not obsolete.isenabled(self, obsolete.createmarkersopt)
486 store = obsolete.obsstore(self.svfs, readonly=readonly,
486 store = obsolete.obsstore(self.svfs, readonly=readonly,
487 **kwargs)
487 **kwargs)
488 if store and readonly:
488 if store and readonly:
489 self.ui.warn(
489 self.ui.warn(
490 _('obsolete feature not enabled but %i markers found!\n')
490 _('obsolete feature not enabled but %i markers found!\n')
491 % len(list(store)))
491 % len(list(store)))
492 return store
492 return store
493
493
494 @storecache('00changelog.i')
494 @storecache('00changelog.i')
495 def changelog(self):
495 def changelog(self):
496 c = changelog.changelog(self.svfs)
496 c = changelog.changelog(self.svfs)
497 if 'HG_PENDING' in os.environ:
497 if 'HG_PENDING' in os.environ:
498 p = os.environ['HG_PENDING']
498 p = os.environ['HG_PENDING']
499 if p.startswith(self.root):
499 if p.startswith(self.root):
500 c.readpending('00changelog.i.a')
500 c.readpending('00changelog.i.a')
501 return c
501 return c
502
502
503 @storecache('00manifest.i')
503 @storecache('00manifest.i')
504 def manifest(self):
504 def manifest(self):
505 return manifest.manifest(self.svfs)
505 return manifest.manifest(self.svfs)
506
506
507 @property
507 @property
508 def manifestlog(self):
508 def manifestlog(self):
509 return manifest.manifestlog(self.svfs, self)
509 return manifest.manifestlog(self.svfs, self)
510
510
511 @repofilecache('dirstate')
511 @repofilecache('dirstate')
512 def dirstate(self):
512 def dirstate(self):
513 return dirstate.dirstate(self.vfs, self.ui, self.root,
513 return dirstate.dirstate(self.vfs, self.ui, self.root,
514 self._dirstatevalidate)
514 self._dirstatevalidate)
515
515
516 def _dirstatevalidate(self, node):
516 def _dirstatevalidate(self, node):
517 try:
517 try:
518 self.changelog.rev(node)
518 self.changelog.rev(node)
519 return node
519 return node
520 except error.LookupError:
520 except error.LookupError:
521 if not self._dirstatevalidatewarned:
521 if not self._dirstatevalidatewarned:
522 self._dirstatevalidatewarned = True
522 self._dirstatevalidatewarned = True
523 self.ui.warn(_("warning: ignoring unknown"
523 self.ui.warn(_("warning: ignoring unknown"
524 " working parent %s!\n") % short(node))
524 " working parent %s!\n") % short(node))
525 return nullid
525 return nullid
526
526
527 def __getitem__(self, changeid):
527 def __getitem__(self, changeid):
528 if changeid is None or changeid == wdirrev:
528 if changeid is None or changeid == wdirrev:
529 return context.workingctx(self)
529 return context.workingctx(self)
530 if isinstance(changeid, slice):
530 if isinstance(changeid, slice):
531 return [context.changectx(self, i)
531 return [context.changectx(self, i)
532 for i in xrange(*changeid.indices(len(self)))
532 for i in xrange(*changeid.indices(len(self)))
533 if i not in self.changelog.filteredrevs]
533 if i not in self.changelog.filteredrevs]
534 return context.changectx(self, changeid)
534 return context.changectx(self, changeid)
535
535
536 def __contains__(self, changeid):
536 def __contains__(self, changeid):
537 try:
537 try:
538 self[changeid]
538 self[changeid]
539 return True
539 return True
540 except error.RepoLookupError:
540 except error.RepoLookupError:
541 return False
541 return False
542
542
543 def __nonzero__(self):
543 def __nonzero__(self):
544 return True
544 return True
545
545
546 def __len__(self):
546 def __len__(self):
547 return len(self.changelog)
547 return len(self.changelog)
548
548
549 def __iter__(self):
549 def __iter__(self):
550 return iter(self.changelog)
550 return iter(self.changelog)
551
551
552 def revs(self, expr, *args):
552 def revs(self, expr, *args):
553 '''Find revisions matching a revset.
553 '''Find revisions matching a revset.
554
554
555 The revset is specified as a string ``expr`` that may contain
555 The revset is specified as a string ``expr`` that may contain
556 %-formatting to escape certain types. See ``revset.formatspec``.
556 %-formatting to escape certain types. See ``revset.formatspec``.
557
557
558 Revset aliases from the configuration are not expanded. To expand
558 Revset aliases from the configuration are not expanded. To expand
559 user aliases, consider calling ``scmutil.revrange()``.
559 user aliases, consider calling ``scmutil.revrange()``.
560
560
561 Returns a revset.abstractsmartset, which is a list-like interface
561 Returns a revset.abstractsmartset, which is a list-like interface
562 that contains integer revisions.
562 that contains integer revisions.
563 '''
563 '''
564 expr = revset.formatspec(expr, *args)
564 expr = revset.formatspec(expr, *args)
565 m = revset.match(None, expr)
565 m = revset.match(None, expr)
566 return m(self)
566 return m(self)
567
567
568 def set(self, expr, *args):
568 def set(self, expr, *args):
569 '''Find revisions matching a revset and emit changectx instances.
569 '''Find revisions matching a revset and emit changectx instances.
570
570
571 This is a convenience wrapper around ``revs()`` that iterates the
571 This is a convenience wrapper around ``revs()`` that iterates the
572 result and is a generator of changectx instances.
572 result and is a generator of changectx instances.
573
573
574 Revset aliases from the configuration are not expanded. To expand
574 Revset aliases from the configuration are not expanded. To expand
575 user aliases, consider calling ``scmutil.revrange()``.
575 user aliases, consider calling ``scmutil.revrange()``.
576 '''
576 '''
577 for r in self.revs(expr, *args):
577 for r in self.revs(expr, *args):
578 yield self[r]
578 yield self[r]
579
579
580 def url(self):
580 def url(self):
581 return 'file:' + self.root
581 return 'file:' + self.root
582
582
583 def hook(self, name, throw=False, **args):
583 def hook(self, name, throw=False, **args):
584 """Call a hook, passing this repo instance.
584 """Call a hook, passing this repo instance.
585
585
586 This a convenience method to aid invoking hooks. Extensions likely
586 This a convenience method to aid invoking hooks. Extensions likely
587 won't call this unless they have registered a custom hook or are
587 won't call this unless they have registered a custom hook or are
588 replacing code that is expected to call a hook.
588 replacing code that is expected to call a hook.
589 """
589 """
590 return hook.hook(self.ui, self, name, throw, **args)
590 return hook.hook(self.ui, self, name, throw, **args)
591
591
592 @unfilteredmethod
592 @unfilteredmethod
593 def _tag(self, names, node, message, local, user, date, extra=None,
593 def _tag(self, names, node, message, local, user, date, extra=None,
594 editor=False):
594 editor=False):
595 if isinstance(names, str):
595 if isinstance(names, str):
596 names = (names,)
596 names = (names,)
597
597
598 branches = self.branchmap()
598 branches = self.branchmap()
599 for name in names:
599 for name in names:
600 self.hook('pretag', throw=True, node=hex(node), tag=name,
600 self.hook('pretag', throw=True, node=hex(node), tag=name,
601 local=local)
601 local=local)
602 if name in branches:
602 if name in branches:
603 self.ui.warn(_("warning: tag %s conflicts with existing"
603 self.ui.warn(_("warning: tag %s conflicts with existing"
604 " branch name\n") % name)
604 " branch name\n") % name)
605
605
606 def writetags(fp, names, munge, prevtags):
606 def writetags(fp, names, munge, prevtags):
607 fp.seek(0, 2)
607 fp.seek(0, 2)
608 if prevtags and prevtags[-1] != '\n':
608 if prevtags and prevtags[-1] != '\n':
609 fp.write('\n')
609 fp.write('\n')
610 for name in names:
610 for name in names:
611 if munge:
611 if munge:
612 m = munge(name)
612 m = munge(name)
613 else:
613 else:
614 m = name
614 m = name
615
615
616 if (self._tagscache.tagtypes and
616 if (self._tagscache.tagtypes and
617 name in self._tagscache.tagtypes):
617 name in self._tagscache.tagtypes):
618 old = self.tags().get(name, nullid)
618 old = self.tags().get(name, nullid)
619 fp.write('%s %s\n' % (hex(old), m))
619 fp.write('%s %s\n' % (hex(old), m))
620 fp.write('%s %s\n' % (hex(node), m))
620 fp.write('%s %s\n' % (hex(node), m))
621 fp.close()
621 fp.close()
622
622
623 prevtags = ''
623 prevtags = ''
624 if local:
624 if local:
625 try:
625 try:
626 fp = self.vfs('localtags', 'r+')
626 fp = self.vfs('localtags', 'r+')
627 except IOError:
627 except IOError:
628 fp = self.vfs('localtags', 'a')
628 fp = self.vfs('localtags', 'a')
629 else:
629 else:
630 prevtags = fp.read()
630 prevtags = fp.read()
631
631
632 # local tags are stored in the current charset
632 # local tags are stored in the current charset
633 writetags(fp, names, None, prevtags)
633 writetags(fp, names, None, prevtags)
634 for name in names:
634 for name in names:
635 self.hook('tag', node=hex(node), tag=name, local=local)
635 self.hook('tag', node=hex(node), tag=name, local=local)
636 return
636 return
637
637
638 try:
638 try:
639 fp = self.wfile('.hgtags', 'rb+')
639 fp = self.wfile('.hgtags', 'rb+')
640 except IOError as e:
640 except IOError as e:
641 if e.errno != errno.ENOENT:
641 if e.errno != errno.ENOENT:
642 raise
642 raise
643 fp = self.wfile('.hgtags', 'ab')
643 fp = self.wfile('.hgtags', 'ab')
644 else:
644 else:
645 prevtags = fp.read()
645 prevtags = fp.read()
646
646
647 # committed tags are stored in UTF-8
647 # committed tags are stored in UTF-8
648 writetags(fp, names, encoding.fromlocal, prevtags)
648 writetags(fp, names, encoding.fromlocal, prevtags)
649
649
650 fp.close()
650 fp.close()
651
651
652 self.invalidatecaches()
652 self.invalidatecaches()
653
653
654 if '.hgtags' not in self.dirstate:
654 if '.hgtags' not in self.dirstate:
655 self[None].add(['.hgtags'])
655 self[None].add(['.hgtags'])
656
656
657 m = matchmod.exact(self.root, '', ['.hgtags'])
657 m = matchmod.exact(self.root, '', ['.hgtags'])
658 tagnode = self.commit(message, user, date, extra=extra, match=m,
658 tagnode = self.commit(message, user, date, extra=extra, match=m,
659 editor=editor)
659 editor=editor)
660
660
661 for name in names:
661 for name in names:
662 self.hook('tag', node=hex(node), tag=name, local=local)
662 self.hook('tag', node=hex(node), tag=name, local=local)
663
663
664 return tagnode
664 return tagnode
665
665
666 def tag(self, names, node, message, local, user, date, editor=False):
666 def tag(self, names, node, message, local, user, date, editor=False):
667 '''tag a revision with one or more symbolic names.
667 '''tag a revision with one or more symbolic names.
668
668
669 names is a list of strings or, when adding a single tag, names may be a
669 names is a list of strings or, when adding a single tag, names may be a
670 string.
670 string.
671
671
672 if local is True, the tags are stored in a per-repository file.
672 if local is True, the tags are stored in a per-repository file.
673 otherwise, they are stored in the .hgtags file, and a new
673 otherwise, they are stored in the .hgtags file, and a new
674 changeset is committed with the change.
674 changeset is committed with the change.
675
675
676 keyword arguments:
676 keyword arguments:
677
677
678 local: whether to store tags in non-version-controlled file
678 local: whether to store tags in non-version-controlled file
679 (default False)
679 (default False)
680
680
681 message: commit message to use if committing
681 message: commit message to use if committing
682
682
683 user: name of user to use if committing
683 user: name of user to use if committing
684
684
685 date: date tuple to use if committing'''
685 date: date tuple to use if committing'''
686
686
687 if not local:
687 if not local:
688 m = matchmod.exact(self.root, '', ['.hgtags'])
688 m = matchmod.exact(self.root, '', ['.hgtags'])
689 if any(self.status(match=m, unknown=True, ignored=True)):
689 if any(self.status(match=m, unknown=True, ignored=True)):
690 raise error.Abort(_('working copy of .hgtags is changed'),
690 raise error.Abort(_('working copy of .hgtags is changed'),
691 hint=_('please commit .hgtags manually'))
691 hint=_('please commit .hgtags manually'))
692
692
693 self.tags() # instantiate the cache
693 self.tags() # instantiate the cache
694 self._tag(names, node, message, local, user, date, editor=editor)
694 self._tag(names, node, message, local, user, date, editor=editor)
695
695
696 @filteredpropertycache
696 @filteredpropertycache
697 def _tagscache(self):
697 def _tagscache(self):
698 '''Returns a tagscache object that contains various tags related
698 '''Returns a tagscache object that contains various tags related
699 caches.'''
699 caches.'''
700
700
701 # This simplifies its cache management by having one decorated
701 # This simplifies its cache management by having one decorated
702 # function (this one) and the rest simply fetch things from it.
702 # function (this one) and the rest simply fetch things from it.
703 class tagscache(object):
703 class tagscache(object):
704 def __init__(self):
704 def __init__(self):
705 # These two define the set of tags for this repository. tags
705 # These two define the set of tags for this repository. tags
706 # maps tag name to node; tagtypes maps tag name to 'global' or
706 # maps tag name to node; tagtypes maps tag name to 'global' or
707 # 'local'. (Global tags are defined by .hgtags across all
707 # 'local'. (Global tags are defined by .hgtags across all
708 # heads, and local tags are defined in .hg/localtags.)
708 # heads, and local tags are defined in .hg/localtags.)
709 # They constitute the in-memory cache of tags.
709 # They constitute the in-memory cache of tags.
710 self.tags = self.tagtypes = None
710 self.tags = self.tagtypes = None
711
711
712 self.nodetagscache = self.tagslist = None
712 self.nodetagscache = self.tagslist = None
713
713
714 cache = tagscache()
714 cache = tagscache()
715 cache.tags, cache.tagtypes = self._findtags()
715 cache.tags, cache.tagtypes = self._findtags()
716
716
717 return cache
717 return cache
718
718
719 def tags(self):
719 def tags(self):
720 '''return a mapping of tag to node'''
720 '''return a mapping of tag to node'''
721 t = {}
721 t = {}
722 if self.changelog.filteredrevs:
722 if self.changelog.filteredrevs:
723 tags, tt = self._findtags()
723 tags, tt = self._findtags()
724 else:
724 else:
725 tags = self._tagscache.tags
725 tags = self._tagscache.tags
726 for k, v in tags.iteritems():
726 for k, v in tags.iteritems():
727 try:
727 try:
728 # ignore tags to unknown nodes
728 # ignore tags to unknown nodes
729 self.changelog.rev(v)
729 self.changelog.rev(v)
730 t[k] = v
730 t[k] = v
731 except (error.LookupError, ValueError):
731 except (error.LookupError, ValueError):
732 pass
732 pass
733 return t
733 return t
734
734
735 def _findtags(self):
735 def _findtags(self):
736 '''Do the hard work of finding tags. Return a pair of dicts
736 '''Do the hard work of finding tags. Return a pair of dicts
737 (tags, tagtypes) where tags maps tag name to node, and tagtypes
737 (tags, tagtypes) where tags maps tag name to node, and tagtypes
738 maps tag name to a string like \'global\' or \'local\'.
738 maps tag name to a string like \'global\' or \'local\'.
739 Subclasses or extensions are free to add their own tags, but
739 Subclasses or extensions are free to add their own tags, but
740 should be aware that the returned dicts will be retained for the
740 should be aware that the returned dicts will be retained for the
741 duration of the localrepo object.'''
741 duration of the localrepo object.'''
742
742
743 # XXX what tagtype should subclasses/extensions use? Currently
743 # XXX what tagtype should subclasses/extensions use? Currently
744 # mq and bookmarks add tags, but do not set the tagtype at all.
744 # mq and bookmarks add tags, but do not set the tagtype at all.
745 # Should each extension invent its own tag type? Should there
745 # Should each extension invent its own tag type? Should there
746 # be one tagtype for all such "virtual" tags? Or is the status
746 # be one tagtype for all such "virtual" tags? Or is the status
747 # quo fine?
747 # quo fine?
748
748
749 alltags = {} # map tag name to (node, hist)
749 alltags = {} # map tag name to (node, hist)
750 tagtypes = {}
750 tagtypes = {}
751
751
752 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
752 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
753 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
753 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
754
754
755 # Build the return dicts. Have to re-encode tag names because
755 # Build the return dicts. Have to re-encode tag names because
756 # the tags module always uses UTF-8 (in order not to lose info
756 # the tags module always uses UTF-8 (in order not to lose info
757 # writing to the cache), but the rest of Mercurial wants them in
757 # writing to the cache), but the rest of Mercurial wants them in
758 # local encoding.
758 # local encoding.
759 tags = {}
759 tags = {}
760 for (name, (node, hist)) in alltags.iteritems():
760 for (name, (node, hist)) in alltags.iteritems():
761 if node != nullid:
761 if node != nullid:
762 tags[encoding.tolocal(name)] = node
762 tags[encoding.tolocal(name)] = node
763 tags['tip'] = self.changelog.tip()
763 tags['tip'] = self.changelog.tip()
764 tagtypes = dict([(encoding.tolocal(name), value)
764 tagtypes = dict([(encoding.tolocal(name), value)
765 for (name, value) in tagtypes.iteritems()])
765 for (name, value) in tagtypes.iteritems()])
766 return (tags, tagtypes)
766 return (tags, tagtypes)
767
767
768 def tagtype(self, tagname):
768 def tagtype(self, tagname):
769 '''
769 '''
770 return the type of the given tag. result can be:
770 return the type of the given tag. result can be:
771
771
772 'local' : a local tag
772 'local' : a local tag
773 'global' : a global tag
773 'global' : a global tag
774 None : tag does not exist
774 None : tag does not exist
775 '''
775 '''
776
776
777 return self._tagscache.tagtypes.get(tagname)
777 return self._tagscache.tagtypes.get(tagname)
778
778
779 def tagslist(self):
779 def tagslist(self):
780 '''return a list of tags ordered by revision'''
780 '''return a list of tags ordered by revision'''
781 if not self._tagscache.tagslist:
781 if not self._tagscache.tagslist:
782 l = []
782 l = []
783 for t, n in self.tags().iteritems():
783 for t, n in self.tags().iteritems():
784 l.append((self.changelog.rev(n), t, n))
784 l.append((self.changelog.rev(n), t, n))
785 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
785 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
786
786
787 return self._tagscache.tagslist
787 return self._tagscache.tagslist
788
788
789 def nodetags(self, node):
789 def nodetags(self, node):
790 '''return the tags associated with a node'''
790 '''return the tags associated with a node'''
791 if not self._tagscache.nodetagscache:
791 if not self._tagscache.nodetagscache:
792 nodetagscache = {}
792 nodetagscache = {}
793 for t, n in self._tagscache.tags.iteritems():
793 for t, n in self._tagscache.tags.iteritems():
794 nodetagscache.setdefault(n, []).append(t)
794 nodetagscache.setdefault(n, []).append(t)
795 for tags in nodetagscache.itervalues():
795 for tags in nodetagscache.itervalues():
796 tags.sort()
796 tags.sort()
797 self._tagscache.nodetagscache = nodetagscache
797 self._tagscache.nodetagscache = nodetagscache
798 return self._tagscache.nodetagscache.get(node, [])
798 return self._tagscache.nodetagscache.get(node, [])
799
799
800 def nodebookmarks(self, node):
800 def nodebookmarks(self, node):
801 """return the list of bookmarks pointing to the specified node"""
801 """return the list of bookmarks pointing to the specified node"""
802 marks = []
802 marks = []
803 for bookmark, n in self._bookmarks.iteritems():
803 for bookmark, n in self._bookmarks.iteritems():
804 if n == node:
804 if n == node:
805 marks.append(bookmark)
805 marks.append(bookmark)
806 return sorted(marks)
806 return sorted(marks)
807
807
808 def branchmap(self):
808 def branchmap(self):
809 '''returns a dictionary {branch: [branchheads]} with branchheads
809 '''returns a dictionary {branch: [branchheads]} with branchheads
810 ordered by increasing revision number'''
810 ordered by increasing revision number'''
811 branchmap.updatecache(self)
811 branchmap.updatecache(self)
812 return self._branchcaches[self.filtername]
812 return self._branchcaches[self.filtername]
813
813
814 @unfilteredmethod
814 @unfilteredmethod
815 def revbranchcache(self):
815 def revbranchcache(self):
816 if not self._revbranchcache:
816 if not self._revbranchcache:
817 self._revbranchcache = branchmap.revbranchcache(self.unfiltered())
817 self._revbranchcache = branchmap.revbranchcache(self.unfiltered())
818 return self._revbranchcache
818 return self._revbranchcache
819
819
820 def branchtip(self, branch, ignoremissing=False):
820 def branchtip(self, branch, ignoremissing=False):
821 '''return the tip node for a given branch
821 '''return the tip node for a given branch
822
822
823 If ignoremissing is True, then this method will not raise an error.
823 If ignoremissing is True, then this method will not raise an error.
824 This is helpful for callers that only expect None for a missing branch
824 This is helpful for callers that only expect None for a missing branch
825 (e.g. namespace).
825 (e.g. namespace).
826
826
827 '''
827 '''
828 try:
828 try:
829 return self.branchmap().branchtip(branch)
829 return self.branchmap().branchtip(branch)
830 except KeyError:
830 except KeyError:
831 if not ignoremissing:
831 if not ignoremissing:
832 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
832 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
833 else:
833 else:
834 pass
834 pass
835
835
836 def lookup(self, key):
836 def lookup(self, key):
837 return self[key].node()
837 return self[key].node()
838
838
839 def lookupbranch(self, key, remote=None):
839 def lookupbranch(self, key, remote=None):
840 repo = remote or self
840 repo = remote or self
841 if key in repo.branchmap():
841 if key in repo.branchmap():
842 return key
842 return key
843
843
844 repo = (remote and remote.local()) and remote or self
844 repo = (remote and remote.local()) and remote or self
845 return repo[key].branch()
845 return repo[key].branch()
846
846
847 def known(self, nodes):
847 def known(self, nodes):
848 cl = self.changelog
848 cl = self.changelog
849 nm = cl.nodemap
849 nm = cl.nodemap
850 filtered = cl.filteredrevs
850 filtered = cl.filteredrevs
851 result = []
851 result = []
852 for n in nodes:
852 for n in nodes:
853 r = nm.get(n)
853 r = nm.get(n)
854 resp = not (r is None or r in filtered)
854 resp = not (r is None or r in filtered)
855 result.append(resp)
855 result.append(resp)
856 return result
856 return result
857
857
858 def local(self):
858 def local(self):
859 return self
859 return self
860
860
861 def publishing(self):
861 def publishing(self):
862 # it's safe (and desirable) to trust the publish flag unconditionally
862 # it's safe (and desirable) to trust the publish flag unconditionally
863 # so that we don't finalize changes shared between users via ssh or nfs
863 # so that we don't finalize changes shared between users via ssh or nfs
864 return self.ui.configbool('phases', 'publish', True, untrusted=True)
864 return self.ui.configbool('phases', 'publish', True, untrusted=True)
865
865
866 def cancopy(self):
866 def cancopy(self):
867 # so statichttprepo's override of local() works
867 # so statichttprepo's override of local() works
868 if not self.local():
868 if not self.local():
869 return False
869 return False
870 if not self.publishing():
870 if not self.publishing():
871 return True
871 return True
872 # if publishing we can't copy if there is filtered content
872 # if publishing we can't copy if there is filtered content
873 return not self.filtered('visible').changelog.filteredrevs
873 return not self.filtered('visible').changelog.filteredrevs
874
874
875 def shared(self):
875 def shared(self):
876 '''the type of shared repository (None if not shared)'''
876 '''the type of shared repository (None if not shared)'''
877 if self.sharedpath != self.path:
877 if self.sharedpath != self.path:
878 return 'store'
878 return 'store'
879 return None
879 return None
880
880
881 def join(self, f, *insidef):
881 def join(self, f, *insidef):
882 return self.vfs.join(os.path.join(f, *insidef))
882 return self.vfs.join(os.path.join(f, *insidef))
883
883
884 def wjoin(self, f, *insidef):
884 def wjoin(self, f, *insidef):
885 return self.vfs.reljoin(self.root, f, *insidef)
885 return self.vfs.reljoin(self.root, f, *insidef)
886
886
887 def file(self, f):
887 def file(self, f):
888 if f[0] == '/':
888 if f[0] == '/':
889 f = f[1:]
889 f = f[1:]
890 return filelog.filelog(self.svfs, f)
890 return filelog.filelog(self.svfs, f)
891
891
892 def changectx(self, changeid):
892 def changectx(self, changeid):
893 return self[changeid]
893 return self[changeid]
894
894
895 def setparents(self, p1, p2=nullid):
895 def setparents(self, p1, p2=nullid):
896 self.dirstate.beginparentchange()
896 self.dirstate.beginparentchange()
897 copies = self.dirstate.setparents(p1, p2)
897 copies = self.dirstate.setparents(p1, p2)
898 pctx = self[p1]
898 pctx = self[p1]
899 if copies:
899 if copies:
900 # Adjust copy records, the dirstate cannot do it, it
900 # Adjust copy records, the dirstate cannot do it, it
901 # requires access to parents manifests. Preserve them
901 # requires access to parents manifests. Preserve them
902 # only for entries added to first parent.
902 # only for entries added to first parent.
903 for f in copies:
903 for f in copies:
904 if f not in pctx and copies[f] in pctx:
904 if f not in pctx and copies[f] in pctx:
905 self.dirstate.copy(copies[f], f)
905 self.dirstate.copy(copies[f], f)
906 if p2 == nullid:
906 if p2 == nullid:
907 for f, s in sorted(self.dirstate.copies().items()):
907 for f, s in sorted(self.dirstate.copies().items()):
908 if f not in pctx and s not in pctx:
908 if f not in pctx and s not in pctx:
909 self.dirstate.copy(None, f)
909 self.dirstate.copy(None, f)
910 self.dirstate.endparentchange()
910 self.dirstate.endparentchange()
911
911
912 def filectx(self, path, changeid=None, fileid=None):
912 def filectx(self, path, changeid=None, fileid=None):
913 """changeid can be a changeset revision, node, or tag.
913 """changeid can be a changeset revision, node, or tag.
914 fileid can be a file revision or node."""
914 fileid can be a file revision or node."""
915 return context.filectx(self, path, changeid, fileid)
915 return context.filectx(self, path, changeid, fileid)
916
916
917 def getcwd(self):
917 def getcwd(self):
918 return self.dirstate.getcwd()
918 return self.dirstate.getcwd()
919
919
920 def pathto(self, f, cwd=None):
920 def pathto(self, f, cwd=None):
921 return self.dirstate.pathto(f, cwd)
921 return self.dirstate.pathto(f, cwd)
922
922
923 def wfile(self, f, mode='r'):
923 def wfile(self, f, mode='r'):
924 return self.wvfs(f, mode)
924 return self.wvfs(f, mode)
925
925
926 def _link(self, f):
926 def _link(self, f):
927 return self.wvfs.islink(f)
927 return self.wvfs.islink(f)
928
928
929 def _loadfilter(self, filter):
929 def _loadfilter(self, filter):
930 if filter not in self.filterpats:
930 if filter not in self.filterpats:
931 l = []
931 l = []
932 for pat, cmd in self.ui.configitems(filter):
932 for pat, cmd in self.ui.configitems(filter):
933 if cmd == '!':
933 if cmd == '!':
934 continue
934 continue
935 mf = matchmod.match(self.root, '', [pat])
935 mf = matchmod.match(self.root, '', [pat])
936 fn = None
936 fn = None
937 params = cmd
937 params = cmd
938 for name, filterfn in self._datafilters.iteritems():
938 for name, filterfn in self._datafilters.iteritems():
939 if cmd.startswith(name):
939 if cmd.startswith(name):
940 fn = filterfn
940 fn = filterfn
941 params = cmd[len(name):].lstrip()
941 params = cmd[len(name):].lstrip()
942 break
942 break
943 if not fn:
943 if not fn:
944 fn = lambda s, c, **kwargs: util.filter(s, c)
944 fn = lambda s, c, **kwargs: util.filter(s, c)
945 # Wrap old filters not supporting keyword arguments
945 # Wrap old filters not supporting keyword arguments
946 if not inspect.getargspec(fn)[2]:
946 if not inspect.getargspec(fn)[2]:
947 oldfn = fn
947 oldfn = fn
948 fn = lambda s, c, **kwargs: oldfn(s, c)
948 fn = lambda s, c, **kwargs: oldfn(s, c)
949 l.append((mf, fn, params))
949 l.append((mf, fn, params))
950 self.filterpats[filter] = l
950 self.filterpats[filter] = l
951 return self.filterpats[filter]
951 return self.filterpats[filter]
952
952
953 def _filter(self, filterpats, filename, data):
953 def _filter(self, filterpats, filename, data):
954 for mf, fn, cmd in filterpats:
954 for mf, fn, cmd in filterpats:
955 if mf(filename):
955 if mf(filename):
956 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
956 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
957 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
957 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
958 break
958 break
959
959
960 return data
960 return data
961
961
962 @unfilteredpropertycache
962 @unfilteredpropertycache
963 def _encodefilterpats(self):
963 def _encodefilterpats(self):
964 return self._loadfilter('encode')
964 return self._loadfilter('encode')
965
965
966 @unfilteredpropertycache
966 @unfilteredpropertycache
967 def _decodefilterpats(self):
967 def _decodefilterpats(self):
968 return self._loadfilter('decode')
968 return self._loadfilter('decode')
969
969
970 def adddatafilter(self, name, filter):
970 def adddatafilter(self, name, filter):
971 self._datafilters[name] = filter
971 self._datafilters[name] = filter
972
972
973 def wread(self, filename):
973 def wread(self, filename):
974 if self._link(filename):
974 if self._link(filename):
975 data = self.wvfs.readlink(filename)
975 data = self.wvfs.readlink(filename)
976 else:
976 else:
977 data = self.wvfs.read(filename)
977 data = self.wvfs.read(filename)
978 return self._filter(self._encodefilterpats, filename, data)
978 return self._filter(self._encodefilterpats, filename, data)
979
979
980 def wwrite(self, filename, data, flags, backgroundclose=False):
980 def wwrite(self, filename, data, flags, backgroundclose=False):
981 """write ``data`` into ``filename`` in the working directory
981 """write ``data`` into ``filename`` in the working directory
982
982
983 This returns length of written (maybe decoded) data.
983 This returns length of written (maybe decoded) data.
984 """
984 """
985 data = self._filter(self._decodefilterpats, filename, data)
985 data = self._filter(self._decodefilterpats, filename, data)
986 if 'l' in flags:
986 if 'l' in flags:
987 self.wvfs.symlink(data, filename)
987 self.wvfs.symlink(data, filename)
988 else:
988 else:
989 self.wvfs.write(filename, data, backgroundclose=backgroundclose)
989 self.wvfs.write(filename, data, backgroundclose=backgroundclose)
990 if 'x' in flags:
990 if 'x' in flags:
991 self.wvfs.setflags(filename, False, True)
991 self.wvfs.setflags(filename, False, True)
992 return len(data)
992 return len(data)
993
993
994 def wwritedata(self, filename, data):
994 def wwritedata(self, filename, data):
995 return self._filter(self._decodefilterpats, filename, data)
995 return self._filter(self._decodefilterpats, filename, data)
996
996
997 def currenttransaction(self):
997 def currenttransaction(self):
998 """return the current transaction or None if non exists"""
998 """return the current transaction or None if non exists"""
999 if self._transref:
999 if self._transref:
1000 tr = self._transref()
1000 tr = self._transref()
1001 else:
1001 else:
1002 tr = None
1002 tr = None
1003
1003
1004 if tr and tr.running():
1004 if tr and tr.running():
1005 return tr
1005 return tr
1006 return None
1006 return None
1007
1007
1008 def transaction(self, desc, report=None):
1008 def transaction(self, desc, report=None):
1009 if (self.ui.configbool('devel', 'all-warnings')
1009 if (self.ui.configbool('devel', 'all-warnings')
1010 or self.ui.configbool('devel', 'check-locks')):
1010 or self.ui.configbool('devel', 'check-locks')):
1011 if self._currentlock(self._lockref) is None:
1011 if self._currentlock(self._lockref) is None:
1012 raise RuntimeError('programming error: transaction requires '
1012 raise RuntimeError('programming error: transaction requires '
1013 'locking')
1013 'locking')
1014 tr = self.currenttransaction()
1014 tr = self.currenttransaction()
1015 if tr is not None:
1015 if tr is not None:
1016 return tr.nest()
1016 return tr.nest()
1017
1017
1018 # abort here if the journal already exists
1018 # abort here if the journal already exists
1019 if self.svfs.exists("journal"):
1019 if self.svfs.exists("journal"):
1020 raise error.RepoError(
1020 raise error.RepoError(
1021 _("abandoned transaction found"),
1021 _("abandoned transaction found"),
1022 hint=_("run 'hg recover' to clean up transaction"))
1022 hint=_("run 'hg recover' to clean up transaction"))
1023
1023
1024 idbase = "%.40f#%f" % (random.random(), time.time())
1024 idbase = "%.40f#%f" % (random.random(), time.time())
1025 txnid = 'TXN:' + hashlib.sha1(idbase).hexdigest()
1025 txnid = 'TXN:' + hashlib.sha1(idbase).hexdigest()
1026 self.hook('pretxnopen', throw=True, txnname=desc, txnid=txnid)
1026 self.hook('pretxnopen', throw=True, txnname=desc, txnid=txnid)
1027
1027
1028 self._writejournal(desc)
1028 self._writejournal(desc)
1029 renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()]
1029 renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()]
1030 if report:
1030 if report:
1031 rp = report
1031 rp = report
1032 else:
1032 else:
1033 rp = self.ui.warn
1033 rp = self.ui.warn
1034 vfsmap = {'plain': self.vfs} # root of .hg/
1034 vfsmap = {'plain': self.vfs} # root of .hg/
1035 # we must avoid cyclic reference between repo and transaction.
1035 # we must avoid cyclic reference between repo and transaction.
1036 reporef = weakref.ref(self)
1036 reporef = weakref.ref(self)
1037 def validate(tr):
1037 def validate(tr):
1038 """will run pre-closing hooks"""
1038 """will run pre-closing hooks"""
1039 reporef().hook('pretxnclose', throw=True,
1039 reporef().hook('pretxnclose', throw=True,
1040 txnname=desc, **tr.hookargs)
1040 txnname=desc, **tr.hookargs)
1041 def releasefn(tr, success):
1041 def releasefn(tr, success):
1042 repo = reporef()
1042 repo = reporef()
1043 if success:
1043 if success:
1044 # this should be explicitly invoked here, because
1044 # this should be explicitly invoked here, because
1045 # in-memory changes aren't written out at closing
1045 # in-memory changes aren't written out at closing
1046 # transaction, if tr.addfilegenerator (via
1046 # transaction, if tr.addfilegenerator (via
1047 # dirstate.write or so) isn't invoked while
1047 # dirstate.write or so) isn't invoked while
1048 # transaction running
1048 # transaction running
1049 repo.dirstate.write(None)
1049 repo.dirstate.write(None)
1050 else:
1050 else:
1051 # discard all changes (including ones already written
1051 # discard all changes (including ones already written
1052 # out) in this transaction
1052 # out) in this transaction
1053 repo.dirstate.restorebackup(None, prefix='journal.')
1053 repo.dirstate.restorebackup(None, prefix='journal.')
1054
1054
1055 repo.invalidate(clearfilecache=True)
1055 repo.invalidate(clearfilecache=True)
1056
1056
1057 tr = transaction.transaction(rp, self.svfs, vfsmap,
1057 tr = transaction.transaction(rp, self.svfs, vfsmap,
1058 "journal",
1058 "journal",
1059 "undo",
1059 "undo",
1060 aftertrans(renames),
1060 aftertrans(renames),
1061 self.store.createmode,
1061 self.store.createmode,
1062 validator=validate,
1062 validator=validate,
1063 releasefn=releasefn)
1063 releasefn=releasefn)
1064
1064
1065 tr.hookargs['txnid'] = txnid
1065 tr.hookargs['txnid'] = txnid
1066 # note: writing the fncache only during finalize mean that the file is
1066 # note: writing the fncache only during finalize mean that the file is
1067 # outdated when running hooks. As fncache is used for streaming clone,
1067 # outdated when running hooks. As fncache is used for streaming clone,
1068 # this is not expected to break anything that happen during the hooks.
1068 # this is not expected to break anything that happen during the hooks.
1069 tr.addfinalize('flush-fncache', self.store.write)
1069 tr.addfinalize('flush-fncache', self.store.write)
1070 def txnclosehook(tr2):
1070 def txnclosehook(tr2):
1071 """To be run if transaction is successful, will schedule a hook run
1071 """To be run if transaction is successful, will schedule a hook run
1072 """
1072 """
1073 # Don't reference tr2 in hook() so we don't hold a reference.
1073 # Don't reference tr2 in hook() so we don't hold a reference.
1074 # This reduces memory consumption when there are multiple
1074 # This reduces memory consumption when there are multiple
1075 # transactions per lock. This can likely go away if issue5045
1075 # transactions per lock. This can likely go away if issue5045
1076 # fixes the function accumulation.
1076 # fixes the function accumulation.
1077 hookargs = tr2.hookargs
1077 hookargs = tr2.hookargs
1078
1078
1079 def hook():
1079 def hook():
1080 reporef().hook('txnclose', throw=False, txnname=desc,
1080 reporef().hook('txnclose', throw=False, txnname=desc,
1081 **hookargs)
1081 **hookargs)
1082 reporef()._afterlock(hook)
1082 reporef()._afterlock(hook)
1083 tr.addfinalize('txnclose-hook', txnclosehook)
1083 tr.addfinalize('txnclose-hook', txnclosehook)
1084 def txnaborthook(tr2):
1084 def txnaborthook(tr2):
1085 """To be run if transaction is aborted
1085 """To be run if transaction is aborted
1086 """
1086 """
1087 reporef().hook('txnabort', throw=False, txnname=desc,
1087 reporef().hook('txnabort', throw=False, txnname=desc,
1088 **tr2.hookargs)
1088 **tr2.hookargs)
1089 tr.addabort('txnabort-hook', txnaborthook)
1089 tr.addabort('txnabort-hook', txnaborthook)
1090 # avoid eager cache invalidation. in-memory data should be identical
1090 # avoid eager cache invalidation. in-memory data should be identical
1091 # to stored data if transaction has no error.
1091 # to stored data if transaction has no error.
1092 tr.addpostclose('refresh-filecachestats', self._refreshfilecachestats)
1092 tr.addpostclose('refresh-filecachestats', self._refreshfilecachestats)
1093 self._transref = weakref.ref(tr)
1093 self._transref = weakref.ref(tr)
1094 return tr
1094 return tr
1095
1095
1096 def _journalfiles(self):
1096 def _journalfiles(self):
1097 return ((self.svfs, 'journal'),
1097 return ((self.svfs, 'journal'),
1098 (self.vfs, 'journal.dirstate'),
1098 (self.vfs, 'journal.dirstate'),
1099 (self.vfs, 'journal.branch'),
1099 (self.vfs, 'journal.branch'),
1100 (self.vfs, 'journal.desc'),
1100 (self.vfs, 'journal.desc'),
1101 (self.vfs, 'journal.bookmarks'),
1101 (self.vfs, 'journal.bookmarks'),
1102 (self.svfs, 'journal.phaseroots'))
1102 (self.svfs, 'journal.phaseroots'))
1103
1103
1104 def undofiles(self):
1104 def undofiles(self):
1105 return [(vfs, undoname(x)) for vfs, x in self._journalfiles()]
1105 return [(vfs, undoname(x)) for vfs, x in self._journalfiles()]
1106
1106
1107 def _writejournal(self, desc):
1107 def _writejournal(self, desc):
1108 self.dirstate.savebackup(None, prefix='journal.')
1108 self.dirstate.savebackup(None, prefix='journal.')
1109 self.vfs.write("journal.branch",
1109 self.vfs.write("journal.branch",
1110 encoding.fromlocal(self.dirstate.branch()))
1110 encoding.fromlocal(self.dirstate.branch()))
1111 self.vfs.write("journal.desc",
1111 self.vfs.write("journal.desc",
1112 "%d\n%s\n" % (len(self), desc))
1112 "%d\n%s\n" % (len(self), desc))
1113 self.vfs.write("journal.bookmarks",
1113 self.vfs.write("journal.bookmarks",
1114 self.vfs.tryread("bookmarks"))
1114 self.vfs.tryread("bookmarks"))
1115 self.svfs.write("journal.phaseroots",
1115 self.svfs.write("journal.phaseroots",
1116 self.svfs.tryread("phaseroots"))
1116 self.svfs.tryread("phaseroots"))
1117
1117
1118 def recover(self):
1118 def recover(self):
1119 with self.lock():
1119 with self.lock():
1120 if self.svfs.exists("journal"):
1120 if self.svfs.exists("journal"):
1121 self.ui.status(_("rolling back interrupted transaction\n"))
1121 self.ui.status(_("rolling back interrupted transaction\n"))
1122 vfsmap = {'': self.svfs,
1122 vfsmap = {'': self.svfs,
1123 'plain': self.vfs,}
1123 'plain': self.vfs,}
1124 transaction.rollback(self.svfs, vfsmap, "journal",
1124 transaction.rollback(self.svfs, vfsmap, "journal",
1125 self.ui.warn)
1125 self.ui.warn)
1126 self.invalidate()
1126 self.invalidate()
1127 return True
1127 return True
1128 else:
1128 else:
1129 self.ui.warn(_("no interrupted transaction available\n"))
1129 self.ui.warn(_("no interrupted transaction available\n"))
1130 return False
1130 return False
1131
1131
1132 def rollback(self, dryrun=False, force=False):
1132 def rollback(self, dryrun=False, force=False):
1133 wlock = lock = dsguard = None
1133 wlock = lock = dsguard = None
1134 try:
1134 try:
1135 wlock = self.wlock()
1135 wlock = self.wlock()
1136 lock = self.lock()
1136 lock = self.lock()
1137 if self.svfs.exists("undo"):
1137 if self.svfs.exists("undo"):
1138 dsguard = cmdutil.dirstateguard(self, 'rollback')
1138 dsguard = cmdutil.dirstateguard(self, 'rollback')
1139
1139
1140 return self._rollback(dryrun, force, dsguard)
1140 return self._rollback(dryrun, force, dsguard)
1141 else:
1141 else:
1142 self.ui.warn(_("no rollback information available\n"))
1142 self.ui.warn(_("no rollback information available\n"))
1143 return 1
1143 return 1
1144 finally:
1144 finally:
1145 release(dsguard, lock, wlock)
1145 release(dsguard, lock, wlock)
1146
1146
1147 @unfilteredmethod # Until we get smarter cache management
1147 @unfilteredmethod # Until we get smarter cache management
1148 def _rollback(self, dryrun, force, dsguard):
1148 def _rollback(self, dryrun, force, dsguard):
1149 ui = self.ui
1149 ui = self.ui
1150 try:
1150 try:
1151 args = self.vfs.read('undo.desc').splitlines()
1151 args = self.vfs.read('undo.desc').splitlines()
1152 (oldlen, desc, detail) = (int(args[0]), args[1], None)
1152 (oldlen, desc, detail) = (int(args[0]), args[1], None)
1153 if len(args) >= 3:
1153 if len(args) >= 3:
1154 detail = args[2]
1154 detail = args[2]
1155 oldtip = oldlen - 1
1155 oldtip = oldlen - 1
1156
1156
1157 if detail and ui.verbose:
1157 if detail and ui.verbose:
1158 msg = (_('repository tip rolled back to revision %s'
1158 msg = (_('repository tip rolled back to revision %s'
1159 ' (undo %s: %s)\n')
1159 ' (undo %s: %s)\n')
1160 % (oldtip, desc, detail))
1160 % (oldtip, desc, detail))
1161 else:
1161 else:
1162 msg = (_('repository tip rolled back to revision %s'
1162 msg = (_('repository tip rolled back to revision %s'
1163 ' (undo %s)\n')
1163 ' (undo %s)\n')
1164 % (oldtip, desc))
1164 % (oldtip, desc))
1165 except IOError:
1165 except IOError:
1166 msg = _('rolling back unknown transaction\n')
1166 msg = _('rolling back unknown transaction\n')
1167 desc = None
1167 desc = None
1168
1168
1169 if not force and self['.'] != self['tip'] and desc == 'commit':
1169 if not force and self['.'] != self['tip'] and desc == 'commit':
1170 raise error.Abort(
1170 raise error.Abort(
1171 _('rollback of last commit while not checked out '
1171 _('rollback of last commit while not checked out '
1172 'may lose data'), hint=_('use -f to force'))
1172 'may lose data'), hint=_('use -f to force'))
1173
1173
1174 ui.status(msg)
1174 ui.status(msg)
1175 if dryrun:
1175 if dryrun:
1176 return 0
1176 return 0
1177
1177
1178 parents = self.dirstate.parents()
1178 parents = self.dirstate.parents()
1179 self.destroying()
1179 self.destroying()
1180 vfsmap = {'plain': self.vfs, '': self.svfs}
1180 vfsmap = {'plain': self.vfs, '': self.svfs}
1181 transaction.rollback(self.svfs, vfsmap, 'undo', ui.warn)
1181 transaction.rollback(self.svfs, vfsmap, 'undo', ui.warn)
1182 if self.vfs.exists('undo.bookmarks'):
1182 if self.vfs.exists('undo.bookmarks'):
1183 self.vfs.rename('undo.bookmarks', 'bookmarks', checkambig=True)
1183 self.vfs.rename('undo.bookmarks', 'bookmarks', checkambig=True)
1184 if self.svfs.exists('undo.phaseroots'):
1184 if self.svfs.exists('undo.phaseroots'):
1185 self.svfs.rename('undo.phaseroots', 'phaseroots', checkambig=True)
1185 self.svfs.rename('undo.phaseroots', 'phaseroots', checkambig=True)
1186 self.invalidate()
1186 self.invalidate()
1187
1187
1188 parentgone = (parents[0] not in self.changelog.nodemap or
1188 parentgone = (parents[0] not in self.changelog.nodemap or
1189 parents[1] not in self.changelog.nodemap)
1189 parents[1] not in self.changelog.nodemap)
1190 if parentgone:
1190 if parentgone:
1191 # prevent dirstateguard from overwriting already restored one
1191 # prevent dirstateguard from overwriting already restored one
1192 dsguard.close()
1192 dsguard.close()
1193
1193
1194 self.dirstate.restorebackup(None, prefix='undo.')
1194 self.dirstate.restorebackup(None, prefix='undo.')
1195 try:
1195 try:
1196 branch = self.vfs.read('undo.branch')
1196 branch = self.vfs.read('undo.branch')
1197 self.dirstate.setbranch(encoding.tolocal(branch))
1197 self.dirstate.setbranch(encoding.tolocal(branch))
1198 except IOError:
1198 except IOError:
1199 ui.warn(_('named branch could not be reset: '
1199 ui.warn(_('named branch could not be reset: '
1200 'current branch is still \'%s\'\n')
1200 'current branch is still \'%s\'\n')
1201 % self.dirstate.branch())
1201 % self.dirstate.branch())
1202
1202
1203 parents = tuple([p.rev() for p in self[None].parents()])
1203 parents = tuple([p.rev() for p in self[None].parents()])
1204 if len(parents) > 1:
1204 if len(parents) > 1:
1205 ui.status(_('working directory now based on '
1205 ui.status(_('working directory now based on '
1206 'revisions %d and %d\n') % parents)
1206 'revisions %d and %d\n') % parents)
1207 else:
1207 else:
1208 ui.status(_('working directory now based on '
1208 ui.status(_('working directory now based on '
1209 'revision %d\n') % parents)
1209 'revision %d\n') % parents)
1210 mergemod.mergestate.clean(self, self['.'].node())
1210 mergemod.mergestate.clean(self, self['.'].node())
1211
1211
1212 # TODO: if we know which new heads may result from this rollback, pass
1212 # TODO: if we know which new heads may result from this rollback, pass
1213 # them to destroy(), which will prevent the branchhead cache from being
1213 # them to destroy(), which will prevent the branchhead cache from being
1214 # invalidated.
1214 # invalidated.
1215 self.destroyed()
1215 self.destroyed()
1216 return 0
1216 return 0
1217
1217
1218 def invalidatecaches(self):
1218 def invalidatecaches(self):
1219
1219
1220 if '_tagscache' in vars(self):
1220 if '_tagscache' in vars(self):
1221 # can't use delattr on proxy
1221 # can't use delattr on proxy
1222 del self.__dict__['_tagscache']
1222 del self.__dict__['_tagscache']
1223
1223
1224 self.unfiltered()._branchcaches.clear()
1224 self.unfiltered()._branchcaches.clear()
1225 self.invalidatevolatilesets()
1225 self.invalidatevolatilesets()
1226
1226
1227 def invalidatevolatilesets(self):
1227 def invalidatevolatilesets(self):
1228 self.filteredrevcache.clear()
1228 self.filteredrevcache.clear()
1229 obsolete.clearobscaches(self)
1229 obsolete.clearobscaches(self)
1230
1230
1231 def invalidatedirstate(self):
1231 def invalidatedirstate(self):
1232 '''Invalidates the dirstate, causing the next call to dirstate
1232 '''Invalidates the dirstate, causing the next call to dirstate
1233 to check if it was modified since the last time it was read,
1233 to check if it was modified since the last time it was read,
1234 rereading it if it has.
1234 rereading it if it has.
1235
1235
1236 This is different to dirstate.invalidate() that it doesn't always
1236 This is different to dirstate.invalidate() that it doesn't always
1237 rereads the dirstate. Use dirstate.invalidate() if you want to
1237 rereads the dirstate. Use dirstate.invalidate() if you want to
1238 explicitly read the dirstate again (i.e. restoring it to a previous
1238 explicitly read the dirstate again (i.e. restoring it to a previous
1239 known good state).'''
1239 known good state).'''
1240 if hasunfilteredcache(self, 'dirstate'):
1240 if hasunfilteredcache(self, 'dirstate'):
1241 for k in self.dirstate._filecache:
1241 for k in self.dirstate._filecache:
1242 try:
1242 try:
1243 delattr(self.dirstate, k)
1243 delattr(self.dirstate, k)
1244 except AttributeError:
1244 except AttributeError:
1245 pass
1245 pass
1246 delattr(self.unfiltered(), 'dirstate')
1246 delattr(self.unfiltered(), 'dirstate')
1247
1247
1248 def invalidate(self, clearfilecache=False):
1248 def invalidate(self, clearfilecache=False):
1249 '''Invalidates both store and non-store parts other than dirstate
1249 '''Invalidates both store and non-store parts other than dirstate
1250
1250
1251 If a transaction is running, invalidation of store is omitted,
1251 If a transaction is running, invalidation of store is omitted,
1252 because discarding in-memory changes might cause inconsistency
1252 because discarding in-memory changes might cause inconsistency
1253 (e.g. incomplete fncache causes unintentional failure, but
1253 (e.g. incomplete fncache causes unintentional failure, but
1254 redundant one doesn't).
1254 redundant one doesn't).
1255 '''
1255 '''
1256 unfiltered = self.unfiltered() # all file caches are stored unfiltered
1256 unfiltered = self.unfiltered() # all file caches are stored unfiltered
1257 for k in self._filecache.keys():
1257 for k in self._filecache.keys():
1258 # dirstate is invalidated separately in invalidatedirstate()
1258 # dirstate is invalidated separately in invalidatedirstate()
1259 if k == 'dirstate':
1259 if k == 'dirstate':
1260 continue
1260 continue
1261
1261
1262 if clearfilecache:
1262 if clearfilecache:
1263 del self._filecache[k]
1263 del self._filecache[k]
1264 try:
1264 try:
1265 delattr(unfiltered, k)
1265 delattr(unfiltered, k)
1266 except AttributeError:
1266 except AttributeError:
1267 pass
1267 pass
1268 self.invalidatecaches()
1268 self.invalidatecaches()
1269 if not self.currenttransaction():
1269 if not self.currenttransaction():
1270 # TODO: Changing contents of store outside transaction
1270 # TODO: Changing contents of store outside transaction
1271 # causes inconsistency. We should make in-memory store
1271 # causes inconsistency. We should make in-memory store
1272 # changes detectable, and abort if changed.
1272 # changes detectable, and abort if changed.
1273 self.store.invalidatecaches()
1273 self.store.invalidatecaches()
1274
1274
1275 def invalidateall(self):
1275 def invalidateall(self):
1276 '''Fully invalidates both store and non-store parts, causing the
1276 '''Fully invalidates both store and non-store parts, causing the
1277 subsequent operation to reread any outside changes.'''
1277 subsequent operation to reread any outside changes.'''
1278 # extension should hook this to invalidate its caches
1278 # extension should hook this to invalidate its caches
1279 self.invalidate()
1279 self.invalidate()
1280 self.invalidatedirstate()
1280 self.invalidatedirstate()
1281
1281
1282 @unfilteredmethod
1282 @unfilteredmethod
1283 def _refreshfilecachestats(self, tr):
1283 def _refreshfilecachestats(self, tr):
1284 """Reload stats of cached files so that they are flagged as valid"""
1284 """Reload stats of cached files so that they are flagged as valid"""
1285 for k, ce in self._filecache.items():
1285 for k, ce in self._filecache.items():
1286 if k == 'dirstate' or k not in self.__dict__:
1286 if k == 'dirstate' or k not in self.__dict__:
1287 continue
1287 continue
1288 ce.refresh()
1288 ce.refresh()
1289
1289
1290 def _lock(self, vfs, lockname, wait, releasefn, acquirefn, desc,
1290 def _lock(self, vfs, lockname, wait, releasefn, acquirefn, desc,
1291 inheritchecker=None, parentenvvar=None):
1291 inheritchecker=None, parentenvvar=None):
1292 parentlock = None
1292 parentlock = None
1293 # the contents of parentenvvar are used by the underlying lock to
1293 # the contents of parentenvvar are used by the underlying lock to
1294 # determine whether it can be inherited
1294 # determine whether it can be inherited
1295 if parentenvvar is not None:
1295 if parentenvvar is not None:
1296 parentlock = os.environ.get(parentenvvar)
1296 parentlock = os.environ.get(parentenvvar)
1297 try:
1297 try:
1298 l = lockmod.lock(vfs, lockname, 0, releasefn=releasefn,
1298 l = lockmod.lock(vfs, lockname, 0, releasefn=releasefn,
1299 acquirefn=acquirefn, desc=desc,
1299 acquirefn=acquirefn, desc=desc,
1300 inheritchecker=inheritchecker,
1300 inheritchecker=inheritchecker,
1301 parentlock=parentlock)
1301 parentlock=parentlock)
1302 except error.LockHeld as inst:
1302 except error.LockHeld as inst:
1303 if not wait:
1303 if not wait:
1304 raise
1304 raise
1305 # show more details for new-style locks
1305 # show more details for new-style locks
1306 if ':' in inst.locker:
1306 if ':' in inst.locker:
1307 host, pid = inst.locker.split(":", 1)
1307 host, pid = inst.locker.split(":", 1)
1308 self.ui.warn(
1308 self.ui.warn(
1309 _("waiting for lock on %s held by process %r "
1309 _("waiting for lock on %s held by process %r "
1310 "on host %r\n") % (desc, pid, host))
1310 "on host %r\n") % (desc, pid, host))
1311 else:
1311 else:
1312 self.ui.warn(_("waiting for lock on %s held by %r\n") %
1312 self.ui.warn(_("waiting for lock on %s held by %r\n") %
1313 (desc, inst.locker))
1313 (desc, inst.locker))
1314 # default to 600 seconds timeout
1314 # default to 600 seconds timeout
1315 l = lockmod.lock(vfs, lockname,
1315 l = lockmod.lock(vfs, lockname,
1316 int(self.ui.config("ui", "timeout", "600")),
1316 int(self.ui.config("ui", "timeout", "600")),
1317 releasefn=releasefn, acquirefn=acquirefn,
1317 releasefn=releasefn, acquirefn=acquirefn,
1318 desc=desc)
1318 desc=desc)
1319 self.ui.warn(_("got lock after %s seconds\n") % l.delay)
1319 self.ui.warn(_("got lock after %s seconds\n") % l.delay)
1320 return l
1320 return l
1321
1321
1322 def _afterlock(self, callback):
1322 def _afterlock(self, callback):
1323 """add a callback to be run when the repository is fully unlocked
1323 """add a callback to be run when the repository is fully unlocked
1324
1324
1325 The callback will be executed when the outermost lock is released
1325 The callback will be executed when the outermost lock is released
1326 (with wlock being higher level than 'lock')."""
1326 (with wlock being higher level than 'lock')."""
1327 for ref in (self._wlockref, self._lockref):
1327 for ref in (self._wlockref, self._lockref):
1328 l = ref and ref()
1328 l = ref and ref()
1329 if l and l.held:
1329 if l and l.held:
1330 l.postrelease.append(callback)
1330 l.postrelease.append(callback)
1331 break
1331 break
1332 else: # no lock have been found.
1332 else: # no lock have been found.
1333 callback()
1333 callback()
1334
1334
1335 def lock(self, wait=True):
1335 def lock(self, wait=True):
1336 '''Lock the repository store (.hg/store) and return a weak reference
1336 '''Lock the repository store (.hg/store) and return a weak reference
1337 to the lock. Use this before modifying the store (e.g. committing or
1337 to the lock. Use this before modifying the store (e.g. committing or
1338 stripping). If you are opening a transaction, get a lock as well.)
1338 stripping). If you are opening a transaction, get a lock as well.)
1339
1339
1340 If both 'lock' and 'wlock' must be acquired, ensure you always acquires
1340 If both 'lock' and 'wlock' must be acquired, ensure you always acquires
1341 'wlock' first to avoid a dead-lock hazard.'''
1341 'wlock' first to avoid a dead-lock hazard.'''
1342 l = self._currentlock(self._lockref)
1342 l = self._currentlock(self._lockref)
1343 if l is not None:
1343 if l is not None:
1344 l.lock()
1344 l.lock()
1345 return l
1345 return l
1346
1346
1347 l = self._lock(self.svfs, "lock", wait, None,
1347 l = self._lock(self.svfs, "lock", wait, None,
1348 self.invalidate, _('repository %s') % self.origroot)
1348 self.invalidate, _('repository %s') % self.origroot)
1349 self._lockref = weakref.ref(l)
1349 self._lockref = weakref.ref(l)
1350 return l
1350 return l
1351
1351
1352 def _wlockchecktransaction(self):
1352 def _wlockchecktransaction(self):
1353 if self.currenttransaction() is not None:
1353 if self.currenttransaction() is not None:
1354 raise error.LockInheritanceContractViolation(
1354 raise error.LockInheritanceContractViolation(
1355 'wlock cannot be inherited in the middle of a transaction')
1355 'wlock cannot be inherited in the middle of a transaction')
1356
1356
1357 def wlock(self, wait=True):
1357 def wlock(self, wait=True):
1358 '''Lock the non-store parts of the repository (everything under
1358 '''Lock the non-store parts of the repository (everything under
1359 .hg except .hg/store) and return a weak reference to the lock.
1359 .hg except .hg/store) and return a weak reference to the lock.
1360
1360
1361 Use this before modifying files in .hg.
1361 Use this before modifying files in .hg.
1362
1362
1363 If both 'lock' and 'wlock' must be acquired, ensure you always acquires
1363 If both 'lock' and 'wlock' must be acquired, ensure you always acquires
1364 'wlock' first to avoid a dead-lock hazard.'''
1364 'wlock' first to avoid a dead-lock hazard.'''
1365 l = self._wlockref and self._wlockref()
1365 l = self._wlockref and self._wlockref()
1366 if l is not None and l.held:
1366 if l is not None and l.held:
1367 l.lock()
1367 l.lock()
1368 return l
1368 return l
1369
1369
1370 # We do not need to check for non-waiting lock acquisition. Such
1370 # We do not need to check for non-waiting lock acquisition. Such
1371 # acquisition would not cause dead-lock as they would just fail.
1371 # acquisition would not cause dead-lock as they would just fail.
1372 if wait and (self.ui.configbool('devel', 'all-warnings')
1372 if wait and (self.ui.configbool('devel', 'all-warnings')
1373 or self.ui.configbool('devel', 'check-locks')):
1373 or self.ui.configbool('devel', 'check-locks')):
1374 if self._currentlock(self._lockref) is not None:
1374 if self._currentlock(self._lockref) is not None:
1375 self.ui.develwarn('"wlock" acquired after "lock"')
1375 self.ui.develwarn('"wlock" acquired after "lock"')
1376
1376
1377 def unlock():
1377 def unlock():
1378 if self.dirstate.pendingparentchange():
1378 if self.dirstate.pendingparentchange():
1379 self.dirstate.invalidate()
1379 self.dirstate.invalidate()
1380 else:
1380 else:
1381 self.dirstate.write(None)
1381 self.dirstate.write(None)
1382
1382
1383 self._filecache['dirstate'].refresh()
1383 self._filecache['dirstate'].refresh()
1384
1384
1385 l = self._lock(self.vfs, "wlock", wait, unlock,
1385 l = self._lock(self.vfs, "wlock", wait, unlock,
1386 self.invalidatedirstate, _('working directory of %s') %
1386 self.invalidatedirstate, _('working directory of %s') %
1387 self.origroot,
1387 self.origroot,
1388 inheritchecker=self._wlockchecktransaction,
1388 inheritchecker=self._wlockchecktransaction,
1389 parentenvvar='HG_WLOCK_LOCKER')
1389 parentenvvar='HG_WLOCK_LOCKER')
1390 self._wlockref = weakref.ref(l)
1390 self._wlockref = weakref.ref(l)
1391 return l
1391 return l
1392
1392
1393 def _currentlock(self, lockref):
1393 def _currentlock(self, lockref):
1394 """Returns the lock if it's held, or None if it's not."""
1394 """Returns the lock if it's held, or None if it's not."""
1395 if lockref is None:
1395 if lockref is None:
1396 return None
1396 return None
1397 l = lockref()
1397 l = lockref()
1398 if l is None or not l.held:
1398 if l is None or not l.held:
1399 return None
1399 return None
1400 return l
1400 return l
1401
1401
1402 def currentwlock(self):
1402 def currentwlock(self):
1403 """Returns the wlock if it's held, or None if it's not."""
1403 """Returns the wlock if it's held, or None if it's not."""
1404 return self._currentlock(self._wlockref)
1404 return self._currentlock(self._wlockref)
1405
1405
1406 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
1406 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
1407 """
1407 """
1408 commit an individual file as part of a larger transaction
1408 commit an individual file as part of a larger transaction
1409 """
1409 """
1410
1410
1411 fname = fctx.path()
1411 fname = fctx.path()
1412 fparent1 = manifest1.get(fname, nullid)
1412 fparent1 = manifest1.get(fname, nullid)
1413 fparent2 = manifest2.get(fname, nullid)
1413 fparent2 = manifest2.get(fname, nullid)
1414 if isinstance(fctx, context.filectx):
1414 if isinstance(fctx, context.filectx):
1415 node = fctx.filenode()
1415 node = fctx.filenode()
1416 if node in [fparent1, fparent2]:
1416 if node in [fparent1, fparent2]:
1417 self.ui.debug('reusing %s filelog entry\n' % fname)
1417 self.ui.debug('reusing %s filelog entry\n' % fname)
1418 if manifest1.flags(fname) != fctx.flags():
1418 if manifest1.flags(fname) != fctx.flags():
1419 changelist.append(fname)
1419 changelist.append(fname)
1420 return node
1420 return node
1421
1421
1422 flog = self.file(fname)
1422 flog = self.file(fname)
1423 meta = {}
1423 meta = {}
1424 copy = fctx.renamed()
1424 copy = fctx.renamed()
1425 if copy and copy[0] != fname:
1425 if copy and copy[0] != fname:
1426 # Mark the new revision of this file as a copy of another
1426 # Mark the new revision of this file as a copy of another
1427 # file. This copy data will effectively act as a parent
1427 # file. This copy data will effectively act as a parent
1428 # of this new revision. If this is a merge, the first
1428 # of this new revision. If this is a merge, the first
1429 # parent will be the nullid (meaning "look up the copy data")
1429 # parent will be the nullid (meaning "look up the copy data")
1430 # and the second one will be the other parent. For example:
1430 # and the second one will be the other parent. For example:
1431 #
1431 #
1432 # 0 --- 1 --- 3 rev1 changes file foo
1432 # 0 --- 1 --- 3 rev1 changes file foo
1433 # \ / rev2 renames foo to bar and changes it
1433 # \ / rev2 renames foo to bar and changes it
1434 # \- 2 -/ rev3 should have bar with all changes and
1434 # \- 2 -/ rev3 should have bar with all changes and
1435 # should record that bar descends from
1435 # should record that bar descends from
1436 # bar in rev2 and foo in rev1
1436 # bar in rev2 and foo in rev1
1437 #
1437 #
1438 # this allows this merge to succeed:
1438 # this allows this merge to succeed:
1439 #
1439 #
1440 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
1440 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
1441 # \ / merging rev3 and rev4 should use bar@rev2
1441 # \ / merging rev3 and rev4 should use bar@rev2
1442 # \- 2 --- 4 as the merge base
1442 # \- 2 --- 4 as the merge base
1443 #
1443 #
1444
1444
1445 cfname = copy[0]
1445 cfname = copy[0]
1446 crev = manifest1.get(cfname)
1446 crev = manifest1.get(cfname)
1447 newfparent = fparent2
1447 newfparent = fparent2
1448
1448
1449 if manifest2: # branch merge
1449 if manifest2: # branch merge
1450 if fparent2 == nullid or crev is None: # copied on remote side
1450 if fparent2 == nullid or crev is None: # copied on remote side
1451 if cfname in manifest2:
1451 if cfname in manifest2:
1452 crev = manifest2[cfname]
1452 crev = manifest2[cfname]
1453 newfparent = fparent1
1453 newfparent = fparent1
1454
1454
1455 # Here, we used to search backwards through history to try to find
1455 # Here, we used to search backwards through history to try to find
1456 # where the file copy came from if the source of a copy was not in
1456 # where the file copy came from if the source of a copy was not in
1457 # the parent directory. However, this doesn't actually make sense to
1457 # the parent directory. However, this doesn't actually make sense to
1458 # do (what does a copy from something not in your working copy even
1458 # do (what does a copy from something not in your working copy even
1459 # mean?) and it causes bugs (eg, issue4476). Instead, we will warn
1459 # mean?) and it causes bugs (eg, issue4476). Instead, we will warn
1460 # the user that copy information was dropped, so if they didn't
1460 # the user that copy information was dropped, so if they didn't
1461 # expect this outcome it can be fixed, but this is the correct
1461 # expect this outcome it can be fixed, but this is the correct
1462 # behavior in this circumstance.
1462 # behavior in this circumstance.
1463
1463
1464 if crev:
1464 if crev:
1465 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
1465 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
1466 meta["copy"] = cfname
1466 meta["copy"] = cfname
1467 meta["copyrev"] = hex(crev)
1467 meta["copyrev"] = hex(crev)
1468 fparent1, fparent2 = nullid, newfparent
1468 fparent1, fparent2 = nullid, newfparent
1469 else:
1469 else:
1470 self.ui.warn(_("warning: can't find ancestor for '%s' "
1470 self.ui.warn(_("warning: can't find ancestor for '%s' "
1471 "copied from '%s'!\n") % (fname, cfname))
1471 "copied from '%s'!\n") % (fname, cfname))
1472
1472
1473 elif fparent1 == nullid:
1473 elif fparent1 == nullid:
1474 fparent1, fparent2 = fparent2, nullid
1474 fparent1, fparent2 = fparent2, nullid
1475 elif fparent2 != nullid:
1475 elif fparent2 != nullid:
1476 # is one parent an ancestor of the other?
1476 # is one parent an ancestor of the other?
1477 fparentancestors = flog.commonancestorsheads(fparent1, fparent2)
1477 fparentancestors = flog.commonancestorsheads(fparent1, fparent2)
1478 if fparent1 in fparentancestors:
1478 if fparent1 in fparentancestors:
1479 fparent1, fparent2 = fparent2, nullid
1479 fparent1, fparent2 = fparent2, nullid
1480 elif fparent2 in fparentancestors:
1480 elif fparent2 in fparentancestors:
1481 fparent2 = nullid
1481 fparent2 = nullid
1482
1482
1483 # is the file changed?
1483 # is the file changed?
1484 text = fctx.data()
1484 text = fctx.data()
1485 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
1485 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
1486 changelist.append(fname)
1486 changelist.append(fname)
1487 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
1487 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
1488 # are just the flags changed during merge?
1488 # are just the flags changed during merge?
1489 elif fname in manifest1 and manifest1.flags(fname) != fctx.flags():
1489 elif fname in manifest1 and manifest1.flags(fname) != fctx.flags():
1490 changelist.append(fname)
1490 changelist.append(fname)
1491
1491
1492 return fparent1
1492 return fparent1
1493
1493
1494 def checkcommitpatterns(self, wctx, vdirs, match, status, fail):
1494 def checkcommitpatterns(self, wctx, vdirs, match, status, fail):
1495 """check for commit arguments that aren't commitable"""
1495 """check for commit arguments that aren't commitable"""
1496 if match.isexact() or match.prefix():
1496 if match.isexact() or match.prefix():
1497 matched = set(status.modified + status.added + status.removed)
1497 matched = set(status.modified + status.added + status.removed)
1498
1498
1499 for f in match.files():
1499 for f in match.files():
1500 f = self.dirstate.normalize(f)
1500 f = self.dirstate.normalize(f)
1501 if f == '.' or f in matched or f in wctx.substate:
1501 if f == '.' or f in matched or f in wctx.substate:
1502 continue
1502 continue
1503 if f in status.deleted:
1503 if f in status.deleted:
1504 fail(f, _('file not found!'))
1504 fail(f, _('file not found!'))
1505 if f in vdirs: # visited directory
1505 if f in vdirs: # visited directory
1506 d = f + '/'
1506 d = f + '/'
1507 for mf in matched:
1507 for mf in matched:
1508 if mf.startswith(d):
1508 if mf.startswith(d):
1509 break
1509 break
1510 else:
1510 else:
1511 fail(f, _("no match under directory!"))
1511 fail(f, _("no match under directory!"))
1512 elif f not in self.dirstate:
1512 elif f not in self.dirstate:
1513 fail(f, _("file not tracked!"))
1513 fail(f, _("file not tracked!"))
1514
1514
1515 @unfilteredmethod
1515 @unfilteredmethod
1516 def commit(self, text="", user=None, date=None, match=None, force=False,
1516 def commit(self, text="", user=None, date=None, match=None, force=False,
1517 editor=False, extra=None):
1517 editor=False, extra=None):
1518 """Add a new revision to current repository.
1518 """Add a new revision to current repository.
1519
1519
1520 Revision information is gathered from the working directory,
1520 Revision information is gathered from the working directory,
1521 match can be used to filter the committed files. If editor is
1521 match can be used to filter the committed files. If editor is
1522 supplied, it is called to get a commit message.
1522 supplied, it is called to get a commit message.
1523 """
1523 """
1524 if extra is None:
1524 if extra is None:
1525 extra = {}
1525 extra = {}
1526
1526
1527 def fail(f, msg):
1527 def fail(f, msg):
1528 raise error.Abort('%s: %s' % (f, msg))
1528 raise error.Abort('%s: %s' % (f, msg))
1529
1529
1530 if not match:
1530 if not match:
1531 match = matchmod.always(self.root, '')
1531 match = matchmod.always(self.root, '')
1532
1532
1533 if not force:
1533 if not force:
1534 vdirs = []
1534 vdirs = []
1535 match.explicitdir = vdirs.append
1535 match.explicitdir = vdirs.append
1536 match.bad = fail
1536 match.bad = fail
1537
1537
1538 wlock = lock = tr = None
1538 wlock = lock = tr = None
1539 try:
1539 try:
1540 wlock = self.wlock()
1540 wlock = self.wlock()
1541 lock = self.lock() # for recent changelog (see issue4368)
1541 lock = self.lock() # for recent changelog (see issue4368)
1542
1542
1543 wctx = self[None]
1543 wctx = self[None]
1544 merge = len(wctx.parents()) > 1
1544 merge = len(wctx.parents()) > 1
1545
1545
1546 if not force and merge and match.ispartial():
1546 if not force and merge and match.ispartial():
1547 raise error.Abort(_('cannot partially commit a merge '
1547 raise error.Abort(_('cannot partially commit a merge '
1548 '(do not specify files or patterns)'))
1548 '(do not specify files or patterns)'))
1549
1549
1550 status = self.status(match=match, clean=force)
1550 status = self.status(match=match, clean=force)
1551 if force:
1551 if force:
1552 status.modified.extend(status.clean) # mq may commit clean files
1552 status.modified.extend(status.clean) # mq may commit clean files
1553
1553
1554 # check subrepos
1554 # check subrepos
1555 subs = []
1555 subs = []
1556 commitsubs = set()
1556 commitsubs = set()
1557 newstate = wctx.substate.copy()
1557 newstate = wctx.substate.copy()
1558 # only manage subrepos and .hgsubstate if .hgsub is present
1558 # only manage subrepos and .hgsubstate if .hgsub is present
1559 if '.hgsub' in wctx:
1559 if '.hgsub' in wctx:
1560 # we'll decide whether to track this ourselves, thanks
1560 # we'll decide whether to track this ourselves, thanks
1561 for c in status.modified, status.added, status.removed:
1561 for c in status.modified, status.added, status.removed:
1562 if '.hgsubstate' in c:
1562 if '.hgsubstate' in c:
1563 c.remove('.hgsubstate')
1563 c.remove('.hgsubstate')
1564
1564
1565 # compare current state to last committed state
1565 # compare current state to last committed state
1566 # build new substate based on last committed state
1566 # build new substate based on last committed state
1567 oldstate = wctx.p1().substate
1567 oldstate = wctx.p1().substate
1568 for s in sorted(newstate.keys()):
1568 for s in sorted(newstate.keys()):
1569 if not match(s):
1569 if not match(s):
1570 # ignore working copy, use old state if present
1570 # ignore working copy, use old state if present
1571 if s in oldstate:
1571 if s in oldstate:
1572 newstate[s] = oldstate[s]
1572 newstate[s] = oldstate[s]
1573 continue
1573 continue
1574 if not force:
1574 if not force:
1575 raise error.Abort(
1575 raise error.Abort(
1576 _("commit with new subrepo %s excluded") % s)
1576 _("commit with new subrepo %s excluded") % s)
1577 dirtyreason = wctx.sub(s).dirtyreason(True)
1577 dirtyreason = wctx.sub(s).dirtyreason(True)
1578 if dirtyreason:
1578 if dirtyreason:
1579 if not self.ui.configbool('ui', 'commitsubrepos'):
1579 if not self.ui.configbool('ui', 'commitsubrepos'):
1580 raise error.Abort(dirtyreason,
1580 raise error.Abort(dirtyreason,
1581 hint=_("use --subrepos for recursive commit"))
1581 hint=_("use --subrepos for recursive commit"))
1582 subs.append(s)
1582 subs.append(s)
1583 commitsubs.add(s)
1583 commitsubs.add(s)
1584 else:
1584 else:
1585 bs = wctx.sub(s).basestate()
1585 bs = wctx.sub(s).basestate()
1586 newstate[s] = (newstate[s][0], bs, newstate[s][2])
1586 newstate[s] = (newstate[s][0], bs, newstate[s][2])
1587 if oldstate.get(s, (None, None, None))[1] != bs:
1587 if oldstate.get(s, (None, None, None))[1] != bs:
1588 subs.append(s)
1588 subs.append(s)
1589
1589
1590 # check for removed subrepos
1590 # check for removed subrepos
1591 for p in wctx.parents():
1591 for p in wctx.parents():
1592 r = [s for s in p.substate if s not in newstate]
1592 r = [s for s in p.substate if s not in newstate]
1593 subs += [s for s in r if match(s)]
1593 subs += [s for s in r if match(s)]
1594 if subs:
1594 if subs:
1595 if (not match('.hgsub') and
1595 if (not match('.hgsub') and
1596 '.hgsub' in (wctx.modified() + wctx.added())):
1596 '.hgsub' in (wctx.modified() + wctx.added())):
1597 raise error.Abort(
1597 raise error.Abort(
1598 _("can't commit subrepos without .hgsub"))
1598 _("can't commit subrepos without .hgsub"))
1599 status.modified.insert(0, '.hgsubstate')
1599 status.modified.insert(0, '.hgsubstate')
1600
1600
1601 elif '.hgsub' in status.removed:
1601 elif '.hgsub' in status.removed:
1602 # clean up .hgsubstate when .hgsub is removed
1602 # clean up .hgsubstate when .hgsub is removed
1603 if ('.hgsubstate' in wctx and
1603 if ('.hgsubstate' in wctx and
1604 '.hgsubstate' not in (status.modified + status.added +
1604 '.hgsubstate' not in (status.modified + status.added +
1605 status.removed)):
1605 status.removed)):
1606 status.removed.insert(0, '.hgsubstate')
1606 status.removed.insert(0, '.hgsubstate')
1607
1607
1608 # make sure all explicit patterns are matched
1608 # make sure all explicit patterns are matched
1609 if not force:
1609 if not force:
1610 self.checkcommitpatterns(wctx, vdirs, match, status, fail)
1610 self.checkcommitpatterns(wctx, vdirs, match, status, fail)
1611
1611
1612 cctx = context.workingcommitctx(self, status,
1612 cctx = context.workingcommitctx(self, status,
1613 text, user, date, extra)
1613 text, user, date, extra)
1614
1614
1615 # internal config: ui.allowemptycommit
1615 # internal config: ui.allowemptycommit
1616 allowemptycommit = (wctx.branch() != wctx.p1().branch()
1616 allowemptycommit = (wctx.branch() != wctx.p1().branch()
1617 or extra.get('close') or merge or cctx.files()
1617 or extra.get('close') or merge or cctx.files()
1618 or self.ui.configbool('ui', 'allowemptycommit'))
1618 or self.ui.configbool('ui', 'allowemptycommit'))
1619 if not allowemptycommit:
1619 if not allowemptycommit:
1620 return None
1620 return None
1621
1621
1622 if merge and cctx.deleted():
1622 if merge and cctx.deleted():
1623 raise error.Abort(_("cannot commit merge with missing files"))
1623 raise error.Abort(_("cannot commit merge with missing files"))
1624
1624
1625 ms = mergemod.mergestate.read(self)
1625 ms = mergemod.mergestate.read(self)
1626
1626
1627 if list(ms.unresolved()):
1627 if list(ms.unresolved()):
1628 raise error.Abort(_('unresolved merge conflicts '
1628 raise error.Abort(_("unresolved merge conflicts "
1629 '(see "hg help resolve")'))
1629 "(see 'hg help resolve')"))
1630 if ms.mdstate() != 's' or list(ms.driverresolved()):
1630 if ms.mdstate() != 's' or list(ms.driverresolved()):
1631 raise error.Abort(_('driver-resolved merge conflicts'),
1631 raise error.Abort(_('driver-resolved merge conflicts'),
1632 hint=_('run "hg resolve --all" to resolve'))
1632 hint=_('run "hg resolve --all" to resolve'))
1633
1633
1634 if editor:
1634 if editor:
1635 cctx._text = editor(self, cctx, subs)
1635 cctx._text = editor(self, cctx, subs)
1636 edited = (text != cctx._text)
1636 edited = (text != cctx._text)
1637
1637
1638 # Save commit message in case this transaction gets rolled back
1638 # Save commit message in case this transaction gets rolled back
1639 # (e.g. by a pretxncommit hook). Leave the content alone on
1639 # (e.g. by a pretxncommit hook). Leave the content alone on
1640 # the assumption that the user will use the same editor again.
1640 # the assumption that the user will use the same editor again.
1641 msgfn = self.savecommitmessage(cctx._text)
1641 msgfn = self.savecommitmessage(cctx._text)
1642
1642
1643 # commit subs and write new state
1643 # commit subs and write new state
1644 if subs:
1644 if subs:
1645 for s in sorted(commitsubs):
1645 for s in sorted(commitsubs):
1646 sub = wctx.sub(s)
1646 sub = wctx.sub(s)
1647 self.ui.status(_('committing subrepository %s\n') %
1647 self.ui.status(_('committing subrepository %s\n') %
1648 subrepo.subrelpath(sub))
1648 subrepo.subrelpath(sub))
1649 sr = sub.commit(cctx._text, user, date)
1649 sr = sub.commit(cctx._text, user, date)
1650 newstate[s] = (newstate[s][0], sr)
1650 newstate[s] = (newstate[s][0], sr)
1651 subrepo.writestate(self, newstate)
1651 subrepo.writestate(self, newstate)
1652
1652
1653 p1, p2 = self.dirstate.parents()
1653 p1, p2 = self.dirstate.parents()
1654 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1654 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1655 try:
1655 try:
1656 self.hook("precommit", throw=True, parent1=hookp1,
1656 self.hook("precommit", throw=True, parent1=hookp1,
1657 parent2=hookp2)
1657 parent2=hookp2)
1658 tr = self.transaction('commit')
1658 tr = self.transaction('commit')
1659 ret = self.commitctx(cctx, True)
1659 ret = self.commitctx(cctx, True)
1660 except: # re-raises
1660 except: # re-raises
1661 if edited:
1661 if edited:
1662 self.ui.write(
1662 self.ui.write(
1663 _('note: commit message saved in %s\n') % msgfn)
1663 _('note: commit message saved in %s\n') % msgfn)
1664 raise
1664 raise
1665 # update bookmarks, dirstate and mergestate
1665 # update bookmarks, dirstate and mergestate
1666 bookmarks.update(self, [p1, p2], ret)
1666 bookmarks.update(self, [p1, p2], ret)
1667 cctx.markcommitted(ret)
1667 cctx.markcommitted(ret)
1668 ms.reset()
1668 ms.reset()
1669 tr.close()
1669 tr.close()
1670
1670
1671 finally:
1671 finally:
1672 lockmod.release(tr, lock, wlock)
1672 lockmod.release(tr, lock, wlock)
1673
1673
1674 def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2):
1674 def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2):
1675 # hack for command that use a temporary commit (eg: histedit)
1675 # hack for command that use a temporary commit (eg: histedit)
1676 # temporary commit got stripped before hook release
1676 # temporary commit got stripped before hook release
1677 if self.changelog.hasnode(ret):
1677 if self.changelog.hasnode(ret):
1678 self.hook("commit", node=node, parent1=parent1,
1678 self.hook("commit", node=node, parent1=parent1,
1679 parent2=parent2)
1679 parent2=parent2)
1680 self._afterlock(commithook)
1680 self._afterlock(commithook)
1681 return ret
1681 return ret
1682
1682
1683 @unfilteredmethod
1683 @unfilteredmethod
1684 def commitctx(self, ctx, error=False):
1684 def commitctx(self, ctx, error=False):
1685 """Add a new revision to current repository.
1685 """Add a new revision to current repository.
1686 Revision information is passed via the context argument.
1686 Revision information is passed via the context argument.
1687 """
1687 """
1688
1688
1689 tr = None
1689 tr = None
1690 p1, p2 = ctx.p1(), ctx.p2()
1690 p1, p2 = ctx.p1(), ctx.p2()
1691 user = ctx.user()
1691 user = ctx.user()
1692
1692
1693 lock = self.lock()
1693 lock = self.lock()
1694 try:
1694 try:
1695 tr = self.transaction("commit")
1695 tr = self.transaction("commit")
1696 trp = weakref.proxy(tr)
1696 trp = weakref.proxy(tr)
1697
1697
1698 if ctx.files():
1698 if ctx.files():
1699 m1 = p1.manifest()
1699 m1 = p1.manifest()
1700 m2 = p2.manifest()
1700 m2 = p2.manifest()
1701 m = m1.copy()
1701 m = m1.copy()
1702
1702
1703 # check in files
1703 # check in files
1704 added = []
1704 added = []
1705 changed = []
1705 changed = []
1706 removed = list(ctx.removed())
1706 removed = list(ctx.removed())
1707 linkrev = len(self)
1707 linkrev = len(self)
1708 self.ui.note(_("committing files:\n"))
1708 self.ui.note(_("committing files:\n"))
1709 for f in sorted(ctx.modified() + ctx.added()):
1709 for f in sorted(ctx.modified() + ctx.added()):
1710 self.ui.note(f + "\n")
1710 self.ui.note(f + "\n")
1711 try:
1711 try:
1712 fctx = ctx[f]
1712 fctx = ctx[f]
1713 if fctx is None:
1713 if fctx is None:
1714 removed.append(f)
1714 removed.append(f)
1715 else:
1715 else:
1716 added.append(f)
1716 added.append(f)
1717 m[f] = self._filecommit(fctx, m1, m2, linkrev,
1717 m[f] = self._filecommit(fctx, m1, m2, linkrev,
1718 trp, changed)
1718 trp, changed)
1719 m.setflag(f, fctx.flags())
1719 m.setflag(f, fctx.flags())
1720 except OSError as inst:
1720 except OSError as inst:
1721 self.ui.warn(_("trouble committing %s!\n") % f)
1721 self.ui.warn(_("trouble committing %s!\n") % f)
1722 raise
1722 raise
1723 except IOError as inst:
1723 except IOError as inst:
1724 errcode = getattr(inst, 'errno', errno.ENOENT)
1724 errcode = getattr(inst, 'errno', errno.ENOENT)
1725 if error or errcode and errcode != errno.ENOENT:
1725 if error or errcode and errcode != errno.ENOENT:
1726 self.ui.warn(_("trouble committing %s!\n") % f)
1726 self.ui.warn(_("trouble committing %s!\n") % f)
1727 raise
1727 raise
1728
1728
1729 # update manifest
1729 # update manifest
1730 self.ui.note(_("committing manifest\n"))
1730 self.ui.note(_("committing manifest\n"))
1731 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1731 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1732 drop = [f for f in removed if f in m]
1732 drop = [f for f in removed if f in m]
1733 for f in drop:
1733 for f in drop:
1734 del m[f]
1734 del m[f]
1735 mn = self.manifestlog.add(m, trp, linkrev,
1735 mn = self.manifestlog.add(m, trp, linkrev,
1736 p1.manifestnode(), p2.manifestnode(),
1736 p1.manifestnode(), p2.manifestnode(),
1737 added, drop)
1737 added, drop)
1738 files = changed + removed
1738 files = changed + removed
1739 else:
1739 else:
1740 mn = p1.manifestnode()
1740 mn = p1.manifestnode()
1741 files = []
1741 files = []
1742
1742
1743 # update changelog
1743 # update changelog
1744 self.ui.note(_("committing changelog\n"))
1744 self.ui.note(_("committing changelog\n"))
1745 self.changelog.delayupdate(tr)
1745 self.changelog.delayupdate(tr)
1746 n = self.changelog.add(mn, files, ctx.description(),
1746 n = self.changelog.add(mn, files, ctx.description(),
1747 trp, p1.node(), p2.node(),
1747 trp, p1.node(), p2.node(),
1748 user, ctx.date(), ctx.extra().copy())
1748 user, ctx.date(), ctx.extra().copy())
1749 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1749 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1750 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1750 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1751 parent2=xp2)
1751 parent2=xp2)
1752 # set the new commit is proper phase
1752 # set the new commit is proper phase
1753 targetphase = subrepo.newcommitphase(self.ui, ctx)
1753 targetphase = subrepo.newcommitphase(self.ui, ctx)
1754 if targetphase:
1754 if targetphase:
1755 # retract boundary do not alter parent changeset.
1755 # retract boundary do not alter parent changeset.
1756 # if a parent have higher the resulting phase will
1756 # if a parent have higher the resulting phase will
1757 # be compliant anyway
1757 # be compliant anyway
1758 #
1758 #
1759 # if minimal phase was 0 we don't need to retract anything
1759 # if minimal phase was 0 we don't need to retract anything
1760 phases.retractboundary(self, tr, targetphase, [n])
1760 phases.retractboundary(self, tr, targetphase, [n])
1761 tr.close()
1761 tr.close()
1762 branchmap.updatecache(self.filtered('served'))
1762 branchmap.updatecache(self.filtered('served'))
1763 return n
1763 return n
1764 finally:
1764 finally:
1765 if tr:
1765 if tr:
1766 tr.release()
1766 tr.release()
1767 lock.release()
1767 lock.release()
1768
1768
1769 @unfilteredmethod
1769 @unfilteredmethod
1770 def destroying(self):
1770 def destroying(self):
1771 '''Inform the repository that nodes are about to be destroyed.
1771 '''Inform the repository that nodes are about to be destroyed.
1772 Intended for use by strip and rollback, so there's a common
1772 Intended for use by strip and rollback, so there's a common
1773 place for anything that has to be done before destroying history.
1773 place for anything that has to be done before destroying history.
1774
1774
1775 This is mostly useful for saving state that is in memory and waiting
1775 This is mostly useful for saving state that is in memory and waiting
1776 to be flushed when the current lock is released. Because a call to
1776 to be flushed when the current lock is released. Because a call to
1777 destroyed is imminent, the repo will be invalidated causing those
1777 destroyed is imminent, the repo will be invalidated causing those
1778 changes to stay in memory (waiting for the next unlock), or vanish
1778 changes to stay in memory (waiting for the next unlock), or vanish
1779 completely.
1779 completely.
1780 '''
1780 '''
1781 # When using the same lock to commit and strip, the phasecache is left
1781 # When using the same lock to commit and strip, the phasecache is left
1782 # dirty after committing. Then when we strip, the repo is invalidated,
1782 # dirty after committing. Then when we strip, the repo is invalidated,
1783 # causing those changes to disappear.
1783 # causing those changes to disappear.
1784 if '_phasecache' in vars(self):
1784 if '_phasecache' in vars(self):
1785 self._phasecache.write()
1785 self._phasecache.write()
1786
1786
1787 @unfilteredmethod
1787 @unfilteredmethod
1788 def destroyed(self):
1788 def destroyed(self):
1789 '''Inform the repository that nodes have been destroyed.
1789 '''Inform the repository that nodes have been destroyed.
1790 Intended for use by strip and rollback, so there's a common
1790 Intended for use by strip and rollback, so there's a common
1791 place for anything that has to be done after destroying history.
1791 place for anything that has to be done after destroying history.
1792 '''
1792 '''
1793 # When one tries to:
1793 # When one tries to:
1794 # 1) destroy nodes thus calling this method (e.g. strip)
1794 # 1) destroy nodes thus calling this method (e.g. strip)
1795 # 2) use phasecache somewhere (e.g. commit)
1795 # 2) use phasecache somewhere (e.g. commit)
1796 #
1796 #
1797 # then 2) will fail because the phasecache contains nodes that were
1797 # then 2) will fail because the phasecache contains nodes that were
1798 # removed. We can either remove phasecache from the filecache,
1798 # removed. We can either remove phasecache from the filecache,
1799 # causing it to reload next time it is accessed, or simply filter
1799 # causing it to reload next time it is accessed, or simply filter
1800 # the removed nodes now and write the updated cache.
1800 # the removed nodes now and write the updated cache.
1801 self._phasecache.filterunknown(self)
1801 self._phasecache.filterunknown(self)
1802 self._phasecache.write()
1802 self._phasecache.write()
1803
1803
1804 # update the 'served' branch cache to help read only server process
1804 # update the 'served' branch cache to help read only server process
1805 # Thanks to branchcache collaboration this is done from the nearest
1805 # Thanks to branchcache collaboration this is done from the nearest
1806 # filtered subset and it is expected to be fast.
1806 # filtered subset and it is expected to be fast.
1807 branchmap.updatecache(self.filtered('served'))
1807 branchmap.updatecache(self.filtered('served'))
1808
1808
1809 # Ensure the persistent tag cache is updated. Doing it now
1809 # Ensure the persistent tag cache is updated. Doing it now
1810 # means that the tag cache only has to worry about destroyed
1810 # means that the tag cache only has to worry about destroyed
1811 # heads immediately after a strip/rollback. That in turn
1811 # heads immediately after a strip/rollback. That in turn
1812 # guarantees that "cachetip == currenttip" (comparing both rev
1812 # guarantees that "cachetip == currenttip" (comparing both rev
1813 # and node) always means no nodes have been added or destroyed.
1813 # and node) always means no nodes have been added or destroyed.
1814
1814
1815 # XXX this is suboptimal when qrefresh'ing: we strip the current
1815 # XXX this is suboptimal when qrefresh'ing: we strip the current
1816 # head, refresh the tag cache, then immediately add a new head.
1816 # head, refresh the tag cache, then immediately add a new head.
1817 # But I think doing it this way is necessary for the "instant
1817 # But I think doing it this way is necessary for the "instant
1818 # tag cache retrieval" case to work.
1818 # tag cache retrieval" case to work.
1819 self.invalidate()
1819 self.invalidate()
1820
1820
1821 def walk(self, match, node=None):
1821 def walk(self, match, node=None):
1822 '''
1822 '''
1823 walk recursively through the directory tree or a given
1823 walk recursively through the directory tree or a given
1824 changeset, finding all files matched by the match
1824 changeset, finding all files matched by the match
1825 function
1825 function
1826 '''
1826 '''
1827 return self[node].walk(match)
1827 return self[node].walk(match)
1828
1828
1829 def status(self, node1='.', node2=None, match=None,
1829 def status(self, node1='.', node2=None, match=None,
1830 ignored=False, clean=False, unknown=False,
1830 ignored=False, clean=False, unknown=False,
1831 listsubrepos=False):
1831 listsubrepos=False):
1832 '''a convenience method that calls node1.status(node2)'''
1832 '''a convenience method that calls node1.status(node2)'''
1833 return self[node1].status(node2, match, ignored, clean, unknown,
1833 return self[node1].status(node2, match, ignored, clean, unknown,
1834 listsubrepos)
1834 listsubrepos)
1835
1835
1836 def heads(self, start=None):
1836 def heads(self, start=None):
1837 heads = self.changelog.heads(start)
1837 heads = self.changelog.heads(start)
1838 # sort the output in rev descending order
1838 # sort the output in rev descending order
1839 return sorted(heads, key=self.changelog.rev, reverse=True)
1839 return sorted(heads, key=self.changelog.rev, reverse=True)
1840
1840
1841 def branchheads(self, branch=None, start=None, closed=False):
1841 def branchheads(self, branch=None, start=None, closed=False):
1842 '''return a (possibly filtered) list of heads for the given branch
1842 '''return a (possibly filtered) list of heads for the given branch
1843
1843
1844 Heads are returned in topological order, from newest to oldest.
1844 Heads are returned in topological order, from newest to oldest.
1845 If branch is None, use the dirstate branch.
1845 If branch is None, use the dirstate branch.
1846 If start is not None, return only heads reachable from start.
1846 If start is not None, return only heads reachable from start.
1847 If closed is True, return heads that are marked as closed as well.
1847 If closed is True, return heads that are marked as closed as well.
1848 '''
1848 '''
1849 if branch is None:
1849 if branch is None:
1850 branch = self[None].branch()
1850 branch = self[None].branch()
1851 branches = self.branchmap()
1851 branches = self.branchmap()
1852 if branch not in branches:
1852 if branch not in branches:
1853 return []
1853 return []
1854 # the cache returns heads ordered lowest to highest
1854 # the cache returns heads ordered lowest to highest
1855 bheads = list(reversed(branches.branchheads(branch, closed=closed)))
1855 bheads = list(reversed(branches.branchheads(branch, closed=closed)))
1856 if start is not None:
1856 if start is not None:
1857 # filter out the heads that cannot be reached from startrev
1857 # filter out the heads that cannot be reached from startrev
1858 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1858 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1859 bheads = [h for h in bheads if h in fbheads]
1859 bheads = [h for h in bheads if h in fbheads]
1860 return bheads
1860 return bheads
1861
1861
1862 def branches(self, nodes):
1862 def branches(self, nodes):
1863 if not nodes:
1863 if not nodes:
1864 nodes = [self.changelog.tip()]
1864 nodes = [self.changelog.tip()]
1865 b = []
1865 b = []
1866 for n in nodes:
1866 for n in nodes:
1867 t = n
1867 t = n
1868 while True:
1868 while True:
1869 p = self.changelog.parents(n)
1869 p = self.changelog.parents(n)
1870 if p[1] != nullid or p[0] == nullid:
1870 if p[1] != nullid or p[0] == nullid:
1871 b.append((t, n, p[0], p[1]))
1871 b.append((t, n, p[0], p[1]))
1872 break
1872 break
1873 n = p[0]
1873 n = p[0]
1874 return b
1874 return b
1875
1875
1876 def between(self, pairs):
1876 def between(self, pairs):
1877 r = []
1877 r = []
1878
1878
1879 for top, bottom in pairs:
1879 for top, bottom in pairs:
1880 n, l, i = top, [], 0
1880 n, l, i = top, [], 0
1881 f = 1
1881 f = 1
1882
1882
1883 while n != bottom and n != nullid:
1883 while n != bottom and n != nullid:
1884 p = self.changelog.parents(n)[0]
1884 p = self.changelog.parents(n)[0]
1885 if i == f:
1885 if i == f:
1886 l.append(n)
1886 l.append(n)
1887 f = f * 2
1887 f = f * 2
1888 n = p
1888 n = p
1889 i += 1
1889 i += 1
1890
1890
1891 r.append(l)
1891 r.append(l)
1892
1892
1893 return r
1893 return r
1894
1894
1895 def checkpush(self, pushop):
1895 def checkpush(self, pushop):
1896 """Extensions can override this function if additional checks have
1896 """Extensions can override this function if additional checks have
1897 to be performed before pushing, or call it if they override push
1897 to be performed before pushing, or call it if they override push
1898 command.
1898 command.
1899 """
1899 """
1900 pass
1900 pass
1901
1901
1902 @unfilteredpropertycache
1902 @unfilteredpropertycache
1903 def prepushoutgoinghooks(self):
1903 def prepushoutgoinghooks(self):
1904 """Return util.hooks consists of a pushop with repo, remote, outgoing
1904 """Return util.hooks consists of a pushop with repo, remote, outgoing
1905 methods, which are called before pushing changesets.
1905 methods, which are called before pushing changesets.
1906 """
1906 """
1907 return util.hooks()
1907 return util.hooks()
1908
1908
1909 def pushkey(self, namespace, key, old, new):
1909 def pushkey(self, namespace, key, old, new):
1910 try:
1910 try:
1911 tr = self.currenttransaction()
1911 tr = self.currenttransaction()
1912 hookargs = {}
1912 hookargs = {}
1913 if tr is not None:
1913 if tr is not None:
1914 hookargs.update(tr.hookargs)
1914 hookargs.update(tr.hookargs)
1915 hookargs['namespace'] = namespace
1915 hookargs['namespace'] = namespace
1916 hookargs['key'] = key
1916 hookargs['key'] = key
1917 hookargs['old'] = old
1917 hookargs['old'] = old
1918 hookargs['new'] = new
1918 hookargs['new'] = new
1919 self.hook('prepushkey', throw=True, **hookargs)
1919 self.hook('prepushkey', throw=True, **hookargs)
1920 except error.HookAbort as exc:
1920 except error.HookAbort as exc:
1921 self.ui.write_err(_("pushkey-abort: %s\n") % exc)
1921 self.ui.write_err(_("pushkey-abort: %s\n") % exc)
1922 if exc.hint:
1922 if exc.hint:
1923 self.ui.write_err(_("(%s)\n") % exc.hint)
1923 self.ui.write_err(_("(%s)\n") % exc.hint)
1924 return False
1924 return False
1925 self.ui.debug('pushing key for "%s:%s"\n' % (namespace, key))
1925 self.ui.debug('pushing key for "%s:%s"\n' % (namespace, key))
1926 ret = pushkey.push(self, namespace, key, old, new)
1926 ret = pushkey.push(self, namespace, key, old, new)
1927 def runhook():
1927 def runhook():
1928 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
1928 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
1929 ret=ret)
1929 ret=ret)
1930 self._afterlock(runhook)
1930 self._afterlock(runhook)
1931 return ret
1931 return ret
1932
1932
1933 def listkeys(self, namespace):
1933 def listkeys(self, namespace):
1934 self.hook('prelistkeys', throw=True, namespace=namespace)
1934 self.hook('prelistkeys', throw=True, namespace=namespace)
1935 self.ui.debug('listing keys for "%s"\n' % namespace)
1935 self.ui.debug('listing keys for "%s"\n' % namespace)
1936 values = pushkey.list(self, namespace)
1936 values = pushkey.list(self, namespace)
1937 self.hook('listkeys', namespace=namespace, values=values)
1937 self.hook('listkeys', namespace=namespace, values=values)
1938 return values
1938 return values
1939
1939
1940 def debugwireargs(self, one, two, three=None, four=None, five=None):
1940 def debugwireargs(self, one, two, three=None, four=None, five=None):
1941 '''used to test argument passing over the wire'''
1941 '''used to test argument passing over the wire'''
1942 return "%s %s %s %s %s" % (one, two, three, four, five)
1942 return "%s %s %s %s %s" % (one, two, three, four, five)
1943
1943
1944 def savecommitmessage(self, text):
1944 def savecommitmessage(self, text):
1945 fp = self.vfs('last-message.txt', 'wb')
1945 fp = self.vfs('last-message.txt', 'wb')
1946 try:
1946 try:
1947 fp.write(text)
1947 fp.write(text)
1948 finally:
1948 finally:
1949 fp.close()
1949 fp.close()
1950 return self.pathto(fp.name[len(self.root) + 1:])
1950 return self.pathto(fp.name[len(self.root) + 1:])
1951
1951
1952 # used to avoid circular references so destructors work
1952 # used to avoid circular references so destructors work
1953 def aftertrans(files):
1953 def aftertrans(files):
1954 renamefiles = [tuple(t) for t in files]
1954 renamefiles = [tuple(t) for t in files]
1955 def a():
1955 def a():
1956 for vfs, src, dest in renamefiles:
1956 for vfs, src, dest in renamefiles:
1957 try:
1957 try:
1958 vfs.rename(src, dest)
1958 vfs.rename(src, dest)
1959 except OSError: # journal file does not yet exist
1959 except OSError: # journal file does not yet exist
1960 pass
1960 pass
1961 return a
1961 return a
1962
1962
1963 def undoname(fn):
1963 def undoname(fn):
1964 base, name = os.path.split(fn)
1964 base, name = os.path.split(fn)
1965 assert name.startswith('journal')
1965 assert name.startswith('journal')
1966 return os.path.join(base, name.replace('journal', 'undo', 1))
1966 return os.path.join(base, name.replace('journal', 'undo', 1))
1967
1967
1968 def instance(ui, path, create):
1968 def instance(ui, path, create):
1969 return localrepository(ui, util.urllocalpath(path), create)
1969 return localrepository(ui, util.urllocalpath(path), create)
1970
1970
1971 def islocal(path):
1971 def islocal(path):
1972 return True
1972 return True
1973
1973
1974 def newreporequirements(repo):
1974 def newreporequirements(repo):
1975 """Determine the set of requirements for a new local repository.
1975 """Determine the set of requirements for a new local repository.
1976
1976
1977 Extensions can wrap this function to specify custom requirements for
1977 Extensions can wrap this function to specify custom requirements for
1978 new repositories.
1978 new repositories.
1979 """
1979 """
1980 ui = repo.ui
1980 ui = repo.ui
1981 requirements = set(['revlogv1'])
1981 requirements = set(['revlogv1'])
1982 if ui.configbool('format', 'usestore', True):
1982 if ui.configbool('format', 'usestore', True):
1983 requirements.add('store')
1983 requirements.add('store')
1984 if ui.configbool('format', 'usefncache', True):
1984 if ui.configbool('format', 'usefncache', True):
1985 requirements.add('fncache')
1985 requirements.add('fncache')
1986 if ui.configbool('format', 'dotencode', True):
1986 if ui.configbool('format', 'dotencode', True):
1987 requirements.add('dotencode')
1987 requirements.add('dotencode')
1988
1988
1989 if scmutil.gdinitconfig(ui):
1989 if scmutil.gdinitconfig(ui):
1990 requirements.add('generaldelta')
1990 requirements.add('generaldelta')
1991 if ui.configbool('experimental', 'treemanifest', False):
1991 if ui.configbool('experimental', 'treemanifest', False):
1992 requirements.add('treemanifest')
1992 requirements.add('treemanifest')
1993 if ui.configbool('experimental', 'manifestv2', False):
1993 if ui.configbool('experimental', 'manifestv2', False):
1994 requirements.add('manifestv2')
1994 requirements.add('manifestv2')
1995
1995
1996 return requirements
1996 return requirements
@@ -1,67 +1,67 b''
1 $ addcommit () {
1 $ addcommit () {
2 > echo $1 > $1
2 > echo $1 > $1
3 > hg add $1
3 > hg add $1
4 > hg commit -d "${2} 0" -m $1
4 > hg commit -d "${2} 0" -m $1
5 > }
5 > }
6
6
7 $ commit () {
7 $ commit () {
8 > hg commit -d "${2} 0" -m $1
8 > hg commit -d "${2} 0" -m $1
9 > }
9 > }
10
10
11 $ hg init a
11 $ hg init a
12 $ cd a
12 $ cd a
13 $ addcommit "A" 0
13 $ addcommit "A" 0
14 $ addcommit "B" 1
14 $ addcommit "B" 1
15 $ echo "C" >> A
15 $ echo "C" >> A
16 $ commit "C" 2
16 $ commit "C" 2
17
17
18 $ hg update -C 0
18 $ hg update -C 0
19 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
19 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
20 $ echo "D" >> A
20 $ echo "D" >> A
21 $ commit "D" 3
21 $ commit "D" 3
22 created new head
22 created new head
23
23
24 Merging a conflict araises
24 Merging a conflict araises
25
25
26 $ hg merge
26 $ hg merge
27 merging A
27 merging A
28 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
28 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
29 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
29 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
30 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
30 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
31 [1]
31 [1]
32
32
33 Correct the conflict without marking the file as resolved
33 Correct the conflict without marking the file as resolved
34
34
35 $ echo "ABCD" > A
35 $ echo "ABCD" > A
36 $ hg commit -m "Merged"
36 $ hg commit -m "Merged"
37 abort: unresolved merge conflicts (see "hg help resolve")
37 abort: unresolved merge conflicts (see 'hg help resolve')
38 [255]
38 [255]
39
39
40 Mark the conflict as resolved and commit
40 Mark the conflict as resolved and commit
41
41
42 $ hg resolve -m A
42 $ hg resolve -m A
43 (no more unresolved files)
43 (no more unresolved files)
44 $ hg commit -m "Merged"
44 $ hg commit -m "Merged"
45
45
46 Test that if a file is removed but not marked resolved, the commit still fails
46 Test that if a file is removed but not marked resolved, the commit still fails
47 (issue4972)
47 (issue4972)
48
48
49 $ hg up ".^"
49 $ hg up ".^"
50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 $ hg merge 2
51 $ hg merge 2
52 merging A
52 merging A
53 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
53 warning: conflicts while merging A! (edit, then use 'hg resolve --mark')
54 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
54 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
55 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
55 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
56 [1]
56 [1]
57 $ hg rm --force A
57 $ hg rm --force A
58 $ hg commit -m merged
58 $ hg commit -m merged
59 abort: unresolved merge conflicts (see "hg help resolve")
59 abort: unresolved merge conflicts (see 'hg help resolve')
60 [255]
60 [255]
61
61
62 $ hg resolve -ma
62 $ hg resolve -ma
63 (no more unresolved files)
63 (no more unresolved files)
64 $ hg commit -m merged
64 $ hg commit -m merged
65 created new head
65 created new head
66
66
67 $ cd ..
67 $ cd ..
@@ -1,844 +1,844 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extdiff]
2 > [extdiff]
3 > # for portability:
3 > # for portability:
4 > pdiff = sh "$RUNTESTDIR/pdiff"
4 > pdiff = sh "$RUNTESTDIR/pdiff"
5 > EOF
5 > EOF
6
6
7 Create a repo with some stuff in it:
7 Create a repo with some stuff in it:
8
8
9 $ hg init a
9 $ hg init a
10 $ cd a
10 $ cd a
11 $ echo a > a
11 $ echo a > a
12 $ echo a > d
12 $ echo a > d
13 $ echo a > e
13 $ echo a > e
14 $ hg ci -qAm0
14 $ hg ci -qAm0
15 $ echo b > a
15 $ echo b > a
16 $ hg ci -m1 -u bar
16 $ hg ci -m1 -u bar
17 $ hg mv a b
17 $ hg mv a b
18 $ hg ci -m2
18 $ hg ci -m2
19 $ hg cp b c
19 $ hg cp b c
20 $ hg ci -m3 -u baz
20 $ hg ci -m3 -u baz
21 $ echo b > d
21 $ echo b > d
22 $ echo f > e
22 $ echo f > e
23 $ hg ci -m4
23 $ hg ci -m4
24 $ hg up -q 3
24 $ hg up -q 3
25 $ echo b > e
25 $ echo b > e
26 $ hg branch -q stable
26 $ hg branch -q stable
27 $ hg ci -m5
27 $ hg ci -m5
28 $ hg merge -q default --tool internal:local
28 $ hg merge -q default --tool internal:local
29 $ hg branch -q default
29 $ hg branch -q default
30 $ hg ci -m6
30 $ hg ci -m6
31 $ hg phase --public 3
31 $ hg phase --public 3
32 $ hg phase --force --secret 6
32 $ hg phase --force --secret 6
33
33
34 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
34 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
35 @ test@6.secret: 6
35 @ test@6.secret: 6
36 |\
36 |\
37 | o test@5.draft: 5
37 | o test@5.draft: 5
38 | |
38 | |
39 o | test@4.draft: 4
39 o | test@4.draft: 4
40 |/
40 |/
41 o baz@3.public: 3
41 o baz@3.public: 3
42 |
42 |
43 o test@2.public: 2
43 o test@2.public: 2
44 |
44 |
45 o bar@1.public: 1
45 o bar@1.public: 1
46 |
46 |
47 o test@0.public: 0
47 o test@0.public: 0
48
48
49 Can't continue without starting:
49 Can't continue without starting:
50
50
51 $ hg rm -q e
51 $ hg rm -q e
52 $ hg graft --continue
52 $ hg graft --continue
53 abort: no graft in progress
53 abort: no graft in progress
54 [255]
54 [255]
55 $ hg revert -r . -q e
55 $ hg revert -r . -q e
56
56
57 Need to specify a rev:
57 Need to specify a rev:
58
58
59 $ hg graft
59 $ hg graft
60 abort: no revisions specified
60 abort: no revisions specified
61 [255]
61 [255]
62
62
63 Can't graft ancestor:
63 Can't graft ancestor:
64
64
65 $ hg graft 1 2
65 $ hg graft 1 2
66 skipping ancestor revision 1:5d205f8b35b6
66 skipping ancestor revision 1:5d205f8b35b6
67 skipping ancestor revision 2:5c095ad7e90f
67 skipping ancestor revision 2:5c095ad7e90f
68 [255]
68 [255]
69
69
70 Specify revisions with -r:
70 Specify revisions with -r:
71
71
72 $ hg graft -r 1 -r 2
72 $ hg graft -r 1 -r 2
73 skipping ancestor revision 1:5d205f8b35b6
73 skipping ancestor revision 1:5d205f8b35b6
74 skipping ancestor revision 2:5c095ad7e90f
74 skipping ancestor revision 2:5c095ad7e90f
75 [255]
75 [255]
76
76
77 $ hg graft -r 1 2
77 $ hg graft -r 1 2
78 warning: inconsistent use of --rev might give unexpected revision ordering!
78 warning: inconsistent use of --rev might give unexpected revision ordering!
79 skipping ancestor revision 2:5c095ad7e90f
79 skipping ancestor revision 2:5c095ad7e90f
80 skipping ancestor revision 1:5d205f8b35b6
80 skipping ancestor revision 1:5d205f8b35b6
81 [255]
81 [255]
82
82
83 Can't graft with dirty wd:
83 Can't graft with dirty wd:
84
84
85 $ hg up -q 0
85 $ hg up -q 0
86 $ echo foo > a
86 $ echo foo > a
87 $ hg graft 1
87 $ hg graft 1
88 abort: uncommitted changes
88 abort: uncommitted changes
89 [255]
89 [255]
90 $ hg revert a
90 $ hg revert a
91
91
92 Graft a rename:
92 Graft a rename:
93 (this also tests that editor is invoked if '--edit' is specified)
93 (this also tests that editor is invoked if '--edit' is specified)
94
94
95 $ hg status --rev "2^1" --rev 2
95 $ hg status --rev "2^1" --rev 2
96 A b
96 A b
97 R a
97 R a
98 $ HGEDITOR=cat hg graft 2 -u foo --edit
98 $ HGEDITOR=cat hg graft 2 -u foo --edit
99 grafting 2:5c095ad7e90f "2"
99 grafting 2:5c095ad7e90f "2"
100 merging a and b to b
100 merging a and b to b
101 2
101 2
102
102
103
103
104 HG: Enter commit message. Lines beginning with 'HG:' are removed.
104 HG: Enter commit message. Lines beginning with 'HG:' are removed.
105 HG: Leave message empty to abort commit.
105 HG: Leave message empty to abort commit.
106 HG: --
106 HG: --
107 HG: user: foo
107 HG: user: foo
108 HG: branch 'default'
108 HG: branch 'default'
109 HG: added b
109 HG: added b
110 HG: removed a
110 HG: removed a
111 $ hg export tip --git
111 $ hg export tip --git
112 # HG changeset patch
112 # HG changeset patch
113 # User foo
113 # User foo
114 # Date 0 0
114 # Date 0 0
115 # Thu Jan 01 00:00:00 1970 +0000
115 # Thu Jan 01 00:00:00 1970 +0000
116 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
116 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
117 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
117 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
118 2
118 2
119
119
120 diff --git a/a b/b
120 diff --git a/a b/b
121 rename from a
121 rename from a
122 rename to b
122 rename to b
123
123
124 Look for extra:source
124 Look for extra:source
125
125
126 $ hg log --debug -r tip
126 $ hg log --debug -r tip
127 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
127 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
128 tag: tip
128 tag: tip
129 phase: draft
129 phase: draft
130 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
130 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
131 parent: -1:0000000000000000000000000000000000000000
131 parent: -1:0000000000000000000000000000000000000000
132 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
132 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
133 user: foo
133 user: foo
134 date: Thu Jan 01 00:00:00 1970 +0000
134 date: Thu Jan 01 00:00:00 1970 +0000
135 files+: b
135 files+: b
136 files-: a
136 files-: a
137 extra: branch=default
137 extra: branch=default
138 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
138 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
139 description:
139 description:
140 2
140 2
141
141
142
142
143
143
144 Graft out of order, skipping a merge and a duplicate
144 Graft out of order, skipping a merge and a duplicate
145 (this also tests that editor is not invoked if '--edit' is not specified)
145 (this also tests that editor is not invoked if '--edit' is not specified)
146
146
147 $ hg graft 1 5 4 3 'merge()' 2 -n
147 $ hg graft 1 5 4 3 'merge()' 2 -n
148 skipping ungraftable merge revision 6
148 skipping ungraftable merge revision 6
149 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
149 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
150 grafting 1:5d205f8b35b6 "1"
150 grafting 1:5d205f8b35b6 "1"
151 grafting 5:97f8bfe72746 "5"
151 grafting 5:97f8bfe72746 "5"
152 grafting 4:9c233e8e184d "4"
152 grafting 4:9c233e8e184d "4"
153 grafting 3:4c60f11aa304 "3"
153 grafting 3:4c60f11aa304 "3"
154
154
155 $ HGEDITOR=cat hg graft 1 5 'merge()' 2 --debug
155 $ HGEDITOR=cat hg graft 1 5 'merge()' 2 --debug
156 skipping ungraftable merge revision 6
156 skipping ungraftable merge revision 6
157 scanning for duplicate grafts
157 scanning for duplicate grafts
158 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
158 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
159 grafting 1:5d205f8b35b6 "1"
159 grafting 1:5d205f8b35b6 "1"
160 searching for copies back to rev 1
160 searching for copies back to rev 1
161 unmatched files in local:
161 unmatched files in local:
162 b
162 b
163 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
163 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
164 src: 'a' -> dst: 'b' *
164 src: 'a' -> dst: 'b' *
165 checking for directory renames
165 checking for directory renames
166 resolving manifests
166 resolving manifests
167 branchmerge: True, force: True, partial: False
167 branchmerge: True, force: True, partial: False
168 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
168 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
169 preserving b for resolve of b
169 preserving b for resolve of b
170 starting 4 threads for background file closing (?)
170 starting 4 threads for background file closing (?)
171 b: local copied/moved from a -> m (premerge)
171 b: local copied/moved from a -> m (premerge)
172 picked tool ':merge' for b (binary False symlink False changedelete False)
172 picked tool ':merge' for b (binary False symlink False changedelete False)
173 merging b and a to b
173 merging b and a to b
174 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
174 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
175 premerge successful
175 premerge successful
176 committing files:
176 committing files:
177 b
177 b
178 committing manifest
178 committing manifest
179 committing changelog
179 committing changelog
180 grafting 5:97f8bfe72746 "5"
180 grafting 5:97f8bfe72746 "5"
181 searching for copies back to rev 1
181 searching for copies back to rev 1
182 resolving manifests
182 resolving manifests
183 branchmerge: True, force: True, partial: False
183 branchmerge: True, force: True, partial: False
184 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
184 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
185 e: remote is newer -> g
185 e: remote is newer -> g
186 getting e
186 getting e
187 b: remote unchanged -> k
187 b: remote unchanged -> k
188 committing files:
188 committing files:
189 e
189 e
190 committing manifest
190 committing manifest
191 committing changelog
191 committing changelog
192 $ HGEDITOR=cat hg graft 4 3 --log --debug
192 $ HGEDITOR=cat hg graft 4 3 --log --debug
193 scanning for duplicate grafts
193 scanning for duplicate grafts
194 grafting 4:9c233e8e184d "4"
194 grafting 4:9c233e8e184d "4"
195 searching for copies back to rev 1
195 searching for copies back to rev 1
196 resolving manifests
196 resolving manifests
197 branchmerge: True, force: True, partial: False
197 branchmerge: True, force: True, partial: False
198 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
198 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
199 preserving e for resolve of e
199 preserving e for resolve of e
200 d: remote is newer -> g
200 d: remote is newer -> g
201 getting d
201 getting d
202 b: remote unchanged -> k
202 b: remote unchanged -> k
203 e: versions differ -> m (premerge)
203 e: versions differ -> m (premerge)
204 picked tool ':merge' for e (binary False symlink False changedelete False)
204 picked tool ':merge' for e (binary False symlink False changedelete False)
205 merging e
205 merging e
206 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
206 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
207 e: versions differ -> m (merge)
207 e: versions differ -> m (merge)
208 picked tool ':merge' for e (binary False symlink False changedelete False)
208 picked tool ':merge' for e (binary False symlink False changedelete False)
209 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
209 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
210 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
210 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
211 abort: unresolved conflicts, can't continue
211 abort: unresolved conflicts, can't continue
212 (use 'hg resolve' and 'hg graft --continue --log')
212 (use 'hg resolve' and 'hg graft --continue --log')
213 [255]
213 [255]
214
214
215 Summary should mention graft:
215 Summary should mention graft:
216
216
217 $ hg summary |grep graft
217 $ hg summary |grep graft
218 commit: 2 modified, 2 unknown, 1 unresolved (graft in progress)
218 commit: 2 modified, 2 unknown, 1 unresolved (graft in progress)
219
219
220 Commit while interrupted should fail:
220 Commit while interrupted should fail:
221
221
222 $ hg ci -m 'commit interrupted graft'
222 $ hg ci -m 'commit interrupted graft'
223 abort: graft in progress
223 abort: graft in progress
224 (use 'hg graft --continue' or 'hg update' to abort)
224 (use 'hg graft --continue' or 'hg update' to abort)
225 [255]
225 [255]
226
226
227 Abort the graft and try committing:
227 Abort the graft and try committing:
228
228
229 $ hg up -C .
229 $ hg up -C .
230 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
230 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 $ echo c >> e
231 $ echo c >> e
232 $ hg ci -mtest
232 $ hg ci -mtest
233
233
234 $ hg strip . --config extensions.strip=
234 $ hg strip . --config extensions.strip=
235 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
236 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
237
237
238 Graft again:
238 Graft again:
239
239
240 $ hg graft 1 5 4 3 'merge()' 2
240 $ hg graft 1 5 4 3 'merge()' 2
241 skipping ungraftable merge revision 6
241 skipping ungraftable merge revision 6
242 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
242 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
243 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
243 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
244 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
244 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
245 grafting 4:9c233e8e184d "4"
245 grafting 4:9c233e8e184d "4"
246 merging e
246 merging e
247 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
247 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
248 abort: unresolved conflicts, can't continue
248 abort: unresolved conflicts, can't continue
249 (use 'hg resolve' and 'hg graft --continue')
249 (use 'hg resolve' and 'hg graft --continue')
250 [255]
250 [255]
251
251
252 Continue without resolve should fail:
252 Continue without resolve should fail:
253
253
254 $ hg graft -c
254 $ hg graft -c
255 grafting 4:9c233e8e184d "4"
255 grafting 4:9c233e8e184d "4"
256 abort: unresolved merge conflicts (see "hg help resolve")
256 abort: unresolved merge conflicts (see 'hg help resolve')
257 [255]
257 [255]
258
258
259 Fix up:
259 Fix up:
260
260
261 $ echo b > e
261 $ echo b > e
262 $ hg resolve -m e
262 $ hg resolve -m e
263 (no more unresolved files)
263 (no more unresolved files)
264 continue: hg graft --continue
264 continue: hg graft --continue
265
265
266 Continue with a revision should fail:
266 Continue with a revision should fail:
267
267
268 $ hg graft -c 6
268 $ hg graft -c 6
269 abort: can't specify --continue and revisions
269 abort: can't specify --continue and revisions
270 [255]
270 [255]
271
271
272 $ hg graft -c -r 6
272 $ hg graft -c -r 6
273 abort: can't specify --continue and revisions
273 abort: can't specify --continue and revisions
274 [255]
274 [255]
275
275
276 Continue for real, clobber usernames
276 Continue for real, clobber usernames
277
277
278 $ hg graft -c -U
278 $ hg graft -c -U
279 grafting 4:9c233e8e184d "4"
279 grafting 4:9c233e8e184d "4"
280 grafting 3:4c60f11aa304 "3"
280 grafting 3:4c60f11aa304 "3"
281
281
282 Compare with original:
282 Compare with original:
283
283
284 $ hg diff -r 6
284 $ hg diff -r 6
285 $ hg status --rev 0:. -C
285 $ hg status --rev 0:. -C
286 M d
286 M d
287 M e
287 M e
288 A b
288 A b
289 a
289 a
290 A c
290 A c
291 a
291 a
292 R a
292 R a
293
293
294 View graph:
294 View graph:
295
295
296 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
296 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
297 @ test@11.draft: 3
297 @ test@11.draft: 3
298 |
298 |
299 o test@10.draft: 4
299 o test@10.draft: 4
300 |
300 |
301 o test@9.draft: 5
301 o test@9.draft: 5
302 |
302 |
303 o bar@8.draft: 1
303 o bar@8.draft: 1
304 |
304 |
305 o foo@7.draft: 2
305 o foo@7.draft: 2
306 |
306 |
307 | o test@6.secret: 6
307 | o test@6.secret: 6
308 | |\
308 | |\
309 | | o test@5.draft: 5
309 | | o test@5.draft: 5
310 | | |
310 | | |
311 | o | test@4.draft: 4
311 | o | test@4.draft: 4
312 | |/
312 | |/
313 | o baz@3.public: 3
313 | o baz@3.public: 3
314 | |
314 | |
315 | o test@2.public: 2
315 | o test@2.public: 2
316 | |
316 | |
317 | o bar@1.public: 1
317 | o bar@1.public: 1
318 |/
318 |/
319 o test@0.public: 0
319 o test@0.public: 0
320
320
321 Graft again onto another branch should preserve the original source
321 Graft again onto another branch should preserve the original source
322 $ hg up -q 0
322 $ hg up -q 0
323 $ echo 'g'>g
323 $ echo 'g'>g
324 $ hg add g
324 $ hg add g
325 $ hg ci -m 7
325 $ hg ci -m 7
326 created new head
326 created new head
327 $ hg graft 7
327 $ hg graft 7
328 grafting 7:ef0ef43d49e7 "2"
328 grafting 7:ef0ef43d49e7 "2"
329
329
330 $ hg log -r 7 --template '{rev}:{node}\n'
330 $ hg log -r 7 --template '{rev}:{node}\n'
331 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
331 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
332 $ hg log -r 2 --template '{rev}:{node}\n'
332 $ hg log -r 2 --template '{rev}:{node}\n'
333 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
333 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
334
334
335 $ hg log --debug -r tip
335 $ hg log --debug -r tip
336 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
336 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
337 tag: tip
337 tag: tip
338 phase: draft
338 phase: draft
339 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
339 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
340 parent: -1:0000000000000000000000000000000000000000
340 parent: -1:0000000000000000000000000000000000000000
341 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
341 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
342 user: foo
342 user: foo
343 date: Thu Jan 01 00:00:00 1970 +0000
343 date: Thu Jan 01 00:00:00 1970 +0000
344 files+: b
344 files+: b
345 files-: a
345 files-: a
346 extra: branch=default
346 extra: branch=default
347 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
347 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
348 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
348 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
349 description:
349 description:
350 2
350 2
351
351
352
352
353 Disallow grafting an already grafted cset onto its original branch
353 Disallow grafting an already grafted cset onto its original branch
354 $ hg up -q 6
354 $ hg up -q 6
355 $ hg graft 7
355 $ hg graft 7
356 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
356 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
357 [255]
357 [255]
358
358
359 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13
359 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13
360 --- */hg-5c095ad7e90f.patch * (glob)
360 --- */hg-5c095ad7e90f.patch * (glob)
361 +++ */hg-7a4785234d87.patch * (glob)
361 +++ */hg-7a4785234d87.patch * (glob)
362 @@ -1,18 +1,18 @@
362 @@ -1,18 +1,18 @@
363 # HG changeset patch
363 # HG changeset patch
364 -# User test
364 -# User test
365 +# User foo
365 +# User foo
366 # Date 0 0
366 # Date 0 0
367 # Thu Jan 01 00:00:00 1970 +0000
367 # Thu Jan 01 00:00:00 1970 +0000
368 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
368 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
369 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
369 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
370 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
370 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
371 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
371 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
372 2
372 2
373
373
374 -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
374 -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
375 +diff -r b592ea63bb0c -r 7a4785234d87 a
375 +diff -r b592ea63bb0c -r 7a4785234d87 a
376 --- a/a Thu Jan 01 00:00:00 1970 +0000
376 --- a/a Thu Jan 01 00:00:00 1970 +0000
377 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
377 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
378 @@ -1,1 +0,0 @@
378 @@ -1,1 +0,0 @@
379 --b
379 --b
380 -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
380 -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
381 +-a
381 +-a
382 +diff -r b592ea63bb0c -r 7a4785234d87 b
382 +diff -r b592ea63bb0c -r 7a4785234d87 b
383 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
383 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
384 +++ b/b Thu Jan 01 00:00:00 1970 +0000
384 +++ b/b Thu Jan 01 00:00:00 1970 +0000
385 @@ -0,0 +1,1 @@
385 @@ -0,0 +1,1 @@
386 -+b
386 -+b
387 ++a
387 ++a
388 [1]
388 [1]
389
389
390 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
390 $ hg pdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
391 --- */hg-5c095ad7e90f.patch * (glob)
391 --- */hg-5c095ad7e90f.patch * (glob)
392 +++ */hg-7a4785234d87.patch * (glob)
392 +++ */hg-7a4785234d87.patch * (glob)
393 @@ -1,8 +1,8 @@
393 @@ -1,8 +1,8 @@
394 # HG changeset patch
394 # HG changeset patch
395 -# User test
395 -# User test
396 +# User foo
396 +# User foo
397 # Date 0 0
397 # Date 0 0
398 # Thu Jan 01 00:00:00 1970 +0000
398 # Thu Jan 01 00:00:00 1970 +0000
399 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
399 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
400 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
400 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
401 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
401 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
402 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
402 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
403 2
403 2
404
404
405 [1]
405 [1]
406
406
407 Disallow grafting already grafted csets with the same origin onto each other
407 Disallow grafting already grafted csets with the same origin onto each other
408 $ hg up -q 13
408 $ hg up -q 13
409 $ hg graft 2
409 $ hg graft 2
410 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
410 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
411 [255]
411 [255]
412 $ hg graft 7
412 $ hg graft 7
413 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
413 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
414 [255]
414 [255]
415
415
416 $ hg up -q 7
416 $ hg up -q 7
417 $ hg graft 2
417 $ hg graft 2
418 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
418 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
419 [255]
419 [255]
420 $ hg graft tip
420 $ hg graft tip
421 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
421 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
422 [255]
422 [255]
423
423
424 Graft with --log
424 Graft with --log
425
425
426 $ hg up -Cq 1
426 $ hg up -Cq 1
427 $ hg graft 3 --log -u foo
427 $ hg graft 3 --log -u foo
428 grafting 3:4c60f11aa304 "3"
428 grafting 3:4c60f11aa304 "3"
429 warning: can't find ancestor for 'c' copied from 'b'!
429 warning: can't find ancestor for 'c' copied from 'b'!
430 $ hg log --template '{rev} {parents} {desc}\n' -r tip
430 $ hg log --template '{rev} {parents} {desc}\n' -r tip
431 14 1:5d205f8b35b6 3
431 14 1:5d205f8b35b6 3
432 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
432 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
433
433
434 Resolve conflicted graft
434 Resolve conflicted graft
435 $ hg up -q 0
435 $ hg up -q 0
436 $ echo b > a
436 $ echo b > a
437 $ hg ci -m 8
437 $ hg ci -m 8
438 created new head
438 created new head
439 $ echo c > a
439 $ echo c > a
440 $ hg ci -m 9
440 $ hg ci -m 9
441 $ hg graft 1 --tool internal:fail
441 $ hg graft 1 --tool internal:fail
442 grafting 1:5d205f8b35b6 "1"
442 grafting 1:5d205f8b35b6 "1"
443 abort: unresolved conflicts, can't continue
443 abort: unresolved conflicts, can't continue
444 (use 'hg resolve' and 'hg graft --continue')
444 (use 'hg resolve' and 'hg graft --continue')
445 [255]
445 [255]
446 $ hg resolve --all
446 $ hg resolve --all
447 merging a
447 merging a
448 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
448 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
449 [1]
449 [1]
450 $ cat a
450 $ cat a
451 <<<<<<< local: aaa4406d4f0a - test: 9
451 <<<<<<< local: aaa4406d4f0a - test: 9
452 c
452 c
453 =======
453 =======
454 b
454 b
455 >>>>>>> graft: 5d205f8b35b6 - bar: 1
455 >>>>>>> graft: 5d205f8b35b6 - bar: 1
456 $ echo b > a
456 $ echo b > a
457 $ hg resolve -m a
457 $ hg resolve -m a
458 (no more unresolved files)
458 (no more unresolved files)
459 continue: hg graft --continue
459 continue: hg graft --continue
460 $ hg graft -c
460 $ hg graft -c
461 grafting 1:5d205f8b35b6 "1"
461 grafting 1:5d205f8b35b6 "1"
462 $ hg export tip --git
462 $ hg export tip --git
463 # HG changeset patch
463 # HG changeset patch
464 # User bar
464 # User bar
465 # Date 0 0
465 # Date 0 0
466 # Thu Jan 01 00:00:00 1970 +0000
466 # Thu Jan 01 00:00:00 1970 +0000
467 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
467 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
468 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
468 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
469 1
469 1
470
470
471 diff --git a/a b/a
471 diff --git a/a b/a
472 --- a/a
472 --- a/a
473 +++ b/a
473 +++ b/a
474 @@ -1,1 +1,1 @@
474 @@ -1,1 +1,1 @@
475 -c
475 -c
476 +b
476 +b
477
477
478 Resolve conflicted graft with rename
478 Resolve conflicted graft with rename
479 $ echo c > a
479 $ echo c > a
480 $ hg ci -m 10
480 $ hg ci -m 10
481 $ hg graft 2 --tool internal:fail
481 $ hg graft 2 --tool internal:fail
482 grafting 2:5c095ad7e90f "2"
482 grafting 2:5c095ad7e90f "2"
483 abort: unresolved conflicts, can't continue
483 abort: unresolved conflicts, can't continue
484 (use 'hg resolve' and 'hg graft --continue')
484 (use 'hg resolve' and 'hg graft --continue')
485 [255]
485 [255]
486 $ hg resolve --all
486 $ hg resolve --all
487 merging a and b to b
487 merging a and b to b
488 (no more unresolved files)
488 (no more unresolved files)
489 continue: hg graft --continue
489 continue: hg graft --continue
490 $ hg graft -c
490 $ hg graft -c
491 grafting 2:5c095ad7e90f "2"
491 grafting 2:5c095ad7e90f "2"
492 $ hg export tip --git
492 $ hg export tip --git
493 # HG changeset patch
493 # HG changeset patch
494 # User test
494 # User test
495 # Date 0 0
495 # Date 0 0
496 # Thu Jan 01 00:00:00 1970 +0000
496 # Thu Jan 01 00:00:00 1970 +0000
497 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
497 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
498 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
498 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
499 2
499 2
500
500
501 diff --git a/a b/b
501 diff --git a/a b/b
502 rename from a
502 rename from a
503 rename to b
503 rename to b
504
504
505 Test simple origin(), with and without args
505 Test simple origin(), with and without args
506 $ hg log -r 'origin()'
506 $ hg log -r 'origin()'
507 changeset: 1:5d205f8b35b6
507 changeset: 1:5d205f8b35b6
508 user: bar
508 user: bar
509 date: Thu Jan 01 00:00:00 1970 +0000
509 date: Thu Jan 01 00:00:00 1970 +0000
510 summary: 1
510 summary: 1
511
511
512 changeset: 2:5c095ad7e90f
512 changeset: 2:5c095ad7e90f
513 user: test
513 user: test
514 date: Thu Jan 01 00:00:00 1970 +0000
514 date: Thu Jan 01 00:00:00 1970 +0000
515 summary: 2
515 summary: 2
516
516
517 changeset: 3:4c60f11aa304
517 changeset: 3:4c60f11aa304
518 user: baz
518 user: baz
519 date: Thu Jan 01 00:00:00 1970 +0000
519 date: Thu Jan 01 00:00:00 1970 +0000
520 summary: 3
520 summary: 3
521
521
522 changeset: 4:9c233e8e184d
522 changeset: 4:9c233e8e184d
523 user: test
523 user: test
524 date: Thu Jan 01 00:00:00 1970 +0000
524 date: Thu Jan 01 00:00:00 1970 +0000
525 summary: 4
525 summary: 4
526
526
527 changeset: 5:97f8bfe72746
527 changeset: 5:97f8bfe72746
528 branch: stable
528 branch: stable
529 parent: 3:4c60f11aa304
529 parent: 3:4c60f11aa304
530 user: test
530 user: test
531 date: Thu Jan 01 00:00:00 1970 +0000
531 date: Thu Jan 01 00:00:00 1970 +0000
532 summary: 5
532 summary: 5
533
533
534 $ hg log -r 'origin(7)'
534 $ hg log -r 'origin(7)'
535 changeset: 2:5c095ad7e90f
535 changeset: 2:5c095ad7e90f
536 user: test
536 user: test
537 date: Thu Jan 01 00:00:00 1970 +0000
537 date: Thu Jan 01 00:00:00 1970 +0000
538 summary: 2
538 summary: 2
539
539
540 Now transplant a graft to test following through copies
540 Now transplant a graft to test following through copies
541 $ hg up -q 0
541 $ hg up -q 0
542 $ hg branch -q dev
542 $ hg branch -q dev
543 $ hg ci -qm "dev branch"
543 $ hg ci -qm "dev branch"
544 $ hg --config extensions.transplant= transplant -q 7
544 $ hg --config extensions.transplant= transplant -q 7
545 $ hg log -r 'origin(.)'
545 $ hg log -r 'origin(.)'
546 changeset: 2:5c095ad7e90f
546 changeset: 2:5c095ad7e90f
547 user: test
547 user: test
548 date: Thu Jan 01 00:00:00 1970 +0000
548 date: Thu Jan 01 00:00:00 1970 +0000
549 summary: 2
549 summary: 2
550
550
551 Test that the graft and transplant markers in extra are converted, allowing
551 Test that the graft and transplant markers in extra are converted, allowing
552 origin() to still work. Note that these recheck the immediately preceeding two
552 origin() to still work. Note that these recheck the immediately preceeding two
553 tests.
553 tests.
554 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
554 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
555
555
556 The graft case
556 The graft case
557 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
557 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
558 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
558 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
559 branch=default
559 branch=default
560 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
560 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
561 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
561 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
562 $ hg -R ../converted log -r 'origin(7)'
562 $ hg -R ../converted log -r 'origin(7)'
563 changeset: 2:e0213322b2c1
563 changeset: 2:e0213322b2c1
564 user: test
564 user: test
565 date: Thu Jan 01 00:00:00 1970 +0000
565 date: Thu Jan 01 00:00:00 1970 +0000
566 summary: 2
566 summary: 2
567
567
568 Test that template correctly expands more than one 'extra' (issue4362), and that
568 Test that template correctly expands more than one 'extra' (issue4362), and that
569 'intermediate-source' is converted.
569 'intermediate-source' is converted.
570 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
570 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
571 Extra: branch=default
571 Extra: branch=default
572 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
572 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
573 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
573 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
574 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
574 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
575
575
576 The transplant case
576 The transplant case
577 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
577 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
578 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
578 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
579 branch=dev
579 branch=dev
580 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
580 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
581 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
581 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
582 `h\x9b (esc)
582 `h\x9b (esc)
583 $ hg -R ../converted log -r 'origin(tip)'
583 $ hg -R ../converted log -r 'origin(tip)'
584 changeset: 2:e0213322b2c1
584 changeset: 2:e0213322b2c1
585 user: test
585 user: test
586 date: Thu Jan 01 00:00:00 1970 +0000
586 date: Thu Jan 01 00:00:00 1970 +0000
587 summary: 2
587 summary: 2
588
588
589
589
590 Test simple destination
590 Test simple destination
591 $ hg log -r 'destination()'
591 $ hg log -r 'destination()'
592 changeset: 7:ef0ef43d49e7
592 changeset: 7:ef0ef43d49e7
593 parent: 0:68795b066622
593 parent: 0:68795b066622
594 user: foo
594 user: foo
595 date: Thu Jan 01 00:00:00 1970 +0000
595 date: Thu Jan 01 00:00:00 1970 +0000
596 summary: 2
596 summary: 2
597
597
598 changeset: 8:6b9e5368ca4e
598 changeset: 8:6b9e5368ca4e
599 user: bar
599 user: bar
600 date: Thu Jan 01 00:00:00 1970 +0000
600 date: Thu Jan 01 00:00:00 1970 +0000
601 summary: 1
601 summary: 1
602
602
603 changeset: 9:1905859650ec
603 changeset: 9:1905859650ec
604 user: test
604 user: test
605 date: Thu Jan 01 00:00:00 1970 +0000
605 date: Thu Jan 01 00:00:00 1970 +0000
606 summary: 5
606 summary: 5
607
607
608 changeset: 10:52dc0b4c6907
608 changeset: 10:52dc0b4c6907
609 user: test
609 user: test
610 date: Thu Jan 01 00:00:00 1970 +0000
610 date: Thu Jan 01 00:00:00 1970 +0000
611 summary: 4
611 summary: 4
612
612
613 changeset: 11:882b35362a6b
613 changeset: 11:882b35362a6b
614 user: test
614 user: test
615 date: Thu Jan 01 00:00:00 1970 +0000
615 date: Thu Jan 01 00:00:00 1970 +0000
616 summary: 3
616 summary: 3
617
617
618 changeset: 13:7a4785234d87
618 changeset: 13:7a4785234d87
619 user: foo
619 user: foo
620 date: Thu Jan 01 00:00:00 1970 +0000
620 date: Thu Jan 01 00:00:00 1970 +0000
621 summary: 2
621 summary: 2
622
622
623 changeset: 14:f64defefacee
623 changeset: 14:f64defefacee
624 parent: 1:5d205f8b35b6
624 parent: 1:5d205f8b35b6
625 user: foo
625 user: foo
626 date: Thu Jan 01 00:00:00 1970 +0000
626 date: Thu Jan 01 00:00:00 1970 +0000
627 summary: 3
627 summary: 3
628
628
629 changeset: 17:f67661df0c48
629 changeset: 17:f67661df0c48
630 user: bar
630 user: bar
631 date: Thu Jan 01 00:00:00 1970 +0000
631 date: Thu Jan 01 00:00:00 1970 +0000
632 summary: 1
632 summary: 1
633
633
634 changeset: 19:9627f653b421
634 changeset: 19:9627f653b421
635 user: test
635 user: test
636 date: Thu Jan 01 00:00:00 1970 +0000
636 date: Thu Jan 01 00:00:00 1970 +0000
637 summary: 2
637 summary: 2
638
638
639 changeset: 21:7e61b508e709
639 changeset: 21:7e61b508e709
640 branch: dev
640 branch: dev
641 tag: tip
641 tag: tip
642 user: foo
642 user: foo
643 date: Thu Jan 01 00:00:00 1970 +0000
643 date: Thu Jan 01 00:00:00 1970 +0000
644 summary: 2
644 summary: 2
645
645
646 $ hg log -r 'destination(2)'
646 $ hg log -r 'destination(2)'
647 changeset: 7:ef0ef43d49e7
647 changeset: 7:ef0ef43d49e7
648 parent: 0:68795b066622
648 parent: 0:68795b066622
649 user: foo
649 user: foo
650 date: Thu Jan 01 00:00:00 1970 +0000
650 date: Thu Jan 01 00:00:00 1970 +0000
651 summary: 2
651 summary: 2
652
652
653 changeset: 13:7a4785234d87
653 changeset: 13:7a4785234d87
654 user: foo
654 user: foo
655 date: Thu Jan 01 00:00:00 1970 +0000
655 date: Thu Jan 01 00:00:00 1970 +0000
656 summary: 2
656 summary: 2
657
657
658 changeset: 19:9627f653b421
658 changeset: 19:9627f653b421
659 user: test
659 user: test
660 date: Thu Jan 01 00:00:00 1970 +0000
660 date: Thu Jan 01 00:00:00 1970 +0000
661 summary: 2
661 summary: 2
662
662
663 changeset: 21:7e61b508e709
663 changeset: 21:7e61b508e709
664 branch: dev
664 branch: dev
665 tag: tip
665 tag: tip
666 user: foo
666 user: foo
667 date: Thu Jan 01 00:00:00 1970 +0000
667 date: Thu Jan 01 00:00:00 1970 +0000
668 summary: 2
668 summary: 2
669
669
670 Transplants of grafts can find a destination...
670 Transplants of grafts can find a destination...
671 $ hg log -r 'destination(7)'
671 $ hg log -r 'destination(7)'
672 changeset: 21:7e61b508e709
672 changeset: 21:7e61b508e709
673 branch: dev
673 branch: dev
674 tag: tip
674 tag: tip
675 user: foo
675 user: foo
676 date: Thu Jan 01 00:00:00 1970 +0000
676 date: Thu Jan 01 00:00:00 1970 +0000
677 summary: 2
677 summary: 2
678
678
679 ... grafts of grafts unfortunately can't
679 ... grafts of grafts unfortunately can't
680 $ hg graft -q 13
680 $ hg graft -q 13
681 warning: can't find ancestor for 'b' copied from 'a'!
681 warning: can't find ancestor for 'b' copied from 'a'!
682 $ hg log -r 'destination(13)'
682 $ hg log -r 'destination(13)'
683 All copies of a cset
683 All copies of a cset
684 $ hg log -r 'origin(13) or destination(origin(13))'
684 $ hg log -r 'origin(13) or destination(origin(13))'
685 changeset: 2:5c095ad7e90f
685 changeset: 2:5c095ad7e90f
686 user: test
686 user: test
687 date: Thu Jan 01 00:00:00 1970 +0000
687 date: Thu Jan 01 00:00:00 1970 +0000
688 summary: 2
688 summary: 2
689
689
690 changeset: 7:ef0ef43d49e7
690 changeset: 7:ef0ef43d49e7
691 parent: 0:68795b066622
691 parent: 0:68795b066622
692 user: foo
692 user: foo
693 date: Thu Jan 01 00:00:00 1970 +0000
693 date: Thu Jan 01 00:00:00 1970 +0000
694 summary: 2
694 summary: 2
695
695
696 changeset: 13:7a4785234d87
696 changeset: 13:7a4785234d87
697 user: foo
697 user: foo
698 date: Thu Jan 01 00:00:00 1970 +0000
698 date: Thu Jan 01 00:00:00 1970 +0000
699 summary: 2
699 summary: 2
700
700
701 changeset: 19:9627f653b421
701 changeset: 19:9627f653b421
702 user: test
702 user: test
703 date: Thu Jan 01 00:00:00 1970 +0000
703 date: Thu Jan 01 00:00:00 1970 +0000
704 summary: 2
704 summary: 2
705
705
706 changeset: 21:7e61b508e709
706 changeset: 21:7e61b508e709
707 branch: dev
707 branch: dev
708 user: foo
708 user: foo
709 date: Thu Jan 01 00:00:00 1970 +0000
709 date: Thu Jan 01 00:00:00 1970 +0000
710 summary: 2
710 summary: 2
711
711
712 changeset: 22:d1cb6591fa4b
712 changeset: 22:d1cb6591fa4b
713 branch: dev
713 branch: dev
714 tag: tip
714 tag: tip
715 user: foo
715 user: foo
716 date: Thu Jan 01 00:00:00 1970 +0000
716 date: Thu Jan 01 00:00:00 1970 +0000
717 summary: 2
717 summary: 2
718
718
719
719
720 graft works on complex revset
720 graft works on complex revset
721
721
722 $ hg graft 'origin(13) or destination(origin(13))'
722 $ hg graft 'origin(13) or destination(origin(13))'
723 skipping ancestor revision 21:7e61b508e709
723 skipping ancestor revision 21:7e61b508e709
724 skipping ancestor revision 22:d1cb6591fa4b
724 skipping ancestor revision 22:d1cb6591fa4b
725 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
725 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
726 grafting 7:ef0ef43d49e7 "2"
726 grafting 7:ef0ef43d49e7 "2"
727 warning: can't find ancestor for 'b' copied from 'a'!
727 warning: can't find ancestor for 'b' copied from 'a'!
728 grafting 13:7a4785234d87 "2"
728 grafting 13:7a4785234d87 "2"
729 warning: can't find ancestor for 'b' copied from 'a'!
729 warning: can't find ancestor for 'b' copied from 'a'!
730 grafting 19:9627f653b421 "2"
730 grafting 19:9627f653b421 "2"
731 merging b
731 merging b
732 warning: can't find ancestor for 'b' copied from 'a'!
732 warning: can't find ancestor for 'b' copied from 'a'!
733
733
734 graft with --force (still doesn't graft merges)
734 graft with --force (still doesn't graft merges)
735
735
736 $ hg graft 19 0 6
736 $ hg graft 19 0 6
737 skipping ungraftable merge revision 6
737 skipping ungraftable merge revision 6
738 skipping ancestor revision 0:68795b066622
738 skipping ancestor revision 0:68795b066622
739 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
739 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
740 [255]
740 [255]
741 $ hg graft 19 0 6 --force
741 $ hg graft 19 0 6 --force
742 skipping ungraftable merge revision 6
742 skipping ungraftable merge revision 6
743 grafting 19:9627f653b421 "2"
743 grafting 19:9627f653b421 "2"
744 merging b
744 merging b
745 warning: can't find ancestor for 'b' copied from 'a'!
745 warning: can't find ancestor for 'b' copied from 'a'!
746 grafting 0:68795b066622 "0"
746 grafting 0:68795b066622 "0"
747
747
748 graft --force after backout
748 graft --force after backout
749
749
750 $ echo abc > a
750 $ echo abc > a
751 $ hg ci -m 28
751 $ hg ci -m 28
752 $ hg backout 28
752 $ hg backout 28
753 reverting a
753 reverting a
754 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
754 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
755 $ hg graft 28
755 $ hg graft 28
756 skipping ancestor revision 28:50a516bb8b57
756 skipping ancestor revision 28:50a516bb8b57
757 [255]
757 [255]
758 $ hg graft 28 --force
758 $ hg graft 28 --force
759 grafting 28:50a516bb8b57 "28"
759 grafting 28:50a516bb8b57 "28"
760 merging a
760 merging a
761 $ cat a
761 $ cat a
762 abc
762 abc
763
763
764 graft --continue after --force
764 graft --continue after --force
765
765
766 $ echo def > a
766 $ echo def > a
767 $ hg ci -m 31
767 $ hg ci -m 31
768 $ hg graft 28 --force --tool internal:fail
768 $ hg graft 28 --force --tool internal:fail
769 grafting 28:50a516bb8b57 "28"
769 grafting 28:50a516bb8b57 "28"
770 abort: unresolved conflicts, can't continue
770 abort: unresolved conflicts, can't continue
771 (use 'hg resolve' and 'hg graft --continue')
771 (use 'hg resolve' and 'hg graft --continue')
772 [255]
772 [255]
773 $ hg resolve --all
773 $ hg resolve --all
774 merging a
774 merging a
775 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
775 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
776 [1]
776 [1]
777 $ echo abc > a
777 $ echo abc > a
778 $ hg resolve -m a
778 $ hg resolve -m a
779 (no more unresolved files)
779 (no more unresolved files)
780 continue: hg graft --continue
780 continue: hg graft --continue
781 $ hg graft -c
781 $ hg graft -c
782 grafting 28:50a516bb8b57 "28"
782 grafting 28:50a516bb8b57 "28"
783 $ cat a
783 $ cat a
784 abc
784 abc
785
785
786 Continue testing same origin policy, using revision numbers from test above
786 Continue testing same origin policy, using revision numbers from test above
787 but do some destructive editing of the repo:
787 but do some destructive editing of the repo:
788
788
789 $ hg up -qC 7
789 $ hg up -qC 7
790 $ hg tag -l -r 13 tmp
790 $ hg tag -l -r 13 tmp
791 $ hg --config extensions.strip= strip 2
791 $ hg --config extensions.strip= strip 2
792 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
792 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
793 $ hg graft tmp
793 $ hg graft tmp
794 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
794 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
795 [255]
795 [255]
796
796
797 Empty graft
797 Empty graft
798
798
799 $ hg up -qr 26
799 $ hg up -qr 26
800 $ hg tag -f something
800 $ hg tag -f something
801 $ hg graft -qr 27
801 $ hg graft -qr 27
802 $ hg graft -f 27
802 $ hg graft -f 27
803 grafting 27:ed6c7e54e319 "28"
803 grafting 27:ed6c7e54e319 "28"
804 note: graft of 27:ed6c7e54e319 created no changes to commit
804 note: graft of 27:ed6c7e54e319 created no changes to commit
805
805
806 $ cd ..
806 $ cd ..
807
807
808 Graft to duplicate a commit
808 Graft to duplicate a commit
809
809
810 $ hg init graftsibling
810 $ hg init graftsibling
811 $ cd graftsibling
811 $ cd graftsibling
812 $ touch a
812 $ touch a
813 $ hg commit -qAm a
813 $ hg commit -qAm a
814 $ touch b
814 $ touch b
815 $ hg commit -qAm b
815 $ hg commit -qAm b
816 $ hg log -G -T '{rev}\n'
816 $ hg log -G -T '{rev}\n'
817 @ 1
817 @ 1
818 |
818 |
819 o 0
819 o 0
820
820
821 $ hg up -q 0
821 $ hg up -q 0
822 $ hg graft -r 1
822 $ hg graft -r 1
823 grafting 1:0e067c57feba "b" (tip)
823 grafting 1:0e067c57feba "b" (tip)
824 $ hg log -G -T '{rev}\n'
824 $ hg log -G -T '{rev}\n'
825 @ 2
825 @ 2
826 |
826 |
827 | o 1
827 | o 1
828 |/
828 |/
829 o 0
829 o 0
830
830
831 Graft to duplicate a commit twice
831 Graft to duplicate a commit twice
832
832
833 $ hg up -q 0
833 $ hg up -q 0
834 $ hg graft -r 2
834 $ hg graft -r 2
835 grafting 2:044ec77f6389 "b" (tip)
835 grafting 2:044ec77f6389 "b" (tip)
836 $ hg log -G -T '{rev}\n'
836 $ hg log -G -T '{rev}\n'
837 @ 3
837 @ 3
838 |
838 |
839 | o 2
839 | o 2
840 |/
840 |/
841 | o 1
841 | o 1
842 |/
842 |/
843 o 0
843 o 0
844
844
@@ -1,359 +1,359 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [format]
2 > [format]
3 > usegeneraldelta=yes
3 > usegeneraldelta=yes
4 > [extensions]
4 > [extensions]
5 > rebase=
5 > rebase=
6 >
6 >
7 > [phases]
7 > [phases]
8 > publish=False
8 > publish=False
9 >
9 >
10 > [alias]
10 > [alias]
11 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches} {bookmarks}\n"
11 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches} {bookmarks}\n"
12 > EOF
12 > EOF
13
13
14 $ hg init a
14 $ hg init a
15 $ cd a
15 $ cd a
16 $ echo c1 >common
16 $ echo c1 >common
17 $ hg add common
17 $ hg add common
18 $ hg ci -m C1
18 $ hg ci -m C1
19
19
20 $ echo c2 >>common
20 $ echo c2 >>common
21 $ hg ci -m C2
21 $ hg ci -m C2
22
22
23 $ echo c3 >>common
23 $ echo c3 >>common
24 $ hg ci -m C3
24 $ hg ci -m C3
25
25
26 $ hg up -q -C 1
26 $ hg up -q -C 1
27
27
28 $ echo l1 >>extra
28 $ echo l1 >>extra
29 $ hg add extra
29 $ hg add extra
30 $ hg ci -m L1
30 $ hg ci -m L1
31 created new head
31 created new head
32
32
33 $ sed -e 's/c2/l2/' common > common.new
33 $ sed -e 's/c2/l2/' common > common.new
34 $ mv common.new common
34 $ mv common.new common
35 $ hg ci -m L2
35 $ hg ci -m L2
36
36
37 $ echo l3 >> extra2
37 $ echo l3 >> extra2
38 $ hg add extra2
38 $ hg add extra2
39 $ hg ci -m L3
39 $ hg ci -m L3
40 $ hg bookmark mybook
40 $ hg bookmark mybook
41
41
42 $ hg phase --force --secret 4
42 $ hg phase --force --secret 4
43
43
44 $ hg tglog
44 $ hg tglog
45 @ 5:secret 'L3' mybook
45 @ 5:secret 'L3' mybook
46 |
46 |
47 o 4:secret 'L2'
47 o 4:secret 'L2'
48 |
48 |
49 o 3:draft 'L1'
49 o 3:draft 'L1'
50 |
50 |
51 | o 2:draft 'C3'
51 | o 2:draft 'C3'
52 |/
52 |/
53 o 1:draft 'C2'
53 o 1:draft 'C2'
54 |
54 |
55 o 0:draft 'C1'
55 o 0:draft 'C1'
56
56
57 Try to call --continue:
57 Try to call --continue:
58
58
59 $ hg rebase --continue
59 $ hg rebase --continue
60 abort: no rebase in progress
60 abort: no rebase in progress
61 [255]
61 [255]
62
62
63 Conflicting rebase:
63 Conflicting rebase:
64
64
65 $ hg rebase -s 3 -d 2
65 $ hg rebase -s 3 -d 2
66 rebasing 3:3163e20567cc "L1"
66 rebasing 3:3163e20567cc "L1"
67 rebasing 4:46f0b057b5c0 "L2"
67 rebasing 4:46f0b057b5c0 "L2"
68 merging common
68 merging common
69 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
69 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
70 unresolved conflicts (see hg resolve, then hg rebase --continue)
70 unresolved conflicts (see hg resolve, then hg rebase --continue)
71 [1]
71 [1]
72
72
73 Try to continue without solving the conflict:
73 Try to continue without solving the conflict:
74
74
75 $ hg rebase --continue
75 $ hg rebase --continue
76 already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
76 already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
77 rebasing 4:46f0b057b5c0 "L2"
77 rebasing 4:46f0b057b5c0 "L2"
78 abort: unresolved merge conflicts (see "hg help resolve")
78 abort: unresolved merge conflicts (see 'hg help resolve')
79 [255]
79 [255]
80
80
81 Conclude rebase:
81 Conclude rebase:
82
82
83 $ echo 'resolved merge' >common
83 $ echo 'resolved merge' >common
84 $ hg resolve -m common
84 $ hg resolve -m common
85 (no more unresolved files)
85 (no more unresolved files)
86 continue: hg rebase --continue
86 continue: hg rebase --continue
87 $ hg rebase --continue
87 $ hg rebase --continue
88 already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
88 already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
89 rebasing 4:46f0b057b5c0 "L2"
89 rebasing 4:46f0b057b5c0 "L2"
90 rebasing 5:8029388f38dc "L3" (mybook)
90 rebasing 5:8029388f38dc "L3" (mybook)
91 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3163e20567cc-5ca4656e-backup.hg (glob)
91 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3163e20567cc-5ca4656e-backup.hg (glob)
92
92
93 $ hg tglog
93 $ hg tglog
94 @ 5:secret 'L3' mybook
94 @ 5:secret 'L3' mybook
95 |
95 |
96 o 4:secret 'L2'
96 o 4:secret 'L2'
97 |
97 |
98 o 3:draft 'L1'
98 o 3:draft 'L1'
99 |
99 |
100 o 2:draft 'C3'
100 o 2:draft 'C3'
101 |
101 |
102 o 1:draft 'C2'
102 o 1:draft 'C2'
103 |
103 |
104 o 0:draft 'C1'
104 o 0:draft 'C1'
105
105
106 Check correctness:
106 Check correctness:
107
107
108 $ hg cat -r 0 common
108 $ hg cat -r 0 common
109 c1
109 c1
110
110
111 $ hg cat -r 1 common
111 $ hg cat -r 1 common
112 c1
112 c1
113 c2
113 c2
114
114
115 $ hg cat -r 2 common
115 $ hg cat -r 2 common
116 c1
116 c1
117 c2
117 c2
118 c3
118 c3
119
119
120 $ hg cat -r 3 common
120 $ hg cat -r 3 common
121 c1
121 c1
122 c2
122 c2
123 c3
123 c3
124
124
125 $ hg cat -r 4 common
125 $ hg cat -r 4 common
126 resolved merge
126 resolved merge
127
127
128 $ hg cat -r 5 common
128 $ hg cat -r 5 common
129 resolved merge
129 resolved merge
130
130
131 Bookmark stays active after --continue
131 Bookmark stays active after --continue
132 $ hg bookmarks
132 $ hg bookmarks
133 * mybook 5:d67b21408fc0
133 * mybook 5:d67b21408fc0
134
134
135 $ cd ..
135 $ cd ..
136
136
137 Check that the right ancestors is used while rebasing a merge (issue4041)
137 Check that the right ancestors is used while rebasing a merge (issue4041)
138
138
139 $ hg clone "$TESTDIR/bundles/issue4041.hg" issue4041
139 $ hg clone "$TESTDIR/bundles/issue4041.hg" issue4041
140 requesting all changes
140 requesting all changes
141 adding changesets
141 adding changesets
142 adding manifests
142 adding manifests
143 adding file changes
143 adding file changes
144 added 11 changesets with 8 changes to 3 files (+1 heads)
144 added 11 changesets with 8 changes to 3 files (+1 heads)
145 updating to branch default
145 updating to branch default
146 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
147 $ cd issue4041
147 $ cd issue4041
148 $ hg log -G
148 $ hg log -G
149 o changeset: 10:2f2496ddf49d
149 o changeset: 10:2f2496ddf49d
150 |\ branch: f1
150 |\ branch: f1
151 | | tag: tip
151 | | tag: tip
152 | | parent: 7:4c9fbe56a16f
152 | | parent: 7:4c9fbe56a16f
153 | | parent: 9:e31216eec445
153 | | parent: 9:e31216eec445
154 | | user: szhang
154 | | user: szhang
155 | | date: Thu Sep 05 12:59:39 2013 -0400
155 | | date: Thu Sep 05 12:59:39 2013 -0400
156 | | summary: merge
156 | | summary: merge
157 | |
157 | |
158 | o changeset: 9:e31216eec445
158 | o changeset: 9:e31216eec445
159 | | branch: f1
159 | | branch: f1
160 | | user: szhang
160 | | user: szhang
161 | | date: Thu Sep 05 12:59:10 2013 -0400
161 | | date: Thu Sep 05 12:59:10 2013 -0400
162 | | summary: more changes to f1
162 | | summary: more changes to f1
163 | |
163 | |
164 | o changeset: 8:8e4e2c1a07ae
164 | o changeset: 8:8e4e2c1a07ae
165 | |\ branch: f1
165 | |\ branch: f1
166 | | | parent: 2:4bc80088dc6b
166 | | | parent: 2:4bc80088dc6b
167 | | | parent: 6:400110238667
167 | | | parent: 6:400110238667
168 | | | user: szhang
168 | | | user: szhang
169 | | | date: Thu Sep 05 12:57:59 2013 -0400
169 | | | date: Thu Sep 05 12:57:59 2013 -0400
170 | | | summary: bad merge
170 | | | summary: bad merge
171 | | |
171 | | |
172 o | | changeset: 7:4c9fbe56a16f
172 o | | changeset: 7:4c9fbe56a16f
173 |/ / branch: f1
173 |/ / branch: f1
174 | | parent: 2:4bc80088dc6b
174 | | parent: 2:4bc80088dc6b
175 | | user: szhang
175 | | user: szhang
176 | | date: Thu Sep 05 12:54:00 2013 -0400
176 | | date: Thu Sep 05 12:54:00 2013 -0400
177 | | summary: changed f1
177 | | summary: changed f1
178 | |
178 | |
179 | o changeset: 6:400110238667
179 | o changeset: 6:400110238667
180 | | branch: f2
180 | | branch: f2
181 | | parent: 4:12e8ec6bb010
181 | | parent: 4:12e8ec6bb010
182 | | user: szhang
182 | | user: szhang
183 | | date: Tue Sep 03 13:58:02 2013 -0400
183 | | date: Tue Sep 03 13:58:02 2013 -0400
184 | | summary: changed f2 on f2
184 | | summary: changed f2 on f2
185 | |
185 | |
186 | | @ changeset: 5:d79e2059b5c0
186 | | @ changeset: 5:d79e2059b5c0
187 | | | parent: 3:8a951942e016
187 | | | parent: 3:8a951942e016
188 | | | user: szhang
188 | | | user: szhang
189 | | | date: Tue Sep 03 13:57:39 2013 -0400
189 | | | date: Tue Sep 03 13:57:39 2013 -0400
190 | | | summary: changed f2 on default
190 | | | summary: changed f2 on default
191 | | |
191 | | |
192 | o | changeset: 4:12e8ec6bb010
192 | o | changeset: 4:12e8ec6bb010
193 | |/ branch: f2
193 | |/ branch: f2
194 | | user: szhang
194 | | user: szhang
195 | | date: Tue Sep 03 13:57:18 2013 -0400
195 | | date: Tue Sep 03 13:57:18 2013 -0400
196 | | summary: created f2 branch
196 | | summary: created f2 branch
197 | |
197 | |
198 | o changeset: 3:8a951942e016
198 | o changeset: 3:8a951942e016
199 | | parent: 0:24797d4f68de
199 | | parent: 0:24797d4f68de
200 | | user: szhang
200 | | user: szhang
201 | | date: Tue Sep 03 13:57:11 2013 -0400
201 | | date: Tue Sep 03 13:57:11 2013 -0400
202 | | summary: added f2.txt
202 | | summary: added f2.txt
203 | |
203 | |
204 o | changeset: 2:4bc80088dc6b
204 o | changeset: 2:4bc80088dc6b
205 | | branch: f1
205 | | branch: f1
206 | | user: szhang
206 | | user: szhang
207 | | date: Tue Sep 03 13:56:20 2013 -0400
207 | | date: Tue Sep 03 13:56:20 2013 -0400
208 | | summary: added f1.txt
208 | | summary: added f1.txt
209 | |
209 | |
210 o | changeset: 1:ef53c9e6b608
210 o | changeset: 1:ef53c9e6b608
211 |/ branch: f1
211 |/ branch: f1
212 | user: szhang
212 | user: szhang
213 | date: Tue Sep 03 13:55:26 2013 -0400
213 | date: Tue Sep 03 13:55:26 2013 -0400
214 | summary: created f1 branch
214 | summary: created f1 branch
215 |
215 |
216 o changeset: 0:24797d4f68de
216 o changeset: 0:24797d4f68de
217 user: szhang
217 user: szhang
218 date: Tue Sep 03 13:55:08 2013 -0400
218 date: Tue Sep 03 13:55:08 2013 -0400
219 summary: added default.txt
219 summary: added default.txt
220
220
221 $ hg rebase -s9 -d2 --debug # use debug to really check merge base used
221 $ hg rebase -s9 -d2 --debug # use debug to really check merge base used
222 rebase onto 4bc80088dc6b starting from e31216eec445
222 rebase onto 4bc80088dc6b starting from e31216eec445
223 ignoring null merge rebase of 3
223 ignoring null merge rebase of 3
224 ignoring null merge rebase of 4
224 ignoring null merge rebase of 4
225 ignoring null merge rebase of 6
225 ignoring null merge rebase of 6
226 ignoring null merge rebase of 8
226 ignoring null merge rebase of 8
227 rebasing 9:e31216eec445 "more changes to f1"
227 rebasing 9:e31216eec445 "more changes to f1"
228 future parents are 2 and -1
228 future parents are 2 and -1
229 rebase status stored
229 rebase status stored
230 update to 2:4bc80088dc6b
230 update to 2:4bc80088dc6b
231 resolving manifests
231 resolving manifests
232 branchmerge: False, force: True, partial: False
232 branchmerge: False, force: True, partial: False
233 ancestor: d79e2059b5c0+, local: d79e2059b5c0+, remote: 4bc80088dc6b
233 ancestor: d79e2059b5c0+, local: d79e2059b5c0+, remote: 4bc80088dc6b
234 f2.txt: other deleted -> r
234 f2.txt: other deleted -> r
235 removing f2.txt
235 removing f2.txt
236 f1.txt: remote created -> g
236 f1.txt: remote created -> g
237 getting f1.txt
237 getting f1.txt
238 merge against 9:e31216eec445
238 merge against 9:e31216eec445
239 detach base 8:8e4e2c1a07ae
239 detach base 8:8e4e2c1a07ae
240 searching for copies back to rev 3
240 searching for copies back to rev 3
241 resolving manifests
241 resolving manifests
242 branchmerge: True, force: True, partial: False
242 branchmerge: True, force: True, partial: False
243 ancestor: 8e4e2c1a07ae, local: 4bc80088dc6b+, remote: e31216eec445
243 ancestor: 8e4e2c1a07ae, local: 4bc80088dc6b+, remote: e31216eec445
244 f1.txt: remote is newer -> g
244 f1.txt: remote is newer -> g
245 getting f1.txt
245 getting f1.txt
246 committing files:
246 committing files:
247 f1.txt
247 f1.txt
248 committing manifest
248 committing manifest
249 committing changelog
249 committing changelog
250 rebased as 19c888675e13
250 rebased as 19c888675e13
251 rebasing 10:2f2496ddf49d "merge" (tip)
251 rebasing 10:2f2496ddf49d "merge" (tip)
252 future parents are 11 and 7
252 future parents are 11 and 7
253 rebase status stored
253 rebase status stored
254 already in target
254 already in target
255 merge against 10:2f2496ddf49d
255 merge against 10:2f2496ddf49d
256 detach base 9:e31216eec445
256 detach base 9:e31216eec445
257 searching for copies back to rev 3
257 searching for copies back to rev 3
258 resolving manifests
258 resolving manifests
259 branchmerge: True, force: True, partial: False
259 branchmerge: True, force: True, partial: False
260 ancestor: e31216eec445, local: 19c888675e13+, remote: 2f2496ddf49d
260 ancestor: e31216eec445, local: 19c888675e13+, remote: 2f2496ddf49d
261 f1.txt: remote is newer -> g
261 f1.txt: remote is newer -> g
262 getting f1.txt
262 getting f1.txt
263 committing files:
263 committing files:
264 f1.txt
264 f1.txt
265 committing manifest
265 committing manifest
266 committing changelog
266 committing changelog
267 rebased as 2a7f09cac94c
267 rebased as 2a7f09cac94c
268 rebase merging completed
268 rebase merging completed
269 update back to initial working directory parent
269 update back to initial working directory parent
270 resolving manifests
270 resolving manifests
271 branchmerge: False, force: False, partial: False
271 branchmerge: False, force: False, partial: False
272 ancestor: 2a7f09cac94c, local: 2a7f09cac94c+, remote: d79e2059b5c0
272 ancestor: 2a7f09cac94c, local: 2a7f09cac94c+, remote: d79e2059b5c0
273 f1.txt: other deleted -> r
273 f1.txt: other deleted -> r
274 removing f1.txt
274 removing f1.txt
275 f2.txt: remote created -> g
275 f2.txt: remote created -> g
276 getting f2.txt
276 getting f2.txt
277 2 changesets found
277 2 changesets found
278 list of changesets:
278 list of changesets:
279 e31216eec445e44352c5f01588856059466a24c9
279 e31216eec445e44352c5f01588856059466a24c9
280 2f2496ddf49d69b5ef23ad8cf9fb2e0e4faf0ac2
280 2f2496ddf49d69b5ef23ad8cf9fb2e0e4faf0ac2
281 bundle2-output-bundle: "HG20", (1 params) 1 parts total
281 bundle2-output-bundle: "HG20", (1 params) 1 parts total
282 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
282 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
283 saved backup bundle to $TESTTMP/issue4041/.hg/strip-backup/e31216eec445-15f7a814-backup.hg (glob)
283 saved backup bundle to $TESTTMP/issue4041/.hg/strip-backup/e31216eec445-15f7a814-backup.hg (glob)
284 3 changesets found
284 3 changesets found
285 list of changesets:
285 list of changesets:
286 4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
286 4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
287 19c888675e133ab5dff84516926a65672eaf04d9
287 19c888675e133ab5dff84516926a65672eaf04d9
288 2a7f09cac94c7f4b73ebd5cd1a62d3b2e8e336bf
288 2a7f09cac94c7f4b73ebd5cd1a62d3b2e8e336bf
289 bundle2-output-bundle: "HG20", 1 parts total
289 bundle2-output-bundle: "HG20", 1 parts total
290 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
290 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
291 adding branch
291 adding branch
292 bundle2-input-bundle: with-transaction
292 bundle2-input-bundle: with-transaction
293 bundle2-input-part: "changegroup" (params: 1 mandatory 1 advisory) supported
293 bundle2-input-part: "changegroup" (params: 1 mandatory 1 advisory) supported
294 adding changesets
294 adding changesets
295 add changeset 4c9fbe56a16f
295 add changeset 4c9fbe56a16f
296 add changeset 19c888675e13
296 add changeset 19c888675e13
297 add changeset 2a7f09cac94c
297 add changeset 2a7f09cac94c
298 adding manifests
298 adding manifests
299 adding file changes
299 adding file changes
300 adding f1.txt revisions
300 adding f1.txt revisions
301 added 2 changesets with 2 changes to 1 files
301 added 2 changesets with 2 changes to 1 files
302 bundle2-input-part: total payload size 1713
302 bundle2-input-part: total payload size 1713
303 bundle2-input-bundle: 0 parts total
303 bundle2-input-bundle: 0 parts total
304 invalid branchheads cache (served): tip differs
304 invalid branchheads cache (served): tip differs
305 history modification detected - truncating revision branch cache to revision 9
305 history modification detected - truncating revision branch cache to revision 9
306 rebase completed
306 rebase completed
307 truncating cache/rbc-revs-v1 to 72
307 truncating cache/rbc-revs-v1 to 72
308
308
309 Test minimization of merge conflicts
309 Test minimization of merge conflicts
310 $ hg up -q null
310 $ hg up -q null
311 $ echo a > a
311 $ echo a > a
312 $ hg add a
312 $ hg add a
313 $ hg commit -q -m 'a'
313 $ hg commit -q -m 'a'
314 $ echo b >> a
314 $ echo b >> a
315 $ hg commit -q -m 'ab'
315 $ hg commit -q -m 'ab'
316 $ hg bookmark ab
316 $ hg bookmark ab
317 $ hg up -q '.^'
317 $ hg up -q '.^'
318 $ echo b >> a
318 $ echo b >> a
319 $ echo c >> a
319 $ echo c >> a
320 $ hg commit -q -m 'abc'
320 $ hg commit -q -m 'abc'
321 $ hg rebase -s 7bc217434fc1 -d ab --keep
321 $ hg rebase -s 7bc217434fc1 -d ab --keep
322 rebasing 13:7bc217434fc1 "abc" (tip)
322 rebasing 13:7bc217434fc1 "abc" (tip)
323 merging a
323 merging a
324 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
324 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
325 unresolved conflicts (see hg resolve, then hg rebase --continue)
325 unresolved conflicts (see hg resolve, then hg rebase --continue)
326 [1]
326 [1]
327 $ hg diff
327 $ hg diff
328 diff -r 328e4ab1f7cc a
328 diff -r 328e4ab1f7cc a
329 --- a/a Thu Jan 01 00:00:00 1970 +0000
329 --- a/a Thu Jan 01 00:00:00 1970 +0000
330 +++ b/a * (glob)
330 +++ b/a * (glob)
331 @@ -1,2 +1,6 @@
331 @@ -1,2 +1,6 @@
332 a
332 a
333 b
333 b
334 +<<<<<<< dest: 328e4ab1f7cc ab - test: ab
334 +<<<<<<< dest: 328e4ab1f7cc ab - test: ab
335 +=======
335 +=======
336 +c
336 +c
337 +>>>>>>> source: 7bc217434fc1 - test: abc
337 +>>>>>>> source: 7bc217434fc1 - test: abc
338 $ hg rebase --abort
338 $ hg rebase --abort
339 rebase aborted
339 rebase aborted
340 $ hg up -q -C 7bc217434fc1
340 $ hg up -q -C 7bc217434fc1
341 $ hg rebase -s . -d ab --keep -t internal:merge3
341 $ hg rebase -s . -d ab --keep -t internal:merge3
342 rebasing 13:7bc217434fc1 "abc" (tip)
342 rebasing 13:7bc217434fc1 "abc" (tip)
343 merging a
343 merging a
344 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
344 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
345 unresolved conflicts (see hg resolve, then hg rebase --continue)
345 unresolved conflicts (see hg resolve, then hg rebase --continue)
346 [1]
346 [1]
347 $ hg diff
347 $ hg diff
348 diff -r 328e4ab1f7cc a
348 diff -r 328e4ab1f7cc a
349 --- a/a Thu Jan 01 00:00:00 1970 +0000
349 --- a/a Thu Jan 01 00:00:00 1970 +0000
350 +++ b/a * (glob)
350 +++ b/a * (glob)
351 @@ -1,2 +1,8 @@
351 @@ -1,2 +1,8 @@
352 a
352 a
353 +<<<<<<< dest: 328e4ab1f7cc ab - test: ab
353 +<<<<<<< dest: 328e4ab1f7cc ab - test: ab
354 b
354 b
355 +||||||| base
355 +||||||| base
356 +=======
356 +=======
357 +b
357 +b
358 +c
358 +c
359 +>>>>>>> source: 7bc217434fc1 - test: abc
359 +>>>>>>> source: 7bc217434fc1 - test: abc
@@ -1,1071 +1,1071 b''
1
1
2 $ mkdir -p t
2 $ mkdir -p t
3 $ cd t
3 $ cd t
4 $ cat <<EOF > merge
4 $ cat <<EOF > merge
5 > import sys, os
5 > import sys, os
6 > f = open(sys.argv[1], "wb")
6 > f = open(sys.argv[1], "wb")
7 > f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
7 > f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
8 > f.close()
8 > f.close()
9 > EOF
9 > EOF
10
10
11 perform a test merge with possible renaming
11 perform a test merge with possible renaming
12 args:
12 args:
13 $1 = action in local branch
13 $1 = action in local branch
14 $2 = action in remote branch
14 $2 = action in remote branch
15 $3 = action in working dir
15 $3 = action in working dir
16 $4 = expected result
16 $4 = expected result
17
17
18 $ tm()
18 $ tm()
19 > {
19 > {
20 > hg init t
20 > hg init t
21 > cd t
21 > cd t
22 > echo "[merge]" >> .hg/hgrc
22 > echo "[merge]" >> .hg/hgrc
23 > echo "followcopies = 1" >> .hg/hgrc
23 > echo "followcopies = 1" >> .hg/hgrc
24 >
24 >
25 > # base
25 > # base
26 > echo base > a
26 > echo base > a
27 > echo base > rev # used to force commits
27 > echo base > rev # used to force commits
28 > hg add a rev
28 > hg add a rev
29 > hg ci -m "base"
29 > hg ci -m "base"
30 >
30 >
31 > # remote
31 > # remote
32 > echo remote > rev
32 > echo remote > rev
33 > if [ "$2" != "" ] ; then $2 ; fi
33 > if [ "$2" != "" ] ; then $2 ; fi
34 > hg ci -m "remote"
34 > hg ci -m "remote"
35 >
35 >
36 > # local
36 > # local
37 > hg co -q 0
37 > hg co -q 0
38 > echo local > rev
38 > echo local > rev
39 > if [ "$1" != "" ] ; then $1 ; fi
39 > if [ "$1" != "" ] ; then $1 ; fi
40 > hg ci -m "local"
40 > hg ci -m "local"
41 >
41 >
42 > # working dir
42 > # working dir
43 > echo local > rev
43 > echo local > rev
44 > if [ "$3" != "" ] ; then $3 ; fi
44 > if [ "$3" != "" ] ; then $3 ; fi
45 >
45 >
46 > # merge
46 > # merge
47 > echo "--------------"
47 > echo "--------------"
48 > echo "test L:$1 R:$2 W:$3 - $4"
48 > echo "test L:$1 R:$2 W:$3 - $4"
49 > echo "--------------"
49 > echo "--------------"
50 > hg merge -y --debug --traceback --tool="python ../merge"
50 > hg merge -y --debug --traceback --tool="python ../merge"
51 >
51 >
52 > echo "--------------"
52 > echo "--------------"
53 > hg status -camC -X rev
53 > hg status -camC -X rev
54 >
54 >
55 > hg ci -m "merge"
55 > hg ci -m "merge"
56 >
56 >
57 > echo "--------------"
57 > echo "--------------"
58 > echo
58 > echo
59 >
59 >
60 > cd ..
60 > cd ..
61 > rm -r t
61 > rm -r t
62 > }
62 > }
63 $ up() {
63 $ up() {
64 > cp rev $1
64 > cp rev $1
65 > hg add $1 2> /dev/null
65 > hg add $1 2> /dev/null
66 > if [ "$2" != "" ] ; then
66 > if [ "$2" != "" ] ; then
67 > cp rev $2
67 > cp rev $2
68 > hg add $2 2> /dev/null
68 > hg add $2 2> /dev/null
69 > fi
69 > fi
70 > }
70 > }
71 $ uc() { up $1; hg cp $1 $2; } # update + copy
71 $ uc() { up $1; hg cp $1 $2; } # update + copy
72 $ um() { up $1; hg mv $1 $2; }
72 $ um() { up $1; hg mv $1 $2; }
73 $ nc() { hg cp $1 $2; } # just copy
73 $ nc() { hg cp $1 $2; } # just copy
74 $ nm() { hg mv $1 $2; } # just move
74 $ nm() { hg mv $1 $2; } # just move
75 $ tm "up a " "nc a b" " " "1 get local a to b"
75 $ tm "up a " "nc a b" " " "1 get local a to b"
76 created new head
76 created new head
77 --------------
77 --------------
78 test L:up a R:nc a b W: - 1 get local a to b
78 test L:up a R:nc a b W: - 1 get local a to b
79 --------------
79 --------------
80 searching for copies back to rev 1
80 searching for copies back to rev 1
81 unmatched files in other:
81 unmatched files in other:
82 b
82 b
83 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
83 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
84 src: 'a' -> dst: 'b' *
84 src: 'a' -> dst: 'b' *
85 checking for directory renames
85 checking for directory renames
86 resolving manifests
86 resolving manifests
87 branchmerge: True, force: False, partial: False
87 branchmerge: True, force: False, partial: False
88 ancestor: 924404dff337, local: e300d1c794ec+, remote: 4ce40f5aca24
88 ancestor: 924404dff337, local: e300d1c794ec+, remote: 4ce40f5aca24
89 preserving a for resolve of b
89 preserving a for resolve of b
90 preserving rev for resolve of rev
90 preserving rev for resolve of rev
91 starting 4 threads for background file closing (?)
91 starting 4 threads for background file closing (?)
92 a: remote unchanged -> k
92 a: remote unchanged -> k
93 b: remote copied from a -> m (premerge)
93 b: remote copied from a -> m (premerge)
94 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
94 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
95 merging a and b to b
95 merging a and b to b
96 my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
96 my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
97 premerge successful
97 premerge successful
98 rev: versions differ -> m (premerge)
98 rev: versions differ -> m (premerge)
99 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
99 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
100 merging rev
100 merging rev
101 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
101 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
102 rev: versions differ -> m (merge)
102 rev: versions differ -> m (merge)
103 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
103 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
104 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
104 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
105 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
105 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
106 merge tool returned: 0
106 merge tool returned: 0
107 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
107 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
108 (branch merge, don't forget to commit)
108 (branch merge, don't forget to commit)
109 --------------
109 --------------
110 M b
110 M b
111 a
111 a
112 C a
112 C a
113 --------------
113 --------------
114
114
115 $ tm "nc a b" "up a " " " "2 get rem change to a and b"
115 $ tm "nc a b" "up a " " " "2 get rem change to a and b"
116 created new head
116 created new head
117 --------------
117 --------------
118 test L:nc a b R:up a W: - 2 get rem change to a and b
118 test L:nc a b R:up a W: - 2 get rem change to a and b
119 --------------
119 --------------
120 searching for copies back to rev 1
120 searching for copies back to rev 1
121 unmatched files in local:
121 unmatched files in local:
122 b
122 b
123 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
123 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
124 src: 'a' -> dst: 'b' *
124 src: 'a' -> dst: 'b' *
125 checking for directory renames
125 checking for directory renames
126 resolving manifests
126 resolving manifests
127 branchmerge: True, force: False, partial: False
127 branchmerge: True, force: False, partial: False
128 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: f4db7e329e71
128 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: f4db7e329e71
129 preserving b for resolve of b
129 preserving b for resolve of b
130 preserving rev for resolve of rev
130 preserving rev for resolve of rev
131 a: remote is newer -> g
131 a: remote is newer -> g
132 getting a
132 getting a
133 b: local copied/moved from a -> m (premerge)
133 b: local copied/moved from a -> m (premerge)
134 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
134 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
135 merging b and a to b
135 merging b and a to b
136 my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
136 my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
137 premerge successful
137 premerge successful
138 rev: versions differ -> m (premerge)
138 rev: versions differ -> m (premerge)
139 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
139 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
140 merging rev
140 merging rev
141 my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
141 my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
142 rev: versions differ -> m (merge)
142 rev: versions differ -> m (merge)
143 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
143 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
144 my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
144 my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
145 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
145 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
146 merge tool returned: 0
146 merge tool returned: 0
147 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
147 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
148 (branch merge, don't forget to commit)
148 (branch merge, don't forget to commit)
149 --------------
149 --------------
150 M a
150 M a
151 M b
151 M b
152 a
152 a
153 --------------
153 --------------
154
154
155 $ tm "up a " "nm a b" " " "3 get local a change to b, remove a"
155 $ tm "up a " "nm a b" " " "3 get local a change to b, remove a"
156 created new head
156 created new head
157 --------------
157 --------------
158 test L:up a R:nm a b W: - 3 get local a change to b, remove a
158 test L:up a R:nm a b W: - 3 get local a change to b, remove a
159 --------------
159 --------------
160 searching for copies back to rev 1
160 searching for copies back to rev 1
161 unmatched files in other:
161 unmatched files in other:
162 b
162 b
163 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
163 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
164 src: 'a' -> dst: 'b' *
164 src: 'a' -> dst: 'b' *
165 checking for directory renames
165 checking for directory renames
166 resolving manifests
166 resolving manifests
167 branchmerge: True, force: False, partial: False
167 branchmerge: True, force: False, partial: False
168 ancestor: 924404dff337, local: e300d1c794ec+, remote: bdb19105162a
168 ancestor: 924404dff337, local: e300d1c794ec+, remote: bdb19105162a
169 preserving a for resolve of b
169 preserving a for resolve of b
170 preserving rev for resolve of rev
170 preserving rev for resolve of rev
171 removing a
171 removing a
172 starting 4 threads for background file closing (?)
172 starting 4 threads for background file closing (?)
173 b: remote moved from a -> m (premerge)
173 b: remote moved from a -> m (premerge)
174 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
174 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
175 merging a and b to b
175 merging a and b to b
176 my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
176 my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
177 premerge successful
177 premerge successful
178 rev: versions differ -> m (premerge)
178 rev: versions differ -> m (premerge)
179 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
179 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
180 merging rev
180 merging rev
181 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
181 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
182 rev: versions differ -> m (merge)
182 rev: versions differ -> m (merge)
183 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
183 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
184 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
184 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
185 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
185 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
186 merge tool returned: 0
186 merge tool returned: 0
187 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
187 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
188 (branch merge, don't forget to commit)
188 (branch merge, don't forget to commit)
189 --------------
189 --------------
190 M b
190 M b
191 a
191 a
192 --------------
192 --------------
193
193
194 $ tm "nm a b" "up a " " " "4 get remote change to b"
194 $ tm "nm a b" "up a " " " "4 get remote change to b"
195 created new head
195 created new head
196 --------------
196 --------------
197 test L:nm a b R:up a W: - 4 get remote change to b
197 test L:nm a b R:up a W: - 4 get remote change to b
198 --------------
198 --------------
199 searching for copies back to rev 1
199 searching for copies back to rev 1
200 unmatched files in local:
200 unmatched files in local:
201 b
201 b
202 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
202 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
203 src: 'a' -> dst: 'b' *
203 src: 'a' -> dst: 'b' *
204 checking for directory renames
204 checking for directory renames
205 resolving manifests
205 resolving manifests
206 branchmerge: True, force: False, partial: False
206 branchmerge: True, force: False, partial: False
207 ancestor: 924404dff337, local: 02963e448370+, remote: f4db7e329e71
207 ancestor: 924404dff337, local: 02963e448370+, remote: f4db7e329e71
208 preserving b for resolve of b
208 preserving b for resolve of b
209 preserving rev for resolve of rev
209 preserving rev for resolve of rev
210 starting 4 threads for background file closing (?)
210 starting 4 threads for background file closing (?)
211 b: local copied/moved from a -> m (premerge)
211 b: local copied/moved from a -> m (premerge)
212 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
212 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
213 merging b and a to b
213 merging b and a to b
214 my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
214 my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
215 premerge successful
215 premerge successful
216 rev: versions differ -> m (premerge)
216 rev: versions differ -> m (premerge)
217 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
217 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
218 merging rev
218 merging rev
219 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
219 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
220 rev: versions differ -> m (merge)
220 rev: versions differ -> m (merge)
221 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
221 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
222 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
222 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
223 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
223 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
224 merge tool returned: 0
224 merge tool returned: 0
225 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
225 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
226 (branch merge, don't forget to commit)
226 (branch merge, don't forget to commit)
227 --------------
227 --------------
228 M b
228 M b
229 a
229 a
230 --------------
230 --------------
231
231
232 $ tm " " "nc a b" " " "5 get b"
232 $ tm " " "nc a b" " " "5 get b"
233 created new head
233 created new head
234 --------------
234 --------------
235 test L: R:nc a b W: - 5 get b
235 test L: R:nc a b W: - 5 get b
236 --------------
236 --------------
237 searching for copies back to rev 1
237 searching for copies back to rev 1
238 unmatched files in other:
238 unmatched files in other:
239 b
239 b
240 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
240 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
241 src: 'a' -> dst: 'b'
241 src: 'a' -> dst: 'b'
242 checking for directory renames
242 checking for directory renames
243 resolving manifests
243 resolving manifests
244 branchmerge: True, force: False, partial: False
244 branchmerge: True, force: False, partial: False
245 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: 4ce40f5aca24
245 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: 4ce40f5aca24
246 preserving rev for resolve of rev
246 preserving rev for resolve of rev
247 b: remote created -> g
247 b: remote created -> g
248 getting b
248 getting b
249 rev: versions differ -> m (premerge)
249 rev: versions differ -> m (premerge)
250 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
250 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
251 merging rev
251 merging rev
252 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
252 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
253 rev: versions differ -> m (merge)
253 rev: versions differ -> m (merge)
254 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
254 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
255 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
255 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
256 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
256 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
257 merge tool returned: 0
257 merge tool returned: 0
258 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
258 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
259 (branch merge, don't forget to commit)
259 (branch merge, don't forget to commit)
260 --------------
260 --------------
261 M b
261 M b
262 C a
262 C a
263 --------------
263 --------------
264
264
265 $ tm "nc a b" " " " " "6 nothing"
265 $ tm "nc a b" " " " " "6 nothing"
266 created new head
266 created new head
267 --------------
267 --------------
268 test L:nc a b R: W: - 6 nothing
268 test L:nc a b R: W: - 6 nothing
269 --------------
269 --------------
270 searching for copies back to rev 1
270 searching for copies back to rev 1
271 unmatched files in local:
271 unmatched files in local:
272 b
272 b
273 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
273 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
274 src: 'a' -> dst: 'b'
274 src: 'a' -> dst: 'b'
275 checking for directory renames
275 checking for directory renames
276 resolving manifests
276 resolving manifests
277 branchmerge: True, force: False, partial: False
277 branchmerge: True, force: False, partial: False
278 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 97c705ade336
278 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 97c705ade336
279 preserving rev for resolve of rev
279 preserving rev for resolve of rev
280 starting 4 threads for background file closing (?)
280 starting 4 threads for background file closing (?)
281 rev: versions differ -> m (premerge)
281 rev: versions differ -> m (premerge)
282 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
282 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
283 merging rev
283 merging rev
284 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
284 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
285 rev: versions differ -> m (merge)
285 rev: versions differ -> m (merge)
286 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
286 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
287 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
287 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
288 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
288 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
289 merge tool returned: 0
289 merge tool returned: 0
290 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
290 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
291 (branch merge, don't forget to commit)
291 (branch merge, don't forget to commit)
292 --------------
292 --------------
293 C a
293 C a
294 C b
294 C b
295 --------------
295 --------------
296
296
297 $ tm " " "nm a b" " " "7 get b"
297 $ tm " " "nm a b" " " "7 get b"
298 created new head
298 created new head
299 --------------
299 --------------
300 test L: R:nm a b W: - 7 get b
300 test L: R:nm a b W: - 7 get b
301 --------------
301 --------------
302 searching for copies back to rev 1
302 searching for copies back to rev 1
303 unmatched files in other:
303 unmatched files in other:
304 b
304 b
305 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
305 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
306 src: 'a' -> dst: 'b'
306 src: 'a' -> dst: 'b'
307 checking for directory renames
307 checking for directory renames
308 resolving manifests
308 resolving manifests
309 branchmerge: True, force: False, partial: False
309 branchmerge: True, force: False, partial: False
310 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: bdb19105162a
310 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: bdb19105162a
311 preserving rev for resolve of rev
311 preserving rev for resolve of rev
312 a: other deleted -> r
312 a: other deleted -> r
313 removing a
313 removing a
314 b: remote created -> g
314 b: remote created -> g
315 getting b
315 getting b
316 rev: versions differ -> m (premerge)
316 rev: versions differ -> m (premerge)
317 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
317 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
318 merging rev
318 merging rev
319 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
319 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
320 rev: versions differ -> m (merge)
320 rev: versions differ -> m (merge)
321 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
321 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
322 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
322 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
323 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
323 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
324 merge tool returned: 0
324 merge tool returned: 0
325 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
325 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
326 (branch merge, don't forget to commit)
326 (branch merge, don't forget to commit)
327 --------------
327 --------------
328 M b
328 M b
329 --------------
329 --------------
330
330
331 $ tm "nm a b" " " " " "8 nothing"
331 $ tm "nm a b" " " " " "8 nothing"
332 created new head
332 created new head
333 --------------
333 --------------
334 test L:nm a b R: W: - 8 nothing
334 test L:nm a b R: W: - 8 nothing
335 --------------
335 --------------
336 searching for copies back to rev 1
336 searching for copies back to rev 1
337 unmatched files in local:
337 unmatched files in local:
338 b
338 b
339 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
339 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
340 src: 'a' -> dst: 'b'
340 src: 'a' -> dst: 'b'
341 checking for directory renames
341 checking for directory renames
342 resolving manifests
342 resolving manifests
343 branchmerge: True, force: False, partial: False
343 branchmerge: True, force: False, partial: False
344 ancestor: 924404dff337, local: 02963e448370+, remote: 97c705ade336
344 ancestor: 924404dff337, local: 02963e448370+, remote: 97c705ade336
345 preserving rev for resolve of rev
345 preserving rev for resolve of rev
346 starting 4 threads for background file closing (?)
346 starting 4 threads for background file closing (?)
347 rev: versions differ -> m (premerge)
347 rev: versions differ -> m (premerge)
348 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
348 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
349 merging rev
349 merging rev
350 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
350 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
351 rev: versions differ -> m (merge)
351 rev: versions differ -> m (merge)
352 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
352 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
353 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
353 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
354 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
354 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
355 merge tool returned: 0
355 merge tool returned: 0
356 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
356 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
357 (branch merge, don't forget to commit)
357 (branch merge, don't forget to commit)
358 --------------
358 --------------
359 C b
359 C b
360 --------------
360 --------------
361
361
362 $ tm "um a b" "um a b" " " "9 do merge with ancestor in a"
362 $ tm "um a b" "um a b" " " "9 do merge with ancestor in a"
363 created new head
363 created new head
364 --------------
364 --------------
365 test L:um a b R:um a b W: - 9 do merge with ancestor in a
365 test L:um a b R:um a b W: - 9 do merge with ancestor in a
366 --------------
366 --------------
367 searching for copies back to rev 1
367 searching for copies back to rev 1
368 unmatched files new in both:
368 unmatched files new in both:
369 b
369 b
370 resolving manifests
370 resolving manifests
371 branchmerge: True, force: False, partial: False
371 branchmerge: True, force: False, partial: False
372 ancestor: 924404dff337, local: 62e7bf090eba+, remote: 49b6d8032493
372 ancestor: 924404dff337, local: 62e7bf090eba+, remote: 49b6d8032493
373 preserving b for resolve of b
373 preserving b for resolve of b
374 preserving rev for resolve of rev
374 preserving rev for resolve of rev
375 starting 4 threads for background file closing (?)
375 starting 4 threads for background file closing (?)
376 b: both renamed from a -> m (premerge)
376 b: both renamed from a -> m (premerge)
377 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
377 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
378 merging b
378 merging b
379 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
379 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
380 rev: versions differ -> m (premerge)
380 rev: versions differ -> m (premerge)
381 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
381 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
382 merging rev
382 merging rev
383 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
383 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
384 b: both renamed from a -> m (merge)
384 b: both renamed from a -> m (merge)
385 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
385 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
386 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
386 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
387 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
387 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
388 merge tool returned: 0
388 merge tool returned: 0
389 rev: versions differ -> m (merge)
389 rev: versions differ -> m (merge)
390 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
390 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
391 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
391 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
392 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
392 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
393 merge tool returned: 0
393 merge tool returned: 0
394 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
394 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
395 (branch merge, don't forget to commit)
395 (branch merge, don't forget to commit)
396 --------------
396 --------------
397 M b
397 M b
398 --------------
398 --------------
399
399
400
400
401 m "um a c" "um x c" " " "10 do merge with no ancestor"
401 m "um a c" "um x c" " " "10 do merge with no ancestor"
402
402
403 $ tm "nm a b" "nm a c" " " "11 get c, keep b"
403 $ tm "nm a b" "nm a c" " " "11 get c, keep b"
404 created new head
404 created new head
405 --------------
405 --------------
406 test L:nm a b R:nm a c W: - 11 get c, keep b
406 test L:nm a b R:nm a c W: - 11 get c, keep b
407 --------------
407 --------------
408 searching for copies back to rev 1
408 searching for copies back to rev 1
409 unmatched files in local:
409 unmatched files in local:
410 b
410 b
411 unmatched files in other:
411 unmatched files in other:
412 c
412 c
413 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
413 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
414 src: 'a' -> dst: 'b' !
414 src: 'a' -> dst: 'b' !
415 src: 'a' -> dst: 'c' !
415 src: 'a' -> dst: 'c' !
416 checking for directory renames
416 checking for directory renames
417 resolving manifests
417 resolving manifests
418 branchmerge: True, force: False, partial: False
418 branchmerge: True, force: False, partial: False
419 ancestor: 924404dff337, local: 02963e448370+, remote: fe905ef2c33e
419 ancestor: 924404dff337, local: 02963e448370+, remote: fe905ef2c33e
420 note: possible conflict - a was renamed multiple times to:
420 note: possible conflict - a was renamed multiple times to:
421 b
421 b
422 c
422 c
423 preserving rev for resolve of rev
423 preserving rev for resolve of rev
424 c: remote created -> g
424 c: remote created -> g
425 getting c
425 getting c
426 rev: versions differ -> m (premerge)
426 rev: versions differ -> m (premerge)
427 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
427 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
428 merging rev
428 merging rev
429 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
429 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
430 rev: versions differ -> m (merge)
430 rev: versions differ -> m (merge)
431 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
431 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
432 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
432 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
433 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
433 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
434 merge tool returned: 0
434 merge tool returned: 0
435 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
435 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
436 (branch merge, don't forget to commit)
436 (branch merge, don't forget to commit)
437 --------------
437 --------------
438 M c
438 M c
439 C b
439 C b
440 --------------
440 --------------
441
441
442 $ tm "nc a b" "up b " " " "12 merge b no ancestor"
442 $ tm "nc a b" "up b " " " "12 merge b no ancestor"
443 created new head
443 created new head
444 --------------
444 --------------
445 test L:nc a b R:up b W: - 12 merge b no ancestor
445 test L:nc a b R:up b W: - 12 merge b no ancestor
446 --------------
446 --------------
447 searching for copies back to rev 1
447 searching for copies back to rev 1
448 unmatched files new in both:
448 unmatched files new in both:
449 b
449 b
450 resolving manifests
450 resolving manifests
451 branchmerge: True, force: False, partial: False
451 branchmerge: True, force: False, partial: False
452 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
452 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
453 preserving b for resolve of b
453 preserving b for resolve of b
454 preserving rev for resolve of rev
454 preserving rev for resolve of rev
455 starting 4 threads for background file closing (?)
455 starting 4 threads for background file closing (?)
456 b: both created -> m (premerge)
456 b: both created -> m (premerge)
457 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
457 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
458 merging b
458 merging b
459 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
459 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
460 rev: versions differ -> m (premerge)
460 rev: versions differ -> m (premerge)
461 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
461 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
462 merging rev
462 merging rev
463 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
463 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
464 b: both created -> m (merge)
464 b: both created -> m (merge)
465 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
465 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
466 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
466 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
467 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
467 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
468 merge tool returned: 0
468 merge tool returned: 0
469 rev: versions differ -> m (merge)
469 rev: versions differ -> m (merge)
470 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
470 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
471 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
471 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
472 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
472 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
473 merge tool returned: 0
473 merge tool returned: 0
474 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
474 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
475 (branch merge, don't forget to commit)
475 (branch merge, don't forget to commit)
476 --------------
476 --------------
477 M b
477 M b
478 C a
478 C a
479 --------------
479 --------------
480
480
481 $ tm "up b " "nm a b" " " "13 merge b no ancestor"
481 $ tm "up b " "nm a b" " " "13 merge b no ancestor"
482 created new head
482 created new head
483 --------------
483 --------------
484 test L:up b R:nm a b W: - 13 merge b no ancestor
484 test L:up b R:nm a b W: - 13 merge b no ancestor
485 --------------
485 --------------
486 searching for copies back to rev 1
486 searching for copies back to rev 1
487 unmatched files new in both:
487 unmatched files new in both:
488 b
488 b
489 resolving manifests
489 resolving manifests
490 branchmerge: True, force: False, partial: False
490 branchmerge: True, force: False, partial: False
491 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
491 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
492 preserving b for resolve of b
492 preserving b for resolve of b
493 preserving rev for resolve of rev
493 preserving rev for resolve of rev
494 a: other deleted -> r
494 a: other deleted -> r
495 removing a
495 removing a
496 starting 4 threads for background file closing (?)
496 starting 4 threads for background file closing (?)
497 b: both created -> m (premerge)
497 b: both created -> m (premerge)
498 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
498 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
499 merging b
499 merging b
500 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
500 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
501 rev: versions differ -> m (premerge)
501 rev: versions differ -> m (premerge)
502 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
502 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
503 merging rev
503 merging rev
504 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
504 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
505 b: both created -> m (merge)
505 b: both created -> m (merge)
506 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
506 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
507 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
507 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
508 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
508 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
509 merge tool returned: 0
509 merge tool returned: 0
510 rev: versions differ -> m (merge)
510 rev: versions differ -> m (merge)
511 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
511 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
512 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
512 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
513 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
513 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
514 merge tool returned: 0
514 merge tool returned: 0
515 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
515 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
516 (branch merge, don't forget to commit)
516 (branch merge, don't forget to commit)
517 --------------
517 --------------
518 M b
518 M b
519 --------------
519 --------------
520
520
521 $ tm "nc a b" "up a b" " " "14 merge b no ancestor"
521 $ tm "nc a b" "up a b" " " "14 merge b no ancestor"
522 created new head
522 created new head
523 --------------
523 --------------
524 test L:nc a b R:up a b W: - 14 merge b no ancestor
524 test L:nc a b R:up a b W: - 14 merge b no ancestor
525 --------------
525 --------------
526 searching for copies back to rev 1
526 searching for copies back to rev 1
527 unmatched files new in both:
527 unmatched files new in both:
528 b
528 b
529 resolving manifests
529 resolving manifests
530 branchmerge: True, force: False, partial: False
530 branchmerge: True, force: False, partial: False
531 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
531 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
532 preserving b for resolve of b
532 preserving b for resolve of b
533 preserving rev for resolve of rev
533 preserving rev for resolve of rev
534 a: remote is newer -> g
534 a: remote is newer -> g
535 getting a
535 getting a
536 b: both created -> m (premerge)
536 b: both created -> m (premerge)
537 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
537 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
538 merging b
538 merging b
539 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
539 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
540 rev: versions differ -> m (premerge)
540 rev: versions differ -> m (premerge)
541 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
541 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
542 merging rev
542 merging rev
543 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
543 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
544 b: both created -> m (merge)
544 b: both created -> m (merge)
545 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
545 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
546 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
546 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
547 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
547 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
548 merge tool returned: 0
548 merge tool returned: 0
549 rev: versions differ -> m (merge)
549 rev: versions differ -> m (merge)
550 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
550 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
551 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
551 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
552 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
552 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
553 merge tool returned: 0
553 merge tool returned: 0
554 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
554 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
555 (branch merge, don't forget to commit)
555 (branch merge, don't forget to commit)
556 --------------
556 --------------
557 M a
557 M a
558 M b
558 M b
559 --------------
559 --------------
560
560
561 $ tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
561 $ tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
562 created new head
562 created new head
563 --------------
563 --------------
564 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
564 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
565 --------------
565 --------------
566 searching for copies back to rev 1
566 searching for copies back to rev 1
567 unmatched files new in both:
567 unmatched files new in both:
568 b
568 b
569 resolving manifests
569 resolving manifests
570 branchmerge: True, force: False, partial: False
570 branchmerge: True, force: False, partial: False
571 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
571 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
572 preserving b for resolve of b
572 preserving b for resolve of b
573 preserving rev for resolve of rev
573 preserving rev for resolve of rev
574 a: other deleted -> r
574 a: other deleted -> r
575 removing a
575 removing a
576 starting 4 threads for background file closing (?)
576 starting 4 threads for background file closing (?)
577 b: both created -> m (premerge)
577 b: both created -> m (premerge)
578 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
578 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
579 merging b
579 merging b
580 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
580 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
581 rev: versions differ -> m (premerge)
581 rev: versions differ -> m (premerge)
582 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
582 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
583 merging rev
583 merging rev
584 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
584 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
585 b: both created -> m (merge)
585 b: both created -> m (merge)
586 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
586 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
587 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
587 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
588 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
588 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
589 merge tool returned: 0
589 merge tool returned: 0
590 rev: versions differ -> m (merge)
590 rev: versions differ -> m (merge)
591 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
591 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
592 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
592 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
593 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
593 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
594 merge tool returned: 0
594 merge tool returned: 0
595 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
595 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
596 (branch merge, don't forget to commit)
596 (branch merge, don't forget to commit)
597 --------------
597 --------------
598 M b
598 M b
599 --------------
599 --------------
600
600
601 $ tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
601 $ tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
602 created new head
602 created new head
603 --------------
603 --------------
604 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
604 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
605 --------------
605 --------------
606 searching for copies back to rev 1
606 searching for copies back to rev 1
607 unmatched files new in both:
607 unmatched files new in both:
608 b
608 b
609 resolving manifests
609 resolving manifests
610 branchmerge: True, force: False, partial: False
610 branchmerge: True, force: False, partial: False
611 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
611 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
612 preserving b for resolve of b
612 preserving b for resolve of b
613 preserving rev for resolve of rev
613 preserving rev for resolve of rev
614 a: remote is newer -> g
614 a: remote is newer -> g
615 getting a
615 getting a
616 b: both created -> m (premerge)
616 b: both created -> m (premerge)
617 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
617 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
618 merging b
618 merging b
619 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
619 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
620 rev: versions differ -> m (premerge)
620 rev: versions differ -> m (premerge)
621 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
621 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
622 merging rev
622 merging rev
623 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
623 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
624 b: both created -> m (merge)
624 b: both created -> m (merge)
625 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
625 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
626 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
626 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
627 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
627 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
628 merge tool returned: 0
628 merge tool returned: 0
629 rev: versions differ -> m (merge)
629 rev: versions differ -> m (merge)
630 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
630 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
631 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
631 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
632 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
632 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
633 merge tool returned: 0
633 merge tool returned: 0
634 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
634 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
635 (branch merge, don't forget to commit)
635 (branch merge, don't forget to commit)
636 --------------
636 --------------
637 M a
637 M a
638 M b
638 M b
639 --------------
639 --------------
640
640
641 $ tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
641 $ tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
642 created new head
642 created new head
643 --------------
643 --------------
644 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
644 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
645 --------------
645 --------------
646 searching for copies back to rev 1
646 searching for copies back to rev 1
647 unmatched files new in both:
647 unmatched files new in both:
648 b
648 b
649 resolving manifests
649 resolving manifests
650 branchmerge: True, force: False, partial: False
650 branchmerge: True, force: False, partial: False
651 ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
651 ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
652 preserving b for resolve of b
652 preserving b for resolve of b
653 preserving rev for resolve of rev
653 preserving rev for resolve of rev
654 starting 4 threads for background file closing (?)
654 starting 4 threads for background file closing (?)
655 a: remote unchanged -> k
655 a: remote unchanged -> k
656 b: both created -> m (premerge)
656 b: both created -> m (premerge)
657 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
657 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
658 merging b
658 merging b
659 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
659 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
660 rev: versions differ -> m (premerge)
660 rev: versions differ -> m (premerge)
661 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
661 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
662 merging rev
662 merging rev
663 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
663 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
664 b: both created -> m (merge)
664 b: both created -> m (merge)
665 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
665 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
666 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
666 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
667 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
667 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
668 merge tool returned: 0
668 merge tool returned: 0
669 rev: versions differ -> m (merge)
669 rev: versions differ -> m (merge)
670 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
670 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
671 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
671 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
672 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
672 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
673 merge tool returned: 0
673 merge tool returned: 0
674 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
674 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
675 (branch merge, don't forget to commit)
675 (branch merge, don't forget to commit)
676 --------------
676 --------------
677 M b
677 M b
678 C a
678 C a
679 --------------
679 --------------
680
680
681 $ tm "nm a b" "up a b" " " "18 merge b no ancestor"
681 $ tm "nm a b" "up a b" " " "18 merge b no ancestor"
682 created new head
682 created new head
683 --------------
683 --------------
684 test L:nm a b R:up a b W: - 18 merge b no ancestor
684 test L:nm a b R:up a b W: - 18 merge b no ancestor
685 --------------
685 --------------
686 searching for copies back to rev 1
686 searching for copies back to rev 1
687 unmatched files new in both:
687 unmatched files new in both:
688 b
688 b
689 resolving manifests
689 resolving manifests
690 branchmerge: True, force: False, partial: False
690 branchmerge: True, force: False, partial: False
691 ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
691 ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
692 preserving b for resolve of b
692 preserving b for resolve of b
693 preserving rev for resolve of rev
693 preserving rev for resolve of rev
694 starting 4 threads for background file closing (?)
694 starting 4 threads for background file closing (?)
695 a: prompt deleted/changed -> m (premerge)
695 a: prompt deleted/changed -> m (premerge)
696 picked tool ':prompt' for a (binary False symlink False changedelete True)
696 picked tool ':prompt' for a (binary False symlink False changedelete True)
697 other changed a which local deleted
697 other changed a which local deleted
698 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
698 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
699 b: both created -> m (premerge)
699 b: both created -> m (premerge)
700 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
700 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
701 merging b
701 merging b
702 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
702 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
703 rev: versions differ -> m (premerge)
703 rev: versions differ -> m (premerge)
704 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
704 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
705 merging rev
705 merging rev
706 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
706 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
707 b: both created -> m (merge)
707 b: both created -> m (merge)
708 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
708 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
709 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
709 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
710 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
710 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
711 merge tool returned: 0
711 merge tool returned: 0
712 rev: versions differ -> m (merge)
712 rev: versions differ -> m (merge)
713 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
713 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
714 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
714 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
715 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
715 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
716 merge tool returned: 0
716 merge tool returned: 0
717 0 files updated, 2 files merged, 0 files removed, 1 files unresolved
717 0 files updated, 2 files merged, 0 files removed, 1 files unresolved
718 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
718 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
719 --------------
719 --------------
720 M a
720 M a
721 M b
721 M b
722 abort: unresolved merge conflicts (see "hg help resolve")
722 abort: unresolved merge conflicts (see 'hg help resolve')
723 --------------
723 --------------
724
724
725 $ tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
725 $ tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
726 created new head
726 created new head
727 --------------
727 --------------
728 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
728 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
729 --------------
729 --------------
730 searching for copies back to rev 1
730 searching for copies back to rev 1
731 unmatched files new in both:
731 unmatched files new in both:
732 b
732 b
733 resolving manifests
733 resolving manifests
734 branchmerge: True, force: False, partial: False
734 branchmerge: True, force: False, partial: False
735 ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
735 ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
736 preserving a for resolve of a
736 preserving a for resolve of a
737 preserving b for resolve of b
737 preserving b for resolve of b
738 preserving rev for resolve of rev
738 preserving rev for resolve of rev
739 starting 4 threads for background file closing (?)
739 starting 4 threads for background file closing (?)
740 a: prompt changed/deleted -> m (premerge)
740 a: prompt changed/deleted -> m (premerge)
741 picked tool ':prompt' for a (binary False symlink False changedelete True)
741 picked tool ':prompt' for a (binary False symlink False changedelete True)
742 local changed a which other deleted
742 local changed a which other deleted
743 use (c)hanged version, (d)elete, or leave (u)nresolved? u
743 use (c)hanged version, (d)elete, or leave (u)nresolved? u
744 b: both created -> m (premerge)
744 b: both created -> m (premerge)
745 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
745 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
746 merging b
746 merging b
747 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
747 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
748 rev: versions differ -> m (premerge)
748 rev: versions differ -> m (premerge)
749 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
749 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
750 merging rev
750 merging rev
751 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
751 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
752 b: both created -> m (merge)
752 b: both created -> m (merge)
753 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
753 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
754 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
754 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
755 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
755 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
756 merge tool returned: 0
756 merge tool returned: 0
757 rev: versions differ -> m (merge)
757 rev: versions differ -> m (merge)
758 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
758 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
759 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
759 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
760 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
760 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
761 merge tool returned: 0
761 merge tool returned: 0
762 0 files updated, 2 files merged, 0 files removed, 1 files unresolved
762 0 files updated, 2 files merged, 0 files removed, 1 files unresolved
763 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
763 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
764 --------------
764 --------------
765 M b
765 M b
766 C a
766 C a
767 abort: unresolved merge conflicts (see "hg help resolve")
767 abort: unresolved merge conflicts (see 'hg help resolve')
768 --------------
768 --------------
769
769
770 $ tm "up a " "um a b" " " "20 merge a and b to b, remove a"
770 $ tm "up a " "um a b" " " "20 merge a and b to b, remove a"
771 created new head
771 created new head
772 --------------
772 --------------
773 test L:up a R:um a b W: - 20 merge a and b to b, remove a
773 test L:up a R:um a b W: - 20 merge a and b to b, remove a
774 --------------
774 --------------
775 searching for copies back to rev 1
775 searching for copies back to rev 1
776 unmatched files in other:
776 unmatched files in other:
777 b
777 b
778 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
778 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
779 src: 'a' -> dst: 'b' *
779 src: 'a' -> dst: 'b' *
780 checking for directory renames
780 checking for directory renames
781 resolving manifests
781 resolving manifests
782 branchmerge: True, force: False, partial: False
782 branchmerge: True, force: False, partial: False
783 ancestor: 924404dff337, local: e300d1c794ec+, remote: 49b6d8032493
783 ancestor: 924404dff337, local: e300d1c794ec+, remote: 49b6d8032493
784 preserving a for resolve of b
784 preserving a for resolve of b
785 preserving rev for resolve of rev
785 preserving rev for resolve of rev
786 removing a
786 removing a
787 starting 4 threads for background file closing (?)
787 starting 4 threads for background file closing (?)
788 b: remote moved from a -> m (premerge)
788 b: remote moved from a -> m (premerge)
789 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
789 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
790 merging a and b to b
790 merging a and b to b
791 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
791 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
792 rev: versions differ -> m (premerge)
792 rev: versions differ -> m (premerge)
793 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
793 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
794 merging rev
794 merging rev
795 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
795 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
796 b: remote moved from a -> m (merge)
796 b: remote moved from a -> m (merge)
797 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
797 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
798 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
798 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
799 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
799 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
800 merge tool returned: 0
800 merge tool returned: 0
801 rev: versions differ -> m (merge)
801 rev: versions differ -> m (merge)
802 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
802 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
803 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
803 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
804 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
804 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
805 merge tool returned: 0
805 merge tool returned: 0
806 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
806 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
807 (branch merge, don't forget to commit)
807 (branch merge, don't forget to commit)
808 --------------
808 --------------
809 M b
809 M b
810 a
810 a
811 --------------
811 --------------
812
812
813 $ tm "um a b" "up a " " " "21 merge a and b to b"
813 $ tm "um a b" "up a " " " "21 merge a and b to b"
814 created new head
814 created new head
815 --------------
815 --------------
816 test L:um a b R:up a W: - 21 merge a and b to b
816 test L:um a b R:up a W: - 21 merge a and b to b
817 --------------
817 --------------
818 searching for copies back to rev 1
818 searching for copies back to rev 1
819 unmatched files in local:
819 unmatched files in local:
820 b
820 b
821 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
821 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
822 src: 'a' -> dst: 'b' *
822 src: 'a' -> dst: 'b' *
823 checking for directory renames
823 checking for directory renames
824 resolving manifests
824 resolving manifests
825 branchmerge: True, force: False, partial: False
825 branchmerge: True, force: False, partial: False
826 ancestor: 924404dff337, local: 62e7bf090eba+, remote: f4db7e329e71
826 ancestor: 924404dff337, local: 62e7bf090eba+, remote: f4db7e329e71
827 preserving b for resolve of b
827 preserving b for resolve of b
828 preserving rev for resolve of rev
828 preserving rev for resolve of rev
829 starting 4 threads for background file closing (?)
829 starting 4 threads for background file closing (?)
830 b: local copied/moved from a -> m (premerge)
830 b: local copied/moved from a -> m (premerge)
831 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
831 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
832 merging b and a to b
832 merging b and a to b
833 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
833 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
834 rev: versions differ -> m (premerge)
834 rev: versions differ -> m (premerge)
835 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
835 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
836 merging rev
836 merging rev
837 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
837 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
838 b: local copied/moved from a -> m (merge)
838 b: local copied/moved from a -> m (merge)
839 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
839 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
840 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
840 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
841 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
841 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
842 merge tool returned: 0
842 merge tool returned: 0
843 rev: versions differ -> m (merge)
843 rev: versions differ -> m (merge)
844 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
844 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
845 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
845 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
846 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
846 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
847 merge tool returned: 0
847 merge tool returned: 0
848 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
848 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
849 (branch merge, don't forget to commit)
849 (branch merge, don't forget to commit)
850 --------------
850 --------------
851 M b
851 M b
852 a
852 a
853 --------------
853 --------------
854
854
855
855
856 m "nm a b" "um x a" " " "22 get a, keep b"
856 m "nm a b" "um x a" " " "22 get a, keep b"
857
857
858 $ tm "nm a b" "up a c" " " "23 get c, keep b"
858 $ tm "nm a b" "up a c" " " "23 get c, keep b"
859 created new head
859 created new head
860 --------------
860 --------------
861 test L:nm a b R:up a c W: - 23 get c, keep b
861 test L:nm a b R:up a c W: - 23 get c, keep b
862 --------------
862 --------------
863 searching for copies back to rev 1
863 searching for copies back to rev 1
864 unmatched files in local:
864 unmatched files in local:
865 b
865 b
866 unmatched files in other:
866 unmatched files in other:
867 c
867 c
868 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
868 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
869 src: 'a' -> dst: 'b' *
869 src: 'a' -> dst: 'b' *
870 checking for directory renames
870 checking for directory renames
871 resolving manifests
871 resolving manifests
872 branchmerge: True, force: False, partial: False
872 branchmerge: True, force: False, partial: False
873 ancestor: 924404dff337, local: 02963e448370+, remote: 2b958612230f
873 ancestor: 924404dff337, local: 02963e448370+, remote: 2b958612230f
874 preserving b for resolve of b
874 preserving b for resolve of b
875 preserving rev for resolve of rev
875 preserving rev for resolve of rev
876 c: remote created -> g
876 c: remote created -> g
877 getting c
877 getting c
878 b: local copied/moved from a -> m (premerge)
878 b: local copied/moved from a -> m (premerge)
879 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
879 picked tool 'python ../merge' for b (binary False symlink False changedelete False)
880 merging b and a to b
880 merging b and a to b
881 my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
881 my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
882 premerge successful
882 premerge successful
883 rev: versions differ -> m (premerge)
883 rev: versions differ -> m (premerge)
884 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
884 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
885 merging rev
885 merging rev
886 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
886 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
887 rev: versions differ -> m (merge)
887 rev: versions differ -> m (merge)
888 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
888 picked tool 'python ../merge' for rev (binary False symlink False changedelete False)
889 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
889 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
890 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
890 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
891 merge tool returned: 0
891 merge tool returned: 0
892 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
892 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
893 (branch merge, don't forget to commit)
893 (branch merge, don't forget to commit)
894 --------------
894 --------------
895 M b
895 M b
896 a
896 a
897 M c
897 M c
898 --------------
898 --------------
899
899
900
900
901 $ cd ..
901 $ cd ..
902
902
903
903
904 Systematic and terse testing of merge merges and ancestor calculation:
904 Systematic and terse testing of merge merges and ancestor calculation:
905
905
906 Expected result:
906 Expected result:
907
907
908 \ a m1 m2 dst
908 \ a m1 m2 dst
909 0 - f f f "versions differ"
909 0 - f f f "versions differ"
910 1 f g g g "versions differ"
910 1 f g g g "versions differ"
911 2 f f f f "versions differ"
911 2 f f f f "versions differ"
912 3 f f g f+g "remote copied to " + f
912 3 f f g f+g "remote copied to " + f
913 4 f f g g "remote moved to " + f
913 4 f f g g "remote moved to " + f
914 5 f g f f+g "local copied to " + f2
914 5 f g f f+g "local copied to " + f2
915 6 f g f g "local moved to " + f2
915 6 f g f g "local moved to " + f2
916 7 - (f) f f "remote differs from untracked local"
916 7 - (f) f f "remote differs from untracked local"
917 8 f (f) f f "remote differs from untracked local"
917 8 f (f) f f "remote differs from untracked local"
918
918
919 $ hg init ancestortest
919 $ hg init ancestortest
920 $ cd ancestortest
920 $ cd ancestortest
921 $ for x in 1 2 3 4 5 6 8; do mkdir $x; echo a > $x/f; done
921 $ for x in 1 2 3 4 5 6 8; do mkdir $x; echo a > $x/f; done
922 $ hg ci -Aqm "a"
922 $ hg ci -Aqm "a"
923 $ mkdir 0
923 $ mkdir 0
924 $ touch 0/f
924 $ touch 0/f
925 $ hg mv 1/f 1/g
925 $ hg mv 1/f 1/g
926 $ hg cp 5/f 5/g
926 $ hg cp 5/f 5/g
927 $ hg mv 6/f 6/g
927 $ hg mv 6/f 6/g
928 $ hg rm 8/f
928 $ hg rm 8/f
929 $ for x in */*; do echo m1 > $x; done
929 $ for x in */*; do echo m1 > $x; done
930 $ hg ci -Aqm "m1"
930 $ hg ci -Aqm "m1"
931 $ hg up -qr0
931 $ hg up -qr0
932 $ mkdir 0 7
932 $ mkdir 0 7
933 $ touch 0/f 7/f
933 $ touch 0/f 7/f
934 $ hg mv 1/f 1/g
934 $ hg mv 1/f 1/g
935 $ hg cp 3/f 3/g
935 $ hg cp 3/f 3/g
936 $ hg mv 4/f 4/g
936 $ hg mv 4/f 4/g
937 $ for x in */*; do echo m2 > $x; done
937 $ for x in */*; do echo m2 > $x; done
938 $ hg ci -Aqm "m2"
938 $ hg ci -Aqm "m2"
939 $ hg up -qr1
939 $ hg up -qr1
940 $ mkdir 7 8
940 $ mkdir 7 8
941 $ echo m > 7/f
941 $ echo m > 7/f
942 $ echo m > 8/f
942 $ echo m > 8/f
943 $ hg merge -f --tool internal:dump -v --debug -r2 | sed '/^resolving manifests/,$d' 2> /dev/null
943 $ hg merge -f --tool internal:dump -v --debug -r2 | sed '/^resolving manifests/,$d' 2> /dev/null
944 searching for copies back to rev 1
944 searching for copies back to rev 1
945 unmatched files in local:
945 unmatched files in local:
946 5/g
946 5/g
947 6/g
947 6/g
948 unmatched files in other:
948 unmatched files in other:
949 3/g
949 3/g
950 4/g
950 4/g
951 7/f
951 7/f
952 unmatched files new in both:
952 unmatched files new in both:
953 0/f
953 0/f
954 1/g
954 1/g
955 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
955 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
956 src: '3/f' -> dst: '3/g' *
956 src: '3/f' -> dst: '3/g' *
957 src: '4/f' -> dst: '4/g' *
957 src: '4/f' -> dst: '4/g' *
958 src: '5/f' -> dst: '5/g' *
958 src: '5/f' -> dst: '5/g' *
959 src: '6/f' -> dst: '6/g' *
959 src: '6/f' -> dst: '6/g' *
960 checking for directory renames
960 checking for directory renames
961 $ hg mani
961 $ hg mani
962 0/f
962 0/f
963 1/g
963 1/g
964 2/f
964 2/f
965 3/f
965 3/f
966 4/f
966 4/f
967 5/f
967 5/f
968 5/g
968 5/g
969 6/g
969 6/g
970 $ for f in */*; do echo $f:; cat $f; done
970 $ for f in */*; do echo $f:; cat $f; done
971 0/f:
971 0/f:
972 m1
972 m1
973 0/f.base:
973 0/f.base:
974 0/f.local:
974 0/f.local:
975 m1
975 m1
976 0/f.orig:
976 0/f.orig:
977 m1
977 m1
978 0/f.other:
978 0/f.other:
979 m2
979 m2
980 1/g:
980 1/g:
981 m1
981 m1
982 1/g.base:
982 1/g.base:
983 a
983 a
984 1/g.local:
984 1/g.local:
985 m1
985 m1
986 1/g.orig:
986 1/g.orig:
987 m1
987 m1
988 1/g.other:
988 1/g.other:
989 m2
989 m2
990 2/f:
990 2/f:
991 m1
991 m1
992 2/f.base:
992 2/f.base:
993 a
993 a
994 2/f.local:
994 2/f.local:
995 m1
995 m1
996 2/f.orig:
996 2/f.orig:
997 m1
997 m1
998 2/f.other:
998 2/f.other:
999 m2
999 m2
1000 3/f:
1000 3/f:
1001 m1
1001 m1
1002 3/f.base:
1002 3/f.base:
1003 a
1003 a
1004 3/f.local:
1004 3/f.local:
1005 m1
1005 m1
1006 3/f.orig:
1006 3/f.orig:
1007 m1
1007 m1
1008 3/f.other:
1008 3/f.other:
1009 m2
1009 m2
1010 3/g:
1010 3/g:
1011 m1
1011 m1
1012 3/g.base:
1012 3/g.base:
1013 a
1013 a
1014 3/g.local:
1014 3/g.local:
1015 m1
1015 m1
1016 3/g.orig:
1016 3/g.orig:
1017 m1
1017 m1
1018 3/g.other:
1018 3/g.other:
1019 m2
1019 m2
1020 4/g:
1020 4/g:
1021 m1
1021 m1
1022 4/g.base:
1022 4/g.base:
1023 a
1023 a
1024 4/g.local:
1024 4/g.local:
1025 m1
1025 m1
1026 4/g.orig:
1026 4/g.orig:
1027 m1
1027 m1
1028 4/g.other:
1028 4/g.other:
1029 m2
1029 m2
1030 5/f:
1030 5/f:
1031 m1
1031 m1
1032 5/f.base:
1032 5/f.base:
1033 a
1033 a
1034 5/f.local:
1034 5/f.local:
1035 m1
1035 m1
1036 5/f.orig:
1036 5/f.orig:
1037 m1
1037 m1
1038 5/f.other:
1038 5/f.other:
1039 m2
1039 m2
1040 5/g:
1040 5/g:
1041 m1
1041 m1
1042 5/g.base:
1042 5/g.base:
1043 a
1043 a
1044 5/g.local:
1044 5/g.local:
1045 m1
1045 m1
1046 5/g.orig:
1046 5/g.orig:
1047 m1
1047 m1
1048 5/g.other:
1048 5/g.other:
1049 m2
1049 m2
1050 6/g:
1050 6/g:
1051 m1
1051 m1
1052 6/g.base:
1052 6/g.base:
1053 a
1053 a
1054 6/g.local:
1054 6/g.local:
1055 m1
1055 m1
1056 6/g.orig:
1056 6/g.orig:
1057 m1
1057 m1
1058 6/g.other:
1058 6/g.other:
1059 m2
1059 m2
1060 7/f:
1060 7/f:
1061 m
1061 m
1062 7/f.base:
1062 7/f.base:
1063 7/f.local:
1063 7/f.local:
1064 m
1064 m
1065 7/f.orig:
1065 7/f.orig:
1066 m
1066 m
1067 7/f.other:
1067 7/f.other:
1068 m2
1068 m2
1069 8/f:
1069 8/f:
1070 m2
1070 m2
1071 $ cd ..
1071 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now