##// END OF EJS Templates
rollback: only restore dirstate and branch when appropriate....
Greg Ward -
r15131:7c26ce9e default
parent child Browse files
Show More
@@ -1,2067 +1,2074 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 node import bin, hex, nullid, nullrev, short
8 from node import bin, hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import repo, changegroup, subrepo, discovery, pushkey
10 import repo, changegroup, subrepo, discovery, pushkey
11 import changelog, dirstate, filelog, manifest, context, bookmarks
11 import changelog, dirstate, filelog, manifest, context, bookmarks
12 import lock, transaction, store, encoding
12 import lock, transaction, store, encoding
13 import scmutil, util, extensions, hook, error, revset
13 import scmutil, util, extensions, hook, error, revset
14 import match as matchmod
14 import match as matchmod
15 import merge as mergemod
15 import merge as mergemod
16 import tags as tagsmod
16 import tags as tagsmod
17 from lock import release
17 from lock import release
18 import weakref, errno, os, time, inspect
18 import weakref, errno, os, time, inspect
19 propertycache = util.propertycache
19 propertycache = util.propertycache
20 filecache = scmutil.filecache
20 filecache = scmutil.filecache
21
21
22 class localrepository(repo.repository):
22 class localrepository(repo.repository):
23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
24 'known', 'getbundle'))
24 'known', 'getbundle'))
25 supportedformats = set(('revlogv1', 'generaldelta'))
25 supportedformats = set(('revlogv1', 'generaldelta'))
26 supported = supportedformats | set(('store', 'fncache', 'shared',
26 supported = supportedformats | set(('store', 'fncache', 'shared',
27 'dotencode'))
27 'dotencode'))
28
28
29 def __init__(self, baseui, path=None, create=False):
29 def __init__(self, baseui, path=None, create=False):
30 repo.repository.__init__(self)
30 repo.repository.__init__(self)
31 self.root = os.path.realpath(util.expandpath(path))
31 self.root = os.path.realpath(util.expandpath(path))
32 self.path = os.path.join(self.root, ".hg")
32 self.path = os.path.join(self.root, ".hg")
33 self.origroot = path
33 self.origroot = path
34 self.auditor = scmutil.pathauditor(self.root, self._checknested)
34 self.auditor = scmutil.pathauditor(self.root, self._checknested)
35 self.opener = scmutil.opener(self.path)
35 self.opener = scmutil.opener(self.path)
36 self.wopener = scmutil.opener(self.root)
36 self.wopener = scmutil.opener(self.root)
37 self.baseui = baseui
37 self.baseui = baseui
38 self.ui = baseui.copy()
38 self.ui = baseui.copy()
39
39
40 try:
40 try:
41 self.ui.readconfig(self.join("hgrc"), self.root)
41 self.ui.readconfig(self.join("hgrc"), self.root)
42 extensions.loadall(self.ui)
42 extensions.loadall(self.ui)
43 except IOError:
43 except IOError:
44 pass
44 pass
45
45
46 if not os.path.isdir(self.path):
46 if not os.path.isdir(self.path):
47 if create:
47 if create:
48 if not os.path.exists(path):
48 if not os.path.exists(path):
49 util.makedirs(path)
49 util.makedirs(path)
50 util.makedir(self.path, notindexed=True)
50 util.makedir(self.path, notindexed=True)
51 requirements = ["revlogv1"]
51 requirements = ["revlogv1"]
52 if self.ui.configbool('format', 'usestore', True):
52 if self.ui.configbool('format', 'usestore', True):
53 os.mkdir(os.path.join(self.path, "store"))
53 os.mkdir(os.path.join(self.path, "store"))
54 requirements.append("store")
54 requirements.append("store")
55 if self.ui.configbool('format', 'usefncache', True):
55 if self.ui.configbool('format', 'usefncache', True):
56 requirements.append("fncache")
56 requirements.append("fncache")
57 if self.ui.configbool('format', 'dotencode', True):
57 if self.ui.configbool('format', 'dotencode', True):
58 requirements.append('dotencode')
58 requirements.append('dotencode')
59 # create an invalid changelog
59 # create an invalid changelog
60 self.opener.append(
60 self.opener.append(
61 "00changelog.i",
61 "00changelog.i",
62 '\0\0\0\2' # represents revlogv2
62 '\0\0\0\2' # represents revlogv2
63 ' dummy changelog to prevent using the old repo layout'
63 ' dummy changelog to prevent using the old repo layout'
64 )
64 )
65 if self.ui.configbool('format', 'generaldelta', False):
65 if self.ui.configbool('format', 'generaldelta', False):
66 requirements.append("generaldelta")
66 requirements.append("generaldelta")
67 requirements = set(requirements)
67 requirements = set(requirements)
68 else:
68 else:
69 raise error.RepoError(_("repository %s not found") % path)
69 raise error.RepoError(_("repository %s not found") % path)
70 elif create:
70 elif create:
71 raise error.RepoError(_("repository %s already exists") % path)
71 raise error.RepoError(_("repository %s already exists") % path)
72 else:
72 else:
73 try:
73 try:
74 requirements = scmutil.readrequires(self.opener, self.supported)
74 requirements = scmutil.readrequires(self.opener, self.supported)
75 except IOError, inst:
75 except IOError, inst:
76 if inst.errno != errno.ENOENT:
76 if inst.errno != errno.ENOENT:
77 raise
77 raise
78 requirements = set()
78 requirements = set()
79
79
80 self.sharedpath = self.path
80 self.sharedpath = self.path
81 try:
81 try:
82 s = os.path.realpath(self.opener.read("sharedpath").rstrip('\n'))
82 s = os.path.realpath(self.opener.read("sharedpath").rstrip('\n'))
83 if not os.path.exists(s):
83 if not os.path.exists(s):
84 raise error.RepoError(
84 raise error.RepoError(
85 _('.hg/sharedpath points to nonexistent directory %s') % s)
85 _('.hg/sharedpath points to nonexistent directory %s') % s)
86 self.sharedpath = s
86 self.sharedpath = s
87 except IOError, inst:
87 except IOError, inst:
88 if inst.errno != errno.ENOENT:
88 if inst.errno != errno.ENOENT:
89 raise
89 raise
90
90
91 self.store = store.store(requirements, self.sharedpath, scmutil.opener)
91 self.store = store.store(requirements, self.sharedpath, scmutil.opener)
92 self.spath = self.store.path
92 self.spath = self.store.path
93 self.sopener = self.store.opener
93 self.sopener = self.store.opener
94 self.sjoin = self.store.join
94 self.sjoin = self.store.join
95 self.opener.createmode = self.store.createmode
95 self.opener.createmode = self.store.createmode
96 self._applyrequirements(requirements)
96 self._applyrequirements(requirements)
97 if create:
97 if create:
98 self._writerequirements()
98 self._writerequirements()
99
99
100
100
101 self._branchcache = None
101 self._branchcache = None
102 self._branchcachetip = None
102 self._branchcachetip = None
103 self.filterpats = {}
103 self.filterpats = {}
104 self._datafilters = {}
104 self._datafilters = {}
105 self._transref = self._lockref = self._wlockref = None
105 self._transref = self._lockref = self._wlockref = None
106
106
107 # A cache for various files under .hg/ that tracks file changes,
107 # A cache for various files under .hg/ that tracks file changes,
108 # (used by the filecache decorator)
108 # (used by the filecache decorator)
109 #
109 #
110 # Maps a property name to its util.filecacheentry
110 # Maps a property name to its util.filecacheentry
111 self._filecache = {}
111 self._filecache = {}
112
112
113 def _applyrequirements(self, requirements):
113 def _applyrequirements(self, requirements):
114 self.requirements = requirements
114 self.requirements = requirements
115 openerreqs = set(('revlogv1', 'generaldelta'))
115 openerreqs = set(('revlogv1', 'generaldelta'))
116 self.sopener.options = dict((r, 1) for r in requirements
116 self.sopener.options = dict((r, 1) for r in requirements
117 if r in openerreqs)
117 if r in openerreqs)
118
118
119 def _writerequirements(self):
119 def _writerequirements(self):
120 reqfile = self.opener("requires", "w")
120 reqfile = self.opener("requires", "w")
121 for r in self.requirements:
121 for r in self.requirements:
122 reqfile.write("%s\n" % r)
122 reqfile.write("%s\n" % r)
123 reqfile.close()
123 reqfile.close()
124
124
125 def _checknested(self, path):
125 def _checknested(self, path):
126 """Determine if path is a legal nested repository."""
126 """Determine if path is a legal nested repository."""
127 if not path.startswith(self.root):
127 if not path.startswith(self.root):
128 return False
128 return False
129 subpath = path[len(self.root) + 1:]
129 subpath = path[len(self.root) + 1:]
130
130
131 # XXX: Checking against the current working copy is wrong in
131 # XXX: Checking against the current working copy is wrong in
132 # the sense that it can reject things like
132 # the sense that it can reject things like
133 #
133 #
134 # $ hg cat -r 10 sub/x.txt
134 # $ hg cat -r 10 sub/x.txt
135 #
135 #
136 # if sub/ is no longer a subrepository in the working copy
136 # if sub/ is no longer a subrepository in the working copy
137 # parent revision.
137 # parent revision.
138 #
138 #
139 # However, it can of course also allow things that would have
139 # However, it can of course also allow things that would have
140 # been rejected before, such as the above cat command if sub/
140 # been rejected before, such as the above cat command if sub/
141 # is a subrepository now, but was a normal directory before.
141 # is a subrepository now, but was a normal directory before.
142 # The old path auditor would have rejected by mistake since it
142 # The old path auditor would have rejected by mistake since it
143 # panics when it sees sub/.hg/.
143 # panics when it sees sub/.hg/.
144 #
144 #
145 # All in all, checking against the working copy seems sensible
145 # All in all, checking against the working copy seems sensible
146 # since we want to prevent access to nested repositories on
146 # since we want to prevent access to nested repositories on
147 # the filesystem *now*.
147 # the filesystem *now*.
148 ctx = self[None]
148 ctx = self[None]
149 parts = util.splitpath(subpath)
149 parts = util.splitpath(subpath)
150 while parts:
150 while parts:
151 prefix = os.sep.join(parts)
151 prefix = os.sep.join(parts)
152 if prefix in ctx.substate:
152 if prefix in ctx.substate:
153 if prefix == subpath:
153 if prefix == subpath:
154 return True
154 return True
155 else:
155 else:
156 sub = ctx.sub(prefix)
156 sub = ctx.sub(prefix)
157 return sub.checknested(subpath[len(prefix) + 1:])
157 return sub.checknested(subpath[len(prefix) + 1:])
158 else:
158 else:
159 parts.pop()
159 parts.pop()
160 return False
160 return False
161
161
162 @filecache('bookmarks')
162 @filecache('bookmarks')
163 def _bookmarks(self):
163 def _bookmarks(self):
164 return bookmarks.read(self)
164 return bookmarks.read(self)
165
165
166 @filecache('bookmarks.current')
166 @filecache('bookmarks.current')
167 def _bookmarkcurrent(self):
167 def _bookmarkcurrent(self):
168 return bookmarks.readcurrent(self)
168 return bookmarks.readcurrent(self)
169
169
170 @filecache('00changelog.i', True)
170 @filecache('00changelog.i', True)
171 def changelog(self):
171 def changelog(self):
172 c = changelog.changelog(self.sopener)
172 c = changelog.changelog(self.sopener)
173 if 'HG_PENDING' in os.environ:
173 if 'HG_PENDING' in os.environ:
174 p = os.environ['HG_PENDING']
174 p = os.environ['HG_PENDING']
175 if p.startswith(self.root):
175 if p.startswith(self.root):
176 c.readpending('00changelog.i.a')
176 c.readpending('00changelog.i.a')
177 return c
177 return c
178
178
179 @filecache('00manifest.i', True)
179 @filecache('00manifest.i', True)
180 def manifest(self):
180 def manifest(self):
181 return manifest.manifest(self.sopener)
181 return manifest.manifest(self.sopener)
182
182
183 @filecache('dirstate')
183 @filecache('dirstate')
184 def dirstate(self):
184 def dirstate(self):
185 warned = [0]
185 warned = [0]
186 def validate(node):
186 def validate(node):
187 try:
187 try:
188 self.changelog.rev(node)
188 self.changelog.rev(node)
189 return node
189 return node
190 except error.LookupError:
190 except error.LookupError:
191 if not warned[0]:
191 if not warned[0]:
192 warned[0] = True
192 warned[0] = True
193 self.ui.warn(_("warning: ignoring unknown"
193 self.ui.warn(_("warning: ignoring unknown"
194 " working parent %s!\n") % short(node))
194 " working parent %s!\n") % short(node))
195 return nullid
195 return nullid
196
196
197 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
197 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
198
198
199 def __getitem__(self, changeid):
199 def __getitem__(self, changeid):
200 if changeid is None:
200 if changeid is None:
201 return context.workingctx(self)
201 return context.workingctx(self)
202 return context.changectx(self, changeid)
202 return context.changectx(self, changeid)
203
203
204 def __contains__(self, changeid):
204 def __contains__(self, changeid):
205 try:
205 try:
206 return bool(self.lookup(changeid))
206 return bool(self.lookup(changeid))
207 except error.RepoLookupError:
207 except error.RepoLookupError:
208 return False
208 return False
209
209
210 def __nonzero__(self):
210 def __nonzero__(self):
211 return True
211 return True
212
212
213 def __len__(self):
213 def __len__(self):
214 return len(self.changelog)
214 return len(self.changelog)
215
215
216 def __iter__(self):
216 def __iter__(self):
217 for i in xrange(len(self)):
217 for i in xrange(len(self)):
218 yield i
218 yield i
219
219
220 def set(self, expr, *args):
220 def set(self, expr, *args):
221 '''
221 '''
222 Yield a context for each matching revision, after doing arg
222 Yield a context for each matching revision, after doing arg
223 replacement via revset.formatspec
223 replacement via revset.formatspec
224 '''
224 '''
225
225
226 expr = revset.formatspec(expr, *args)
226 expr = revset.formatspec(expr, *args)
227 m = revset.match(None, expr)
227 m = revset.match(None, expr)
228 for r in m(self, range(len(self))):
228 for r in m(self, range(len(self))):
229 yield self[r]
229 yield self[r]
230
230
231 def url(self):
231 def url(self):
232 return 'file:' + self.root
232 return 'file:' + self.root
233
233
234 def hook(self, name, throw=False, **args):
234 def hook(self, name, throw=False, **args):
235 return hook.hook(self.ui, self, name, throw, **args)
235 return hook.hook(self.ui, self, name, throw, **args)
236
236
237 tag_disallowed = ':\r\n'
237 tag_disallowed = ':\r\n'
238
238
239 def _tag(self, names, node, message, local, user, date, extra={}):
239 def _tag(self, names, node, message, local, user, date, extra={}):
240 if isinstance(names, str):
240 if isinstance(names, str):
241 allchars = names
241 allchars = names
242 names = (names,)
242 names = (names,)
243 else:
243 else:
244 allchars = ''.join(names)
244 allchars = ''.join(names)
245 for c in self.tag_disallowed:
245 for c in self.tag_disallowed:
246 if c in allchars:
246 if c in allchars:
247 raise util.Abort(_('%r cannot be used in a tag name') % c)
247 raise util.Abort(_('%r cannot be used in a tag name') % c)
248
248
249 branches = self.branchmap()
249 branches = self.branchmap()
250 for name in names:
250 for name in names:
251 self.hook('pretag', throw=True, node=hex(node), tag=name,
251 self.hook('pretag', throw=True, node=hex(node), tag=name,
252 local=local)
252 local=local)
253 if name in branches:
253 if name in branches:
254 self.ui.warn(_("warning: tag %s conflicts with existing"
254 self.ui.warn(_("warning: tag %s conflicts with existing"
255 " branch name\n") % name)
255 " branch name\n") % name)
256
256
257 def writetags(fp, names, munge, prevtags):
257 def writetags(fp, names, munge, prevtags):
258 fp.seek(0, 2)
258 fp.seek(0, 2)
259 if prevtags and prevtags[-1] != '\n':
259 if prevtags and prevtags[-1] != '\n':
260 fp.write('\n')
260 fp.write('\n')
261 for name in names:
261 for name in names:
262 m = munge and munge(name) or name
262 m = munge and munge(name) or name
263 if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
263 if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
264 old = self.tags().get(name, nullid)
264 old = self.tags().get(name, nullid)
265 fp.write('%s %s\n' % (hex(old), m))
265 fp.write('%s %s\n' % (hex(old), m))
266 fp.write('%s %s\n' % (hex(node), m))
266 fp.write('%s %s\n' % (hex(node), m))
267 fp.close()
267 fp.close()
268
268
269 prevtags = ''
269 prevtags = ''
270 if local:
270 if local:
271 try:
271 try:
272 fp = self.opener('localtags', 'r+')
272 fp = self.opener('localtags', 'r+')
273 except IOError:
273 except IOError:
274 fp = self.opener('localtags', 'a')
274 fp = self.opener('localtags', 'a')
275 else:
275 else:
276 prevtags = fp.read()
276 prevtags = fp.read()
277
277
278 # local tags are stored in the current charset
278 # local tags are stored in the current charset
279 writetags(fp, names, None, prevtags)
279 writetags(fp, names, None, prevtags)
280 for name in names:
280 for name in names:
281 self.hook('tag', node=hex(node), tag=name, local=local)
281 self.hook('tag', node=hex(node), tag=name, local=local)
282 return
282 return
283
283
284 try:
284 try:
285 fp = self.wfile('.hgtags', 'rb+')
285 fp = self.wfile('.hgtags', 'rb+')
286 except IOError, e:
286 except IOError, e:
287 if e.errno != errno.ENOENT:
287 if e.errno != errno.ENOENT:
288 raise
288 raise
289 fp = self.wfile('.hgtags', 'ab')
289 fp = self.wfile('.hgtags', 'ab')
290 else:
290 else:
291 prevtags = fp.read()
291 prevtags = fp.read()
292
292
293 # committed tags are stored in UTF-8
293 # committed tags are stored in UTF-8
294 writetags(fp, names, encoding.fromlocal, prevtags)
294 writetags(fp, names, encoding.fromlocal, prevtags)
295
295
296 fp.close()
296 fp.close()
297
297
298 if '.hgtags' not in self.dirstate:
298 if '.hgtags' not in self.dirstate:
299 self[None].add(['.hgtags'])
299 self[None].add(['.hgtags'])
300
300
301 m = matchmod.exact(self.root, '', ['.hgtags'])
301 m = matchmod.exact(self.root, '', ['.hgtags'])
302 tagnode = self.commit(message, user, date, extra=extra, match=m)
302 tagnode = self.commit(message, user, date, extra=extra, match=m)
303
303
304 for name in names:
304 for name in names:
305 self.hook('tag', node=hex(node), tag=name, local=local)
305 self.hook('tag', node=hex(node), tag=name, local=local)
306
306
307 return tagnode
307 return tagnode
308
308
309 def tag(self, names, node, message, local, user, date):
309 def tag(self, names, node, message, local, user, date):
310 '''tag a revision with one or more symbolic names.
310 '''tag a revision with one or more symbolic names.
311
311
312 names is a list of strings or, when adding a single tag, names may be a
312 names is a list of strings or, when adding a single tag, names may be a
313 string.
313 string.
314
314
315 if local is True, the tags are stored in a per-repository file.
315 if local is True, the tags are stored in a per-repository file.
316 otherwise, they are stored in the .hgtags file, and a new
316 otherwise, they are stored in the .hgtags file, and a new
317 changeset is committed with the change.
317 changeset is committed with the change.
318
318
319 keyword arguments:
319 keyword arguments:
320
320
321 local: whether to store tags in non-version-controlled file
321 local: whether to store tags in non-version-controlled file
322 (default False)
322 (default False)
323
323
324 message: commit message to use if committing
324 message: commit message to use if committing
325
325
326 user: name of user to use if committing
326 user: name of user to use if committing
327
327
328 date: date tuple to use if committing'''
328 date: date tuple to use if committing'''
329
329
330 if not local:
330 if not local:
331 for x in self.status()[:5]:
331 for x in self.status()[:5]:
332 if '.hgtags' in x:
332 if '.hgtags' in x:
333 raise util.Abort(_('working copy of .hgtags is changed '
333 raise util.Abort(_('working copy of .hgtags is changed '
334 '(please commit .hgtags manually)'))
334 '(please commit .hgtags manually)'))
335
335
336 self.tags() # instantiate the cache
336 self.tags() # instantiate the cache
337 self._tag(names, node, message, local, user, date)
337 self._tag(names, node, message, local, user, date)
338
338
339 @propertycache
339 @propertycache
340 def _tagscache(self):
340 def _tagscache(self):
341 '''Returns a tagscache object that contains various tags related caches.'''
341 '''Returns a tagscache object that contains various tags related caches.'''
342
342
343 # This simplifies its cache management by having one decorated
343 # This simplifies its cache management by having one decorated
344 # function (this one) and the rest simply fetch things from it.
344 # function (this one) and the rest simply fetch things from it.
345 class tagscache(object):
345 class tagscache(object):
346 def __init__(self):
346 def __init__(self):
347 # These two define the set of tags for this repository. tags
347 # These two define the set of tags for this repository. tags
348 # maps tag name to node; tagtypes maps tag name to 'global' or
348 # maps tag name to node; tagtypes maps tag name to 'global' or
349 # 'local'. (Global tags are defined by .hgtags across all
349 # 'local'. (Global tags are defined by .hgtags across all
350 # heads, and local tags are defined in .hg/localtags.)
350 # heads, and local tags are defined in .hg/localtags.)
351 # They constitute the in-memory cache of tags.
351 # They constitute the in-memory cache of tags.
352 self.tags = self.tagtypes = None
352 self.tags = self.tagtypes = None
353
353
354 self.nodetagscache = self.tagslist = None
354 self.nodetagscache = self.tagslist = None
355
355
356 cache = tagscache()
356 cache = tagscache()
357 cache.tags, cache.tagtypes = self._findtags()
357 cache.tags, cache.tagtypes = self._findtags()
358
358
359 return cache
359 return cache
360
360
361 def tags(self):
361 def tags(self):
362 '''return a mapping of tag to node'''
362 '''return a mapping of tag to node'''
363 return self._tagscache.tags
363 return self._tagscache.tags
364
364
365 def _findtags(self):
365 def _findtags(self):
366 '''Do the hard work of finding tags. Return a pair of dicts
366 '''Do the hard work of finding tags. Return a pair of dicts
367 (tags, tagtypes) where tags maps tag name to node, and tagtypes
367 (tags, tagtypes) where tags maps tag name to node, and tagtypes
368 maps tag name to a string like \'global\' or \'local\'.
368 maps tag name to a string like \'global\' or \'local\'.
369 Subclasses or extensions are free to add their own tags, but
369 Subclasses or extensions are free to add their own tags, but
370 should be aware that the returned dicts will be retained for the
370 should be aware that the returned dicts will be retained for the
371 duration of the localrepo object.'''
371 duration of the localrepo object.'''
372
372
373 # XXX what tagtype should subclasses/extensions use? Currently
373 # XXX what tagtype should subclasses/extensions use? Currently
374 # mq and bookmarks add tags, but do not set the tagtype at all.
374 # mq and bookmarks add tags, but do not set the tagtype at all.
375 # Should each extension invent its own tag type? Should there
375 # Should each extension invent its own tag type? Should there
376 # be one tagtype for all such "virtual" tags? Or is the status
376 # be one tagtype for all such "virtual" tags? Or is the status
377 # quo fine?
377 # quo fine?
378
378
379 alltags = {} # map tag name to (node, hist)
379 alltags = {} # map tag name to (node, hist)
380 tagtypes = {}
380 tagtypes = {}
381
381
382 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
382 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
383 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
383 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
384
384
385 # Build the return dicts. Have to re-encode tag names because
385 # Build the return dicts. Have to re-encode tag names because
386 # the tags module always uses UTF-8 (in order not to lose info
386 # the tags module always uses UTF-8 (in order not to lose info
387 # writing to the cache), but the rest of Mercurial wants them in
387 # writing to the cache), but the rest of Mercurial wants them in
388 # local encoding.
388 # local encoding.
389 tags = {}
389 tags = {}
390 for (name, (node, hist)) in alltags.iteritems():
390 for (name, (node, hist)) in alltags.iteritems():
391 if node != nullid:
391 if node != nullid:
392 try:
392 try:
393 # ignore tags to unknown nodes
393 # ignore tags to unknown nodes
394 self.changelog.lookup(node)
394 self.changelog.lookup(node)
395 tags[encoding.tolocal(name)] = node
395 tags[encoding.tolocal(name)] = node
396 except error.LookupError:
396 except error.LookupError:
397 pass
397 pass
398 tags['tip'] = self.changelog.tip()
398 tags['tip'] = self.changelog.tip()
399 tagtypes = dict([(encoding.tolocal(name), value)
399 tagtypes = dict([(encoding.tolocal(name), value)
400 for (name, value) in tagtypes.iteritems()])
400 for (name, value) in tagtypes.iteritems()])
401 return (tags, tagtypes)
401 return (tags, tagtypes)
402
402
403 def tagtype(self, tagname):
403 def tagtype(self, tagname):
404 '''
404 '''
405 return the type of the given tag. result can be:
405 return the type of the given tag. result can be:
406
406
407 'local' : a local tag
407 'local' : a local tag
408 'global' : a global tag
408 'global' : a global tag
409 None : tag does not exist
409 None : tag does not exist
410 '''
410 '''
411
411
412 return self._tagscache.tagtypes.get(tagname)
412 return self._tagscache.tagtypes.get(tagname)
413
413
414 def tagslist(self):
414 def tagslist(self):
415 '''return a list of tags ordered by revision'''
415 '''return a list of tags ordered by revision'''
416 if not self._tagscache.tagslist:
416 if not self._tagscache.tagslist:
417 l = []
417 l = []
418 for t, n in self.tags().iteritems():
418 for t, n in self.tags().iteritems():
419 r = self.changelog.rev(n)
419 r = self.changelog.rev(n)
420 l.append((r, t, n))
420 l.append((r, t, n))
421 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
421 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
422
422
423 return self._tagscache.tagslist
423 return self._tagscache.tagslist
424
424
425 def nodetags(self, node):
425 def nodetags(self, node):
426 '''return the tags associated with a node'''
426 '''return the tags associated with a node'''
427 if not self._tagscache.nodetagscache:
427 if not self._tagscache.nodetagscache:
428 nodetagscache = {}
428 nodetagscache = {}
429 for t, n in self.tags().iteritems():
429 for t, n in self.tags().iteritems():
430 nodetagscache.setdefault(n, []).append(t)
430 nodetagscache.setdefault(n, []).append(t)
431 for tags in nodetagscache.itervalues():
431 for tags in nodetagscache.itervalues():
432 tags.sort()
432 tags.sort()
433 self._tagscache.nodetagscache = nodetagscache
433 self._tagscache.nodetagscache = nodetagscache
434 return self._tagscache.nodetagscache.get(node, [])
434 return self._tagscache.nodetagscache.get(node, [])
435
435
436 def nodebookmarks(self, node):
436 def nodebookmarks(self, node):
437 marks = []
437 marks = []
438 for bookmark, n in self._bookmarks.iteritems():
438 for bookmark, n in self._bookmarks.iteritems():
439 if n == node:
439 if n == node:
440 marks.append(bookmark)
440 marks.append(bookmark)
441 return sorted(marks)
441 return sorted(marks)
442
442
443 def _branchtags(self, partial, lrev):
443 def _branchtags(self, partial, lrev):
444 # TODO: rename this function?
444 # TODO: rename this function?
445 tiprev = len(self) - 1
445 tiprev = len(self) - 1
446 if lrev != tiprev:
446 if lrev != tiprev:
447 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
447 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
448 self._updatebranchcache(partial, ctxgen)
448 self._updatebranchcache(partial, ctxgen)
449 self._writebranchcache(partial, self.changelog.tip(), tiprev)
449 self._writebranchcache(partial, self.changelog.tip(), tiprev)
450
450
451 return partial
451 return partial
452
452
453 def updatebranchcache(self):
453 def updatebranchcache(self):
454 tip = self.changelog.tip()
454 tip = self.changelog.tip()
455 if self._branchcache is not None and self._branchcachetip == tip:
455 if self._branchcache is not None and self._branchcachetip == tip:
456 return self._branchcache
456 return self._branchcache
457
457
458 oldtip = self._branchcachetip
458 oldtip = self._branchcachetip
459 self._branchcachetip = tip
459 self._branchcachetip = tip
460 if oldtip is None or oldtip not in self.changelog.nodemap:
460 if oldtip is None or oldtip not in self.changelog.nodemap:
461 partial, last, lrev = self._readbranchcache()
461 partial, last, lrev = self._readbranchcache()
462 else:
462 else:
463 lrev = self.changelog.rev(oldtip)
463 lrev = self.changelog.rev(oldtip)
464 partial = self._branchcache
464 partial = self._branchcache
465
465
466 self._branchtags(partial, lrev)
466 self._branchtags(partial, lrev)
467 # this private cache holds all heads (not just tips)
467 # this private cache holds all heads (not just tips)
468 self._branchcache = partial
468 self._branchcache = partial
469
469
470 def branchmap(self):
470 def branchmap(self):
471 '''returns a dictionary {branch: [branchheads]}'''
471 '''returns a dictionary {branch: [branchheads]}'''
472 self.updatebranchcache()
472 self.updatebranchcache()
473 return self._branchcache
473 return self._branchcache
474
474
475 def branchtags(self):
475 def branchtags(self):
476 '''return a dict where branch names map to the tipmost head of
476 '''return a dict where branch names map to the tipmost head of
477 the branch, open heads come before closed'''
477 the branch, open heads come before closed'''
478 bt = {}
478 bt = {}
479 for bn, heads in self.branchmap().iteritems():
479 for bn, heads in self.branchmap().iteritems():
480 tip = heads[-1]
480 tip = heads[-1]
481 for h in reversed(heads):
481 for h in reversed(heads):
482 if 'close' not in self.changelog.read(h)[5]:
482 if 'close' not in self.changelog.read(h)[5]:
483 tip = h
483 tip = h
484 break
484 break
485 bt[bn] = tip
485 bt[bn] = tip
486 return bt
486 return bt
487
487
488 def _readbranchcache(self):
488 def _readbranchcache(self):
489 partial = {}
489 partial = {}
490 try:
490 try:
491 f = self.opener("cache/branchheads")
491 f = self.opener("cache/branchheads")
492 lines = f.read().split('\n')
492 lines = f.read().split('\n')
493 f.close()
493 f.close()
494 except (IOError, OSError):
494 except (IOError, OSError):
495 return {}, nullid, nullrev
495 return {}, nullid, nullrev
496
496
497 try:
497 try:
498 last, lrev = lines.pop(0).split(" ", 1)
498 last, lrev = lines.pop(0).split(" ", 1)
499 last, lrev = bin(last), int(lrev)
499 last, lrev = bin(last), int(lrev)
500 if lrev >= len(self) or self[lrev].node() != last:
500 if lrev >= len(self) or self[lrev].node() != last:
501 # invalidate the cache
501 # invalidate the cache
502 raise ValueError('invalidating branch cache (tip differs)')
502 raise ValueError('invalidating branch cache (tip differs)')
503 for l in lines:
503 for l in lines:
504 if not l:
504 if not l:
505 continue
505 continue
506 node, label = l.split(" ", 1)
506 node, label = l.split(" ", 1)
507 label = encoding.tolocal(label.strip())
507 label = encoding.tolocal(label.strip())
508 partial.setdefault(label, []).append(bin(node))
508 partial.setdefault(label, []).append(bin(node))
509 except KeyboardInterrupt:
509 except KeyboardInterrupt:
510 raise
510 raise
511 except Exception, inst:
511 except Exception, inst:
512 if self.ui.debugflag:
512 if self.ui.debugflag:
513 self.ui.warn(str(inst), '\n')
513 self.ui.warn(str(inst), '\n')
514 partial, last, lrev = {}, nullid, nullrev
514 partial, last, lrev = {}, nullid, nullrev
515 return partial, last, lrev
515 return partial, last, lrev
516
516
517 def _writebranchcache(self, branches, tip, tiprev):
517 def _writebranchcache(self, branches, tip, tiprev):
518 try:
518 try:
519 f = self.opener("cache/branchheads", "w", atomictemp=True)
519 f = self.opener("cache/branchheads", "w", atomictemp=True)
520 f.write("%s %s\n" % (hex(tip), tiprev))
520 f.write("%s %s\n" % (hex(tip), tiprev))
521 for label, nodes in branches.iteritems():
521 for label, nodes in branches.iteritems():
522 for node in nodes:
522 for node in nodes:
523 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
523 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
524 f.close()
524 f.close()
525 except (IOError, OSError):
525 except (IOError, OSError):
526 pass
526 pass
527
527
528 def _updatebranchcache(self, partial, ctxgen):
528 def _updatebranchcache(self, partial, ctxgen):
529 # collect new branch entries
529 # collect new branch entries
530 newbranches = {}
530 newbranches = {}
531 for c in ctxgen:
531 for c in ctxgen:
532 newbranches.setdefault(c.branch(), []).append(c.node())
532 newbranches.setdefault(c.branch(), []).append(c.node())
533 # if older branchheads are reachable from new ones, they aren't
533 # if older branchheads are reachable from new ones, they aren't
534 # really branchheads. Note checking parents is insufficient:
534 # really branchheads. Note checking parents is insufficient:
535 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
535 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
536 for branch, newnodes in newbranches.iteritems():
536 for branch, newnodes in newbranches.iteritems():
537 bheads = partial.setdefault(branch, [])
537 bheads = partial.setdefault(branch, [])
538 bheads.extend(newnodes)
538 bheads.extend(newnodes)
539 if len(bheads) <= 1:
539 if len(bheads) <= 1:
540 continue
540 continue
541 bheads = sorted(bheads, key=lambda x: self[x].rev())
541 bheads = sorted(bheads, key=lambda x: self[x].rev())
542 # starting from tip means fewer passes over reachable
542 # starting from tip means fewer passes over reachable
543 while newnodes:
543 while newnodes:
544 latest = newnodes.pop()
544 latest = newnodes.pop()
545 if latest not in bheads:
545 if latest not in bheads:
546 continue
546 continue
547 minbhrev = self[bheads[0]].node()
547 minbhrev = self[bheads[0]].node()
548 reachable = self.changelog.reachable(latest, minbhrev)
548 reachable = self.changelog.reachable(latest, minbhrev)
549 reachable.remove(latest)
549 reachable.remove(latest)
550 if reachable:
550 if reachable:
551 bheads = [b for b in bheads if b not in reachable]
551 bheads = [b for b in bheads if b not in reachable]
552 partial[branch] = bheads
552 partial[branch] = bheads
553
553
554 def lookup(self, key):
554 def lookup(self, key):
555 if isinstance(key, int):
555 if isinstance(key, int):
556 return self.changelog.node(key)
556 return self.changelog.node(key)
557 elif key == '.':
557 elif key == '.':
558 return self.dirstate.p1()
558 return self.dirstate.p1()
559 elif key == 'null':
559 elif key == 'null':
560 return nullid
560 return nullid
561 elif key == 'tip':
561 elif key == 'tip':
562 return self.changelog.tip()
562 return self.changelog.tip()
563 n = self.changelog._match(key)
563 n = self.changelog._match(key)
564 if n:
564 if n:
565 return n
565 return n
566 if key in self._bookmarks:
566 if key in self._bookmarks:
567 return self._bookmarks[key]
567 return self._bookmarks[key]
568 if key in self.tags():
568 if key in self.tags():
569 return self.tags()[key]
569 return self.tags()[key]
570 if key in self.branchtags():
570 if key in self.branchtags():
571 return self.branchtags()[key]
571 return self.branchtags()[key]
572 n = self.changelog._partialmatch(key)
572 n = self.changelog._partialmatch(key)
573 if n:
573 if n:
574 return n
574 return n
575
575
576 # can't find key, check if it might have come from damaged dirstate
576 # can't find key, check if it might have come from damaged dirstate
577 if key in self.dirstate.parents():
577 if key in self.dirstate.parents():
578 raise error.Abort(_("working directory has unknown parent '%s'!")
578 raise error.Abort(_("working directory has unknown parent '%s'!")
579 % short(key))
579 % short(key))
580 try:
580 try:
581 if len(key) == 20:
581 if len(key) == 20:
582 key = hex(key)
582 key = hex(key)
583 except TypeError:
583 except TypeError:
584 pass
584 pass
585 raise error.RepoLookupError(_("unknown revision '%s'") % key)
585 raise error.RepoLookupError(_("unknown revision '%s'") % key)
586
586
587 def lookupbranch(self, key, remote=None):
587 def lookupbranch(self, key, remote=None):
588 repo = remote or self
588 repo = remote or self
589 if key in repo.branchmap():
589 if key in repo.branchmap():
590 return key
590 return key
591
591
592 repo = (remote and remote.local()) and remote or self
592 repo = (remote and remote.local()) and remote or self
593 return repo[key].branch()
593 return repo[key].branch()
594
594
595 def known(self, nodes):
595 def known(self, nodes):
596 nm = self.changelog.nodemap
596 nm = self.changelog.nodemap
597 return [(n in nm) for n in nodes]
597 return [(n in nm) for n in nodes]
598
598
599 def local(self):
599 def local(self):
600 return self
600 return self
601
601
602 def join(self, f):
602 def join(self, f):
603 return os.path.join(self.path, f)
603 return os.path.join(self.path, f)
604
604
605 def wjoin(self, f):
605 def wjoin(self, f):
606 return os.path.join(self.root, f)
606 return os.path.join(self.root, f)
607
607
608 def file(self, f):
608 def file(self, f):
609 if f[0] == '/':
609 if f[0] == '/':
610 f = f[1:]
610 f = f[1:]
611 return filelog.filelog(self.sopener, f)
611 return filelog.filelog(self.sopener, f)
612
612
613 def changectx(self, changeid):
613 def changectx(self, changeid):
614 return self[changeid]
614 return self[changeid]
615
615
616 def parents(self, changeid=None):
616 def parents(self, changeid=None):
617 '''get list of changectxs for parents of changeid'''
617 '''get list of changectxs for parents of changeid'''
618 return self[changeid].parents()
618 return self[changeid].parents()
619
619
620 def filectx(self, path, changeid=None, fileid=None):
620 def filectx(self, path, changeid=None, fileid=None):
621 """changeid can be a changeset revision, node, or tag.
621 """changeid can be a changeset revision, node, or tag.
622 fileid can be a file revision or node."""
622 fileid can be a file revision or node."""
623 return context.filectx(self, path, changeid, fileid)
623 return context.filectx(self, path, changeid, fileid)
624
624
625 def getcwd(self):
625 def getcwd(self):
626 return self.dirstate.getcwd()
626 return self.dirstate.getcwd()
627
627
628 def pathto(self, f, cwd=None):
628 def pathto(self, f, cwd=None):
629 return self.dirstate.pathto(f, cwd)
629 return self.dirstate.pathto(f, cwd)
630
630
631 def wfile(self, f, mode='r'):
631 def wfile(self, f, mode='r'):
632 return self.wopener(f, mode)
632 return self.wopener(f, mode)
633
633
634 def _link(self, f):
634 def _link(self, f):
635 return os.path.islink(self.wjoin(f))
635 return os.path.islink(self.wjoin(f))
636
636
637 def _loadfilter(self, filter):
637 def _loadfilter(self, filter):
638 if filter not in self.filterpats:
638 if filter not in self.filterpats:
639 l = []
639 l = []
640 for pat, cmd in self.ui.configitems(filter):
640 for pat, cmd in self.ui.configitems(filter):
641 if cmd == '!':
641 if cmd == '!':
642 continue
642 continue
643 mf = matchmod.match(self.root, '', [pat])
643 mf = matchmod.match(self.root, '', [pat])
644 fn = None
644 fn = None
645 params = cmd
645 params = cmd
646 for name, filterfn in self._datafilters.iteritems():
646 for name, filterfn in self._datafilters.iteritems():
647 if cmd.startswith(name):
647 if cmd.startswith(name):
648 fn = filterfn
648 fn = filterfn
649 params = cmd[len(name):].lstrip()
649 params = cmd[len(name):].lstrip()
650 break
650 break
651 if not fn:
651 if not fn:
652 fn = lambda s, c, **kwargs: util.filter(s, c)
652 fn = lambda s, c, **kwargs: util.filter(s, c)
653 # Wrap old filters not supporting keyword arguments
653 # Wrap old filters not supporting keyword arguments
654 if not inspect.getargspec(fn)[2]:
654 if not inspect.getargspec(fn)[2]:
655 oldfn = fn
655 oldfn = fn
656 fn = lambda s, c, **kwargs: oldfn(s, c)
656 fn = lambda s, c, **kwargs: oldfn(s, c)
657 l.append((mf, fn, params))
657 l.append((mf, fn, params))
658 self.filterpats[filter] = l
658 self.filterpats[filter] = l
659 return self.filterpats[filter]
659 return self.filterpats[filter]
660
660
661 def _filter(self, filterpats, filename, data):
661 def _filter(self, filterpats, filename, data):
662 for mf, fn, cmd in filterpats:
662 for mf, fn, cmd in filterpats:
663 if mf(filename):
663 if mf(filename):
664 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
664 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
665 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
665 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
666 break
666 break
667
667
668 return data
668 return data
669
669
670 @propertycache
670 @propertycache
671 def _encodefilterpats(self):
671 def _encodefilterpats(self):
672 return self._loadfilter('encode')
672 return self._loadfilter('encode')
673
673
674 @propertycache
674 @propertycache
675 def _decodefilterpats(self):
675 def _decodefilterpats(self):
676 return self._loadfilter('decode')
676 return self._loadfilter('decode')
677
677
678 def adddatafilter(self, name, filter):
678 def adddatafilter(self, name, filter):
679 self._datafilters[name] = filter
679 self._datafilters[name] = filter
680
680
681 def wread(self, filename):
681 def wread(self, filename):
682 if self._link(filename):
682 if self._link(filename):
683 data = os.readlink(self.wjoin(filename))
683 data = os.readlink(self.wjoin(filename))
684 else:
684 else:
685 data = self.wopener.read(filename)
685 data = self.wopener.read(filename)
686 return self._filter(self._encodefilterpats, filename, data)
686 return self._filter(self._encodefilterpats, filename, data)
687
687
688 def wwrite(self, filename, data, flags):
688 def wwrite(self, filename, data, flags):
689 data = self._filter(self._decodefilterpats, filename, data)
689 data = self._filter(self._decodefilterpats, filename, data)
690 if 'l' in flags:
690 if 'l' in flags:
691 self.wopener.symlink(data, filename)
691 self.wopener.symlink(data, filename)
692 else:
692 else:
693 self.wopener.write(filename, data)
693 self.wopener.write(filename, data)
694 if 'x' in flags:
694 if 'x' in flags:
695 util.setflags(self.wjoin(filename), False, True)
695 util.setflags(self.wjoin(filename), False, True)
696
696
697 def wwritedata(self, filename, data):
697 def wwritedata(self, filename, data):
698 return self._filter(self._decodefilterpats, filename, data)
698 return self._filter(self._decodefilterpats, filename, data)
699
699
700 def transaction(self, desc):
700 def transaction(self, desc):
701 tr = self._transref and self._transref() or None
701 tr = self._transref and self._transref() or None
702 if tr and tr.running():
702 if tr and tr.running():
703 return tr.nest()
703 return tr.nest()
704
704
705 # abort here if the journal already exists
705 # abort here if the journal already exists
706 if os.path.exists(self.sjoin("journal")):
706 if os.path.exists(self.sjoin("journal")):
707 raise error.RepoError(
707 raise error.RepoError(
708 _("abandoned transaction found - run hg recover"))
708 _("abandoned transaction found - run hg recover"))
709
709
710 journalfiles = self._writejournal(desc)
710 journalfiles = self._writejournal(desc)
711 renames = [(x, undoname(x)) for x in journalfiles]
711 renames = [(x, undoname(x)) for x in journalfiles]
712
712
713 tr = transaction.transaction(self.ui.warn, self.sopener,
713 tr = transaction.transaction(self.ui.warn, self.sopener,
714 self.sjoin("journal"),
714 self.sjoin("journal"),
715 aftertrans(renames),
715 aftertrans(renames),
716 self.store.createmode)
716 self.store.createmode)
717 self._transref = weakref.ref(tr)
717 self._transref = weakref.ref(tr)
718 return tr
718 return tr
719
719
720 def _writejournal(self, desc):
720 def _writejournal(self, desc):
721 # save dirstate for rollback
721 # save dirstate for rollback
722 try:
722 try:
723 ds = self.opener.read("dirstate")
723 ds = self.opener.read("dirstate")
724 except IOError:
724 except IOError:
725 ds = ""
725 ds = ""
726 self.opener.write("journal.dirstate", ds)
726 self.opener.write("journal.dirstate", ds)
727 self.opener.write("journal.branch",
727 self.opener.write("journal.branch",
728 encoding.fromlocal(self.dirstate.branch()))
728 encoding.fromlocal(self.dirstate.branch()))
729 self.opener.write("journal.desc",
729 self.opener.write("journal.desc",
730 "%d\n%s\n" % (len(self), desc))
730 "%d\n%s\n" % (len(self), desc))
731
731
732 bkname = self.join('bookmarks')
732 bkname = self.join('bookmarks')
733 if os.path.exists(bkname):
733 if os.path.exists(bkname):
734 util.copyfile(bkname, self.join('journal.bookmarks'))
734 util.copyfile(bkname, self.join('journal.bookmarks'))
735 else:
735 else:
736 self.opener.write('journal.bookmarks', '')
736 self.opener.write('journal.bookmarks', '')
737
737
738 return (self.sjoin('journal'), self.join('journal.dirstate'),
738 return (self.sjoin('journal'), self.join('journal.dirstate'),
739 self.join('journal.branch'), self.join('journal.desc'),
739 self.join('journal.branch'), self.join('journal.desc'),
740 self.join('journal.bookmarks'))
740 self.join('journal.bookmarks'))
741
741
742 def recover(self):
742 def recover(self):
743 lock = self.lock()
743 lock = self.lock()
744 try:
744 try:
745 if os.path.exists(self.sjoin("journal")):
745 if os.path.exists(self.sjoin("journal")):
746 self.ui.status(_("rolling back interrupted transaction\n"))
746 self.ui.status(_("rolling back interrupted transaction\n"))
747 transaction.rollback(self.sopener, self.sjoin("journal"),
747 transaction.rollback(self.sopener, self.sjoin("journal"),
748 self.ui.warn)
748 self.ui.warn)
749 self.invalidate()
749 self.invalidate()
750 return True
750 return True
751 else:
751 else:
752 self.ui.warn(_("no interrupted transaction available\n"))
752 self.ui.warn(_("no interrupted transaction available\n"))
753 return False
753 return False
754 finally:
754 finally:
755 lock.release()
755 lock.release()
756
756
757 def rollback(self, dryrun=False):
757 def rollback(self, dryrun=False):
758 wlock = lock = None
758 wlock = lock = None
759 try:
759 try:
760 wlock = self.wlock()
760 wlock = self.wlock()
761 lock = self.lock()
761 lock = self.lock()
762 if os.path.exists(self.sjoin("undo")):
762 if os.path.exists(self.sjoin("undo")):
763 return self._rollback(dryrun)
763 return self._rollback(dryrun)
764 else:
764 else:
765 self.ui.warn(_("no rollback information available\n"))
765 self.ui.warn(_("no rollback information available\n"))
766 return 1
766 return 1
767 finally:
767 finally:
768 release(lock, wlock)
768 release(lock, wlock)
769
769
770 def _rollback(self, dryrun):
770 def _rollback(self, dryrun):
771 ui = self.ui
771 ui = self.ui
772 try:
772 try:
773 args = self.opener.read('undo.desc').splitlines()
773 args = self.opener.read('undo.desc').splitlines()
774 (oldlen, desc, detail) = (int(args[0]), args[1], None)
774 (oldlen, desc, detail) = (int(args[0]), args[1], None)
775 if len(args) >= 3:
775 if len(args) >= 3:
776 detail = args[2]
776 detail = args[2]
777 oldtip = oldlen - 1
777 oldtip = oldlen - 1
778
778
779 if detail and ui.verbose:
779 if detail and ui.verbose:
780 msg = (_('repository tip rolled back to revision %s'
780 msg = (_('repository tip rolled back to revision %s'
781 ' (undo %s: %s)\n')
781 ' (undo %s: %s)\n')
782 % (oldtip, desc, detail))
782 % (oldtip, desc, detail))
783 else:
783 else:
784 msg = (_('repository tip rolled back to revision %s'
784 msg = (_('repository tip rolled back to revision %s'
785 ' (undo %s)\n')
785 ' (undo %s)\n')
786 % (oldtip, desc))
786 % (oldtip, desc))
787 except IOError:
787 except IOError:
788 msg = _('rolling back unknown transaction\n')
788 msg = _('rolling back unknown transaction\n')
789 ui.status(msg)
789 ui.status(msg)
790 if dryrun:
790 if dryrun:
791 return 0
791 return 0
792
793 parents = self.dirstate.parents()
792 transaction.rollback(self.sopener, self.sjoin('undo'), ui.warn)
794 transaction.rollback(self.sopener, self.sjoin('undo'), ui.warn)
793 util.rename(self.join('undo.dirstate'), self.join('dirstate'))
794 if os.path.exists(self.join('undo.bookmarks')):
795 if os.path.exists(self.join('undo.bookmarks')):
795 util.rename(self.join('undo.bookmarks'),
796 util.rename(self.join('undo.bookmarks'),
796 self.join('bookmarks'))
797 self.join('bookmarks'))
797 try:
798 branch = self.opener.read('undo.branch')
799 self.dirstate.setbranch(branch)
800 except IOError:
801 ui.warn(_('named branch could not be reset: '
802 'current branch is still \'%s\'\n')
803 % self.dirstate.branch())
804 self.invalidate()
798 self.invalidate()
805 self.dirstate.invalidate()
799
806 self.destroyed()
800 parentgone = (parents[0] not in self.changelog.nodemap or
807 parents = tuple([p.rev() for p in self.parents()])
801 parents[1] not in self.changelog.nodemap)
808 if len(parents) > 1:
802 if parentgone:
809 ui.status(_('working directory now based on '
803 util.rename(self.join('undo.dirstate'), self.join('dirstate'))
810 'revisions %d and %d\n') % parents)
804 try:
811 else:
805 branch = self.opener.read('undo.branch')
812 ui.status(_('working directory now based on '
806 self.dirstate.setbranch(branch)
813 'revision %d\n') % parents)
807 except IOError:
808 ui.warn(_('named branch could not be reset: '
809 'current branch is still \'%s\'\n')
810 % self.dirstate.branch())
811
812 self.dirstate.invalidate()
813 self.destroyed()
814 parents = tuple([p.rev() for p in self.parents()])
815 if len(parents) > 1:
816 ui.status(_('working directory now based on '
817 'revisions %d and %d\n') % parents)
818 else:
819 ui.status(_('working directory now based on '
820 'revision %d\n') % parents)
814 return 0
821 return 0
815
822
816 def invalidatecaches(self):
823 def invalidatecaches(self):
817 try:
824 try:
818 delattr(self, '_tagscache')
825 delattr(self, '_tagscache')
819 except AttributeError:
826 except AttributeError:
820 pass
827 pass
821
828
822 self._branchcache = None # in UTF-8
829 self._branchcache = None # in UTF-8
823 self._branchcachetip = None
830 self._branchcachetip = None
824
831
825 def invalidatedirstate(self):
832 def invalidatedirstate(self):
826 '''Invalidates the dirstate, causing the next call to dirstate
833 '''Invalidates the dirstate, causing the next call to dirstate
827 to check if it was modified since the last time it was read,
834 to check if it was modified since the last time it was read,
828 rereading it if it has.
835 rereading it if it has.
829
836
830 This is different to dirstate.invalidate() that it doesn't always
837 This is different to dirstate.invalidate() that it doesn't always
831 rereads the dirstate. Use dirstate.invalidate() if you want to
838 rereads the dirstate. Use dirstate.invalidate() if you want to
832 explicitly read the dirstate again (i.e. restoring it to a previous
839 explicitly read the dirstate again (i.e. restoring it to a previous
833 known good state).'''
840 known good state).'''
834 try:
841 try:
835 delattr(self, 'dirstate')
842 delattr(self, 'dirstate')
836 except AttributeError:
843 except AttributeError:
837 pass
844 pass
838
845
839 def invalidate(self):
846 def invalidate(self):
840 for k in self._filecache:
847 for k in self._filecache:
841 # dirstate is invalidated separately in invalidatedirstate()
848 # dirstate is invalidated separately in invalidatedirstate()
842 if k == 'dirstate':
849 if k == 'dirstate':
843 continue
850 continue
844
851
845 try:
852 try:
846 delattr(self, k)
853 delattr(self, k)
847 except AttributeError:
854 except AttributeError:
848 pass
855 pass
849 self.invalidatecaches()
856 self.invalidatecaches()
850
857
851 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
858 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
852 try:
859 try:
853 l = lock.lock(lockname, 0, releasefn, desc=desc)
860 l = lock.lock(lockname, 0, releasefn, desc=desc)
854 except error.LockHeld, inst:
861 except error.LockHeld, inst:
855 if not wait:
862 if not wait:
856 raise
863 raise
857 self.ui.warn(_("waiting for lock on %s held by %r\n") %
864 self.ui.warn(_("waiting for lock on %s held by %r\n") %
858 (desc, inst.locker))
865 (desc, inst.locker))
859 # default to 600 seconds timeout
866 # default to 600 seconds timeout
860 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
867 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
861 releasefn, desc=desc)
868 releasefn, desc=desc)
862 if acquirefn:
869 if acquirefn:
863 acquirefn()
870 acquirefn()
864 return l
871 return l
865
872
866 def lock(self, wait=True):
873 def lock(self, wait=True):
867 '''Lock the repository store (.hg/store) and return a weak reference
874 '''Lock the repository store (.hg/store) and return a weak reference
868 to the lock. Use this before modifying the store (e.g. committing or
875 to the lock. Use this before modifying the store (e.g. committing or
869 stripping). If you are opening a transaction, get a lock as well.)'''
876 stripping). If you are opening a transaction, get a lock as well.)'''
870 l = self._lockref and self._lockref()
877 l = self._lockref and self._lockref()
871 if l is not None and l.held:
878 if l is not None and l.held:
872 l.lock()
879 l.lock()
873 return l
880 return l
874
881
875 def unlock():
882 def unlock():
876 self.store.write()
883 self.store.write()
877 for k, ce in self._filecache.items():
884 for k, ce in self._filecache.items():
878 if k == 'dirstate':
885 if k == 'dirstate':
879 continue
886 continue
880 ce.refresh()
887 ce.refresh()
881
888
882 l = self._lock(self.sjoin("lock"), wait, unlock,
889 l = self._lock(self.sjoin("lock"), wait, unlock,
883 self.invalidate, _('repository %s') % self.origroot)
890 self.invalidate, _('repository %s') % self.origroot)
884 self._lockref = weakref.ref(l)
891 self._lockref = weakref.ref(l)
885 return l
892 return l
886
893
887 def wlock(self, wait=True):
894 def wlock(self, wait=True):
888 '''Lock the non-store parts of the repository (everything under
895 '''Lock the non-store parts of the repository (everything under
889 .hg except .hg/store) and return a weak reference to the lock.
896 .hg except .hg/store) and return a weak reference to the lock.
890 Use this before modifying files in .hg.'''
897 Use this before modifying files in .hg.'''
891 l = self._wlockref and self._wlockref()
898 l = self._wlockref and self._wlockref()
892 if l is not None and l.held:
899 if l is not None and l.held:
893 l.lock()
900 l.lock()
894 return l
901 return l
895
902
896 def unlock():
903 def unlock():
897 self.dirstate.write()
904 self.dirstate.write()
898 ce = self._filecache.get('dirstate')
905 ce = self._filecache.get('dirstate')
899 if ce:
906 if ce:
900 ce.refresh()
907 ce.refresh()
901
908
902 l = self._lock(self.join("wlock"), wait, unlock,
909 l = self._lock(self.join("wlock"), wait, unlock,
903 self.invalidatedirstate, _('working directory of %s') %
910 self.invalidatedirstate, _('working directory of %s') %
904 self.origroot)
911 self.origroot)
905 self._wlockref = weakref.ref(l)
912 self._wlockref = weakref.ref(l)
906 return l
913 return l
907
914
908 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
915 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
909 """
916 """
910 commit an individual file as part of a larger transaction
917 commit an individual file as part of a larger transaction
911 """
918 """
912
919
913 fname = fctx.path()
920 fname = fctx.path()
914 text = fctx.data()
921 text = fctx.data()
915 flog = self.file(fname)
922 flog = self.file(fname)
916 fparent1 = manifest1.get(fname, nullid)
923 fparent1 = manifest1.get(fname, nullid)
917 fparent2 = fparent2o = manifest2.get(fname, nullid)
924 fparent2 = fparent2o = manifest2.get(fname, nullid)
918
925
919 meta = {}
926 meta = {}
920 copy = fctx.renamed()
927 copy = fctx.renamed()
921 if copy and copy[0] != fname:
928 if copy and copy[0] != fname:
922 # Mark the new revision of this file as a copy of another
929 # Mark the new revision of this file as a copy of another
923 # file. This copy data will effectively act as a parent
930 # file. This copy data will effectively act as a parent
924 # of this new revision. If this is a merge, the first
931 # of this new revision. If this is a merge, the first
925 # parent will be the nullid (meaning "look up the copy data")
932 # parent will be the nullid (meaning "look up the copy data")
926 # and the second one will be the other parent. For example:
933 # and the second one will be the other parent. For example:
927 #
934 #
928 # 0 --- 1 --- 3 rev1 changes file foo
935 # 0 --- 1 --- 3 rev1 changes file foo
929 # \ / rev2 renames foo to bar and changes it
936 # \ / rev2 renames foo to bar and changes it
930 # \- 2 -/ rev3 should have bar with all changes and
937 # \- 2 -/ rev3 should have bar with all changes and
931 # should record that bar descends from
938 # should record that bar descends from
932 # bar in rev2 and foo in rev1
939 # bar in rev2 and foo in rev1
933 #
940 #
934 # this allows this merge to succeed:
941 # this allows this merge to succeed:
935 #
942 #
936 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
943 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
937 # \ / merging rev3 and rev4 should use bar@rev2
944 # \ / merging rev3 and rev4 should use bar@rev2
938 # \- 2 --- 4 as the merge base
945 # \- 2 --- 4 as the merge base
939 #
946 #
940
947
941 cfname = copy[0]
948 cfname = copy[0]
942 crev = manifest1.get(cfname)
949 crev = manifest1.get(cfname)
943 newfparent = fparent2
950 newfparent = fparent2
944
951
945 if manifest2: # branch merge
952 if manifest2: # branch merge
946 if fparent2 == nullid or crev is None: # copied on remote side
953 if fparent2 == nullid or crev is None: # copied on remote side
947 if cfname in manifest2:
954 if cfname in manifest2:
948 crev = manifest2[cfname]
955 crev = manifest2[cfname]
949 newfparent = fparent1
956 newfparent = fparent1
950
957
951 # find source in nearest ancestor if we've lost track
958 # find source in nearest ancestor if we've lost track
952 if not crev:
959 if not crev:
953 self.ui.debug(" %s: searching for copy revision for %s\n" %
960 self.ui.debug(" %s: searching for copy revision for %s\n" %
954 (fname, cfname))
961 (fname, cfname))
955 for ancestor in self[None].ancestors():
962 for ancestor in self[None].ancestors():
956 if cfname in ancestor:
963 if cfname in ancestor:
957 crev = ancestor[cfname].filenode()
964 crev = ancestor[cfname].filenode()
958 break
965 break
959
966
960 if crev:
967 if crev:
961 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
968 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
962 meta["copy"] = cfname
969 meta["copy"] = cfname
963 meta["copyrev"] = hex(crev)
970 meta["copyrev"] = hex(crev)
964 fparent1, fparent2 = nullid, newfparent
971 fparent1, fparent2 = nullid, newfparent
965 else:
972 else:
966 self.ui.warn(_("warning: can't find ancestor for '%s' "
973 self.ui.warn(_("warning: can't find ancestor for '%s' "
967 "copied from '%s'!\n") % (fname, cfname))
974 "copied from '%s'!\n") % (fname, cfname))
968
975
969 elif fparent2 != nullid:
976 elif fparent2 != nullid:
970 # is one parent an ancestor of the other?
977 # is one parent an ancestor of the other?
971 fparentancestor = flog.ancestor(fparent1, fparent2)
978 fparentancestor = flog.ancestor(fparent1, fparent2)
972 if fparentancestor == fparent1:
979 if fparentancestor == fparent1:
973 fparent1, fparent2 = fparent2, nullid
980 fparent1, fparent2 = fparent2, nullid
974 elif fparentancestor == fparent2:
981 elif fparentancestor == fparent2:
975 fparent2 = nullid
982 fparent2 = nullid
976
983
977 # is the file changed?
984 # is the file changed?
978 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
985 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
979 changelist.append(fname)
986 changelist.append(fname)
980 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
987 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
981
988
982 # are just the flags changed during merge?
989 # are just the flags changed during merge?
983 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
990 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
984 changelist.append(fname)
991 changelist.append(fname)
985
992
986 return fparent1
993 return fparent1
987
994
988 def commit(self, text="", user=None, date=None, match=None, force=False,
995 def commit(self, text="", user=None, date=None, match=None, force=False,
989 editor=False, extra={}):
996 editor=False, extra={}):
990 """Add a new revision to current repository.
997 """Add a new revision to current repository.
991
998
992 Revision information is gathered from the working directory,
999 Revision information is gathered from the working directory,
993 match can be used to filter the committed files. If editor is
1000 match can be used to filter the committed files. If editor is
994 supplied, it is called to get a commit message.
1001 supplied, it is called to get a commit message.
995 """
1002 """
996
1003
997 def fail(f, msg):
1004 def fail(f, msg):
998 raise util.Abort('%s: %s' % (f, msg))
1005 raise util.Abort('%s: %s' % (f, msg))
999
1006
1000 if not match:
1007 if not match:
1001 match = matchmod.always(self.root, '')
1008 match = matchmod.always(self.root, '')
1002
1009
1003 if not force:
1010 if not force:
1004 vdirs = []
1011 vdirs = []
1005 match.dir = vdirs.append
1012 match.dir = vdirs.append
1006 match.bad = fail
1013 match.bad = fail
1007
1014
1008 wlock = self.wlock()
1015 wlock = self.wlock()
1009 try:
1016 try:
1010 wctx = self[None]
1017 wctx = self[None]
1011 merge = len(wctx.parents()) > 1
1018 merge = len(wctx.parents()) > 1
1012
1019
1013 if (not force and merge and match and
1020 if (not force and merge and match and
1014 (match.files() or match.anypats())):
1021 (match.files() or match.anypats())):
1015 raise util.Abort(_('cannot partially commit a merge '
1022 raise util.Abort(_('cannot partially commit a merge '
1016 '(do not specify files or patterns)'))
1023 '(do not specify files or patterns)'))
1017
1024
1018 changes = self.status(match=match, clean=force)
1025 changes = self.status(match=match, clean=force)
1019 if force:
1026 if force:
1020 changes[0].extend(changes[6]) # mq may commit unchanged files
1027 changes[0].extend(changes[6]) # mq may commit unchanged files
1021
1028
1022 # check subrepos
1029 # check subrepos
1023 subs = []
1030 subs = []
1024 removedsubs = set()
1031 removedsubs = set()
1025 if '.hgsub' in wctx:
1032 if '.hgsub' in wctx:
1026 # only manage subrepos and .hgsubstate if .hgsub is present
1033 # only manage subrepos and .hgsubstate if .hgsub is present
1027 for p in wctx.parents():
1034 for p in wctx.parents():
1028 removedsubs.update(s for s in p.substate if match(s))
1035 removedsubs.update(s for s in p.substate if match(s))
1029 for s in wctx.substate:
1036 for s in wctx.substate:
1030 removedsubs.discard(s)
1037 removedsubs.discard(s)
1031 if match(s) and wctx.sub(s).dirty():
1038 if match(s) and wctx.sub(s).dirty():
1032 subs.append(s)
1039 subs.append(s)
1033 if (subs or removedsubs):
1040 if (subs or removedsubs):
1034 if (not match('.hgsub') and
1041 if (not match('.hgsub') and
1035 '.hgsub' in (wctx.modified() + wctx.added())):
1042 '.hgsub' in (wctx.modified() + wctx.added())):
1036 raise util.Abort(
1043 raise util.Abort(
1037 _("can't commit subrepos without .hgsub"))
1044 _("can't commit subrepos without .hgsub"))
1038 if '.hgsubstate' not in changes[0]:
1045 if '.hgsubstate' not in changes[0]:
1039 changes[0].insert(0, '.hgsubstate')
1046 changes[0].insert(0, '.hgsubstate')
1040 if '.hgsubstate' in changes[2]:
1047 if '.hgsubstate' in changes[2]:
1041 changes[2].remove('.hgsubstate')
1048 changes[2].remove('.hgsubstate')
1042 elif '.hgsub' in changes[2]:
1049 elif '.hgsub' in changes[2]:
1043 # clean up .hgsubstate when .hgsub is removed
1050 # clean up .hgsubstate when .hgsub is removed
1044 if ('.hgsubstate' in wctx and
1051 if ('.hgsubstate' in wctx and
1045 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1052 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1046 changes[2].insert(0, '.hgsubstate')
1053 changes[2].insert(0, '.hgsubstate')
1047
1054
1048 if subs and not self.ui.configbool('ui', 'commitsubrepos', True):
1055 if subs and not self.ui.configbool('ui', 'commitsubrepos', True):
1049 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
1056 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
1050 if changedsubs:
1057 if changedsubs:
1051 raise util.Abort(_("uncommitted changes in subrepo %s")
1058 raise util.Abort(_("uncommitted changes in subrepo %s")
1052 % changedsubs[0])
1059 % changedsubs[0])
1053
1060
1054 # make sure all explicit patterns are matched
1061 # make sure all explicit patterns are matched
1055 if not force and match.files():
1062 if not force and match.files():
1056 matched = set(changes[0] + changes[1] + changes[2])
1063 matched = set(changes[0] + changes[1] + changes[2])
1057
1064
1058 for f in match.files():
1065 for f in match.files():
1059 if f == '.' or f in matched or f in wctx.substate:
1066 if f == '.' or f in matched or f in wctx.substate:
1060 continue
1067 continue
1061 if f in changes[3]: # missing
1068 if f in changes[3]: # missing
1062 fail(f, _('file not found!'))
1069 fail(f, _('file not found!'))
1063 if f in vdirs: # visited directory
1070 if f in vdirs: # visited directory
1064 d = f + '/'
1071 d = f + '/'
1065 for mf in matched:
1072 for mf in matched:
1066 if mf.startswith(d):
1073 if mf.startswith(d):
1067 break
1074 break
1068 else:
1075 else:
1069 fail(f, _("no match under directory!"))
1076 fail(f, _("no match under directory!"))
1070 elif f not in self.dirstate:
1077 elif f not in self.dirstate:
1071 fail(f, _("file not tracked!"))
1078 fail(f, _("file not tracked!"))
1072
1079
1073 if (not force and not extra.get("close") and not merge
1080 if (not force and not extra.get("close") and not merge
1074 and not (changes[0] or changes[1] or changes[2])
1081 and not (changes[0] or changes[1] or changes[2])
1075 and wctx.branch() == wctx.p1().branch()):
1082 and wctx.branch() == wctx.p1().branch()):
1076 return None
1083 return None
1077
1084
1078 ms = mergemod.mergestate(self)
1085 ms = mergemod.mergestate(self)
1079 for f in changes[0]:
1086 for f in changes[0]:
1080 if f in ms and ms[f] == 'u':
1087 if f in ms and ms[f] == 'u':
1081 raise util.Abort(_("unresolved merge conflicts "
1088 raise util.Abort(_("unresolved merge conflicts "
1082 "(see hg help resolve)"))
1089 "(see hg help resolve)"))
1083
1090
1084 cctx = context.workingctx(self, text, user, date, extra, changes)
1091 cctx = context.workingctx(self, text, user, date, extra, changes)
1085 if editor:
1092 if editor:
1086 cctx._text = editor(self, cctx, subs)
1093 cctx._text = editor(self, cctx, subs)
1087 edited = (text != cctx._text)
1094 edited = (text != cctx._text)
1088
1095
1089 # commit subs
1096 # commit subs
1090 if subs or removedsubs:
1097 if subs or removedsubs:
1091 state = wctx.substate.copy()
1098 state = wctx.substate.copy()
1092 for s in sorted(subs):
1099 for s in sorted(subs):
1093 sub = wctx.sub(s)
1100 sub = wctx.sub(s)
1094 self.ui.status(_('committing subrepository %s\n') %
1101 self.ui.status(_('committing subrepository %s\n') %
1095 subrepo.subrelpath(sub))
1102 subrepo.subrelpath(sub))
1096 sr = sub.commit(cctx._text, user, date)
1103 sr = sub.commit(cctx._text, user, date)
1097 state[s] = (state[s][0], sr)
1104 state[s] = (state[s][0], sr)
1098 subrepo.writestate(self, state)
1105 subrepo.writestate(self, state)
1099
1106
1100 # Save commit message in case this transaction gets rolled back
1107 # Save commit message in case this transaction gets rolled back
1101 # (e.g. by a pretxncommit hook). Leave the content alone on
1108 # (e.g. by a pretxncommit hook). Leave the content alone on
1102 # the assumption that the user will use the same editor again.
1109 # the assumption that the user will use the same editor again.
1103 msgfn = self.savecommitmessage(cctx._text)
1110 msgfn = self.savecommitmessage(cctx._text)
1104
1111
1105 p1, p2 = self.dirstate.parents()
1112 p1, p2 = self.dirstate.parents()
1106 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1113 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1107 try:
1114 try:
1108 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1115 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1109 ret = self.commitctx(cctx, True)
1116 ret = self.commitctx(cctx, True)
1110 except:
1117 except:
1111 if edited:
1118 if edited:
1112 self.ui.write(
1119 self.ui.write(
1113 _('note: commit message saved in %s\n') % msgfn)
1120 _('note: commit message saved in %s\n') % msgfn)
1114 raise
1121 raise
1115
1122
1116 # update bookmarks, dirstate and mergestate
1123 # update bookmarks, dirstate and mergestate
1117 bookmarks.update(self, p1, ret)
1124 bookmarks.update(self, p1, ret)
1118 for f in changes[0] + changes[1]:
1125 for f in changes[0] + changes[1]:
1119 self.dirstate.normal(f)
1126 self.dirstate.normal(f)
1120 for f in changes[2]:
1127 for f in changes[2]:
1121 self.dirstate.drop(f)
1128 self.dirstate.drop(f)
1122 self.dirstate.setparents(ret)
1129 self.dirstate.setparents(ret)
1123 ms.reset()
1130 ms.reset()
1124 finally:
1131 finally:
1125 wlock.release()
1132 wlock.release()
1126
1133
1127 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1134 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1128 return ret
1135 return ret
1129
1136
1130 def commitctx(self, ctx, error=False):
1137 def commitctx(self, ctx, error=False):
1131 """Add a new revision to current repository.
1138 """Add a new revision to current repository.
1132 Revision information is passed via the context argument.
1139 Revision information is passed via the context argument.
1133 """
1140 """
1134
1141
1135 tr = lock = None
1142 tr = lock = None
1136 removed = list(ctx.removed())
1143 removed = list(ctx.removed())
1137 p1, p2 = ctx.p1(), ctx.p2()
1144 p1, p2 = ctx.p1(), ctx.p2()
1138 user = ctx.user()
1145 user = ctx.user()
1139
1146
1140 lock = self.lock()
1147 lock = self.lock()
1141 try:
1148 try:
1142 tr = self.transaction("commit")
1149 tr = self.transaction("commit")
1143 trp = weakref.proxy(tr)
1150 trp = weakref.proxy(tr)
1144
1151
1145 if ctx.files():
1152 if ctx.files():
1146 m1 = p1.manifest().copy()
1153 m1 = p1.manifest().copy()
1147 m2 = p2.manifest()
1154 m2 = p2.manifest()
1148
1155
1149 # check in files
1156 # check in files
1150 new = {}
1157 new = {}
1151 changed = []
1158 changed = []
1152 linkrev = len(self)
1159 linkrev = len(self)
1153 for f in sorted(ctx.modified() + ctx.added()):
1160 for f in sorted(ctx.modified() + ctx.added()):
1154 self.ui.note(f + "\n")
1161 self.ui.note(f + "\n")
1155 try:
1162 try:
1156 fctx = ctx[f]
1163 fctx = ctx[f]
1157 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1164 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1158 changed)
1165 changed)
1159 m1.set(f, fctx.flags())
1166 m1.set(f, fctx.flags())
1160 except OSError, inst:
1167 except OSError, inst:
1161 self.ui.warn(_("trouble committing %s!\n") % f)
1168 self.ui.warn(_("trouble committing %s!\n") % f)
1162 raise
1169 raise
1163 except IOError, inst:
1170 except IOError, inst:
1164 errcode = getattr(inst, 'errno', errno.ENOENT)
1171 errcode = getattr(inst, 'errno', errno.ENOENT)
1165 if error or errcode and errcode != errno.ENOENT:
1172 if error or errcode and errcode != errno.ENOENT:
1166 self.ui.warn(_("trouble committing %s!\n") % f)
1173 self.ui.warn(_("trouble committing %s!\n") % f)
1167 raise
1174 raise
1168 else:
1175 else:
1169 removed.append(f)
1176 removed.append(f)
1170
1177
1171 # update manifest
1178 # update manifest
1172 m1.update(new)
1179 m1.update(new)
1173 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1180 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1174 drop = [f for f in removed if f in m1]
1181 drop = [f for f in removed if f in m1]
1175 for f in drop:
1182 for f in drop:
1176 del m1[f]
1183 del m1[f]
1177 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1184 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1178 p2.manifestnode(), (new, drop))
1185 p2.manifestnode(), (new, drop))
1179 files = changed + removed
1186 files = changed + removed
1180 else:
1187 else:
1181 mn = p1.manifestnode()
1188 mn = p1.manifestnode()
1182 files = []
1189 files = []
1183
1190
1184 # update changelog
1191 # update changelog
1185 self.changelog.delayupdate()
1192 self.changelog.delayupdate()
1186 n = self.changelog.add(mn, files, ctx.description(),
1193 n = self.changelog.add(mn, files, ctx.description(),
1187 trp, p1.node(), p2.node(),
1194 trp, p1.node(), p2.node(),
1188 user, ctx.date(), ctx.extra().copy())
1195 user, ctx.date(), ctx.extra().copy())
1189 p = lambda: self.changelog.writepending() and self.root or ""
1196 p = lambda: self.changelog.writepending() and self.root or ""
1190 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1197 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1191 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1198 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1192 parent2=xp2, pending=p)
1199 parent2=xp2, pending=p)
1193 self.changelog.finalize(trp)
1200 self.changelog.finalize(trp)
1194 tr.close()
1201 tr.close()
1195
1202
1196 if self._branchcache:
1203 if self._branchcache:
1197 self.updatebranchcache()
1204 self.updatebranchcache()
1198 return n
1205 return n
1199 finally:
1206 finally:
1200 if tr:
1207 if tr:
1201 tr.release()
1208 tr.release()
1202 lock.release()
1209 lock.release()
1203
1210
1204 def destroyed(self):
1211 def destroyed(self):
1205 '''Inform the repository that nodes have been destroyed.
1212 '''Inform the repository that nodes have been destroyed.
1206 Intended for use by strip and rollback, so there's a common
1213 Intended for use by strip and rollback, so there's a common
1207 place for anything that has to be done after destroying history.'''
1214 place for anything that has to be done after destroying history.'''
1208 # XXX it might be nice if we could take the list of destroyed
1215 # XXX it might be nice if we could take the list of destroyed
1209 # nodes, but I don't see an easy way for rollback() to do that
1216 # nodes, but I don't see an easy way for rollback() to do that
1210
1217
1211 # Ensure the persistent tag cache is updated. Doing it now
1218 # Ensure the persistent tag cache is updated. Doing it now
1212 # means that the tag cache only has to worry about destroyed
1219 # means that the tag cache only has to worry about destroyed
1213 # heads immediately after a strip/rollback. That in turn
1220 # heads immediately after a strip/rollback. That in turn
1214 # guarantees that "cachetip == currenttip" (comparing both rev
1221 # guarantees that "cachetip == currenttip" (comparing both rev
1215 # and node) always means no nodes have been added or destroyed.
1222 # and node) always means no nodes have been added or destroyed.
1216
1223
1217 # XXX this is suboptimal when qrefresh'ing: we strip the current
1224 # XXX this is suboptimal when qrefresh'ing: we strip the current
1218 # head, refresh the tag cache, then immediately add a new head.
1225 # head, refresh the tag cache, then immediately add a new head.
1219 # But I think doing it this way is necessary for the "instant
1226 # But I think doing it this way is necessary for the "instant
1220 # tag cache retrieval" case to work.
1227 # tag cache retrieval" case to work.
1221 self.invalidatecaches()
1228 self.invalidatecaches()
1222
1229
1223 def walk(self, match, node=None):
1230 def walk(self, match, node=None):
1224 '''
1231 '''
1225 walk recursively through the directory tree or a given
1232 walk recursively through the directory tree or a given
1226 changeset, finding all files matched by the match
1233 changeset, finding all files matched by the match
1227 function
1234 function
1228 '''
1235 '''
1229 return self[node].walk(match)
1236 return self[node].walk(match)
1230
1237
1231 def status(self, node1='.', node2=None, match=None,
1238 def status(self, node1='.', node2=None, match=None,
1232 ignored=False, clean=False, unknown=False,
1239 ignored=False, clean=False, unknown=False,
1233 listsubrepos=False):
1240 listsubrepos=False):
1234 """return status of files between two nodes or node and working directory
1241 """return status of files between two nodes or node and working directory
1235
1242
1236 If node1 is None, use the first dirstate parent instead.
1243 If node1 is None, use the first dirstate parent instead.
1237 If node2 is None, compare node1 with working directory.
1244 If node2 is None, compare node1 with working directory.
1238 """
1245 """
1239
1246
1240 def mfmatches(ctx):
1247 def mfmatches(ctx):
1241 mf = ctx.manifest().copy()
1248 mf = ctx.manifest().copy()
1242 for fn in mf.keys():
1249 for fn in mf.keys():
1243 if not match(fn):
1250 if not match(fn):
1244 del mf[fn]
1251 del mf[fn]
1245 return mf
1252 return mf
1246
1253
1247 if isinstance(node1, context.changectx):
1254 if isinstance(node1, context.changectx):
1248 ctx1 = node1
1255 ctx1 = node1
1249 else:
1256 else:
1250 ctx1 = self[node1]
1257 ctx1 = self[node1]
1251 if isinstance(node2, context.changectx):
1258 if isinstance(node2, context.changectx):
1252 ctx2 = node2
1259 ctx2 = node2
1253 else:
1260 else:
1254 ctx2 = self[node2]
1261 ctx2 = self[node2]
1255
1262
1256 working = ctx2.rev() is None
1263 working = ctx2.rev() is None
1257 parentworking = working and ctx1 == self['.']
1264 parentworking = working and ctx1 == self['.']
1258 match = match or matchmod.always(self.root, self.getcwd())
1265 match = match or matchmod.always(self.root, self.getcwd())
1259 listignored, listclean, listunknown = ignored, clean, unknown
1266 listignored, listclean, listunknown = ignored, clean, unknown
1260
1267
1261 # load earliest manifest first for caching reasons
1268 # load earliest manifest first for caching reasons
1262 if not working and ctx2.rev() < ctx1.rev():
1269 if not working and ctx2.rev() < ctx1.rev():
1263 ctx2.manifest()
1270 ctx2.manifest()
1264
1271
1265 if not parentworking:
1272 if not parentworking:
1266 def bad(f, msg):
1273 def bad(f, msg):
1267 if f not in ctx1:
1274 if f not in ctx1:
1268 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1275 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1269 match.bad = bad
1276 match.bad = bad
1270
1277
1271 if working: # we need to scan the working dir
1278 if working: # we need to scan the working dir
1272 subrepos = []
1279 subrepos = []
1273 if '.hgsub' in self.dirstate:
1280 if '.hgsub' in self.dirstate:
1274 subrepos = ctx2.substate.keys()
1281 subrepos = ctx2.substate.keys()
1275 s = self.dirstate.status(match, subrepos, listignored,
1282 s = self.dirstate.status(match, subrepos, listignored,
1276 listclean, listunknown)
1283 listclean, listunknown)
1277 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1284 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1278
1285
1279 # check for any possibly clean files
1286 # check for any possibly clean files
1280 if parentworking and cmp:
1287 if parentworking and cmp:
1281 fixup = []
1288 fixup = []
1282 # do a full compare of any files that might have changed
1289 # do a full compare of any files that might have changed
1283 for f in sorted(cmp):
1290 for f in sorted(cmp):
1284 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1291 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1285 or ctx1[f].cmp(ctx2[f])):
1292 or ctx1[f].cmp(ctx2[f])):
1286 modified.append(f)
1293 modified.append(f)
1287 else:
1294 else:
1288 fixup.append(f)
1295 fixup.append(f)
1289
1296
1290 # update dirstate for files that are actually clean
1297 # update dirstate for files that are actually clean
1291 if fixup:
1298 if fixup:
1292 if listclean:
1299 if listclean:
1293 clean += fixup
1300 clean += fixup
1294
1301
1295 try:
1302 try:
1296 # updating the dirstate is optional
1303 # updating the dirstate is optional
1297 # so we don't wait on the lock
1304 # so we don't wait on the lock
1298 wlock = self.wlock(False)
1305 wlock = self.wlock(False)
1299 try:
1306 try:
1300 for f in fixup:
1307 for f in fixup:
1301 self.dirstate.normal(f)
1308 self.dirstate.normal(f)
1302 finally:
1309 finally:
1303 wlock.release()
1310 wlock.release()
1304 except error.LockError:
1311 except error.LockError:
1305 pass
1312 pass
1306
1313
1307 if not parentworking:
1314 if not parentworking:
1308 mf1 = mfmatches(ctx1)
1315 mf1 = mfmatches(ctx1)
1309 if working:
1316 if working:
1310 # we are comparing working dir against non-parent
1317 # we are comparing working dir against non-parent
1311 # generate a pseudo-manifest for the working dir
1318 # generate a pseudo-manifest for the working dir
1312 mf2 = mfmatches(self['.'])
1319 mf2 = mfmatches(self['.'])
1313 for f in cmp + modified + added:
1320 for f in cmp + modified + added:
1314 mf2[f] = None
1321 mf2[f] = None
1315 mf2.set(f, ctx2.flags(f))
1322 mf2.set(f, ctx2.flags(f))
1316 for f in removed:
1323 for f in removed:
1317 if f in mf2:
1324 if f in mf2:
1318 del mf2[f]
1325 del mf2[f]
1319 else:
1326 else:
1320 # we are comparing two revisions
1327 # we are comparing two revisions
1321 deleted, unknown, ignored = [], [], []
1328 deleted, unknown, ignored = [], [], []
1322 mf2 = mfmatches(ctx2)
1329 mf2 = mfmatches(ctx2)
1323
1330
1324 modified, added, clean = [], [], []
1331 modified, added, clean = [], [], []
1325 for fn in mf2:
1332 for fn in mf2:
1326 if fn in mf1:
1333 if fn in mf1:
1327 if (fn not in deleted and
1334 if (fn not in deleted and
1328 (mf1.flags(fn) != mf2.flags(fn) or
1335 (mf1.flags(fn) != mf2.flags(fn) or
1329 (mf1[fn] != mf2[fn] and
1336 (mf1[fn] != mf2[fn] and
1330 (mf2[fn] or ctx1[fn].cmp(ctx2[fn]))))):
1337 (mf2[fn] or ctx1[fn].cmp(ctx2[fn]))))):
1331 modified.append(fn)
1338 modified.append(fn)
1332 elif listclean:
1339 elif listclean:
1333 clean.append(fn)
1340 clean.append(fn)
1334 del mf1[fn]
1341 del mf1[fn]
1335 elif fn not in deleted:
1342 elif fn not in deleted:
1336 added.append(fn)
1343 added.append(fn)
1337 removed = mf1.keys()
1344 removed = mf1.keys()
1338
1345
1339 r = modified, added, removed, deleted, unknown, ignored, clean
1346 r = modified, added, removed, deleted, unknown, ignored, clean
1340
1347
1341 if listsubrepos:
1348 if listsubrepos:
1342 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1349 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1343 if working:
1350 if working:
1344 rev2 = None
1351 rev2 = None
1345 else:
1352 else:
1346 rev2 = ctx2.substate[subpath][1]
1353 rev2 = ctx2.substate[subpath][1]
1347 try:
1354 try:
1348 submatch = matchmod.narrowmatcher(subpath, match)
1355 submatch = matchmod.narrowmatcher(subpath, match)
1349 s = sub.status(rev2, match=submatch, ignored=listignored,
1356 s = sub.status(rev2, match=submatch, ignored=listignored,
1350 clean=listclean, unknown=listunknown,
1357 clean=listclean, unknown=listunknown,
1351 listsubrepos=True)
1358 listsubrepos=True)
1352 for rfiles, sfiles in zip(r, s):
1359 for rfiles, sfiles in zip(r, s):
1353 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1360 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1354 except error.LookupError:
1361 except error.LookupError:
1355 self.ui.status(_("skipping missing subrepository: %s\n")
1362 self.ui.status(_("skipping missing subrepository: %s\n")
1356 % subpath)
1363 % subpath)
1357
1364
1358 for l in r:
1365 for l in r:
1359 l.sort()
1366 l.sort()
1360 return r
1367 return r
1361
1368
1362 def heads(self, start=None):
1369 def heads(self, start=None):
1363 heads = self.changelog.heads(start)
1370 heads = self.changelog.heads(start)
1364 # sort the output in rev descending order
1371 # sort the output in rev descending order
1365 return sorted(heads, key=self.changelog.rev, reverse=True)
1372 return sorted(heads, key=self.changelog.rev, reverse=True)
1366
1373
1367 def branchheads(self, branch=None, start=None, closed=False):
1374 def branchheads(self, branch=None, start=None, closed=False):
1368 '''return a (possibly filtered) list of heads for the given branch
1375 '''return a (possibly filtered) list of heads for the given branch
1369
1376
1370 Heads are returned in topological order, from newest to oldest.
1377 Heads are returned in topological order, from newest to oldest.
1371 If branch is None, use the dirstate branch.
1378 If branch is None, use the dirstate branch.
1372 If start is not None, return only heads reachable from start.
1379 If start is not None, return only heads reachable from start.
1373 If closed is True, return heads that are marked as closed as well.
1380 If closed is True, return heads that are marked as closed as well.
1374 '''
1381 '''
1375 if branch is None:
1382 if branch is None:
1376 branch = self[None].branch()
1383 branch = self[None].branch()
1377 branches = self.branchmap()
1384 branches = self.branchmap()
1378 if branch not in branches:
1385 if branch not in branches:
1379 return []
1386 return []
1380 # the cache returns heads ordered lowest to highest
1387 # the cache returns heads ordered lowest to highest
1381 bheads = list(reversed(branches[branch]))
1388 bheads = list(reversed(branches[branch]))
1382 if start is not None:
1389 if start is not None:
1383 # filter out the heads that cannot be reached from startrev
1390 # filter out the heads that cannot be reached from startrev
1384 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1391 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1385 bheads = [h for h in bheads if h in fbheads]
1392 bheads = [h for h in bheads if h in fbheads]
1386 if not closed:
1393 if not closed:
1387 bheads = [h for h in bheads if
1394 bheads = [h for h in bheads if
1388 ('close' not in self.changelog.read(h)[5])]
1395 ('close' not in self.changelog.read(h)[5])]
1389 return bheads
1396 return bheads
1390
1397
1391 def branches(self, nodes):
1398 def branches(self, nodes):
1392 if not nodes:
1399 if not nodes:
1393 nodes = [self.changelog.tip()]
1400 nodes = [self.changelog.tip()]
1394 b = []
1401 b = []
1395 for n in nodes:
1402 for n in nodes:
1396 t = n
1403 t = n
1397 while True:
1404 while True:
1398 p = self.changelog.parents(n)
1405 p = self.changelog.parents(n)
1399 if p[1] != nullid or p[0] == nullid:
1406 if p[1] != nullid or p[0] == nullid:
1400 b.append((t, n, p[0], p[1]))
1407 b.append((t, n, p[0], p[1]))
1401 break
1408 break
1402 n = p[0]
1409 n = p[0]
1403 return b
1410 return b
1404
1411
1405 def between(self, pairs):
1412 def between(self, pairs):
1406 r = []
1413 r = []
1407
1414
1408 for top, bottom in pairs:
1415 for top, bottom in pairs:
1409 n, l, i = top, [], 0
1416 n, l, i = top, [], 0
1410 f = 1
1417 f = 1
1411
1418
1412 while n != bottom and n != nullid:
1419 while n != bottom and n != nullid:
1413 p = self.changelog.parents(n)[0]
1420 p = self.changelog.parents(n)[0]
1414 if i == f:
1421 if i == f:
1415 l.append(n)
1422 l.append(n)
1416 f = f * 2
1423 f = f * 2
1417 n = p
1424 n = p
1418 i += 1
1425 i += 1
1419
1426
1420 r.append(l)
1427 r.append(l)
1421
1428
1422 return r
1429 return r
1423
1430
1424 def pull(self, remote, heads=None, force=False):
1431 def pull(self, remote, heads=None, force=False):
1425 lock = self.lock()
1432 lock = self.lock()
1426 try:
1433 try:
1427 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1434 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1428 force=force)
1435 force=force)
1429 common, fetch, rheads = tmp
1436 common, fetch, rheads = tmp
1430 if not fetch:
1437 if not fetch:
1431 self.ui.status(_("no changes found\n"))
1438 self.ui.status(_("no changes found\n"))
1432 result = 0
1439 result = 0
1433 else:
1440 else:
1434 if heads is None and list(common) == [nullid]:
1441 if heads is None and list(common) == [nullid]:
1435 self.ui.status(_("requesting all changes\n"))
1442 self.ui.status(_("requesting all changes\n"))
1436 elif heads is None and remote.capable('changegroupsubset'):
1443 elif heads is None and remote.capable('changegroupsubset'):
1437 # issue1320, avoid a race if remote changed after discovery
1444 # issue1320, avoid a race if remote changed after discovery
1438 heads = rheads
1445 heads = rheads
1439
1446
1440 if remote.capable('getbundle'):
1447 if remote.capable('getbundle'):
1441 cg = remote.getbundle('pull', common=common,
1448 cg = remote.getbundle('pull', common=common,
1442 heads=heads or rheads)
1449 heads=heads or rheads)
1443 elif heads is None:
1450 elif heads is None:
1444 cg = remote.changegroup(fetch, 'pull')
1451 cg = remote.changegroup(fetch, 'pull')
1445 elif not remote.capable('changegroupsubset'):
1452 elif not remote.capable('changegroupsubset'):
1446 raise util.Abort(_("partial pull cannot be done because "
1453 raise util.Abort(_("partial pull cannot be done because "
1447 "other repository doesn't support "
1454 "other repository doesn't support "
1448 "changegroupsubset."))
1455 "changegroupsubset."))
1449 else:
1456 else:
1450 cg = remote.changegroupsubset(fetch, heads, 'pull')
1457 cg = remote.changegroupsubset(fetch, heads, 'pull')
1451 result = self.addchangegroup(cg, 'pull', remote.url(),
1458 result = self.addchangegroup(cg, 'pull', remote.url(),
1452 lock=lock)
1459 lock=lock)
1453 finally:
1460 finally:
1454 lock.release()
1461 lock.release()
1455
1462
1456 return result
1463 return result
1457
1464
1458 def checkpush(self, force, revs):
1465 def checkpush(self, force, revs):
1459 """Extensions can override this function if additional checks have
1466 """Extensions can override this function if additional checks have
1460 to be performed before pushing, or call it if they override push
1467 to be performed before pushing, or call it if they override push
1461 command.
1468 command.
1462 """
1469 """
1463 pass
1470 pass
1464
1471
1465 def push(self, remote, force=False, revs=None, newbranch=False):
1472 def push(self, remote, force=False, revs=None, newbranch=False):
1466 '''Push outgoing changesets (limited by revs) from the current
1473 '''Push outgoing changesets (limited by revs) from the current
1467 repository to remote. Return an integer:
1474 repository to remote. Return an integer:
1468 - 0 means HTTP error *or* nothing to push
1475 - 0 means HTTP error *or* nothing to push
1469 - 1 means we pushed and remote head count is unchanged *or*
1476 - 1 means we pushed and remote head count is unchanged *or*
1470 we have outgoing changesets but refused to push
1477 we have outgoing changesets but refused to push
1471 - other values as described by addchangegroup()
1478 - other values as described by addchangegroup()
1472 '''
1479 '''
1473 # there are two ways to push to remote repo:
1480 # there are two ways to push to remote repo:
1474 #
1481 #
1475 # addchangegroup assumes local user can lock remote
1482 # addchangegroup assumes local user can lock remote
1476 # repo (local filesystem, old ssh servers).
1483 # repo (local filesystem, old ssh servers).
1477 #
1484 #
1478 # unbundle assumes local user cannot lock remote repo (new ssh
1485 # unbundle assumes local user cannot lock remote repo (new ssh
1479 # servers, http servers).
1486 # servers, http servers).
1480
1487
1481 self.checkpush(force, revs)
1488 self.checkpush(force, revs)
1482 lock = None
1489 lock = None
1483 unbundle = remote.capable('unbundle')
1490 unbundle = remote.capable('unbundle')
1484 if not unbundle:
1491 if not unbundle:
1485 lock = remote.lock()
1492 lock = remote.lock()
1486 try:
1493 try:
1487 cg, remote_heads = discovery.prepush(self, remote, force, revs,
1494 cg, remote_heads = discovery.prepush(self, remote, force, revs,
1488 newbranch)
1495 newbranch)
1489 ret = remote_heads
1496 ret = remote_heads
1490 if cg is not None:
1497 if cg is not None:
1491 if unbundle:
1498 if unbundle:
1492 # local repo finds heads on server, finds out what
1499 # local repo finds heads on server, finds out what
1493 # revs it must push. once revs transferred, if server
1500 # revs it must push. once revs transferred, if server
1494 # finds it has different heads (someone else won
1501 # finds it has different heads (someone else won
1495 # commit/push race), server aborts.
1502 # commit/push race), server aborts.
1496 if force:
1503 if force:
1497 remote_heads = ['force']
1504 remote_heads = ['force']
1498 # ssh: return remote's addchangegroup()
1505 # ssh: return remote's addchangegroup()
1499 # http: return remote's addchangegroup() or 0 for error
1506 # http: return remote's addchangegroup() or 0 for error
1500 ret = remote.unbundle(cg, remote_heads, 'push')
1507 ret = remote.unbundle(cg, remote_heads, 'push')
1501 else:
1508 else:
1502 # we return an integer indicating remote head count change
1509 # we return an integer indicating remote head count change
1503 ret = remote.addchangegroup(cg, 'push', self.url(),
1510 ret = remote.addchangegroup(cg, 'push', self.url(),
1504 lock=lock)
1511 lock=lock)
1505 finally:
1512 finally:
1506 if lock is not None:
1513 if lock is not None:
1507 lock.release()
1514 lock.release()
1508
1515
1509 self.ui.debug("checking for updated bookmarks\n")
1516 self.ui.debug("checking for updated bookmarks\n")
1510 rb = remote.listkeys('bookmarks')
1517 rb = remote.listkeys('bookmarks')
1511 for k in rb.keys():
1518 for k in rb.keys():
1512 if k in self._bookmarks:
1519 if k in self._bookmarks:
1513 nr, nl = rb[k], hex(self._bookmarks[k])
1520 nr, nl = rb[k], hex(self._bookmarks[k])
1514 if nr in self:
1521 if nr in self:
1515 cr = self[nr]
1522 cr = self[nr]
1516 cl = self[nl]
1523 cl = self[nl]
1517 if cl in cr.descendants():
1524 if cl in cr.descendants():
1518 r = remote.pushkey('bookmarks', k, nr, nl)
1525 r = remote.pushkey('bookmarks', k, nr, nl)
1519 if r:
1526 if r:
1520 self.ui.status(_("updating bookmark %s\n") % k)
1527 self.ui.status(_("updating bookmark %s\n") % k)
1521 else:
1528 else:
1522 self.ui.warn(_('updating bookmark %s'
1529 self.ui.warn(_('updating bookmark %s'
1523 ' failed!\n') % k)
1530 ' failed!\n') % k)
1524
1531
1525 return ret
1532 return ret
1526
1533
1527 def changegroupinfo(self, nodes, source):
1534 def changegroupinfo(self, nodes, source):
1528 if self.ui.verbose or source == 'bundle':
1535 if self.ui.verbose or source == 'bundle':
1529 self.ui.status(_("%d changesets found\n") % len(nodes))
1536 self.ui.status(_("%d changesets found\n") % len(nodes))
1530 if self.ui.debugflag:
1537 if self.ui.debugflag:
1531 self.ui.debug("list of changesets:\n")
1538 self.ui.debug("list of changesets:\n")
1532 for node in nodes:
1539 for node in nodes:
1533 self.ui.debug("%s\n" % hex(node))
1540 self.ui.debug("%s\n" % hex(node))
1534
1541
1535 def changegroupsubset(self, bases, heads, source):
1542 def changegroupsubset(self, bases, heads, source):
1536 """Compute a changegroup consisting of all the nodes that are
1543 """Compute a changegroup consisting of all the nodes that are
1537 descendants of any of the bases and ancestors of any of the heads.
1544 descendants of any of the bases and ancestors of any of the heads.
1538 Return a chunkbuffer object whose read() method will return
1545 Return a chunkbuffer object whose read() method will return
1539 successive changegroup chunks.
1546 successive changegroup chunks.
1540
1547
1541 It is fairly complex as determining which filenodes and which
1548 It is fairly complex as determining which filenodes and which
1542 manifest nodes need to be included for the changeset to be complete
1549 manifest nodes need to be included for the changeset to be complete
1543 is non-trivial.
1550 is non-trivial.
1544
1551
1545 Another wrinkle is doing the reverse, figuring out which changeset in
1552 Another wrinkle is doing the reverse, figuring out which changeset in
1546 the changegroup a particular filenode or manifestnode belongs to.
1553 the changegroup a particular filenode or manifestnode belongs to.
1547 """
1554 """
1548 cl = self.changelog
1555 cl = self.changelog
1549 if not bases:
1556 if not bases:
1550 bases = [nullid]
1557 bases = [nullid]
1551 csets, bases, heads = cl.nodesbetween(bases, heads)
1558 csets, bases, heads = cl.nodesbetween(bases, heads)
1552 # We assume that all ancestors of bases are known
1559 # We assume that all ancestors of bases are known
1553 common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1560 common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1554 return self._changegroupsubset(common, csets, heads, source)
1561 return self._changegroupsubset(common, csets, heads, source)
1555
1562
1556 def getbundle(self, source, heads=None, common=None):
1563 def getbundle(self, source, heads=None, common=None):
1557 """Like changegroupsubset, but returns the set difference between the
1564 """Like changegroupsubset, but returns the set difference between the
1558 ancestors of heads and the ancestors common.
1565 ancestors of heads and the ancestors common.
1559
1566
1560 If heads is None, use the local heads. If common is None, use [nullid].
1567 If heads is None, use the local heads. If common is None, use [nullid].
1561
1568
1562 The nodes in common might not all be known locally due to the way the
1569 The nodes in common might not all be known locally due to the way the
1563 current discovery protocol works.
1570 current discovery protocol works.
1564 """
1571 """
1565 cl = self.changelog
1572 cl = self.changelog
1566 if common:
1573 if common:
1567 nm = cl.nodemap
1574 nm = cl.nodemap
1568 common = [n for n in common if n in nm]
1575 common = [n for n in common if n in nm]
1569 else:
1576 else:
1570 common = [nullid]
1577 common = [nullid]
1571 if not heads:
1578 if not heads:
1572 heads = cl.heads()
1579 heads = cl.heads()
1573 common, missing = cl.findcommonmissing(common, heads)
1580 common, missing = cl.findcommonmissing(common, heads)
1574 if not missing:
1581 if not missing:
1575 return None
1582 return None
1576 return self._changegroupsubset(common, missing, heads, source)
1583 return self._changegroupsubset(common, missing, heads, source)
1577
1584
1578 def _changegroupsubset(self, commonrevs, csets, heads, source):
1585 def _changegroupsubset(self, commonrevs, csets, heads, source):
1579
1586
1580 cl = self.changelog
1587 cl = self.changelog
1581 mf = self.manifest
1588 mf = self.manifest
1582 mfs = {} # needed manifests
1589 mfs = {} # needed manifests
1583 fnodes = {} # needed file nodes
1590 fnodes = {} # needed file nodes
1584 changedfiles = set()
1591 changedfiles = set()
1585 fstate = ['', {}]
1592 fstate = ['', {}]
1586 count = [0]
1593 count = [0]
1587
1594
1588 # can we go through the fast path ?
1595 # can we go through the fast path ?
1589 heads.sort()
1596 heads.sort()
1590 if heads == sorted(self.heads()):
1597 if heads == sorted(self.heads()):
1591 return self._changegroup(csets, source)
1598 return self._changegroup(csets, source)
1592
1599
1593 # slow path
1600 # slow path
1594 self.hook('preoutgoing', throw=True, source=source)
1601 self.hook('preoutgoing', throw=True, source=source)
1595 self.changegroupinfo(csets, source)
1602 self.changegroupinfo(csets, source)
1596
1603
1597 # filter any nodes that claim to be part of the known set
1604 # filter any nodes that claim to be part of the known set
1598 def prune(revlog, missing):
1605 def prune(revlog, missing):
1599 return [n for n in missing
1606 return [n for n in missing
1600 if revlog.linkrev(revlog.rev(n)) not in commonrevs]
1607 if revlog.linkrev(revlog.rev(n)) not in commonrevs]
1601
1608
1602 def lookup(revlog, x):
1609 def lookup(revlog, x):
1603 if revlog == cl:
1610 if revlog == cl:
1604 c = cl.read(x)
1611 c = cl.read(x)
1605 changedfiles.update(c[3])
1612 changedfiles.update(c[3])
1606 mfs.setdefault(c[0], x)
1613 mfs.setdefault(c[0], x)
1607 count[0] += 1
1614 count[0] += 1
1608 self.ui.progress(_('bundling'), count[0],
1615 self.ui.progress(_('bundling'), count[0],
1609 unit=_('changesets'), total=len(csets))
1616 unit=_('changesets'), total=len(csets))
1610 return x
1617 return x
1611 elif revlog == mf:
1618 elif revlog == mf:
1612 clnode = mfs[x]
1619 clnode = mfs[x]
1613 mdata = mf.readfast(x)
1620 mdata = mf.readfast(x)
1614 for f in changedfiles:
1621 for f in changedfiles:
1615 if f in mdata:
1622 if f in mdata:
1616 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1623 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1617 count[0] += 1
1624 count[0] += 1
1618 self.ui.progress(_('bundling'), count[0],
1625 self.ui.progress(_('bundling'), count[0],
1619 unit=_('manifests'), total=len(mfs))
1626 unit=_('manifests'), total=len(mfs))
1620 return mfs[x]
1627 return mfs[x]
1621 else:
1628 else:
1622 self.ui.progress(
1629 self.ui.progress(
1623 _('bundling'), count[0], item=fstate[0],
1630 _('bundling'), count[0], item=fstate[0],
1624 unit=_('files'), total=len(changedfiles))
1631 unit=_('files'), total=len(changedfiles))
1625 return fstate[1][x]
1632 return fstate[1][x]
1626
1633
1627 bundler = changegroup.bundle10(lookup)
1634 bundler = changegroup.bundle10(lookup)
1628 reorder = self.ui.config('bundle', 'reorder', 'auto')
1635 reorder = self.ui.config('bundle', 'reorder', 'auto')
1629 if reorder == 'auto':
1636 if reorder == 'auto':
1630 reorder = None
1637 reorder = None
1631 else:
1638 else:
1632 reorder = util.parsebool(reorder)
1639 reorder = util.parsebool(reorder)
1633
1640
1634 def gengroup():
1641 def gengroup():
1635 # Create a changenode group generator that will call our functions
1642 # Create a changenode group generator that will call our functions
1636 # back to lookup the owning changenode and collect information.
1643 # back to lookup the owning changenode and collect information.
1637 for chunk in cl.group(csets, bundler, reorder=reorder):
1644 for chunk in cl.group(csets, bundler, reorder=reorder):
1638 yield chunk
1645 yield chunk
1639 self.ui.progress(_('bundling'), None)
1646 self.ui.progress(_('bundling'), None)
1640
1647
1641 # Create a generator for the manifestnodes that calls our lookup
1648 # Create a generator for the manifestnodes that calls our lookup
1642 # and data collection functions back.
1649 # and data collection functions back.
1643 count[0] = 0
1650 count[0] = 0
1644 for chunk in mf.group(prune(mf, mfs), bundler, reorder=reorder):
1651 for chunk in mf.group(prune(mf, mfs), bundler, reorder=reorder):
1645 yield chunk
1652 yield chunk
1646 self.ui.progress(_('bundling'), None)
1653 self.ui.progress(_('bundling'), None)
1647
1654
1648 mfs.clear()
1655 mfs.clear()
1649
1656
1650 # Go through all our files in order sorted by name.
1657 # Go through all our files in order sorted by name.
1651 count[0] = 0
1658 count[0] = 0
1652 for fname in sorted(changedfiles):
1659 for fname in sorted(changedfiles):
1653 filerevlog = self.file(fname)
1660 filerevlog = self.file(fname)
1654 if not len(filerevlog):
1661 if not len(filerevlog):
1655 raise util.Abort(_("empty or missing revlog for %s") % fname)
1662 raise util.Abort(_("empty or missing revlog for %s") % fname)
1656 fstate[0] = fname
1663 fstate[0] = fname
1657 fstate[1] = fnodes.pop(fname, {})
1664 fstate[1] = fnodes.pop(fname, {})
1658
1665
1659 nodelist = prune(filerevlog, fstate[1])
1666 nodelist = prune(filerevlog, fstate[1])
1660 if nodelist:
1667 if nodelist:
1661 count[0] += 1
1668 count[0] += 1
1662 yield bundler.fileheader(fname)
1669 yield bundler.fileheader(fname)
1663 for chunk in filerevlog.group(nodelist, bundler, reorder):
1670 for chunk in filerevlog.group(nodelist, bundler, reorder):
1664 yield chunk
1671 yield chunk
1665
1672
1666 # Signal that no more groups are left.
1673 # Signal that no more groups are left.
1667 yield bundler.close()
1674 yield bundler.close()
1668 self.ui.progress(_('bundling'), None)
1675 self.ui.progress(_('bundling'), None)
1669
1676
1670 if csets:
1677 if csets:
1671 self.hook('outgoing', node=hex(csets[0]), source=source)
1678 self.hook('outgoing', node=hex(csets[0]), source=source)
1672
1679
1673 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1680 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1674
1681
1675 def changegroup(self, basenodes, source):
1682 def changegroup(self, basenodes, source):
1676 # to avoid a race we use changegroupsubset() (issue1320)
1683 # to avoid a race we use changegroupsubset() (issue1320)
1677 return self.changegroupsubset(basenodes, self.heads(), source)
1684 return self.changegroupsubset(basenodes, self.heads(), source)
1678
1685
1679 def _changegroup(self, nodes, source):
1686 def _changegroup(self, nodes, source):
1680 """Compute the changegroup of all nodes that we have that a recipient
1687 """Compute the changegroup of all nodes that we have that a recipient
1681 doesn't. Return a chunkbuffer object whose read() method will return
1688 doesn't. Return a chunkbuffer object whose read() method will return
1682 successive changegroup chunks.
1689 successive changegroup chunks.
1683
1690
1684 This is much easier than the previous function as we can assume that
1691 This is much easier than the previous function as we can assume that
1685 the recipient has any changenode we aren't sending them.
1692 the recipient has any changenode we aren't sending them.
1686
1693
1687 nodes is the set of nodes to send"""
1694 nodes is the set of nodes to send"""
1688
1695
1689 cl = self.changelog
1696 cl = self.changelog
1690 mf = self.manifest
1697 mf = self.manifest
1691 mfs = {}
1698 mfs = {}
1692 changedfiles = set()
1699 changedfiles = set()
1693 fstate = ['']
1700 fstate = ['']
1694 count = [0]
1701 count = [0]
1695
1702
1696 self.hook('preoutgoing', throw=True, source=source)
1703 self.hook('preoutgoing', throw=True, source=source)
1697 self.changegroupinfo(nodes, source)
1704 self.changegroupinfo(nodes, source)
1698
1705
1699 revset = set([cl.rev(n) for n in nodes])
1706 revset = set([cl.rev(n) for n in nodes])
1700
1707
1701 def gennodelst(log):
1708 def gennodelst(log):
1702 return [log.node(r) for r in log if log.linkrev(r) in revset]
1709 return [log.node(r) for r in log if log.linkrev(r) in revset]
1703
1710
1704 def lookup(revlog, x):
1711 def lookup(revlog, x):
1705 if revlog == cl:
1712 if revlog == cl:
1706 c = cl.read(x)
1713 c = cl.read(x)
1707 changedfiles.update(c[3])
1714 changedfiles.update(c[3])
1708 mfs.setdefault(c[0], x)
1715 mfs.setdefault(c[0], x)
1709 count[0] += 1
1716 count[0] += 1
1710 self.ui.progress(_('bundling'), count[0],
1717 self.ui.progress(_('bundling'), count[0],
1711 unit=_('changesets'), total=len(nodes))
1718 unit=_('changesets'), total=len(nodes))
1712 return x
1719 return x
1713 elif revlog == mf:
1720 elif revlog == mf:
1714 count[0] += 1
1721 count[0] += 1
1715 self.ui.progress(_('bundling'), count[0],
1722 self.ui.progress(_('bundling'), count[0],
1716 unit=_('manifests'), total=len(mfs))
1723 unit=_('manifests'), total=len(mfs))
1717 return cl.node(revlog.linkrev(revlog.rev(x)))
1724 return cl.node(revlog.linkrev(revlog.rev(x)))
1718 else:
1725 else:
1719 self.ui.progress(
1726 self.ui.progress(
1720 _('bundling'), count[0], item=fstate[0],
1727 _('bundling'), count[0], item=fstate[0],
1721 total=len(changedfiles), unit=_('files'))
1728 total=len(changedfiles), unit=_('files'))
1722 return cl.node(revlog.linkrev(revlog.rev(x)))
1729 return cl.node(revlog.linkrev(revlog.rev(x)))
1723
1730
1724 bundler = changegroup.bundle10(lookup)
1731 bundler = changegroup.bundle10(lookup)
1725 reorder = self.ui.config('bundle', 'reorder', 'auto')
1732 reorder = self.ui.config('bundle', 'reorder', 'auto')
1726 if reorder == 'auto':
1733 if reorder == 'auto':
1727 reorder = None
1734 reorder = None
1728 else:
1735 else:
1729 reorder = util.parsebool(reorder)
1736 reorder = util.parsebool(reorder)
1730
1737
1731 def gengroup():
1738 def gengroup():
1732 '''yield a sequence of changegroup chunks (strings)'''
1739 '''yield a sequence of changegroup chunks (strings)'''
1733 # construct a list of all changed files
1740 # construct a list of all changed files
1734
1741
1735 for chunk in cl.group(nodes, bundler, reorder=reorder):
1742 for chunk in cl.group(nodes, bundler, reorder=reorder):
1736 yield chunk
1743 yield chunk
1737 self.ui.progress(_('bundling'), None)
1744 self.ui.progress(_('bundling'), None)
1738
1745
1739 count[0] = 0
1746 count[0] = 0
1740 for chunk in mf.group(gennodelst(mf), bundler, reorder=reorder):
1747 for chunk in mf.group(gennodelst(mf), bundler, reorder=reorder):
1741 yield chunk
1748 yield chunk
1742 self.ui.progress(_('bundling'), None)
1749 self.ui.progress(_('bundling'), None)
1743
1750
1744 count[0] = 0
1751 count[0] = 0
1745 for fname in sorted(changedfiles):
1752 for fname in sorted(changedfiles):
1746 filerevlog = self.file(fname)
1753 filerevlog = self.file(fname)
1747 if not len(filerevlog):
1754 if not len(filerevlog):
1748 raise util.Abort(_("empty or missing revlog for %s") % fname)
1755 raise util.Abort(_("empty or missing revlog for %s") % fname)
1749 fstate[0] = fname
1756 fstate[0] = fname
1750 nodelist = gennodelst(filerevlog)
1757 nodelist = gennodelst(filerevlog)
1751 if nodelist:
1758 if nodelist:
1752 count[0] += 1
1759 count[0] += 1
1753 yield bundler.fileheader(fname)
1760 yield bundler.fileheader(fname)
1754 for chunk in filerevlog.group(nodelist, bundler, reorder):
1761 for chunk in filerevlog.group(nodelist, bundler, reorder):
1755 yield chunk
1762 yield chunk
1756 yield bundler.close()
1763 yield bundler.close()
1757 self.ui.progress(_('bundling'), None)
1764 self.ui.progress(_('bundling'), None)
1758
1765
1759 if nodes:
1766 if nodes:
1760 self.hook('outgoing', node=hex(nodes[0]), source=source)
1767 self.hook('outgoing', node=hex(nodes[0]), source=source)
1761
1768
1762 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1769 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1763
1770
1764 def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
1771 def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
1765 """Add the changegroup returned by source.read() to this repo.
1772 """Add the changegroup returned by source.read() to this repo.
1766 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1773 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1767 the URL of the repo where this changegroup is coming from.
1774 the URL of the repo where this changegroup is coming from.
1768 If lock is not None, the function takes ownership of the lock
1775 If lock is not None, the function takes ownership of the lock
1769 and releases it after the changegroup is added.
1776 and releases it after the changegroup is added.
1770
1777
1771 Return an integer summarizing the change to this repo:
1778 Return an integer summarizing the change to this repo:
1772 - nothing changed or no source: 0
1779 - nothing changed or no source: 0
1773 - more heads than before: 1+added heads (2..n)
1780 - more heads than before: 1+added heads (2..n)
1774 - fewer heads than before: -1-removed heads (-2..-n)
1781 - fewer heads than before: -1-removed heads (-2..-n)
1775 - number of heads stays the same: 1
1782 - number of heads stays the same: 1
1776 """
1783 """
1777 def csmap(x):
1784 def csmap(x):
1778 self.ui.debug("add changeset %s\n" % short(x))
1785 self.ui.debug("add changeset %s\n" % short(x))
1779 return len(cl)
1786 return len(cl)
1780
1787
1781 def revmap(x):
1788 def revmap(x):
1782 return cl.rev(x)
1789 return cl.rev(x)
1783
1790
1784 if not source:
1791 if not source:
1785 return 0
1792 return 0
1786
1793
1787 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1794 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1788
1795
1789 changesets = files = revisions = 0
1796 changesets = files = revisions = 0
1790 efiles = set()
1797 efiles = set()
1791
1798
1792 # write changelog data to temp files so concurrent readers will not see
1799 # write changelog data to temp files so concurrent readers will not see
1793 # inconsistent view
1800 # inconsistent view
1794 cl = self.changelog
1801 cl = self.changelog
1795 cl.delayupdate()
1802 cl.delayupdate()
1796 oldheads = cl.heads()
1803 oldheads = cl.heads()
1797
1804
1798 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
1805 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
1799 try:
1806 try:
1800 trp = weakref.proxy(tr)
1807 trp = weakref.proxy(tr)
1801 # pull off the changeset group
1808 # pull off the changeset group
1802 self.ui.status(_("adding changesets\n"))
1809 self.ui.status(_("adding changesets\n"))
1803 clstart = len(cl)
1810 clstart = len(cl)
1804 class prog(object):
1811 class prog(object):
1805 step = _('changesets')
1812 step = _('changesets')
1806 count = 1
1813 count = 1
1807 ui = self.ui
1814 ui = self.ui
1808 total = None
1815 total = None
1809 def __call__(self):
1816 def __call__(self):
1810 self.ui.progress(self.step, self.count, unit=_('chunks'),
1817 self.ui.progress(self.step, self.count, unit=_('chunks'),
1811 total=self.total)
1818 total=self.total)
1812 self.count += 1
1819 self.count += 1
1813 pr = prog()
1820 pr = prog()
1814 source.callback = pr
1821 source.callback = pr
1815
1822
1816 source.changelogheader()
1823 source.changelogheader()
1817 if (cl.addgroup(source, csmap, trp) is None
1824 if (cl.addgroup(source, csmap, trp) is None
1818 and not emptyok):
1825 and not emptyok):
1819 raise util.Abort(_("received changelog group is empty"))
1826 raise util.Abort(_("received changelog group is empty"))
1820 clend = len(cl)
1827 clend = len(cl)
1821 changesets = clend - clstart
1828 changesets = clend - clstart
1822 for c in xrange(clstart, clend):
1829 for c in xrange(clstart, clend):
1823 efiles.update(self[c].files())
1830 efiles.update(self[c].files())
1824 efiles = len(efiles)
1831 efiles = len(efiles)
1825 self.ui.progress(_('changesets'), None)
1832 self.ui.progress(_('changesets'), None)
1826
1833
1827 # pull off the manifest group
1834 # pull off the manifest group
1828 self.ui.status(_("adding manifests\n"))
1835 self.ui.status(_("adding manifests\n"))
1829 pr.step = _('manifests')
1836 pr.step = _('manifests')
1830 pr.count = 1
1837 pr.count = 1
1831 pr.total = changesets # manifests <= changesets
1838 pr.total = changesets # manifests <= changesets
1832 # no need to check for empty manifest group here:
1839 # no need to check for empty manifest group here:
1833 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1840 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1834 # no new manifest will be created and the manifest group will
1841 # no new manifest will be created and the manifest group will
1835 # be empty during the pull
1842 # be empty during the pull
1836 source.manifestheader()
1843 source.manifestheader()
1837 self.manifest.addgroup(source, revmap, trp)
1844 self.manifest.addgroup(source, revmap, trp)
1838 self.ui.progress(_('manifests'), None)
1845 self.ui.progress(_('manifests'), None)
1839
1846
1840 needfiles = {}
1847 needfiles = {}
1841 if self.ui.configbool('server', 'validate', default=False):
1848 if self.ui.configbool('server', 'validate', default=False):
1842 # validate incoming csets have their manifests
1849 # validate incoming csets have their manifests
1843 for cset in xrange(clstart, clend):
1850 for cset in xrange(clstart, clend):
1844 mfest = self.changelog.read(self.changelog.node(cset))[0]
1851 mfest = self.changelog.read(self.changelog.node(cset))[0]
1845 mfest = self.manifest.readdelta(mfest)
1852 mfest = self.manifest.readdelta(mfest)
1846 # store file nodes we must see
1853 # store file nodes we must see
1847 for f, n in mfest.iteritems():
1854 for f, n in mfest.iteritems():
1848 needfiles.setdefault(f, set()).add(n)
1855 needfiles.setdefault(f, set()).add(n)
1849
1856
1850 # process the files
1857 # process the files
1851 self.ui.status(_("adding file changes\n"))
1858 self.ui.status(_("adding file changes\n"))
1852 pr.step = _('files')
1859 pr.step = _('files')
1853 pr.count = 1
1860 pr.count = 1
1854 pr.total = efiles
1861 pr.total = efiles
1855 source.callback = None
1862 source.callback = None
1856
1863
1857 while True:
1864 while True:
1858 chunkdata = source.filelogheader()
1865 chunkdata = source.filelogheader()
1859 if not chunkdata:
1866 if not chunkdata:
1860 break
1867 break
1861 f = chunkdata["filename"]
1868 f = chunkdata["filename"]
1862 self.ui.debug("adding %s revisions\n" % f)
1869 self.ui.debug("adding %s revisions\n" % f)
1863 pr()
1870 pr()
1864 fl = self.file(f)
1871 fl = self.file(f)
1865 o = len(fl)
1872 o = len(fl)
1866 if fl.addgroup(source, revmap, trp) is None:
1873 if fl.addgroup(source, revmap, trp) is None:
1867 raise util.Abort(_("received file revlog group is empty"))
1874 raise util.Abort(_("received file revlog group is empty"))
1868 revisions += len(fl) - o
1875 revisions += len(fl) - o
1869 files += 1
1876 files += 1
1870 if f in needfiles:
1877 if f in needfiles:
1871 needs = needfiles[f]
1878 needs = needfiles[f]
1872 for new in xrange(o, len(fl)):
1879 for new in xrange(o, len(fl)):
1873 n = fl.node(new)
1880 n = fl.node(new)
1874 if n in needs:
1881 if n in needs:
1875 needs.remove(n)
1882 needs.remove(n)
1876 if not needs:
1883 if not needs:
1877 del needfiles[f]
1884 del needfiles[f]
1878 self.ui.progress(_('files'), None)
1885 self.ui.progress(_('files'), None)
1879
1886
1880 for f, needs in needfiles.iteritems():
1887 for f, needs in needfiles.iteritems():
1881 fl = self.file(f)
1888 fl = self.file(f)
1882 for n in needs:
1889 for n in needs:
1883 try:
1890 try:
1884 fl.rev(n)
1891 fl.rev(n)
1885 except error.LookupError:
1892 except error.LookupError:
1886 raise util.Abort(
1893 raise util.Abort(
1887 _('missing file data for %s:%s - run hg verify') %
1894 _('missing file data for %s:%s - run hg verify') %
1888 (f, hex(n)))
1895 (f, hex(n)))
1889
1896
1890 dh = 0
1897 dh = 0
1891 if oldheads:
1898 if oldheads:
1892 heads = cl.heads()
1899 heads = cl.heads()
1893 dh = len(heads) - len(oldheads)
1900 dh = len(heads) - len(oldheads)
1894 for h in heads:
1901 for h in heads:
1895 if h not in oldheads and 'close' in self[h].extra():
1902 if h not in oldheads and 'close' in self[h].extra():
1896 dh -= 1
1903 dh -= 1
1897 htext = ""
1904 htext = ""
1898 if dh:
1905 if dh:
1899 htext = _(" (%+d heads)") % dh
1906 htext = _(" (%+d heads)") % dh
1900
1907
1901 self.ui.status(_("added %d changesets"
1908 self.ui.status(_("added %d changesets"
1902 " with %d changes to %d files%s\n")
1909 " with %d changes to %d files%s\n")
1903 % (changesets, revisions, files, htext))
1910 % (changesets, revisions, files, htext))
1904
1911
1905 if changesets > 0:
1912 if changesets > 0:
1906 p = lambda: cl.writepending() and self.root or ""
1913 p = lambda: cl.writepending() and self.root or ""
1907 self.hook('pretxnchangegroup', throw=True,
1914 self.hook('pretxnchangegroup', throw=True,
1908 node=hex(cl.node(clstart)), source=srctype,
1915 node=hex(cl.node(clstart)), source=srctype,
1909 url=url, pending=p)
1916 url=url, pending=p)
1910
1917
1911 # make changelog see real files again
1918 # make changelog see real files again
1912 cl.finalize(trp)
1919 cl.finalize(trp)
1913
1920
1914 tr.close()
1921 tr.close()
1915 finally:
1922 finally:
1916 tr.release()
1923 tr.release()
1917 if lock:
1924 if lock:
1918 lock.release()
1925 lock.release()
1919
1926
1920 if changesets > 0:
1927 if changesets > 0:
1921 # forcefully update the on-disk branch cache
1928 # forcefully update the on-disk branch cache
1922 self.ui.debug("updating the branch cache\n")
1929 self.ui.debug("updating the branch cache\n")
1923 self.updatebranchcache()
1930 self.updatebranchcache()
1924 self.hook("changegroup", node=hex(cl.node(clstart)),
1931 self.hook("changegroup", node=hex(cl.node(clstart)),
1925 source=srctype, url=url)
1932 source=srctype, url=url)
1926
1933
1927 for i in xrange(clstart, clend):
1934 for i in xrange(clstart, clend):
1928 self.hook("incoming", node=hex(cl.node(i)),
1935 self.hook("incoming", node=hex(cl.node(i)),
1929 source=srctype, url=url)
1936 source=srctype, url=url)
1930
1937
1931 # never return 0 here:
1938 # never return 0 here:
1932 if dh < 0:
1939 if dh < 0:
1933 return dh - 1
1940 return dh - 1
1934 else:
1941 else:
1935 return dh + 1
1942 return dh + 1
1936
1943
1937 def stream_in(self, remote, requirements):
1944 def stream_in(self, remote, requirements):
1938 lock = self.lock()
1945 lock = self.lock()
1939 try:
1946 try:
1940 fp = remote.stream_out()
1947 fp = remote.stream_out()
1941 l = fp.readline()
1948 l = fp.readline()
1942 try:
1949 try:
1943 resp = int(l)
1950 resp = int(l)
1944 except ValueError:
1951 except ValueError:
1945 raise error.ResponseError(
1952 raise error.ResponseError(
1946 _('Unexpected response from remote server:'), l)
1953 _('Unexpected response from remote server:'), l)
1947 if resp == 1:
1954 if resp == 1:
1948 raise util.Abort(_('operation forbidden by server'))
1955 raise util.Abort(_('operation forbidden by server'))
1949 elif resp == 2:
1956 elif resp == 2:
1950 raise util.Abort(_('locking the remote repository failed'))
1957 raise util.Abort(_('locking the remote repository failed'))
1951 elif resp != 0:
1958 elif resp != 0:
1952 raise util.Abort(_('the server sent an unknown error code'))
1959 raise util.Abort(_('the server sent an unknown error code'))
1953 self.ui.status(_('streaming all changes\n'))
1960 self.ui.status(_('streaming all changes\n'))
1954 l = fp.readline()
1961 l = fp.readline()
1955 try:
1962 try:
1956 total_files, total_bytes = map(int, l.split(' ', 1))
1963 total_files, total_bytes = map(int, l.split(' ', 1))
1957 except (ValueError, TypeError):
1964 except (ValueError, TypeError):
1958 raise error.ResponseError(
1965 raise error.ResponseError(
1959 _('Unexpected response from remote server:'), l)
1966 _('Unexpected response from remote server:'), l)
1960 self.ui.status(_('%d files to transfer, %s of data\n') %
1967 self.ui.status(_('%d files to transfer, %s of data\n') %
1961 (total_files, util.bytecount(total_bytes)))
1968 (total_files, util.bytecount(total_bytes)))
1962 start = time.time()
1969 start = time.time()
1963 for i in xrange(total_files):
1970 for i in xrange(total_files):
1964 # XXX doesn't support '\n' or '\r' in filenames
1971 # XXX doesn't support '\n' or '\r' in filenames
1965 l = fp.readline()
1972 l = fp.readline()
1966 try:
1973 try:
1967 name, size = l.split('\0', 1)
1974 name, size = l.split('\0', 1)
1968 size = int(size)
1975 size = int(size)
1969 except (ValueError, TypeError):
1976 except (ValueError, TypeError):
1970 raise error.ResponseError(
1977 raise error.ResponseError(
1971 _('Unexpected response from remote server:'), l)
1978 _('Unexpected response from remote server:'), l)
1972 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1979 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1973 # for backwards compat, name was partially encoded
1980 # for backwards compat, name was partially encoded
1974 ofp = self.sopener(store.decodedir(name), 'w')
1981 ofp = self.sopener(store.decodedir(name), 'w')
1975 for chunk in util.filechunkiter(fp, limit=size):
1982 for chunk in util.filechunkiter(fp, limit=size):
1976 ofp.write(chunk)
1983 ofp.write(chunk)
1977 ofp.close()
1984 ofp.close()
1978 elapsed = time.time() - start
1985 elapsed = time.time() - start
1979 if elapsed <= 0:
1986 if elapsed <= 0:
1980 elapsed = 0.001
1987 elapsed = 0.001
1981 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1988 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1982 (util.bytecount(total_bytes), elapsed,
1989 (util.bytecount(total_bytes), elapsed,
1983 util.bytecount(total_bytes / elapsed)))
1990 util.bytecount(total_bytes / elapsed)))
1984
1991
1985 # new requirements = old non-format requirements + new format-related
1992 # new requirements = old non-format requirements + new format-related
1986 # requirements from the streamed-in repository
1993 # requirements from the streamed-in repository
1987 requirements.update(set(self.requirements) - self.supportedformats)
1994 requirements.update(set(self.requirements) - self.supportedformats)
1988 self._applyrequirements(requirements)
1995 self._applyrequirements(requirements)
1989 self._writerequirements()
1996 self._writerequirements()
1990
1997
1991 self.invalidate()
1998 self.invalidate()
1992 return len(self.heads()) + 1
1999 return len(self.heads()) + 1
1993 finally:
2000 finally:
1994 lock.release()
2001 lock.release()
1995
2002
1996 def clone(self, remote, heads=[], stream=False):
2003 def clone(self, remote, heads=[], stream=False):
1997 '''clone remote repository.
2004 '''clone remote repository.
1998
2005
1999 keyword arguments:
2006 keyword arguments:
2000 heads: list of revs to clone (forces use of pull)
2007 heads: list of revs to clone (forces use of pull)
2001 stream: use streaming clone if possible'''
2008 stream: use streaming clone if possible'''
2002
2009
2003 # now, all clients that can request uncompressed clones can
2010 # now, all clients that can request uncompressed clones can
2004 # read repo formats supported by all servers that can serve
2011 # read repo formats supported by all servers that can serve
2005 # them.
2012 # them.
2006
2013
2007 # if revlog format changes, client will have to check version
2014 # if revlog format changes, client will have to check version
2008 # and format flags on "stream" capability, and use
2015 # and format flags on "stream" capability, and use
2009 # uncompressed only if compatible.
2016 # uncompressed only if compatible.
2010
2017
2011 if stream and not heads:
2018 if stream and not heads:
2012 # 'stream' means remote revlog format is revlogv1 only
2019 # 'stream' means remote revlog format is revlogv1 only
2013 if remote.capable('stream'):
2020 if remote.capable('stream'):
2014 return self.stream_in(remote, set(('revlogv1',)))
2021 return self.stream_in(remote, set(('revlogv1',)))
2015 # otherwise, 'streamreqs' contains the remote revlog format
2022 # otherwise, 'streamreqs' contains the remote revlog format
2016 streamreqs = remote.capable('streamreqs')
2023 streamreqs = remote.capable('streamreqs')
2017 if streamreqs:
2024 if streamreqs:
2018 streamreqs = set(streamreqs.split(','))
2025 streamreqs = set(streamreqs.split(','))
2019 # if we support it, stream in and adjust our requirements
2026 # if we support it, stream in and adjust our requirements
2020 if not streamreqs - self.supportedformats:
2027 if not streamreqs - self.supportedformats:
2021 return self.stream_in(remote, streamreqs)
2028 return self.stream_in(remote, streamreqs)
2022 return self.pull(remote, heads)
2029 return self.pull(remote, heads)
2023
2030
2024 def pushkey(self, namespace, key, old, new):
2031 def pushkey(self, namespace, key, old, new):
2025 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2032 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2026 old=old, new=new)
2033 old=old, new=new)
2027 ret = pushkey.push(self, namespace, key, old, new)
2034 ret = pushkey.push(self, namespace, key, old, new)
2028 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2035 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2029 ret=ret)
2036 ret=ret)
2030 return ret
2037 return ret
2031
2038
2032 def listkeys(self, namespace):
2039 def listkeys(self, namespace):
2033 self.hook('prelistkeys', throw=True, namespace=namespace)
2040 self.hook('prelistkeys', throw=True, namespace=namespace)
2034 values = pushkey.list(self, namespace)
2041 values = pushkey.list(self, namespace)
2035 self.hook('listkeys', namespace=namespace, values=values)
2042 self.hook('listkeys', namespace=namespace, values=values)
2036 return values
2043 return values
2037
2044
2038 def debugwireargs(self, one, two, three=None, four=None, five=None):
2045 def debugwireargs(self, one, two, three=None, four=None, five=None):
2039 '''used to test argument passing over the wire'''
2046 '''used to test argument passing over the wire'''
2040 return "%s %s %s %s %s" % (one, two, three, four, five)
2047 return "%s %s %s %s %s" % (one, two, three, four, five)
2041
2048
2042 def savecommitmessage(self, text):
2049 def savecommitmessage(self, text):
2043 fp = self.opener('last-message.txt', 'wb')
2050 fp = self.opener('last-message.txt', 'wb')
2044 try:
2051 try:
2045 fp.write(text)
2052 fp.write(text)
2046 finally:
2053 finally:
2047 fp.close()
2054 fp.close()
2048 return self.pathto(fp.name[len(self.root)+1:])
2055 return self.pathto(fp.name[len(self.root)+1:])
2049
2056
2050 # used to avoid circular references so destructors work
2057 # used to avoid circular references so destructors work
2051 def aftertrans(files):
2058 def aftertrans(files):
2052 renamefiles = [tuple(t) for t in files]
2059 renamefiles = [tuple(t) for t in files]
2053 def a():
2060 def a():
2054 for src, dest in renamefiles:
2061 for src, dest in renamefiles:
2055 util.rename(src, dest)
2062 util.rename(src, dest)
2056 return a
2063 return a
2057
2064
2058 def undoname(fn):
2065 def undoname(fn):
2059 base, name = os.path.split(fn)
2066 base, name = os.path.split(fn)
2060 assert name.startswith('journal')
2067 assert name.startswith('journal')
2061 return os.path.join(base, name.replace('journal', 'undo', 1))
2068 return os.path.join(base, name.replace('journal', 'undo', 1))
2062
2069
2063 def instance(ui, path, create):
2070 def instance(ui, path, create):
2064 return localrepository(ui, util.urllocalpath(path), create)
2071 return localrepository(ui, util.urllocalpath(path), create)
2065
2072
2066 def islocal(path):
2073 def islocal(path):
2067 return True
2074 return True
@@ -1,1920 +1,1910 b''
1 > do_push()
1 > do_push()
2 > {
2 > {
3 > user=$1
3 > user=$1
4 > shift
4 > shift
5 > echo "Pushing as user $user"
5 > echo "Pushing as user $user"
6 > echo 'hgrc = """'
6 > echo 'hgrc = """'
7 > sed -e 1,2d b/.hg/hgrc | grep -v fakegroups.py
7 > sed -e 1,2d b/.hg/hgrc | grep -v fakegroups.py
8 > echo '"""'
8 > echo '"""'
9 > if test -f acl.config; then
9 > if test -f acl.config; then
10 > echo 'acl.config = """'
10 > echo 'acl.config = """'
11 > cat acl.config
11 > cat acl.config
12 > echo '"""'
12 > echo '"""'
13 > fi
13 > fi
14 > # On AIX /etc/profile sets LOGNAME read-only. So
14 > # On AIX /etc/profile sets LOGNAME read-only. So
15 > # LOGNAME=$user hg --cws a --debug push ../b
15 > # LOGNAME=$user hg --cws a --debug push ../b
16 > # fails with "This variable is read only."
16 > # fails with "This variable is read only."
17 > # Use env to work around this.
17 > # Use env to work around this.
18 > env LOGNAME=$user hg --cwd a --debug push ../b
18 > env LOGNAME=$user hg --cwd a --debug push ../b
19 > hg --cwd b rollback
19 > hg --cwd b rollback
20 > hg --cwd b --quiet tip
20 > hg --cwd b --quiet tip
21 > echo
21 > echo
22 > }
22 > }
23
23
24 > init_config()
24 > init_config()
25 > {
25 > {
26 > cat > fakegroups.py <<EOF
26 > cat > fakegroups.py <<EOF
27 > from hgext import acl
27 > from hgext import acl
28 > def fakegetusers(ui, group):
28 > def fakegetusers(ui, group):
29 > try:
29 > try:
30 > return acl._getusersorig(ui, group)
30 > return acl._getusersorig(ui, group)
31 > except:
31 > except:
32 > return ["fred", "betty"]
32 > return ["fred", "betty"]
33 > acl._getusersorig = acl._getusers
33 > acl._getusersorig = acl._getusers
34 > acl._getusers = fakegetusers
34 > acl._getusers = fakegetusers
35 > EOF
35 > EOF
36 > rm -f acl.config
36 > rm -f acl.config
37 > cat > $config <<EOF
37 > cat > $config <<EOF
38 > [hooks]
38 > [hooks]
39 > pretxnchangegroup.acl = python:hgext.acl.hook
39 > pretxnchangegroup.acl = python:hgext.acl.hook
40 > [acl]
40 > [acl]
41 > sources = push
41 > sources = push
42 > [extensions]
42 > [extensions]
43 > f=`pwd`/fakegroups.py
43 > f=`pwd`/fakegroups.py
44 > EOF
44 > EOF
45 > }
45 > }
46
46
47 $ hg init a
47 $ hg init a
48 $ cd a
48 $ cd a
49 $ mkdir foo foo/Bar quux
49 $ mkdir foo foo/Bar quux
50 $ echo 'in foo' > foo/file.txt
50 $ echo 'in foo' > foo/file.txt
51 $ echo 'in foo/Bar' > foo/Bar/file.txt
51 $ echo 'in foo/Bar' > foo/Bar/file.txt
52 $ echo 'in quux' > quux/file.py
52 $ echo 'in quux' > quux/file.py
53 $ hg add -q
53 $ hg add -q
54 $ hg ci -m 'add files' -d '1000000 0'
54 $ hg ci -m 'add files' -d '1000000 0'
55 $ echo >> foo/file.txt
55 $ echo >> foo/file.txt
56 $ hg ci -m 'change foo/file' -d '1000001 0'
56 $ hg ci -m 'change foo/file' -d '1000001 0'
57 $ echo >> foo/Bar/file.txt
57 $ echo >> foo/Bar/file.txt
58 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
58 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
59 $ echo >> quux/file.py
59 $ echo >> quux/file.py
60 $ hg ci -m 'change quux/file' -d '1000003 0'
60 $ hg ci -m 'change quux/file' -d '1000003 0'
61 $ hg tip --quiet
61 $ hg tip --quiet
62 3:911600dab2ae
62 3:911600dab2ae
63
63
64 $ cd ..
64 $ cd ..
65 $ hg clone -r 0 a b
65 $ hg clone -r 0 a b
66 adding changesets
66 adding changesets
67 adding manifests
67 adding manifests
68 adding file changes
68 adding file changes
69 added 1 changesets with 3 changes to 3 files
69 added 1 changesets with 3 changes to 3 files
70 updating to branch default
70 updating to branch default
71 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
72
72
73 $ echo '[extensions]' >> $HGRCPATH
73 $ echo '[extensions]' >> $HGRCPATH
74 $ echo 'acl =' >> $HGRCPATH
74 $ echo 'acl =' >> $HGRCPATH
75
75
76 $ config=b/.hg/hgrc
76 $ config=b/.hg/hgrc
77
77
78 Extension disabled for lack of a hook
78 Extension disabled for lack of a hook
79
79
80 $ do_push fred
80 $ do_push fred
81 Pushing as user fred
81 Pushing as user fred
82 hgrc = """
82 hgrc = """
83 """
83 """
84 pushing to ../b
84 pushing to ../b
85 query 1; heads
85 query 1; heads
86 searching for changes
86 searching for changes
87 all remote heads known locally
87 all remote heads known locally
88 3 changesets found
88 3 changesets found
89 list of changesets:
89 list of changesets:
90 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
90 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
91 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
91 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
92 911600dab2ae7a9baff75958b84fe606851ce955
92 911600dab2ae7a9baff75958b84fe606851ce955
93 adding changesets
93 adding changesets
94 bundling: 1/3 changesets (33.33%)
94 bundling: 1/3 changesets (33.33%)
95 bundling: 2/3 changesets (66.67%)
95 bundling: 2/3 changesets (66.67%)
96 bundling: 3/3 changesets (100.00%)
96 bundling: 3/3 changesets (100.00%)
97 bundling: 1/3 manifests (33.33%)
97 bundling: 1/3 manifests (33.33%)
98 bundling: 2/3 manifests (66.67%)
98 bundling: 2/3 manifests (66.67%)
99 bundling: 3/3 manifests (100.00%)
99 bundling: 3/3 manifests (100.00%)
100 bundling: foo/Bar/file.txt 1/3 files (33.33%)
100 bundling: foo/Bar/file.txt 1/3 files (33.33%)
101 bundling: foo/file.txt 2/3 files (66.67%)
101 bundling: foo/file.txt 2/3 files (66.67%)
102 bundling: quux/file.py 3/3 files (100.00%)
102 bundling: quux/file.py 3/3 files (100.00%)
103 changesets: 1 chunks
103 changesets: 1 chunks
104 add changeset ef1ea85a6374
104 add changeset ef1ea85a6374
105 changesets: 2 chunks
105 changesets: 2 chunks
106 add changeset f9cafe1212c8
106 add changeset f9cafe1212c8
107 changesets: 3 chunks
107 changesets: 3 chunks
108 add changeset 911600dab2ae
108 add changeset 911600dab2ae
109 adding manifests
109 adding manifests
110 manifests: 1/3 chunks (33.33%)
110 manifests: 1/3 chunks (33.33%)
111 manifests: 2/3 chunks (66.67%)
111 manifests: 2/3 chunks (66.67%)
112 manifests: 3/3 chunks (100.00%)
112 manifests: 3/3 chunks (100.00%)
113 adding file changes
113 adding file changes
114 adding foo/Bar/file.txt revisions
114 adding foo/Bar/file.txt revisions
115 files: 1/3 chunks (33.33%)
115 files: 1/3 chunks (33.33%)
116 adding foo/file.txt revisions
116 adding foo/file.txt revisions
117 files: 2/3 chunks (66.67%)
117 files: 2/3 chunks (66.67%)
118 adding quux/file.py revisions
118 adding quux/file.py revisions
119 files: 3/3 chunks (100.00%)
119 files: 3/3 chunks (100.00%)
120 added 3 changesets with 3 changes to 3 files
120 added 3 changesets with 3 changes to 3 files
121 updating the branch cache
121 updating the branch cache
122 checking for updated bookmarks
122 checking for updated bookmarks
123 repository tip rolled back to revision 0 (undo push)
123 repository tip rolled back to revision 0 (undo push)
124 working directory now based on revision 0
125 0:6675d58eff77
124 0:6675d58eff77
126
125
127
126
128 $ echo '[hooks]' >> $config
127 $ echo '[hooks]' >> $config
129 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
128 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
130
129
131 Extension disabled for lack of acl.sources
130 Extension disabled for lack of acl.sources
132
131
133 $ do_push fred
132 $ do_push fred
134 Pushing as user fred
133 Pushing as user fred
135 hgrc = """
134 hgrc = """
136 [hooks]
135 [hooks]
137 pretxnchangegroup.acl = python:hgext.acl.hook
136 pretxnchangegroup.acl = python:hgext.acl.hook
138 """
137 """
139 pushing to ../b
138 pushing to ../b
140 query 1; heads
139 query 1; heads
141 searching for changes
140 searching for changes
142 all remote heads known locally
141 all remote heads known locally
143 invalidating branch cache (tip differs)
142 invalidating branch cache (tip differs)
144 3 changesets found
143 3 changesets found
145 list of changesets:
144 list of changesets:
146 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
145 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
147 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
146 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
148 911600dab2ae7a9baff75958b84fe606851ce955
147 911600dab2ae7a9baff75958b84fe606851ce955
149 adding changesets
148 adding changesets
150 bundling: 1/3 changesets (33.33%)
149 bundling: 1/3 changesets (33.33%)
151 bundling: 2/3 changesets (66.67%)
150 bundling: 2/3 changesets (66.67%)
152 bundling: 3/3 changesets (100.00%)
151 bundling: 3/3 changesets (100.00%)
153 bundling: 1/3 manifests (33.33%)
152 bundling: 1/3 manifests (33.33%)
154 bundling: 2/3 manifests (66.67%)
153 bundling: 2/3 manifests (66.67%)
155 bundling: 3/3 manifests (100.00%)
154 bundling: 3/3 manifests (100.00%)
156 bundling: foo/Bar/file.txt 1/3 files (33.33%)
155 bundling: foo/Bar/file.txt 1/3 files (33.33%)
157 bundling: foo/file.txt 2/3 files (66.67%)
156 bundling: foo/file.txt 2/3 files (66.67%)
158 bundling: quux/file.py 3/3 files (100.00%)
157 bundling: quux/file.py 3/3 files (100.00%)
159 changesets: 1 chunks
158 changesets: 1 chunks
160 add changeset ef1ea85a6374
159 add changeset ef1ea85a6374
161 changesets: 2 chunks
160 changesets: 2 chunks
162 add changeset f9cafe1212c8
161 add changeset f9cafe1212c8
163 changesets: 3 chunks
162 changesets: 3 chunks
164 add changeset 911600dab2ae
163 add changeset 911600dab2ae
165 adding manifests
164 adding manifests
166 manifests: 1/3 chunks (33.33%)
165 manifests: 1/3 chunks (33.33%)
167 manifests: 2/3 chunks (66.67%)
166 manifests: 2/3 chunks (66.67%)
168 manifests: 3/3 chunks (100.00%)
167 manifests: 3/3 chunks (100.00%)
169 adding file changes
168 adding file changes
170 adding foo/Bar/file.txt revisions
169 adding foo/Bar/file.txt revisions
171 files: 1/3 chunks (33.33%)
170 files: 1/3 chunks (33.33%)
172 adding foo/file.txt revisions
171 adding foo/file.txt revisions
173 files: 2/3 chunks (66.67%)
172 files: 2/3 chunks (66.67%)
174 adding quux/file.py revisions
173 adding quux/file.py revisions
175 files: 3/3 chunks (100.00%)
174 files: 3/3 chunks (100.00%)
176 added 3 changesets with 3 changes to 3 files
175 added 3 changesets with 3 changes to 3 files
177 calling hook pretxnchangegroup.acl: hgext.acl.hook
176 calling hook pretxnchangegroup.acl: hgext.acl.hook
178 acl: changes have source "push" - skipping
177 acl: changes have source "push" - skipping
179 updating the branch cache
178 updating the branch cache
180 checking for updated bookmarks
179 checking for updated bookmarks
181 repository tip rolled back to revision 0 (undo push)
180 repository tip rolled back to revision 0 (undo push)
182 working directory now based on revision 0
183 0:6675d58eff77
181 0:6675d58eff77
184
182
185
183
186 No [acl.allow]/[acl.deny]
184 No [acl.allow]/[acl.deny]
187
185
188 $ echo '[acl]' >> $config
186 $ echo '[acl]' >> $config
189 $ echo 'sources = push' >> $config
187 $ echo 'sources = push' >> $config
190 $ do_push fred
188 $ do_push fred
191 Pushing as user fred
189 Pushing as user fred
192 hgrc = """
190 hgrc = """
193 [hooks]
191 [hooks]
194 pretxnchangegroup.acl = python:hgext.acl.hook
192 pretxnchangegroup.acl = python:hgext.acl.hook
195 [acl]
193 [acl]
196 sources = push
194 sources = push
197 """
195 """
198 pushing to ../b
196 pushing to ../b
199 query 1; heads
197 query 1; heads
200 searching for changes
198 searching for changes
201 all remote heads known locally
199 all remote heads known locally
202 invalidating branch cache (tip differs)
200 invalidating branch cache (tip differs)
203 3 changesets found
201 3 changesets found
204 list of changesets:
202 list of changesets:
205 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
203 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
206 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
204 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
207 911600dab2ae7a9baff75958b84fe606851ce955
205 911600dab2ae7a9baff75958b84fe606851ce955
208 adding changesets
206 adding changesets
209 bundling: 1/3 changesets (33.33%)
207 bundling: 1/3 changesets (33.33%)
210 bundling: 2/3 changesets (66.67%)
208 bundling: 2/3 changesets (66.67%)
211 bundling: 3/3 changesets (100.00%)
209 bundling: 3/3 changesets (100.00%)
212 bundling: 1/3 manifests (33.33%)
210 bundling: 1/3 manifests (33.33%)
213 bundling: 2/3 manifests (66.67%)
211 bundling: 2/3 manifests (66.67%)
214 bundling: 3/3 manifests (100.00%)
212 bundling: 3/3 manifests (100.00%)
215 bundling: foo/Bar/file.txt 1/3 files (33.33%)
213 bundling: foo/Bar/file.txt 1/3 files (33.33%)
216 bundling: foo/file.txt 2/3 files (66.67%)
214 bundling: foo/file.txt 2/3 files (66.67%)
217 bundling: quux/file.py 3/3 files (100.00%)
215 bundling: quux/file.py 3/3 files (100.00%)
218 changesets: 1 chunks
216 changesets: 1 chunks
219 add changeset ef1ea85a6374
217 add changeset ef1ea85a6374
220 changesets: 2 chunks
218 changesets: 2 chunks
221 add changeset f9cafe1212c8
219 add changeset f9cafe1212c8
222 changesets: 3 chunks
220 changesets: 3 chunks
223 add changeset 911600dab2ae
221 add changeset 911600dab2ae
224 adding manifests
222 adding manifests
225 manifests: 1/3 chunks (33.33%)
223 manifests: 1/3 chunks (33.33%)
226 manifests: 2/3 chunks (66.67%)
224 manifests: 2/3 chunks (66.67%)
227 manifests: 3/3 chunks (100.00%)
225 manifests: 3/3 chunks (100.00%)
228 adding file changes
226 adding file changes
229 adding foo/Bar/file.txt revisions
227 adding foo/Bar/file.txt revisions
230 files: 1/3 chunks (33.33%)
228 files: 1/3 chunks (33.33%)
231 adding foo/file.txt revisions
229 adding foo/file.txt revisions
232 files: 2/3 chunks (66.67%)
230 files: 2/3 chunks (66.67%)
233 adding quux/file.py revisions
231 adding quux/file.py revisions
234 files: 3/3 chunks (100.00%)
232 files: 3/3 chunks (100.00%)
235 added 3 changesets with 3 changes to 3 files
233 added 3 changesets with 3 changes to 3 files
236 calling hook pretxnchangegroup.acl: hgext.acl.hook
234 calling hook pretxnchangegroup.acl: hgext.acl.hook
237 acl: acl.allow.branches not enabled
235 acl: acl.allow.branches not enabled
238 acl: acl.deny.branches not enabled
236 acl: acl.deny.branches not enabled
239 acl: acl.allow not enabled
237 acl: acl.allow not enabled
240 acl: acl.deny not enabled
238 acl: acl.deny not enabled
241 acl: branch access granted: "ef1ea85a6374" on branch "default"
239 acl: branch access granted: "ef1ea85a6374" on branch "default"
242 acl: allowing changeset ef1ea85a6374
240 acl: allowing changeset ef1ea85a6374
243 acl: branch access granted: "f9cafe1212c8" on branch "default"
241 acl: branch access granted: "f9cafe1212c8" on branch "default"
244 acl: allowing changeset f9cafe1212c8
242 acl: allowing changeset f9cafe1212c8
245 acl: branch access granted: "911600dab2ae" on branch "default"
243 acl: branch access granted: "911600dab2ae" on branch "default"
246 acl: allowing changeset 911600dab2ae
244 acl: allowing changeset 911600dab2ae
247 updating the branch cache
245 updating the branch cache
248 checking for updated bookmarks
246 checking for updated bookmarks
249 repository tip rolled back to revision 0 (undo push)
247 repository tip rolled back to revision 0 (undo push)
250 working directory now based on revision 0
251 0:6675d58eff77
248 0:6675d58eff77
252
249
253
250
254 Empty [acl.allow]
251 Empty [acl.allow]
255
252
256 $ echo '[acl.allow]' >> $config
253 $ echo '[acl.allow]' >> $config
257 $ do_push fred
254 $ do_push fred
258 Pushing as user fred
255 Pushing as user fred
259 hgrc = """
256 hgrc = """
260 [hooks]
257 [hooks]
261 pretxnchangegroup.acl = python:hgext.acl.hook
258 pretxnchangegroup.acl = python:hgext.acl.hook
262 [acl]
259 [acl]
263 sources = push
260 sources = push
264 [acl.allow]
261 [acl.allow]
265 """
262 """
266 pushing to ../b
263 pushing to ../b
267 query 1; heads
264 query 1; heads
268 searching for changes
265 searching for changes
269 all remote heads known locally
266 all remote heads known locally
270 invalidating branch cache (tip differs)
267 invalidating branch cache (tip differs)
271 3 changesets found
268 3 changesets found
272 list of changesets:
269 list of changesets:
273 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
270 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
274 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
271 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
275 911600dab2ae7a9baff75958b84fe606851ce955
272 911600dab2ae7a9baff75958b84fe606851ce955
276 adding changesets
273 adding changesets
277 bundling: 1/3 changesets (33.33%)
274 bundling: 1/3 changesets (33.33%)
278 bundling: 2/3 changesets (66.67%)
275 bundling: 2/3 changesets (66.67%)
279 bundling: 3/3 changesets (100.00%)
276 bundling: 3/3 changesets (100.00%)
280 bundling: 1/3 manifests (33.33%)
277 bundling: 1/3 manifests (33.33%)
281 bundling: 2/3 manifests (66.67%)
278 bundling: 2/3 manifests (66.67%)
282 bundling: 3/3 manifests (100.00%)
279 bundling: 3/3 manifests (100.00%)
283 bundling: foo/Bar/file.txt 1/3 files (33.33%)
280 bundling: foo/Bar/file.txt 1/3 files (33.33%)
284 bundling: foo/file.txt 2/3 files (66.67%)
281 bundling: foo/file.txt 2/3 files (66.67%)
285 bundling: quux/file.py 3/3 files (100.00%)
282 bundling: quux/file.py 3/3 files (100.00%)
286 changesets: 1 chunks
283 changesets: 1 chunks
287 add changeset ef1ea85a6374
284 add changeset ef1ea85a6374
288 changesets: 2 chunks
285 changesets: 2 chunks
289 add changeset f9cafe1212c8
286 add changeset f9cafe1212c8
290 changesets: 3 chunks
287 changesets: 3 chunks
291 add changeset 911600dab2ae
288 add changeset 911600dab2ae
292 adding manifests
289 adding manifests
293 manifests: 1/3 chunks (33.33%)
290 manifests: 1/3 chunks (33.33%)
294 manifests: 2/3 chunks (66.67%)
291 manifests: 2/3 chunks (66.67%)
295 manifests: 3/3 chunks (100.00%)
292 manifests: 3/3 chunks (100.00%)
296 adding file changes
293 adding file changes
297 adding foo/Bar/file.txt revisions
294 adding foo/Bar/file.txt revisions
298 files: 1/3 chunks (33.33%)
295 files: 1/3 chunks (33.33%)
299 adding foo/file.txt revisions
296 adding foo/file.txt revisions
300 files: 2/3 chunks (66.67%)
297 files: 2/3 chunks (66.67%)
301 adding quux/file.py revisions
298 adding quux/file.py revisions
302 files: 3/3 chunks (100.00%)
299 files: 3/3 chunks (100.00%)
303 added 3 changesets with 3 changes to 3 files
300 added 3 changesets with 3 changes to 3 files
304 calling hook pretxnchangegroup.acl: hgext.acl.hook
301 calling hook pretxnchangegroup.acl: hgext.acl.hook
305 acl: acl.allow.branches not enabled
302 acl: acl.allow.branches not enabled
306 acl: acl.deny.branches not enabled
303 acl: acl.deny.branches not enabled
307 acl: acl.allow enabled, 0 entries for user fred
304 acl: acl.allow enabled, 0 entries for user fred
308 acl: acl.deny not enabled
305 acl: acl.deny not enabled
309 acl: branch access granted: "ef1ea85a6374" on branch "default"
306 acl: branch access granted: "ef1ea85a6374" on branch "default"
310 acl: user fred not allowed on foo/file.txt
307 acl: user fred not allowed on foo/file.txt
311 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
308 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
312 transaction abort!
309 transaction abort!
313 rollback completed
310 rollback completed
314 abort: acl: access denied for changeset ef1ea85a6374
311 abort: acl: access denied for changeset ef1ea85a6374
315 no rollback information available
312 no rollback information available
316 0:6675d58eff77
313 0:6675d58eff77
317
314
318
315
319 fred is allowed inside foo/
316 fred is allowed inside foo/
320
317
321 $ echo 'foo/** = fred' >> $config
318 $ echo 'foo/** = fred' >> $config
322 $ do_push fred
319 $ do_push fred
323 Pushing as user fred
320 Pushing as user fred
324 hgrc = """
321 hgrc = """
325 [hooks]
322 [hooks]
326 pretxnchangegroup.acl = python:hgext.acl.hook
323 pretxnchangegroup.acl = python:hgext.acl.hook
327 [acl]
324 [acl]
328 sources = push
325 sources = push
329 [acl.allow]
326 [acl.allow]
330 foo/** = fred
327 foo/** = fred
331 """
328 """
332 pushing to ../b
329 pushing to ../b
333 query 1; heads
330 query 1; heads
334 searching for changes
331 searching for changes
335 all remote heads known locally
332 all remote heads known locally
336 3 changesets found
333 3 changesets found
337 list of changesets:
334 list of changesets:
338 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
335 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
339 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
336 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
340 911600dab2ae7a9baff75958b84fe606851ce955
337 911600dab2ae7a9baff75958b84fe606851ce955
341 adding changesets
338 adding changesets
342 bundling: 1/3 changesets (33.33%)
339 bundling: 1/3 changesets (33.33%)
343 bundling: 2/3 changesets (66.67%)
340 bundling: 2/3 changesets (66.67%)
344 bundling: 3/3 changesets (100.00%)
341 bundling: 3/3 changesets (100.00%)
345 bundling: 1/3 manifests (33.33%)
342 bundling: 1/3 manifests (33.33%)
346 bundling: 2/3 manifests (66.67%)
343 bundling: 2/3 manifests (66.67%)
347 bundling: 3/3 manifests (100.00%)
344 bundling: 3/3 manifests (100.00%)
348 bundling: foo/Bar/file.txt 1/3 files (33.33%)
345 bundling: foo/Bar/file.txt 1/3 files (33.33%)
349 bundling: foo/file.txt 2/3 files (66.67%)
346 bundling: foo/file.txt 2/3 files (66.67%)
350 bundling: quux/file.py 3/3 files (100.00%)
347 bundling: quux/file.py 3/3 files (100.00%)
351 changesets: 1 chunks
348 changesets: 1 chunks
352 add changeset ef1ea85a6374
349 add changeset ef1ea85a6374
353 changesets: 2 chunks
350 changesets: 2 chunks
354 add changeset f9cafe1212c8
351 add changeset f9cafe1212c8
355 changesets: 3 chunks
352 changesets: 3 chunks
356 add changeset 911600dab2ae
353 add changeset 911600dab2ae
357 adding manifests
354 adding manifests
358 manifests: 1/3 chunks (33.33%)
355 manifests: 1/3 chunks (33.33%)
359 manifests: 2/3 chunks (66.67%)
356 manifests: 2/3 chunks (66.67%)
360 manifests: 3/3 chunks (100.00%)
357 manifests: 3/3 chunks (100.00%)
361 adding file changes
358 adding file changes
362 adding foo/Bar/file.txt revisions
359 adding foo/Bar/file.txt revisions
363 files: 1/3 chunks (33.33%)
360 files: 1/3 chunks (33.33%)
364 adding foo/file.txt revisions
361 adding foo/file.txt revisions
365 files: 2/3 chunks (66.67%)
362 files: 2/3 chunks (66.67%)
366 adding quux/file.py revisions
363 adding quux/file.py revisions
367 files: 3/3 chunks (100.00%)
364 files: 3/3 chunks (100.00%)
368 added 3 changesets with 3 changes to 3 files
365 added 3 changesets with 3 changes to 3 files
369 calling hook pretxnchangegroup.acl: hgext.acl.hook
366 calling hook pretxnchangegroup.acl: hgext.acl.hook
370 acl: acl.allow.branches not enabled
367 acl: acl.allow.branches not enabled
371 acl: acl.deny.branches not enabled
368 acl: acl.deny.branches not enabled
372 acl: acl.allow enabled, 1 entries for user fred
369 acl: acl.allow enabled, 1 entries for user fred
373 acl: acl.deny not enabled
370 acl: acl.deny not enabled
374 acl: branch access granted: "ef1ea85a6374" on branch "default"
371 acl: branch access granted: "ef1ea85a6374" on branch "default"
375 acl: allowing changeset ef1ea85a6374
372 acl: allowing changeset ef1ea85a6374
376 acl: branch access granted: "f9cafe1212c8" on branch "default"
373 acl: branch access granted: "f9cafe1212c8" on branch "default"
377 acl: allowing changeset f9cafe1212c8
374 acl: allowing changeset f9cafe1212c8
378 acl: branch access granted: "911600dab2ae" on branch "default"
375 acl: branch access granted: "911600dab2ae" on branch "default"
379 acl: user fred not allowed on quux/file.py
376 acl: user fred not allowed on quux/file.py
380 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
377 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
381 transaction abort!
378 transaction abort!
382 rollback completed
379 rollback completed
383 abort: acl: access denied for changeset 911600dab2ae
380 abort: acl: access denied for changeset 911600dab2ae
384 no rollback information available
381 no rollback information available
385 0:6675d58eff77
382 0:6675d58eff77
386
383
387
384
388 Empty [acl.deny]
385 Empty [acl.deny]
389
386
390 $ echo '[acl.deny]' >> $config
387 $ echo '[acl.deny]' >> $config
391 $ do_push barney
388 $ do_push barney
392 Pushing as user barney
389 Pushing as user barney
393 hgrc = """
390 hgrc = """
394 [hooks]
391 [hooks]
395 pretxnchangegroup.acl = python:hgext.acl.hook
392 pretxnchangegroup.acl = python:hgext.acl.hook
396 [acl]
393 [acl]
397 sources = push
394 sources = push
398 [acl.allow]
395 [acl.allow]
399 foo/** = fred
396 foo/** = fred
400 [acl.deny]
397 [acl.deny]
401 """
398 """
402 pushing to ../b
399 pushing to ../b
403 query 1; heads
400 query 1; heads
404 searching for changes
401 searching for changes
405 all remote heads known locally
402 all remote heads known locally
406 3 changesets found
403 3 changesets found
407 list of changesets:
404 list of changesets:
408 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
405 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
409 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
406 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
410 911600dab2ae7a9baff75958b84fe606851ce955
407 911600dab2ae7a9baff75958b84fe606851ce955
411 adding changesets
408 adding changesets
412 bundling: 1/3 changesets (33.33%)
409 bundling: 1/3 changesets (33.33%)
413 bundling: 2/3 changesets (66.67%)
410 bundling: 2/3 changesets (66.67%)
414 bundling: 3/3 changesets (100.00%)
411 bundling: 3/3 changesets (100.00%)
415 bundling: 1/3 manifests (33.33%)
412 bundling: 1/3 manifests (33.33%)
416 bundling: 2/3 manifests (66.67%)
413 bundling: 2/3 manifests (66.67%)
417 bundling: 3/3 manifests (100.00%)
414 bundling: 3/3 manifests (100.00%)
418 bundling: foo/Bar/file.txt 1/3 files (33.33%)
415 bundling: foo/Bar/file.txt 1/3 files (33.33%)
419 bundling: foo/file.txt 2/3 files (66.67%)
416 bundling: foo/file.txt 2/3 files (66.67%)
420 bundling: quux/file.py 3/3 files (100.00%)
417 bundling: quux/file.py 3/3 files (100.00%)
421 changesets: 1 chunks
418 changesets: 1 chunks
422 add changeset ef1ea85a6374
419 add changeset ef1ea85a6374
423 changesets: 2 chunks
420 changesets: 2 chunks
424 add changeset f9cafe1212c8
421 add changeset f9cafe1212c8
425 changesets: 3 chunks
422 changesets: 3 chunks
426 add changeset 911600dab2ae
423 add changeset 911600dab2ae
427 adding manifests
424 adding manifests
428 manifests: 1/3 chunks (33.33%)
425 manifests: 1/3 chunks (33.33%)
429 manifests: 2/3 chunks (66.67%)
426 manifests: 2/3 chunks (66.67%)
430 manifests: 3/3 chunks (100.00%)
427 manifests: 3/3 chunks (100.00%)
431 adding file changes
428 adding file changes
432 adding foo/Bar/file.txt revisions
429 adding foo/Bar/file.txt revisions
433 files: 1/3 chunks (33.33%)
430 files: 1/3 chunks (33.33%)
434 adding foo/file.txt revisions
431 adding foo/file.txt revisions
435 files: 2/3 chunks (66.67%)
432 files: 2/3 chunks (66.67%)
436 adding quux/file.py revisions
433 adding quux/file.py revisions
437 files: 3/3 chunks (100.00%)
434 files: 3/3 chunks (100.00%)
438 added 3 changesets with 3 changes to 3 files
435 added 3 changesets with 3 changes to 3 files
439 calling hook pretxnchangegroup.acl: hgext.acl.hook
436 calling hook pretxnchangegroup.acl: hgext.acl.hook
440 acl: acl.allow.branches not enabled
437 acl: acl.allow.branches not enabled
441 acl: acl.deny.branches not enabled
438 acl: acl.deny.branches not enabled
442 acl: acl.allow enabled, 0 entries for user barney
439 acl: acl.allow enabled, 0 entries for user barney
443 acl: acl.deny enabled, 0 entries for user barney
440 acl: acl.deny enabled, 0 entries for user barney
444 acl: branch access granted: "ef1ea85a6374" on branch "default"
441 acl: branch access granted: "ef1ea85a6374" on branch "default"
445 acl: user barney not allowed on foo/file.txt
442 acl: user barney not allowed on foo/file.txt
446 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
443 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
447 transaction abort!
444 transaction abort!
448 rollback completed
445 rollback completed
449 abort: acl: access denied for changeset ef1ea85a6374
446 abort: acl: access denied for changeset ef1ea85a6374
450 no rollback information available
447 no rollback information available
451 0:6675d58eff77
448 0:6675d58eff77
452
449
453
450
454 fred is allowed inside foo/, but not foo/bar/ (case matters)
451 fred is allowed inside foo/, but not foo/bar/ (case matters)
455
452
456 $ echo 'foo/bar/** = fred' >> $config
453 $ echo 'foo/bar/** = fred' >> $config
457 $ do_push fred
454 $ do_push fred
458 Pushing as user fred
455 Pushing as user fred
459 hgrc = """
456 hgrc = """
460 [hooks]
457 [hooks]
461 pretxnchangegroup.acl = python:hgext.acl.hook
458 pretxnchangegroup.acl = python:hgext.acl.hook
462 [acl]
459 [acl]
463 sources = push
460 sources = push
464 [acl.allow]
461 [acl.allow]
465 foo/** = fred
462 foo/** = fred
466 [acl.deny]
463 [acl.deny]
467 foo/bar/** = fred
464 foo/bar/** = fred
468 """
465 """
469 pushing to ../b
466 pushing to ../b
470 query 1; heads
467 query 1; heads
471 searching for changes
468 searching for changes
472 all remote heads known locally
469 all remote heads known locally
473 3 changesets found
470 3 changesets found
474 list of changesets:
471 list of changesets:
475 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
472 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
476 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
473 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
477 911600dab2ae7a9baff75958b84fe606851ce955
474 911600dab2ae7a9baff75958b84fe606851ce955
478 adding changesets
475 adding changesets
479 bundling: 1/3 changesets (33.33%)
476 bundling: 1/3 changesets (33.33%)
480 bundling: 2/3 changesets (66.67%)
477 bundling: 2/3 changesets (66.67%)
481 bundling: 3/3 changesets (100.00%)
478 bundling: 3/3 changesets (100.00%)
482 bundling: 1/3 manifests (33.33%)
479 bundling: 1/3 manifests (33.33%)
483 bundling: 2/3 manifests (66.67%)
480 bundling: 2/3 manifests (66.67%)
484 bundling: 3/3 manifests (100.00%)
481 bundling: 3/3 manifests (100.00%)
485 bundling: foo/Bar/file.txt 1/3 files (33.33%)
482 bundling: foo/Bar/file.txt 1/3 files (33.33%)
486 bundling: foo/file.txt 2/3 files (66.67%)
483 bundling: foo/file.txt 2/3 files (66.67%)
487 bundling: quux/file.py 3/3 files (100.00%)
484 bundling: quux/file.py 3/3 files (100.00%)
488 changesets: 1 chunks
485 changesets: 1 chunks
489 add changeset ef1ea85a6374
486 add changeset ef1ea85a6374
490 changesets: 2 chunks
487 changesets: 2 chunks
491 add changeset f9cafe1212c8
488 add changeset f9cafe1212c8
492 changesets: 3 chunks
489 changesets: 3 chunks
493 add changeset 911600dab2ae
490 add changeset 911600dab2ae
494 adding manifests
491 adding manifests
495 manifests: 1/3 chunks (33.33%)
492 manifests: 1/3 chunks (33.33%)
496 manifests: 2/3 chunks (66.67%)
493 manifests: 2/3 chunks (66.67%)
497 manifests: 3/3 chunks (100.00%)
494 manifests: 3/3 chunks (100.00%)
498 adding file changes
495 adding file changes
499 adding foo/Bar/file.txt revisions
496 adding foo/Bar/file.txt revisions
500 files: 1/3 chunks (33.33%)
497 files: 1/3 chunks (33.33%)
501 adding foo/file.txt revisions
498 adding foo/file.txt revisions
502 files: 2/3 chunks (66.67%)
499 files: 2/3 chunks (66.67%)
503 adding quux/file.py revisions
500 adding quux/file.py revisions
504 files: 3/3 chunks (100.00%)
501 files: 3/3 chunks (100.00%)
505 added 3 changesets with 3 changes to 3 files
502 added 3 changesets with 3 changes to 3 files
506 calling hook pretxnchangegroup.acl: hgext.acl.hook
503 calling hook pretxnchangegroup.acl: hgext.acl.hook
507 acl: acl.allow.branches not enabled
504 acl: acl.allow.branches not enabled
508 acl: acl.deny.branches not enabled
505 acl: acl.deny.branches not enabled
509 acl: acl.allow enabled, 1 entries for user fred
506 acl: acl.allow enabled, 1 entries for user fred
510 acl: acl.deny enabled, 1 entries for user fred
507 acl: acl.deny enabled, 1 entries for user fred
511 acl: branch access granted: "ef1ea85a6374" on branch "default"
508 acl: branch access granted: "ef1ea85a6374" on branch "default"
512 acl: allowing changeset ef1ea85a6374
509 acl: allowing changeset ef1ea85a6374
513 acl: branch access granted: "f9cafe1212c8" on branch "default"
510 acl: branch access granted: "f9cafe1212c8" on branch "default"
514 acl: allowing changeset f9cafe1212c8
511 acl: allowing changeset f9cafe1212c8
515 acl: branch access granted: "911600dab2ae" on branch "default"
512 acl: branch access granted: "911600dab2ae" on branch "default"
516 acl: user fred not allowed on quux/file.py
513 acl: user fred not allowed on quux/file.py
517 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
514 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
518 transaction abort!
515 transaction abort!
519 rollback completed
516 rollback completed
520 abort: acl: access denied for changeset 911600dab2ae
517 abort: acl: access denied for changeset 911600dab2ae
521 no rollback information available
518 no rollback information available
522 0:6675d58eff77
519 0:6675d58eff77
523
520
524
521
525 fred is allowed inside foo/, but not foo/Bar/
522 fred is allowed inside foo/, but not foo/Bar/
526
523
527 $ echo 'foo/Bar/** = fred' >> $config
524 $ echo 'foo/Bar/** = fred' >> $config
528 $ do_push fred
525 $ do_push fred
529 Pushing as user fred
526 Pushing as user fred
530 hgrc = """
527 hgrc = """
531 [hooks]
528 [hooks]
532 pretxnchangegroup.acl = python:hgext.acl.hook
529 pretxnchangegroup.acl = python:hgext.acl.hook
533 [acl]
530 [acl]
534 sources = push
531 sources = push
535 [acl.allow]
532 [acl.allow]
536 foo/** = fred
533 foo/** = fred
537 [acl.deny]
534 [acl.deny]
538 foo/bar/** = fred
535 foo/bar/** = fred
539 foo/Bar/** = fred
536 foo/Bar/** = fred
540 """
537 """
541 pushing to ../b
538 pushing to ../b
542 query 1; heads
539 query 1; heads
543 searching for changes
540 searching for changes
544 all remote heads known locally
541 all remote heads known locally
545 3 changesets found
542 3 changesets found
546 list of changesets:
543 list of changesets:
547 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
544 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
548 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
545 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
549 911600dab2ae7a9baff75958b84fe606851ce955
546 911600dab2ae7a9baff75958b84fe606851ce955
550 adding changesets
547 adding changesets
551 bundling: 1/3 changesets (33.33%)
548 bundling: 1/3 changesets (33.33%)
552 bundling: 2/3 changesets (66.67%)
549 bundling: 2/3 changesets (66.67%)
553 bundling: 3/3 changesets (100.00%)
550 bundling: 3/3 changesets (100.00%)
554 bundling: 1/3 manifests (33.33%)
551 bundling: 1/3 manifests (33.33%)
555 bundling: 2/3 manifests (66.67%)
552 bundling: 2/3 manifests (66.67%)
556 bundling: 3/3 manifests (100.00%)
553 bundling: 3/3 manifests (100.00%)
557 bundling: foo/Bar/file.txt 1/3 files (33.33%)
554 bundling: foo/Bar/file.txt 1/3 files (33.33%)
558 bundling: foo/file.txt 2/3 files (66.67%)
555 bundling: foo/file.txt 2/3 files (66.67%)
559 bundling: quux/file.py 3/3 files (100.00%)
556 bundling: quux/file.py 3/3 files (100.00%)
560 changesets: 1 chunks
557 changesets: 1 chunks
561 add changeset ef1ea85a6374
558 add changeset ef1ea85a6374
562 changesets: 2 chunks
559 changesets: 2 chunks
563 add changeset f9cafe1212c8
560 add changeset f9cafe1212c8
564 changesets: 3 chunks
561 changesets: 3 chunks
565 add changeset 911600dab2ae
562 add changeset 911600dab2ae
566 adding manifests
563 adding manifests
567 manifests: 1/3 chunks (33.33%)
564 manifests: 1/3 chunks (33.33%)
568 manifests: 2/3 chunks (66.67%)
565 manifests: 2/3 chunks (66.67%)
569 manifests: 3/3 chunks (100.00%)
566 manifests: 3/3 chunks (100.00%)
570 adding file changes
567 adding file changes
571 adding foo/Bar/file.txt revisions
568 adding foo/Bar/file.txt revisions
572 files: 1/3 chunks (33.33%)
569 files: 1/3 chunks (33.33%)
573 adding foo/file.txt revisions
570 adding foo/file.txt revisions
574 files: 2/3 chunks (66.67%)
571 files: 2/3 chunks (66.67%)
575 adding quux/file.py revisions
572 adding quux/file.py revisions
576 files: 3/3 chunks (100.00%)
573 files: 3/3 chunks (100.00%)
577 added 3 changesets with 3 changes to 3 files
574 added 3 changesets with 3 changes to 3 files
578 calling hook pretxnchangegroup.acl: hgext.acl.hook
575 calling hook pretxnchangegroup.acl: hgext.acl.hook
579 acl: acl.allow.branches not enabled
576 acl: acl.allow.branches not enabled
580 acl: acl.deny.branches not enabled
577 acl: acl.deny.branches not enabled
581 acl: acl.allow enabled, 1 entries for user fred
578 acl: acl.allow enabled, 1 entries for user fred
582 acl: acl.deny enabled, 2 entries for user fred
579 acl: acl.deny enabled, 2 entries for user fred
583 acl: branch access granted: "ef1ea85a6374" on branch "default"
580 acl: branch access granted: "ef1ea85a6374" on branch "default"
584 acl: allowing changeset ef1ea85a6374
581 acl: allowing changeset ef1ea85a6374
585 acl: branch access granted: "f9cafe1212c8" on branch "default"
582 acl: branch access granted: "f9cafe1212c8" on branch "default"
586 acl: user fred denied on foo/Bar/file.txt
583 acl: user fred denied on foo/Bar/file.txt
587 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
584 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
588 transaction abort!
585 transaction abort!
589 rollback completed
586 rollback completed
590 abort: acl: access denied for changeset f9cafe1212c8
587 abort: acl: access denied for changeset f9cafe1212c8
591 no rollback information available
588 no rollback information available
592 0:6675d58eff77
589 0:6675d58eff77
593
590
594
591
595 $ echo 'barney is not mentioned => not allowed anywhere'
592 $ echo 'barney is not mentioned => not allowed anywhere'
596 barney is not mentioned => not allowed anywhere
593 barney is not mentioned => not allowed anywhere
597 $ do_push barney
594 $ do_push barney
598 Pushing as user barney
595 Pushing as user barney
599 hgrc = """
596 hgrc = """
600 [hooks]
597 [hooks]
601 pretxnchangegroup.acl = python:hgext.acl.hook
598 pretxnchangegroup.acl = python:hgext.acl.hook
602 [acl]
599 [acl]
603 sources = push
600 sources = push
604 [acl.allow]
601 [acl.allow]
605 foo/** = fred
602 foo/** = fred
606 [acl.deny]
603 [acl.deny]
607 foo/bar/** = fred
604 foo/bar/** = fred
608 foo/Bar/** = fred
605 foo/Bar/** = fred
609 """
606 """
610 pushing to ../b
607 pushing to ../b
611 query 1; heads
608 query 1; heads
612 searching for changes
609 searching for changes
613 all remote heads known locally
610 all remote heads known locally
614 3 changesets found
611 3 changesets found
615 list of changesets:
612 list of changesets:
616 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
613 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
617 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
614 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
618 911600dab2ae7a9baff75958b84fe606851ce955
615 911600dab2ae7a9baff75958b84fe606851ce955
619 adding changesets
616 adding changesets
620 bundling: 1/3 changesets (33.33%)
617 bundling: 1/3 changesets (33.33%)
621 bundling: 2/3 changesets (66.67%)
618 bundling: 2/3 changesets (66.67%)
622 bundling: 3/3 changesets (100.00%)
619 bundling: 3/3 changesets (100.00%)
623 bundling: 1/3 manifests (33.33%)
620 bundling: 1/3 manifests (33.33%)
624 bundling: 2/3 manifests (66.67%)
621 bundling: 2/3 manifests (66.67%)
625 bundling: 3/3 manifests (100.00%)
622 bundling: 3/3 manifests (100.00%)
626 bundling: foo/Bar/file.txt 1/3 files (33.33%)
623 bundling: foo/Bar/file.txt 1/3 files (33.33%)
627 bundling: foo/file.txt 2/3 files (66.67%)
624 bundling: foo/file.txt 2/3 files (66.67%)
628 bundling: quux/file.py 3/3 files (100.00%)
625 bundling: quux/file.py 3/3 files (100.00%)
629 changesets: 1 chunks
626 changesets: 1 chunks
630 add changeset ef1ea85a6374
627 add changeset ef1ea85a6374
631 changesets: 2 chunks
628 changesets: 2 chunks
632 add changeset f9cafe1212c8
629 add changeset f9cafe1212c8
633 changesets: 3 chunks
630 changesets: 3 chunks
634 add changeset 911600dab2ae
631 add changeset 911600dab2ae
635 adding manifests
632 adding manifests
636 manifests: 1/3 chunks (33.33%)
633 manifests: 1/3 chunks (33.33%)
637 manifests: 2/3 chunks (66.67%)
634 manifests: 2/3 chunks (66.67%)
638 manifests: 3/3 chunks (100.00%)
635 manifests: 3/3 chunks (100.00%)
639 adding file changes
636 adding file changes
640 adding foo/Bar/file.txt revisions
637 adding foo/Bar/file.txt revisions
641 files: 1/3 chunks (33.33%)
638 files: 1/3 chunks (33.33%)
642 adding foo/file.txt revisions
639 adding foo/file.txt revisions
643 files: 2/3 chunks (66.67%)
640 files: 2/3 chunks (66.67%)
644 adding quux/file.py revisions
641 adding quux/file.py revisions
645 files: 3/3 chunks (100.00%)
642 files: 3/3 chunks (100.00%)
646 added 3 changesets with 3 changes to 3 files
643 added 3 changesets with 3 changes to 3 files
647 calling hook pretxnchangegroup.acl: hgext.acl.hook
644 calling hook pretxnchangegroup.acl: hgext.acl.hook
648 acl: acl.allow.branches not enabled
645 acl: acl.allow.branches not enabled
649 acl: acl.deny.branches not enabled
646 acl: acl.deny.branches not enabled
650 acl: acl.allow enabled, 0 entries for user barney
647 acl: acl.allow enabled, 0 entries for user barney
651 acl: acl.deny enabled, 0 entries for user barney
648 acl: acl.deny enabled, 0 entries for user barney
652 acl: branch access granted: "ef1ea85a6374" on branch "default"
649 acl: branch access granted: "ef1ea85a6374" on branch "default"
653 acl: user barney not allowed on foo/file.txt
650 acl: user barney not allowed on foo/file.txt
654 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
651 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
655 transaction abort!
652 transaction abort!
656 rollback completed
653 rollback completed
657 abort: acl: access denied for changeset ef1ea85a6374
654 abort: acl: access denied for changeset ef1ea85a6374
658 no rollback information available
655 no rollback information available
659 0:6675d58eff77
656 0:6675d58eff77
660
657
661
658
662 barney is allowed everywhere
659 barney is allowed everywhere
663
660
664 $ echo '[acl.allow]' >> $config
661 $ echo '[acl.allow]' >> $config
665 $ echo '** = barney' >> $config
662 $ echo '** = barney' >> $config
666 $ do_push barney
663 $ do_push barney
667 Pushing as user barney
664 Pushing as user barney
668 hgrc = """
665 hgrc = """
669 [hooks]
666 [hooks]
670 pretxnchangegroup.acl = python:hgext.acl.hook
667 pretxnchangegroup.acl = python:hgext.acl.hook
671 [acl]
668 [acl]
672 sources = push
669 sources = push
673 [acl.allow]
670 [acl.allow]
674 foo/** = fred
671 foo/** = fred
675 [acl.deny]
672 [acl.deny]
676 foo/bar/** = fred
673 foo/bar/** = fred
677 foo/Bar/** = fred
674 foo/Bar/** = fred
678 [acl.allow]
675 [acl.allow]
679 ** = barney
676 ** = barney
680 """
677 """
681 pushing to ../b
678 pushing to ../b
682 query 1; heads
679 query 1; heads
683 searching for changes
680 searching for changes
684 all remote heads known locally
681 all remote heads known locally
685 3 changesets found
682 3 changesets found
686 list of changesets:
683 list of changesets:
687 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
684 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
688 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
685 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
689 911600dab2ae7a9baff75958b84fe606851ce955
686 911600dab2ae7a9baff75958b84fe606851ce955
690 adding changesets
687 adding changesets
691 bundling: 1/3 changesets (33.33%)
688 bundling: 1/3 changesets (33.33%)
692 bundling: 2/3 changesets (66.67%)
689 bundling: 2/3 changesets (66.67%)
693 bundling: 3/3 changesets (100.00%)
690 bundling: 3/3 changesets (100.00%)
694 bundling: 1/3 manifests (33.33%)
691 bundling: 1/3 manifests (33.33%)
695 bundling: 2/3 manifests (66.67%)
692 bundling: 2/3 manifests (66.67%)
696 bundling: 3/3 manifests (100.00%)
693 bundling: 3/3 manifests (100.00%)
697 bundling: foo/Bar/file.txt 1/3 files (33.33%)
694 bundling: foo/Bar/file.txt 1/3 files (33.33%)
698 bundling: foo/file.txt 2/3 files (66.67%)
695 bundling: foo/file.txt 2/3 files (66.67%)
699 bundling: quux/file.py 3/3 files (100.00%)
696 bundling: quux/file.py 3/3 files (100.00%)
700 changesets: 1 chunks
697 changesets: 1 chunks
701 add changeset ef1ea85a6374
698 add changeset ef1ea85a6374
702 changesets: 2 chunks
699 changesets: 2 chunks
703 add changeset f9cafe1212c8
700 add changeset f9cafe1212c8
704 changesets: 3 chunks
701 changesets: 3 chunks
705 add changeset 911600dab2ae
702 add changeset 911600dab2ae
706 adding manifests
703 adding manifests
707 manifests: 1/3 chunks (33.33%)
704 manifests: 1/3 chunks (33.33%)
708 manifests: 2/3 chunks (66.67%)
705 manifests: 2/3 chunks (66.67%)
709 manifests: 3/3 chunks (100.00%)
706 manifests: 3/3 chunks (100.00%)
710 adding file changes
707 adding file changes
711 adding foo/Bar/file.txt revisions
708 adding foo/Bar/file.txt revisions
712 files: 1/3 chunks (33.33%)
709 files: 1/3 chunks (33.33%)
713 adding foo/file.txt revisions
710 adding foo/file.txt revisions
714 files: 2/3 chunks (66.67%)
711 files: 2/3 chunks (66.67%)
715 adding quux/file.py revisions
712 adding quux/file.py revisions
716 files: 3/3 chunks (100.00%)
713 files: 3/3 chunks (100.00%)
717 added 3 changesets with 3 changes to 3 files
714 added 3 changesets with 3 changes to 3 files
718 calling hook pretxnchangegroup.acl: hgext.acl.hook
715 calling hook pretxnchangegroup.acl: hgext.acl.hook
719 acl: acl.allow.branches not enabled
716 acl: acl.allow.branches not enabled
720 acl: acl.deny.branches not enabled
717 acl: acl.deny.branches not enabled
721 acl: acl.allow enabled, 1 entries for user barney
718 acl: acl.allow enabled, 1 entries for user barney
722 acl: acl.deny enabled, 0 entries for user barney
719 acl: acl.deny enabled, 0 entries for user barney
723 acl: branch access granted: "ef1ea85a6374" on branch "default"
720 acl: branch access granted: "ef1ea85a6374" on branch "default"
724 acl: allowing changeset ef1ea85a6374
721 acl: allowing changeset ef1ea85a6374
725 acl: branch access granted: "f9cafe1212c8" on branch "default"
722 acl: branch access granted: "f9cafe1212c8" on branch "default"
726 acl: allowing changeset f9cafe1212c8
723 acl: allowing changeset f9cafe1212c8
727 acl: branch access granted: "911600dab2ae" on branch "default"
724 acl: branch access granted: "911600dab2ae" on branch "default"
728 acl: allowing changeset 911600dab2ae
725 acl: allowing changeset 911600dab2ae
729 updating the branch cache
726 updating the branch cache
730 checking for updated bookmarks
727 checking for updated bookmarks
731 repository tip rolled back to revision 0 (undo push)
728 repository tip rolled back to revision 0 (undo push)
732 working directory now based on revision 0
733 0:6675d58eff77
729 0:6675d58eff77
734
730
735
731
736 wilma can change files with a .txt extension
732 wilma can change files with a .txt extension
737
733
738 $ echo '**/*.txt = wilma' >> $config
734 $ echo '**/*.txt = wilma' >> $config
739 $ do_push wilma
735 $ do_push wilma
740 Pushing as user wilma
736 Pushing as user wilma
741 hgrc = """
737 hgrc = """
742 [hooks]
738 [hooks]
743 pretxnchangegroup.acl = python:hgext.acl.hook
739 pretxnchangegroup.acl = python:hgext.acl.hook
744 [acl]
740 [acl]
745 sources = push
741 sources = push
746 [acl.allow]
742 [acl.allow]
747 foo/** = fred
743 foo/** = fred
748 [acl.deny]
744 [acl.deny]
749 foo/bar/** = fred
745 foo/bar/** = fred
750 foo/Bar/** = fred
746 foo/Bar/** = fred
751 [acl.allow]
747 [acl.allow]
752 ** = barney
748 ** = barney
753 **/*.txt = wilma
749 **/*.txt = wilma
754 """
750 """
755 pushing to ../b
751 pushing to ../b
756 query 1; heads
752 query 1; heads
757 searching for changes
753 searching for changes
758 all remote heads known locally
754 all remote heads known locally
759 invalidating branch cache (tip differs)
755 invalidating branch cache (tip differs)
760 3 changesets found
756 3 changesets found
761 list of changesets:
757 list of changesets:
762 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
758 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
763 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
759 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
764 911600dab2ae7a9baff75958b84fe606851ce955
760 911600dab2ae7a9baff75958b84fe606851ce955
765 adding changesets
761 adding changesets
766 bundling: 1/3 changesets (33.33%)
762 bundling: 1/3 changesets (33.33%)
767 bundling: 2/3 changesets (66.67%)
763 bundling: 2/3 changesets (66.67%)
768 bundling: 3/3 changesets (100.00%)
764 bundling: 3/3 changesets (100.00%)
769 bundling: 1/3 manifests (33.33%)
765 bundling: 1/3 manifests (33.33%)
770 bundling: 2/3 manifests (66.67%)
766 bundling: 2/3 manifests (66.67%)
771 bundling: 3/3 manifests (100.00%)
767 bundling: 3/3 manifests (100.00%)
772 bundling: foo/Bar/file.txt 1/3 files (33.33%)
768 bundling: foo/Bar/file.txt 1/3 files (33.33%)
773 bundling: foo/file.txt 2/3 files (66.67%)
769 bundling: foo/file.txt 2/3 files (66.67%)
774 bundling: quux/file.py 3/3 files (100.00%)
770 bundling: quux/file.py 3/3 files (100.00%)
775 changesets: 1 chunks
771 changesets: 1 chunks
776 add changeset ef1ea85a6374
772 add changeset ef1ea85a6374
777 changesets: 2 chunks
773 changesets: 2 chunks
778 add changeset f9cafe1212c8
774 add changeset f9cafe1212c8
779 changesets: 3 chunks
775 changesets: 3 chunks
780 add changeset 911600dab2ae
776 add changeset 911600dab2ae
781 adding manifests
777 adding manifests
782 manifests: 1/3 chunks (33.33%)
778 manifests: 1/3 chunks (33.33%)
783 manifests: 2/3 chunks (66.67%)
779 manifests: 2/3 chunks (66.67%)
784 manifests: 3/3 chunks (100.00%)
780 manifests: 3/3 chunks (100.00%)
785 adding file changes
781 adding file changes
786 adding foo/Bar/file.txt revisions
782 adding foo/Bar/file.txt revisions
787 files: 1/3 chunks (33.33%)
783 files: 1/3 chunks (33.33%)
788 adding foo/file.txt revisions
784 adding foo/file.txt revisions
789 files: 2/3 chunks (66.67%)
785 files: 2/3 chunks (66.67%)
790 adding quux/file.py revisions
786 adding quux/file.py revisions
791 files: 3/3 chunks (100.00%)
787 files: 3/3 chunks (100.00%)
792 added 3 changesets with 3 changes to 3 files
788 added 3 changesets with 3 changes to 3 files
793 calling hook pretxnchangegroup.acl: hgext.acl.hook
789 calling hook pretxnchangegroup.acl: hgext.acl.hook
794 acl: acl.allow.branches not enabled
790 acl: acl.allow.branches not enabled
795 acl: acl.deny.branches not enabled
791 acl: acl.deny.branches not enabled
796 acl: acl.allow enabled, 1 entries for user wilma
792 acl: acl.allow enabled, 1 entries for user wilma
797 acl: acl.deny enabled, 0 entries for user wilma
793 acl: acl.deny enabled, 0 entries for user wilma
798 acl: branch access granted: "ef1ea85a6374" on branch "default"
794 acl: branch access granted: "ef1ea85a6374" on branch "default"
799 acl: allowing changeset ef1ea85a6374
795 acl: allowing changeset ef1ea85a6374
800 acl: branch access granted: "f9cafe1212c8" on branch "default"
796 acl: branch access granted: "f9cafe1212c8" on branch "default"
801 acl: allowing changeset f9cafe1212c8
797 acl: allowing changeset f9cafe1212c8
802 acl: branch access granted: "911600dab2ae" on branch "default"
798 acl: branch access granted: "911600dab2ae" on branch "default"
803 acl: user wilma not allowed on quux/file.py
799 acl: user wilma not allowed on quux/file.py
804 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
800 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
805 transaction abort!
801 transaction abort!
806 rollback completed
802 rollback completed
807 abort: acl: access denied for changeset 911600dab2ae
803 abort: acl: access denied for changeset 911600dab2ae
808 no rollback information available
804 no rollback information available
809 0:6675d58eff77
805 0:6675d58eff77
810
806
811
807
812 file specified by acl.config does not exist
808 file specified by acl.config does not exist
813
809
814 $ echo '[acl]' >> $config
810 $ echo '[acl]' >> $config
815 $ echo 'config = ../acl.config' >> $config
811 $ echo 'config = ../acl.config' >> $config
816 $ do_push barney
812 $ do_push barney
817 Pushing as user barney
813 Pushing as user barney
818 hgrc = """
814 hgrc = """
819 [hooks]
815 [hooks]
820 pretxnchangegroup.acl = python:hgext.acl.hook
816 pretxnchangegroup.acl = python:hgext.acl.hook
821 [acl]
817 [acl]
822 sources = push
818 sources = push
823 [acl.allow]
819 [acl.allow]
824 foo/** = fred
820 foo/** = fred
825 [acl.deny]
821 [acl.deny]
826 foo/bar/** = fred
822 foo/bar/** = fred
827 foo/Bar/** = fred
823 foo/Bar/** = fred
828 [acl.allow]
824 [acl.allow]
829 ** = barney
825 ** = barney
830 **/*.txt = wilma
826 **/*.txt = wilma
831 [acl]
827 [acl]
832 config = ../acl.config
828 config = ../acl.config
833 """
829 """
834 pushing to ../b
830 pushing to ../b
835 query 1; heads
831 query 1; heads
836 searching for changes
832 searching for changes
837 all remote heads known locally
833 all remote heads known locally
838 3 changesets found
834 3 changesets found
839 list of changesets:
835 list of changesets:
840 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
836 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
841 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
837 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
842 911600dab2ae7a9baff75958b84fe606851ce955
838 911600dab2ae7a9baff75958b84fe606851ce955
843 adding changesets
839 adding changesets
844 bundling: 1/3 changesets (33.33%)
840 bundling: 1/3 changesets (33.33%)
845 bundling: 2/3 changesets (66.67%)
841 bundling: 2/3 changesets (66.67%)
846 bundling: 3/3 changesets (100.00%)
842 bundling: 3/3 changesets (100.00%)
847 bundling: 1/3 manifests (33.33%)
843 bundling: 1/3 manifests (33.33%)
848 bundling: 2/3 manifests (66.67%)
844 bundling: 2/3 manifests (66.67%)
849 bundling: 3/3 manifests (100.00%)
845 bundling: 3/3 manifests (100.00%)
850 bundling: foo/Bar/file.txt 1/3 files (33.33%)
846 bundling: foo/Bar/file.txt 1/3 files (33.33%)
851 bundling: foo/file.txt 2/3 files (66.67%)
847 bundling: foo/file.txt 2/3 files (66.67%)
852 bundling: quux/file.py 3/3 files (100.00%)
848 bundling: quux/file.py 3/3 files (100.00%)
853 changesets: 1 chunks
849 changesets: 1 chunks
854 add changeset ef1ea85a6374
850 add changeset ef1ea85a6374
855 changesets: 2 chunks
851 changesets: 2 chunks
856 add changeset f9cafe1212c8
852 add changeset f9cafe1212c8
857 changesets: 3 chunks
853 changesets: 3 chunks
858 add changeset 911600dab2ae
854 add changeset 911600dab2ae
859 adding manifests
855 adding manifests
860 manifests: 1/3 chunks (33.33%)
856 manifests: 1/3 chunks (33.33%)
861 manifests: 2/3 chunks (66.67%)
857 manifests: 2/3 chunks (66.67%)
862 manifests: 3/3 chunks (100.00%)
858 manifests: 3/3 chunks (100.00%)
863 adding file changes
859 adding file changes
864 adding foo/Bar/file.txt revisions
860 adding foo/Bar/file.txt revisions
865 files: 1/3 chunks (33.33%)
861 files: 1/3 chunks (33.33%)
866 adding foo/file.txt revisions
862 adding foo/file.txt revisions
867 files: 2/3 chunks (66.67%)
863 files: 2/3 chunks (66.67%)
868 adding quux/file.py revisions
864 adding quux/file.py revisions
869 files: 3/3 chunks (100.00%)
865 files: 3/3 chunks (100.00%)
870 added 3 changesets with 3 changes to 3 files
866 added 3 changesets with 3 changes to 3 files
871 calling hook pretxnchangegroup.acl: hgext.acl.hook
867 calling hook pretxnchangegroup.acl: hgext.acl.hook
872 error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config'
868 error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config'
873 transaction abort!
869 transaction abort!
874 rollback completed
870 rollback completed
875 abort: No such file or directory: ../acl.config
871 abort: No such file or directory: ../acl.config
876 no rollback information available
872 no rollback information available
877 0:6675d58eff77
873 0:6675d58eff77
878
874
879
875
880 betty is allowed inside foo/ by a acl.config file
876 betty is allowed inside foo/ by a acl.config file
881
877
882 $ echo '[acl.allow]' >> acl.config
878 $ echo '[acl.allow]' >> acl.config
883 $ echo 'foo/** = betty' >> acl.config
879 $ echo 'foo/** = betty' >> acl.config
884 $ do_push betty
880 $ do_push betty
885 Pushing as user betty
881 Pushing as user betty
886 hgrc = """
882 hgrc = """
887 [hooks]
883 [hooks]
888 pretxnchangegroup.acl = python:hgext.acl.hook
884 pretxnchangegroup.acl = python:hgext.acl.hook
889 [acl]
885 [acl]
890 sources = push
886 sources = push
891 [acl.allow]
887 [acl.allow]
892 foo/** = fred
888 foo/** = fred
893 [acl.deny]
889 [acl.deny]
894 foo/bar/** = fred
890 foo/bar/** = fred
895 foo/Bar/** = fred
891 foo/Bar/** = fred
896 [acl.allow]
892 [acl.allow]
897 ** = barney
893 ** = barney
898 **/*.txt = wilma
894 **/*.txt = wilma
899 [acl]
895 [acl]
900 config = ../acl.config
896 config = ../acl.config
901 """
897 """
902 acl.config = """
898 acl.config = """
903 [acl.allow]
899 [acl.allow]
904 foo/** = betty
900 foo/** = betty
905 """
901 """
906 pushing to ../b
902 pushing to ../b
907 query 1; heads
903 query 1; heads
908 searching for changes
904 searching for changes
909 all remote heads known locally
905 all remote heads known locally
910 3 changesets found
906 3 changesets found
911 list of changesets:
907 list of changesets:
912 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
908 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
913 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
909 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
914 911600dab2ae7a9baff75958b84fe606851ce955
910 911600dab2ae7a9baff75958b84fe606851ce955
915 adding changesets
911 adding changesets
916 bundling: 1/3 changesets (33.33%)
912 bundling: 1/3 changesets (33.33%)
917 bundling: 2/3 changesets (66.67%)
913 bundling: 2/3 changesets (66.67%)
918 bundling: 3/3 changesets (100.00%)
914 bundling: 3/3 changesets (100.00%)
919 bundling: 1/3 manifests (33.33%)
915 bundling: 1/3 manifests (33.33%)
920 bundling: 2/3 manifests (66.67%)
916 bundling: 2/3 manifests (66.67%)
921 bundling: 3/3 manifests (100.00%)
917 bundling: 3/3 manifests (100.00%)
922 bundling: foo/Bar/file.txt 1/3 files (33.33%)
918 bundling: foo/Bar/file.txt 1/3 files (33.33%)
923 bundling: foo/file.txt 2/3 files (66.67%)
919 bundling: foo/file.txt 2/3 files (66.67%)
924 bundling: quux/file.py 3/3 files (100.00%)
920 bundling: quux/file.py 3/3 files (100.00%)
925 changesets: 1 chunks
921 changesets: 1 chunks
926 add changeset ef1ea85a6374
922 add changeset ef1ea85a6374
927 changesets: 2 chunks
923 changesets: 2 chunks
928 add changeset f9cafe1212c8
924 add changeset f9cafe1212c8
929 changesets: 3 chunks
925 changesets: 3 chunks
930 add changeset 911600dab2ae
926 add changeset 911600dab2ae
931 adding manifests
927 adding manifests
932 manifests: 1/3 chunks (33.33%)
928 manifests: 1/3 chunks (33.33%)
933 manifests: 2/3 chunks (66.67%)
929 manifests: 2/3 chunks (66.67%)
934 manifests: 3/3 chunks (100.00%)
930 manifests: 3/3 chunks (100.00%)
935 adding file changes
931 adding file changes
936 adding foo/Bar/file.txt revisions
932 adding foo/Bar/file.txt revisions
937 files: 1/3 chunks (33.33%)
933 files: 1/3 chunks (33.33%)
938 adding foo/file.txt revisions
934 adding foo/file.txt revisions
939 files: 2/3 chunks (66.67%)
935 files: 2/3 chunks (66.67%)
940 adding quux/file.py revisions
936 adding quux/file.py revisions
941 files: 3/3 chunks (100.00%)
937 files: 3/3 chunks (100.00%)
942 added 3 changesets with 3 changes to 3 files
938 added 3 changesets with 3 changes to 3 files
943 calling hook pretxnchangegroup.acl: hgext.acl.hook
939 calling hook pretxnchangegroup.acl: hgext.acl.hook
944 acl: acl.allow.branches not enabled
940 acl: acl.allow.branches not enabled
945 acl: acl.deny.branches not enabled
941 acl: acl.deny.branches not enabled
946 acl: acl.allow enabled, 1 entries for user betty
942 acl: acl.allow enabled, 1 entries for user betty
947 acl: acl.deny enabled, 0 entries for user betty
943 acl: acl.deny enabled, 0 entries for user betty
948 acl: branch access granted: "ef1ea85a6374" on branch "default"
944 acl: branch access granted: "ef1ea85a6374" on branch "default"
949 acl: allowing changeset ef1ea85a6374
945 acl: allowing changeset ef1ea85a6374
950 acl: branch access granted: "f9cafe1212c8" on branch "default"
946 acl: branch access granted: "f9cafe1212c8" on branch "default"
951 acl: allowing changeset f9cafe1212c8
947 acl: allowing changeset f9cafe1212c8
952 acl: branch access granted: "911600dab2ae" on branch "default"
948 acl: branch access granted: "911600dab2ae" on branch "default"
953 acl: user betty not allowed on quux/file.py
949 acl: user betty not allowed on quux/file.py
954 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
950 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
955 transaction abort!
951 transaction abort!
956 rollback completed
952 rollback completed
957 abort: acl: access denied for changeset 911600dab2ae
953 abort: acl: access denied for changeset 911600dab2ae
958 no rollback information available
954 no rollback information available
959 0:6675d58eff77
955 0:6675d58eff77
960
956
961
957
962 acl.config can set only [acl.allow]/[acl.deny]
958 acl.config can set only [acl.allow]/[acl.deny]
963
959
964 $ echo '[hooks]' >> acl.config
960 $ echo '[hooks]' >> acl.config
965 $ echo 'changegroup.acl = false' >> acl.config
961 $ echo 'changegroup.acl = false' >> acl.config
966 $ do_push barney
962 $ do_push barney
967 Pushing as user barney
963 Pushing as user barney
968 hgrc = """
964 hgrc = """
969 [hooks]
965 [hooks]
970 pretxnchangegroup.acl = python:hgext.acl.hook
966 pretxnchangegroup.acl = python:hgext.acl.hook
971 [acl]
967 [acl]
972 sources = push
968 sources = push
973 [acl.allow]
969 [acl.allow]
974 foo/** = fred
970 foo/** = fred
975 [acl.deny]
971 [acl.deny]
976 foo/bar/** = fred
972 foo/bar/** = fred
977 foo/Bar/** = fred
973 foo/Bar/** = fred
978 [acl.allow]
974 [acl.allow]
979 ** = barney
975 ** = barney
980 **/*.txt = wilma
976 **/*.txt = wilma
981 [acl]
977 [acl]
982 config = ../acl.config
978 config = ../acl.config
983 """
979 """
984 acl.config = """
980 acl.config = """
985 [acl.allow]
981 [acl.allow]
986 foo/** = betty
982 foo/** = betty
987 [hooks]
983 [hooks]
988 changegroup.acl = false
984 changegroup.acl = false
989 """
985 """
990 pushing to ../b
986 pushing to ../b
991 query 1; heads
987 query 1; heads
992 searching for changes
988 searching for changes
993 all remote heads known locally
989 all remote heads known locally
994 3 changesets found
990 3 changesets found
995 list of changesets:
991 list of changesets:
996 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
992 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
997 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
993 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
998 911600dab2ae7a9baff75958b84fe606851ce955
994 911600dab2ae7a9baff75958b84fe606851ce955
999 adding changesets
995 adding changesets
1000 bundling: 1/3 changesets (33.33%)
996 bundling: 1/3 changesets (33.33%)
1001 bundling: 2/3 changesets (66.67%)
997 bundling: 2/3 changesets (66.67%)
1002 bundling: 3/3 changesets (100.00%)
998 bundling: 3/3 changesets (100.00%)
1003 bundling: 1/3 manifests (33.33%)
999 bundling: 1/3 manifests (33.33%)
1004 bundling: 2/3 manifests (66.67%)
1000 bundling: 2/3 manifests (66.67%)
1005 bundling: 3/3 manifests (100.00%)
1001 bundling: 3/3 manifests (100.00%)
1006 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1002 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1007 bundling: foo/file.txt 2/3 files (66.67%)
1003 bundling: foo/file.txt 2/3 files (66.67%)
1008 bundling: quux/file.py 3/3 files (100.00%)
1004 bundling: quux/file.py 3/3 files (100.00%)
1009 changesets: 1 chunks
1005 changesets: 1 chunks
1010 add changeset ef1ea85a6374
1006 add changeset ef1ea85a6374
1011 changesets: 2 chunks
1007 changesets: 2 chunks
1012 add changeset f9cafe1212c8
1008 add changeset f9cafe1212c8
1013 changesets: 3 chunks
1009 changesets: 3 chunks
1014 add changeset 911600dab2ae
1010 add changeset 911600dab2ae
1015 adding manifests
1011 adding manifests
1016 manifests: 1/3 chunks (33.33%)
1012 manifests: 1/3 chunks (33.33%)
1017 manifests: 2/3 chunks (66.67%)
1013 manifests: 2/3 chunks (66.67%)
1018 manifests: 3/3 chunks (100.00%)
1014 manifests: 3/3 chunks (100.00%)
1019 adding file changes
1015 adding file changes
1020 adding foo/Bar/file.txt revisions
1016 adding foo/Bar/file.txt revisions
1021 files: 1/3 chunks (33.33%)
1017 files: 1/3 chunks (33.33%)
1022 adding foo/file.txt revisions
1018 adding foo/file.txt revisions
1023 files: 2/3 chunks (66.67%)
1019 files: 2/3 chunks (66.67%)
1024 adding quux/file.py revisions
1020 adding quux/file.py revisions
1025 files: 3/3 chunks (100.00%)
1021 files: 3/3 chunks (100.00%)
1026 added 3 changesets with 3 changes to 3 files
1022 added 3 changesets with 3 changes to 3 files
1027 calling hook pretxnchangegroup.acl: hgext.acl.hook
1023 calling hook pretxnchangegroup.acl: hgext.acl.hook
1028 acl: acl.allow.branches not enabled
1024 acl: acl.allow.branches not enabled
1029 acl: acl.deny.branches not enabled
1025 acl: acl.deny.branches not enabled
1030 acl: acl.allow enabled, 1 entries for user barney
1026 acl: acl.allow enabled, 1 entries for user barney
1031 acl: acl.deny enabled, 0 entries for user barney
1027 acl: acl.deny enabled, 0 entries for user barney
1032 acl: branch access granted: "ef1ea85a6374" on branch "default"
1028 acl: branch access granted: "ef1ea85a6374" on branch "default"
1033 acl: allowing changeset ef1ea85a6374
1029 acl: allowing changeset ef1ea85a6374
1034 acl: branch access granted: "f9cafe1212c8" on branch "default"
1030 acl: branch access granted: "f9cafe1212c8" on branch "default"
1035 acl: allowing changeset f9cafe1212c8
1031 acl: allowing changeset f9cafe1212c8
1036 acl: branch access granted: "911600dab2ae" on branch "default"
1032 acl: branch access granted: "911600dab2ae" on branch "default"
1037 acl: allowing changeset 911600dab2ae
1033 acl: allowing changeset 911600dab2ae
1038 updating the branch cache
1034 updating the branch cache
1039 checking for updated bookmarks
1035 checking for updated bookmarks
1040 repository tip rolled back to revision 0 (undo push)
1036 repository tip rolled back to revision 0 (undo push)
1041 working directory now based on revision 0
1042 0:6675d58eff77
1037 0:6675d58eff77
1043
1038
1044
1039
1045 asterisk
1040 asterisk
1046
1041
1047 $ init_config
1042 $ init_config
1048
1043
1049 asterisk test
1044 asterisk test
1050
1045
1051 $ echo '[acl.allow]' >> $config
1046 $ echo '[acl.allow]' >> $config
1052 $ echo "** = fred" >> $config
1047 $ echo "** = fred" >> $config
1053
1048
1054 fred is always allowed
1049 fred is always allowed
1055
1050
1056 $ do_push fred
1051 $ do_push fred
1057 Pushing as user fred
1052 Pushing as user fred
1058 hgrc = """
1053 hgrc = """
1059 [acl]
1054 [acl]
1060 sources = push
1055 sources = push
1061 [extensions]
1056 [extensions]
1062 [acl.allow]
1057 [acl.allow]
1063 ** = fred
1058 ** = fred
1064 """
1059 """
1065 pushing to ../b
1060 pushing to ../b
1066 query 1; heads
1061 query 1; heads
1067 searching for changes
1062 searching for changes
1068 all remote heads known locally
1063 all remote heads known locally
1069 invalidating branch cache (tip differs)
1064 invalidating branch cache (tip differs)
1070 3 changesets found
1065 3 changesets found
1071 list of changesets:
1066 list of changesets:
1072 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1067 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1073 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1068 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1074 911600dab2ae7a9baff75958b84fe606851ce955
1069 911600dab2ae7a9baff75958b84fe606851ce955
1075 adding changesets
1070 adding changesets
1076 bundling: 1/3 changesets (33.33%)
1071 bundling: 1/3 changesets (33.33%)
1077 bundling: 2/3 changesets (66.67%)
1072 bundling: 2/3 changesets (66.67%)
1078 bundling: 3/3 changesets (100.00%)
1073 bundling: 3/3 changesets (100.00%)
1079 bundling: 1/3 manifests (33.33%)
1074 bundling: 1/3 manifests (33.33%)
1080 bundling: 2/3 manifests (66.67%)
1075 bundling: 2/3 manifests (66.67%)
1081 bundling: 3/3 manifests (100.00%)
1076 bundling: 3/3 manifests (100.00%)
1082 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1077 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1083 bundling: foo/file.txt 2/3 files (66.67%)
1078 bundling: foo/file.txt 2/3 files (66.67%)
1084 bundling: quux/file.py 3/3 files (100.00%)
1079 bundling: quux/file.py 3/3 files (100.00%)
1085 changesets: 1 chunks
1080 changesets: 1 chunks
1086 add changeset ef1ea85a6374
1081 add changeset ef1ea85a6374
1087 changesets: 2 chunks
1082 changesets: 2 chunks
1088 add changeset f9cafe1212c8
1083 add changeset f9cafe1212c8
1089 changesets: 3 chunks
1084 changesets: 3 chunks
1090 add changeset 911600dab2ae
1085 add changeset 911600dab2ae
1091 adding manifests
1086 adding manifests
1092 manifests: 1/3 chunks (33.33%)
1087 manifests: 1/3 chunks (33.33%)
1093 manifests: 2/3 chunks (66.67%)
1088 manifests: 2/3 chunks (66.67%)
1094 manifests: 3/3 chunks (100.00%)
1089 manifests: 3/3 chunks (100.00%)
1095 adding file changes
1090 adding file changes
1096 adding foo/Bar/file.txt revisions
1091 adding foo/Bar/file.txt revisions
1097 files: 1/3 chunks (33.33%)
1092 files: 1/3 chunks (33.33%)
1098 adding foo/file.txt revisions
1093 adding foo/file.txt revisions
1099 files: 2/3 chunks (66.67%)
1094 files: 2/3 chunks (66.67%)
1100 adding quux/file.py revisions
1095 adding quux/file.py revisions
1101 files: 3/3 chunks (100.00%)
1096 files: 3/3 chunks (100.00%)
1102 added 3 changesets with 3 changes to 3 files
1097 added 3 changesets with 3 changes to 3 files
1103 calling hook pretxnchangegroup.acl: hgext.acl.hook
1098 calling hook pretxnchangegroup.acl: hgext.acl.hook
1104 acl: acl.allow.branches not enabled
1099 acl: acl.allow.branches not enabled
1105 acl: acl.deny.branches not enabled
1100 acl: acl.deny.branches not enabled
1106 acl: acl.allow enabled, 1 entries for user fred
1101 acl: acl.allow enabled, 1 entries for user fred
1107 acl: acl.deny not enabled
1102 acl: acl.deny not enabled
1108 acl: branch access granted: "ef1ea85a6374" on branch "default"
1103 acl: branch access granted: "ef1ea85a6374" on branch "default"
1109 acl: allowing changeset ef1ea85a6374
1104 acl: allowing changeset ef1ea85a6374
1110 acl: branch access granted: "f9cafe1212c8" on branch "default"
1105 acl: branch access granted: "f9cafe1212c8" on branch "default"
1111 acl: allowing changeset f9cafe1212c8
1106 acl: allowing changeset f9cafe1212c8
1112 acl: branch access granted: "911600dab2ae" on branch "default"
1107 acl: branch access granted: "911600dab2ae" on branch "default"
1113 acl: allowing changeset 911600dab2ae
1108 acl: allowing changeset 911600dab2ae
1114 updating the branch cache
1109 updating the branch cache
1115 checking for updated bookmarks
1110 checking for updated bookmarks
1116 repository tip rolled back to revision 0 (undo push)
1111 repository tip rolled back to revision 0 (undo push)
1117 working directory now based on revision 0
1118 0:6675d58eff77
1112 0:6675d58eff77
1119
1113
1120
1114
1121 $ echo '[acl.deny]' >> $config
1115 $ echo '[acl.deny]' >> $config
1122 $ echo "foo/Bar/** = *" >> $config
1116 $ echo "foo/Bar/** = *" >> $config
1123
1117
1124 no one is allowed inside foo/Bar/
1118 no one is allowed inside foo/Bar/
1125
1119
1126 $ do_push fred
1120 $ do_push fred
1127 Pushing as user fred
1121 Pushing as user fred
1128 hgrc = """
1122 hgrc = """
1129 [acl]
1123 [acl]
1130 sources = push
1124 sources = push
1131 [extensions]
1125 [extensions]
1132 [acl.allow]
1126 [acl.allow]
1133 ** = fred
1127 ** = fred
1134 [acl.deny]
1128 [acl.deny]
1135 foo/Bar/** = *
1129 foo/Bar/** = *
1136 """
1130 """
1137 pushing to ../b
1131 pushing to ../b
1138 query 1; heads
1132 query 1; heads
1139 searching for changes
1133 searching for changes
1140 all remote heads known locally
1134 all remote heads known locally
1141 invalidating branch cache (tip differs)
1135 invalidating branch cache (tip differs)
1142 3 changesets found
1136 3 changesets found
1143 list of changesets:
1137 list of changesets:
1144 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1138 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1145 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1139 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1146 911600dab2ae7a9baff75958b84fe606851ce955
1140 911600dab2ae7a9baff75958b84fe606851ce955
1147 adding changesets
1141 adding changesets
1148 bundling: 1/3 changesets (33.33%)
1142 bundling: 1/3 changesets (33.33%)
1149 bundling: 2/3 changesets (66.67%)
1143 bundling: 2/3 changesets (66.67%)
1150 bundling: 3/3 changesets (100.00%)
1144 bundling: 3/3 changesets (100.00%)
1151 bundling: 1/3 manifests (33.33%)
1145 bundling: 1/3 manifests (33.33%)
1152 bundling: 2/3 manifests (66.67%)
1146 bundling: 2/3 manifests (66.67%)
1153 bundling: 3/3 manifests (100.00%)
1147 bundling: 3/3 manifests (100.00%)
1154 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1148 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1155 bundling: foo/file.txt 2/3 files (66.67%)
1149 bundling: foo/file.txt 2/3 files (66.67%)
1156 bundling: quux/file.py 3/3 files (100.00%)
1150 bundling: quux/file.py 3/3 files (100.00%)
1157 changesets: 1 chunks
1151 changesets: 1 chunks
1158 add changeset ef1ea85a6374
1152 add changeset ef1ea85a6374
1159 changesets: 2 chunks
1153 changesets: 2 chunks
1160 add changeset f9cafe1212c8
1154 add changeset f9cafe1212c8
1161 changesets: 3 chunks
1155 changesets: 3 chunks
1162 add changeset 911600dab2ae
1156 add changeset 911600dab2ae
1163 adding manifests
1157 adding manifests
1164 manifests: 1/3 chunks (33.33%)
1158 manifests: 1/3 chunks (33.33%)
1165 manifests: 2/3 chunks (66.67%)
1159 manifests: 2/3 chunks (66.67%)
1166 manifests: 3/3 chunks (100.00%)
1160 manifests: 3/3 chunks (100.00%)
1167 adding file changes
1161 adding file changes
1168 adding foo/Bar/file.txt revisions
1162 adding foo/Bar/file.txt revisions
1169 files: 1/3 chunks (33.33%)
1163 files: 1/3 chunks (33.33%)
1170 adding foo/file.txt revisions
1164 adding foo/file.txt revisions
1171 files: 2/3 chunks (66.67%)
1165 files: 2/3 chunks (66.67%)
1172 adding quux/file.py revisions
1166 adding quux/file.py revisions
1173 files: 3/3 chunks (100.00%)
1167 files: 3/3 chunks (100.00%)
1174 added 3 changesets with 3 changes to 3 files
1168 added 3 changesets with 3 changes to 3 files
1175 calling hook pretxnchangegroup.acl: hgext.acl.hook
1169 calling hook pretxnchangegroup.acl: hgext.acl.hook
1176 acl: acl.allow.branches not enabled
1170 acl: acl.allow.branches not enabled
1177 acl: acl.deny.branches not enabled
1171 acl: acl.deny.branches not enabled
1178 acl: acl.allow enabled, 1 entries for user fred
1172 acl: acl.allow enabled, 1 entries for user fred
1179 acl: acl.deny enabled, 1 entries for user fred
1173 acl: acl.deny enabled, 1 entries for user fred
1180 acl: branch access granted: "ef1ea85a6374" on branch "default"
1174 acl: branch access granted: "ef1ea85a6374" on branch "default"
1181 acl: allowing changeset ef1ea85a6374
1175 acl: allowing changeset ef1ea85a6374
1182 acl: branch access granted: "f9cafe1212c8" on branch "default"
1176 acl: branch access granted: "f9cafe1212c8" on branch "default"
1183 acl: user fred denied on foo/Bar/file.txt
1177 acl: user fred denied on foo/Bar/file.txt
1184 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
1178 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
1185 transaction abort!
1179 transaction abort!
1186 rollback completed
1180 rollback completed
1187 abort: acl: access denied for changeset f9cafe1212c8
1181 abort: acl: access denied for changeset f9cafe1212c8
1188 no rollback information available
1182 no rollback information available
1189 0:6675d58eff77
1183 0:6675d58eff77
1190
1184
1191
1185
1192 Groups
1186 Groups
1193
1187
1194 $ init_config
1188 $ init_config
1195
1189
1196 OS-level groups
1190 OS-level groups
1197
1191
1198 $ echo '[acl.allow]' >> $config
1192 $ echo '[acl.allow]' >> $config
1199 $ echo "** = @group1" >> $config
1193 $ echo "** = @group1" >> $config
1200
1194
1201 @group1 is always allowed
1195 @group1 is always allowed
1202
1196
1203 $ do_push fred
1197 $ do_push fred
1204 Pushing as user fred
1198 Pushing as user fred
1205 hgrc = """
1199 hgrc = """
1206 [acl]
1200 [acl]
1207 sources = push
1201 sources = push
1208 [extensions]
1202 [extensions]
1209 [acl.allow]
1203 [acl.allow]
1210 ** = @group1
1204 ** = @group1
1211 """
1205 """
1212 pushing to ../b
1206 pushing to ../b
1213 query 1; heads
1207 query 1; heads
1214 searching for changes
1208 searching for changes
1215 all remote heads known locally
1209 all remote heads known locally
1216 3 changesets found
1210 3 changesets found
1217 list of changesets:
1211 list of changesets:
1218 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1212 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1219 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1213 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1220 911600dab2ae7a9baff75958b84fe606851ce955
1214 911600dab2ae7a9baff75958b84fe606851ce955
1221 adding changesets
1215 adding changesets
1222 bundling: 1/3 changesets (33.33%)
1216 bundling: 1/3 changesets (33.33%)
1223 bundling: 2/3 changesets (66.67%)
1217 bundling: 2/3 changesets (66.67%)
1224 bundling: 3/3 changesets (100.00%)
1218 bundling: 3/3 changesets (100.00%)
1225 bundling: 1/3 manifests (33.33%)
1219 bundling: 1/3 manifests (33.33%)
1226 bundling: 2/3 manifests (66.67%)
1220 bundling: 2/3 manifests (66.67%)
1227 bundling: 3/3 manifests (100.00%)
1221 bundling: 3/3 manifests (100.00%)
1228 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1222 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1229 bundling: foo/file.txt 2/3 files (66.67%)
1223 bundling: foo/file.txt 2/3 files (66.67%)
1230 bundling: quux/file.py 3/3 files (100.00%)
1224 bundling: quux/file.py 3/3 files (100.00%)
1231 changesets: 1 chunks
1225 changesets: 1 chunks
1232 add changeset ef1ea85a6374
1226 add changeset ef1ea85a6374
1233 changesets: 2 chunks
1227 changesets: 2 chunks
1234 add changeset f9cafe1212c8
1228 add changeset f9cafe1212c8
1235 changesets: 3 chunks
1229 changesets: 3 chunks
1236 add changeset 911600dab2ae
1230 add changeset 911600dab2ae
1237 adding manifests
1231 adding manifests
1238 manifests: 1/3 chunks (33.33%)
1232 manifests: 1/3 chunks (33.33%)
1239 manifests: 2/3 chunks (66.67%)
1233 manifests: 2/3 chunks (66.67%)
1240 manifests: 3/3 chunks (100.00%)
1234 manifests: 3/3 chunks (100.00%)
1241 adding file changes
1235 adding file changes
1242 adding foo/Bar/file.txt revisions
1236 adding foo/Bar/file.txt revisions
1243 files: 1/3 chunks (33.33%)
1237 files: 1/3 chunks (33.33%)
1244 adding foo/file.txt revisions
1238 adding foo/file.txt revisions
1245 files: 2/3 chunks (66.67%)
1239 files: 2/3 chunks (66.67%)
1246 adding quux/file.py revisions
1240 adding quux/file.py revisions
1247 files: 3/3 chunks (100.00%)
1241 files: 3/3 chunks (100.00%)
1248 added 3 changesets with 3 changes to 3 files
1242 added 3 changesets with 3 changes to 3 files
1249 calling hook pretxnchangegroup.acl: hgext.acl.hook
1243 calling hook pretxnchangegroup.acl: hgext.acl.hook
1250 acl: acl.allow.branches not enabled
1244 acl: acl.allow.branches not enabled
1251 acl: acl.deny.branches not enabled
1245 acl: acl.deny.branches not enabled
1252 acl: "group1" not defined in [acl.groups]
1246 acl: "group1" not defined in [acl.groups]
1253 acl: acl.allow enabled, 1 entries for user fred
1247 acl: acl.allow enabled, 1 entries for user fred
1254 acl: acl.deny not enabled
1248 acl: acl.deny not enabled
1255 acl: branch access granted: "ef1ea85a6374" on branch "default"
1249 acl: branch access granted: "ef1ea85a6374" on branch "default"
1256 acl: allowing changeset ef1ea85a6374
1250 acl: allowing changeset ef1ea85a6374
1257 acl: branch access granted: "f9cafe1212c8" on branch "default"
1251 acl: branch access granted: "f9cafe1212c8" on branch "default"
1258 acl: allowing changeset f9cafe1212c8
1252 acl: allowing changeset f9cafe1212c8
1259 acl: branch access granted: "911600dab2ae" on branch "default"
1253 acl: branch access granted: "911600dab2ae" on branch "default"
1260 acl: allowing changeset 911600dab2ae
1254 acl: allowing changeset 911600dab2ae
1261 updating the branch cache
1255 updating the branch cache
1262 checking for updated bookmarks
1256 checking for updated bookmarks
1263 repository tip rolled back to revision 0 (undo push)
1257 repository tip rolled back to revision 0 (undo push)
1264 working directory now based on revision 0
1265 0:6675d58eff77
1258 0:6675d58eff77
1266
1259
1267
1260
1268 $ echo '[acl.deny]' >> $config
1261 $ echo '[acl.deny]' >> $config
1269 $ echo "foo/Bar/** = @group1" >> $config
1262 $ echo "foo/Bar/** = @group1" >> $config
1270
1263
1271 @group is allowed inside anything but foo/Bar/
1264 @group is allowed inside anything but foo/Bar/
1272
1265
1273 $ do_push fred
1266 $ do_push fred
1274 Pushing as user fred
1267 Pushing as user fred
1275 hgrc = """
1268 hgrc = """
1276 [acl]
1269 [acl]
1277 sources = push
1270 sources = push
1278 [extensions]
1271 [extensions]
1279 [acl.allow]
1272 [acl.allow]
1280 ** = @group1
1273 ** = @group1
1281 [acl.deny]
1274 [acl.deny]
1282 foo/Bar/** = @group1
1275 foo/Bar/** = @group1
1283 """
1276 """
1284 pushing to ../b
1277 pushing to ../b
1285 query 1; heads
1278 query 1; heads
1286 searching for changes
1279 searching for changes
1287 all remote heads known locally
1280 all remote heads known locally
1288 invalidating branch cache (tip differs)
1281 invalidating branch cache (tip differs)
1289 3 changesets found
1282 3 changesets found
1290 list of changesets:
1283 list of changesets:
1291 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1284 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1292 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1285 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1293 911600dab2ae7a9baff75958b84fe606851ce955
1286 911600dab2ae7a9baff75958b84fe606851ce955
1294 adding changesets
1287 adding changesets
1295 bundling: 1/3 changesets (33.33%)
1288 bundling: 1/3 changesets (33.33%)
1296 bundling: 2/3 changesets (66.67%)
1289 bundling: 2/3 changesets (66.67%)
1297 bundling: 3/3 changesets (100.00%)
1290 bundling: 3/3 changesets (100.00%)
1298 bundling: 1/3 manifests (33.33%)
1291 bundling: 1/3 manifests (33.33%)
1299 bundling: 2/3 manifests (66.67%)
1292 bundling: 2/3 manifests (66.67%)
1300 bundling: 3/3 manifests (100.00%)
1293 bundling: 3/3 manifests (100.00%)
1301 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1294 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1302 bundling: foo/file.txt 2/3 files (66.67%)
1295 bundling: foo/file.txt 2/3 files (66.67%)
1303 bundling: quux/file.py 3/3 files (100.00%)
1296 bundling: quux/file.py 3/3 files (100.00%)
1304 changesets: 1 chunks
1297 changesets: 1 chunks
1305 add changeset ef1ea85a6374
1298 add changeset ef1ea85a6374
1306 changesets: 2 chunks
1299 changesets: 2 chunks
1307 add changeset f9cafe1212c8
1300 add changeset f9cafe1212c8
1308 changesets: 3 chunks
1301 changesets: 3 chunks
1309 add changeset 911600dab2ae
1302 add changeset 911600dab2ae
1310 adding manifests
1303 adding manifests
1311 manifests: 1/3 chunks (33.33%)
1304 manifests: 1/3 chunks (33.33%)
1312 manifests: 2/3 chunks (66.67%)
1305 manifests: 2/3 chunks (66.67%)
1313 manifests: 3/3 chunks (100.00%)
1306 manifests: 3/3 chunks (100.00%)
1314 adding file changes
1307 adding file changes
1315 adding foo/Bar/file.txt revisions
1308 adding foo/Bar/file.txt revisions
1316 files: 1/3 chunks (33.33%)
1309 files: 1/3 chunks (33.33%)
1317 adding foo/file.txt revisions
1310 adding foo/file.txt revisions
1318 files: 2/3 chunks (66.67%)
1311 files: 2/3 chunks (66.67%)
1319 adding quux/file.py revisions
1312 adding quux/file.py revisions
1320 files: 3/3 chunks (100.00%)
1313 files: 3/3 chunks (100.00%)
1321 added 3 changesets with 3 changes to 3 files
1314 added 3 changesets with 3 changes to 3 files
1322 calling hook pretxnchangegroup.acl: hgext.acl.hook
1315 calling hook pretxnchangegroup.acl: hgext.acl.hook
1323 acl: acl.allow.branches not enabled
1316 acl: acl.allow.branches not enabled
1324 acl: acl.deny.branches not enabled
1317 acl: acl.deny.branches not enabled
1325 acl: "group1" not defined in [acl.groups]
1318 acl: "group1" not defined in [acl.groups]
1326 acl: acl.allow enabled, 1 entries for user fred
1319 acl: acl.allow enabled, 1 entries for user fred
1327 acl: "group1" not defined in [acl.groups]
1320 acl: "group1" not defined in [acl.groups]
1328 acl: acl.deny enabled, 1 entries for user fred
1321 acl: acl.deny enabled, 1 entries for user fred
1329 acl: branch access granted: "ef1ea85a6374" on branch "default"
1322 acl: branch access granted: "ef1ea85a6374" on branch "default"
1330 acl: allowing changeset ef1ea85a6374
1323 acl: allowing changeset ef1ea85a6374
1331 acl: branch access granted: "f9cafe1212c8" on branch "default"
1324 acl: branch access granted: "f9cafe1212c8" on branch "default"
1332 acl: user fred denied on foo/Bar/file.txt
1325 acl: user fred denied on foo/Bar/file.txt
1333 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
1326 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
1334 transaction abort!
1327 transaction abort!
1335 rollback completed
1328 rollback completed
1336 abort: acl: access denied for changeset f9cafe1212c8
1329 abort: acl: access denied for changeset f9cafe1212c8
1337 no rollback information available
1330 no rollback information available
1338 0:6675d58eff77
1331 0:6675d58eff77
1339
1332
1340
1333
1341 Invalid group
1334 Invalid group
1342
1335
1343 Disable the fakegroups trick to get real failures
1336 Disable the fakegroups trick to get real failures
1344
1337
1345 $ grep -v fakegroups $config > config.tmp
1338 $ grep -v fakegroups $config > config.tmp
1346 $ mv config.tmp $config
1339 $ mv config.tmp $config
1347 $ echo '[acl.allow]' >> $config
1340 $ echo '[acl.allow]' >> $config
1348 $ echo "** = @unlikelytoexist" >> $config
1341 $ echo "** = @unlikelytoexist" >> $config
1349 $ do_push fred 2>&1 | grep unlikelytoexist
1342 $ do_push fred 2>&1 | grep unlikelytoexist
1350 ** = @unlikelytoexist
1343 ** = @unlikelytoexist
1351 acl: "unlikelytoexist" not defined in [acl.groups]
1344 acl: "unlikelytoexist" not defined in [acl.groups]
1352 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1345 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1353 abort: group 'unlikelytoexist' is undefined
1346 abort: group 'unlikelytoexist' is undefined
1354
1347
1355
1348
1356 Branch acl tests setup
1349 Branch acl tests setup
1357
1350
1358 $ init_config
1351 $ init_config
1359 $ cd b
1352 $ cd b
1360 $ hg up
1353 $ hg up
1361 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1354 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1362 $ hg branch foobar
1355 $ hg branch foobar
1363 marked working directory as branch foobar
1356 marked working directory as branch foobar
1364 $ hg commit -m 'create foobar'
1357 $ hg commit -m 'create foobar'
1365 $ echo 'foo contents' > abc.txt
1358 $ echo 'foo contents' > abc.txt
1366 $ hg add abc.txt
1359 $ hg add abc.txt
1367 $ hg commit -m 'foobar contents'
1360 $ hg commit -m 'foobar contents'
1368 $ cd ..
1361 $ cd ..
1369 $ hg --cwd a pull ../b
1362 $ hg --cwd a pull ../b
1370 pulling from ../b
1363 pulling from ../b
1371 searching for changes
1364 searching for changes
1372 adding changesets
1365 adding changesets
1373 adding manifests
1366 adding manifests
1374 adding file changes
1367 adding file changes
1375 added 2 changesets with 1 changes to 1 files (+1 heads)
1368 added 2 changesets with 1 changes to 1 files (+1 heads)
1376 (run 'hg heads' to see heads)
1369 (run 'hg heads' to see heads)
1377
1370
1378 Create additional changeset on foobar branch
1371 Create additional changeset on foobar branch
1379
1372
1380 $ cd a
1373 $ cd a
1381 $ hg up -C foobar
1374 $ hg up -C foobar
1382 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1375 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1383 $ echo 'foo contents2' > abc.txt
1376 $ echo 'foo contents2' > abc.txt
1384 $ hg commit -m 'foobar contents2'
1377 $ hg commit -m 'foobar contents2'
1385 $ cd ..
1378 $ cd ..
1386
1379
1387
1380
1388 No branch acls specified
1381 No branch acls specified
1389
1382
1390 $ do_push astro
1383 $ do_push astro
1391 Pushing as user astro
1384 Pushing as user astro
1392 hgrc = """
1385 hgrc = """
1393 [acl]
1386 [acl]
1394 sources = push
1387 sources = push
1395 [extensions]
1388 [extensions]
1396 """
1389 """
1397 pushing to ../b
1390 pushing to ../b
1398 query 1; heads
1391 query 1; heads
1399 searching for changes
1392 searching for changes
1400 all remote heads known locally
1393 all remote heads known locally
1401 4 changesets found
1394 4 changesets found
1402 list of changesets:
1395 list of changesets:
1403 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1396 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1404 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1397 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1405 911600dab2ae7a9baff75958b84fe606851ce955
1398 911600dab2ae7a9baff75958b84fe606851ce955
1406 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1399 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1407 adding changesets
1400 adding changesets
1408 bundling: 1/4 changesets (25.00%)
1401 bundling: 1/4 changesets (25.00%)
1409 bundling: 2/4 changesets (50.00%)
1402 bundling: 2/4 changesets (50.00%)
1410 bundling: 3/4 changesets (75.00%)
1403 bundling: 3/4 changesets (75.00%)
1411 bundling: 4/4 changesets (100.00%)
1404 bundling: 4/4 changesets (100.00%)
1412 bundling: 1/4 manifests (25.00%)
1405 bundling: 1/4 manifests (25.00%)
1413 bundling: 2/4 manifests (50.00%)
1406 bundling: 2/4 manifests (50.00%)
1414 bundling: 3/4 manifests (75.00%)
1407 bundling: 3/4 manifests (75.00%)
1415 bundling: 4/4 manifests (100.00%)
1408 bundling: 4/4 manifests (100.00%)
1416 bundling: abc.txt 1/4 files (25.00%)
1409 bundling: abc.txt 1/4 files (25.00%)
1417 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1410 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1418 bundling: foo/file.txt 3/4 files (75.00%)
1411 bundling: foo/file.txt 3/4 files (75.00%)
1419 bundling: quux/file.py 4/4 files (100.00%)
1412 bundling: quux/file.py 4/4 files (100.00%)
1420 changesets: 1 chunks
1413 changesets: 1 chunks
1421 add changeset ef1ea85a6374
1414 add changeset ef1ea85a6374
1422 changesets: 2 chunks
1415 changesets: 2 chunks
1423 add changeset f9cafe1212c8
1416 add changeset f9cafe1212c8
1424 changesets: 3 chunks
1417 changesets: 3 chunks
1425 add changeset 911600dab2ae
1418 add changeset 911600dab2ae
1426 changesets: 4 chunks
1419 changesets: 4 chunks
1427 add changeset e8fc755d4d82
1420 add changeset e8fc755d4d82
1428 adding manifests
1421 adding manifests
1429 manifests: 1/4 chunks (25.00%)
1422 manifests: 1/4 chunks (25.00%)
1430 manifests: 2/4 chunks (50.00%)
1423 manifests: 2/4 chunks (50.00%)
1431 manifests: 3/4 chunks (75.00%)
1424 manifests: 3/4 chunks (75.00%)
1432 manifests: 4/4 chunks (100.00%)
1425 manifests: 4/4 chunks (100.00%)
1433 adding file changes
1426 adding file changes
1434 adding abc.txt revisions
1427 adding abc.txt revisions
1435 files: 1/4 chunks (25.00%)
1428 files: 1/4 chunks (25.00%)
1436 adding foo/Bar/file.txt revisions
1429 adding foo/Bar/file.txt revisions
1437 files: 2/4 chunks (50.00%)
1430 files: 2/4 chunks (50.00%)
1438 adding foo/file.txt revisions
1431 adding foo/file.txt revisions
1439 files: 3/4 chunks (75.00%)
1432 files: 3/4 chunks (75.00%)
1440 adding quux/file.py revisions
1433 adding quux/file.py revisions
1441 files: 4/4 chunks (100.00%)
1434 files: 4/4 chunks (100.00%)
1442 added 4 changesets with 4 changes to 4 files (+1 heads)
1435 added 4 changesets with 4 changes to 4 files (+1 heads)
1443 calling hook pretxnchangegroup.acl: hgext.acl.hook
1436 calling hook pretxnchangegroup.acl: hgext.acl.hook
1444 acl: acl.allow.branches not enabled
1437 acl: acl.allow.branches not enabled
1445 acl: acl.deny.branches not enabled
1438 acl: acl.deny.branches not enabled
1446 acl: acl.allow not enabled
1439 acl: acl.allow not enabled
1447 acl: acl.deny not enabled
1440 acl: acl.deny not enabled
1448 acl: branch access granted: "ef1ea85a6374" on branch "default"
1441 acl: branch access granted: "ef1ea85a6374" on branch "default"
1449 acl: allowing changeset ef1ea85a6374
1442 acl: allowing changeset ef1ea85a6374
1450 acl: branch access granted: "f9cafe1212c8" on branch "default"
1443 acl: branch access granted: "f9cafe1212c8" on branch "default"
1451 acl: allowing changeset f9cafe1212c8
1444 acl: allowing changeset f9cafe1212c8
1452 acl: branch access granted: "911600dab2ae" on branch "default"
1445 acl: branch access granted: "911600dab2ae" on branch "default"
1453 acl: allowing changeset 911600dab2ae
1446 acl: allowing changeset 911600dab2ae
1454 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1447 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1455 acl: allowing changeset e8fc755d4d82
1448 acl: allowing changeset e8fc755d4d82
1456 updating the branch cache
1449 updating the branch cache
1457 checking for updated bookmarks
1450 checking for updated bookmarks
1458 repository tip rolled back to revision 2 (undo push)
1451 repository tip rolled back to revision 2 (undo push)
1459 working directory now based on revision 2
1460 2:fb35475503ef
1452 2:fb35475503ef
1461
1453
1462
1454
1463 Branch acl deny test
1455 Branch acl deny test
1464
1456
1465 $ echo "[acl.deny.branches]" >> $config
1457 $ echo "[acl.deny.branches]" >> $config
1466 $ echo "foobar = *" >> $config
1458 $ echo "foobar = *" >> $config
1467 $ do_push astro
1459 $ do_push astro
1468 Pushing as user astro
1460 Pushing as user astro
1469 hgrc = """
1461 hgrc = """
1470 [acl]
1462 [acl]
1471 sources = push
1463 sources = push
1472 [extensions]
1464 [extensions]
1473 [acl.deny.branches]
1465 [acl.deny.branches]
1474 foobar = *
1466 foobar = *
1475 """
1467 """
1476 pushing to ../b
1468 pushing to ../b
1477 query 1; heads
1469 query 1; heads
1478 searching for changes
1470 searching for changes
1479 all remote heads known locally
1471 all remote heads known locally
1480 invalidating branch cache (tip differs)
1472 invalidating branch cache (tip differs)
1481 4 changesets found
1473 4 changesets found
1482 list of changesets:
1474 list of changesets:
1483 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1475 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1484 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1476 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1485 911600dab2ae7a9baff75958b84fe606851ce955
1477 911600dab2ae7a9baff75958b84fe606851ce955
1486 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1478 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1487 adding changesets
1479 adding changesets
1488 bundling: 1/4 changesets (25.00%)
1480 bundling: 1/4 changesets (25.00%)
1489 bundling: 2/4 changesets (50.00%)
1481 bundling: 2/4 changesets (50.00%)
1490 bundling: 3/4 changesets (75.00%)
1482 bundling: 3/4 changesets (75.00%)
1491 bundling: 4/4 changesets (100.00%)
1483 bundling: 4/4 changesets (100.00%)
1492 bundling: 1/4 manifests (25.00%)
1484 bundling: 1/4 manifests (25.00%)
1493 bundling: 2/4 manifests (50.00%)
1485 bundling: 2/4 manifests (50.00%)
1494 bundling: 3/4 manifests (75.00%)
1486 bundling: 3/4 manifests (75.00%)
1495 bundling: 4/4 manifests (100.00%)
1487 bundling: 4/4 manifests (100.00%)
1496 bundling: abc.txt 1/4 files (25.00%)
1488 bundling: abc.txt 1/4 files (25.00%)
1497 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1489 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1498 bundling: foo/file.txt 3/4 files (75.00%)
1490 bundling: foo/file.txt 3/4 files (75.00%)
1499 bundling: quux/file.py 4/4 files (100.00%)
1491 bundling: quux/file.py 4/4 files (100.00%)
1500 changesets: 1 chunks
1492 changesets: 1 chunks
1501 add changeset ef1ea85a6374
1493 add changeset ef1ea85a6374
1502 changesets: 2 chunks
1494 changesets: 2 chunks
1503 add changeset f9cafe1212c8
1495 add changeset f9cafe1212c8
1504 changesets: 3 chunks
1496 changesets: 3 chunks
1505 add changeset 911600dab2ae
1497 add changeset 911600dab2ae
1506 changesets: 4 chunks
1498 changesets: 4 chunks
1507 add changeset e8fc755d4d82
1499 add changeset e8fc755d4d82
1508 adding manifests
1500 adding manifests
1509 manifests: 1/4 chunks (25.00%)
1501 manifests: 1/4 chunks (25.00%)
1510 manifests: 2/4 chunks (50.00%)
1502 manifests: 2/4 chunks (50.00%)
1511 manifests: 3/4 chunks (75.00%)
1503 manifests: 3/4 chunks (75.00%)
1512 manifests: 4/4 chunks (100.00%)
1504 manifests: 4/4 chunks (100.00%)
1513 adding file changes
1505 adding file changes
1514 adding abc.txt revisions
1506 adding abc.txt revisions
1515 files: 1/4 chunks (25.00%)
1507 files: 1/4 chunks (25.00%)
1516 adding foo/Bar/file.txt revisions
1508 adding foo/Bar/file.txt revisions
1517 files: 2/4 chunks (50.00%)
1509 files: 2/4 chunks (50.00%)
1518 adding foo/file.txt revisions
1510 adding foo/file.txt revisions
1519 files: 3/4 chunks (75.00%)
1511 files: 3/4 chunks (75.00%)
1520 adding quux/file.py revisions
1512 adding quux/file.py revisions
1521 files: 4/4 chunks (100.00%)
1513 files: 4/4 chunks (100.00%)
1522 added 4 changesets with 4 changes to 4 files (+1 heads)
1514 added 4 changesets with 4 changes to 4 files (+1 heads)
1523 calling hook pretxnchangegroup.acl: hgext.acl.hook
1515 calling hook pretxnchangegroup.acl: hgext.acl.hook
1524 acl: acl.allow.branches not enabled
1516 acl: acl.allow.branches not enabled
1525 acl: acl.deny.branches enabled, 1 entries for user astro
1517 acl: acl.deny.branches enabled, 1 entries for user astro
1526 acl: acl.allow not enabled
1518 acl: acl.allow not enabled
1527 acl: acl.deny not enabled
1519 acl: acl.deny not enabled
1528 acl: branch access granted: "ef1ea85a6374" on branch "default"
1520 acl: branch access granted: "ef1ea85a6374" on branch "default"
1529 acl: allowing changeset ef1ea85a6374
1521 acl: allowing changeset ef1ea85a6374
1530 acl: branch access granted: "f9cafe1212c8" on branch "default"
1522 acl: branch access granted: "f9cafe1212c8" on branch "default"
1531 acl: allowing changeset f9cafe1212c8
1523 acl: allowing changeset f9cafe1212c8
1532 acl: branch access granted: "911600dab2ae" on branch "default"
1524 acl: branch access granted: "911600dab2ae" on branch "default"
1533 acl: allowing changeset 911600dab2ae
1525 acl: allowing changeset 911600dab2ae
1534 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1526 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1535 transaction abort!
1527 transaction abort!
1536 rollback completed
1528 rollback completed
1537 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1529 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1538 no rollback information available
1530 no rollback information available
1539 2:fb35475503ef
1531 2:fb35475503ef
1540
1532
1541
1533
1542 Branch acl empty allow test
1534 Branch acl empty allow test
1543
1535
1544 $ init_config
1536 $ init_config
1545 $ echo "[acl.allow.branches]" >> $config
1537 $ echo "[acl.allow.branches]" >> $config
1546 $ do_push astro
1538 $ do_push astro
1547 Pushing as user astro
1539 Pushing as user astro
1548 hgrc = """
1540 hgrc = """
1549 [acl]
1541 [acl]
1550 sources = push
1542 sources = push
1551 [extensions]
1543 [extensions]
1552 [acl.allow.branches]
1544 [acl.allow.branches]
1553 """
1545 """
1554 pushing to ../b
1546 pushing to ../b
1555 query 1; heads
1547 query 1; heads
1556 searching for changes
1548 searching for changes
1557 all remote heads known locally
1549 all remote heads known locally
1558 4 changesets found
1550 4 changesets found
1559 list of changesets:
1551 list of changesets:
1560 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1552 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1561 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1553 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1562 911600dab2ae7a9baff75958b84fe606851ce955
1554 911600dab2ae7a9baff75958b84fe606851ce955
1563 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1555 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1564 adding changesets
1556 adding changesets
1565 bundling: 1/4 changesets (25.00%)
1557 bundling: 1/4 changesets (25.00%)
1566 bundling: 2/4 changesets (50.00%)
1558 bundling: 2/4 changesets (50.00%)
1567 bundling: 3/4 changesets (75.00%)
1559 bundling: 3/4 changesets (75.00%)
1568 bundling: 4/4 changesets (100.00%)
1560 bundling: 4/4 changesets (100.00%)
1569 bundling: 1/4 manifests (25.00%)
1561 bundling: 1/4 manifests (25.00%)
1570 bundling: 2/4 manifests (50.00%)
1562 bundling: 2/4 manifests (50.00%)
1571 bundling: 3/4 manifests (75.00%)
1563 bundling: 3/4 manifests (75.00%)
1572 bundling: 4/4 manifests (100.00%)
1564 bundling: 4/4 manifests (100.00%)
1573 bundling: abc.txt 1/4 files (25.00%)
1565 bundling: abc.txt 1/4 files (25.00%)
1574 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1566 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1575 bundling: foo/file.txt 3/4 files (75.00%)
1567 bundling: foo/file.txt 3/4 files (75.00%)
1576 bundling: quux/file.py 4/4 files (100.00%)
1568 bundling: quux/file.py 4/4 files (100.00%)
1577 changesets: 1 chunks
1569 changesets: 1 chunks
1578 add changeset ef1ea85a6374
1570 add changeset ef1ea85a6374
1579 changesets: 2 chunks
1571 changesets: 2 chunks
1580 add changeset f9cafe1212c8
1572 add changeset f9cafe1212c8
1581 changesets: 3 chunks
1573 changesets: 3 chunks
1582 add changeset 911600dab2ae
1574 add changeset 911600dab2ae
1583 changesets: 4 chunks
1575 changesets: 4 chunks
1584 add changeset e8fc755d4d82
1576 add changeset e8fc755d4d82
1585 adding manifests
1577 adding manifests
1586 manifests: 1/4 chunks (25.00%)
1578 manifests: 1/4 chunks (25.00%)
1587 manifests: 2/4 chunks (50.00%)
1579 manifests: 2/4 chunks (50.00%)
1588 manifests: 3/4 chunks (75.00%)
1580 manifests: 3/4 chunks (75.00%)
1589 manifests: 4/4 chunks (100.00%)
1581 manifests: 4/4 chunks (100.00%)
1590 adding file changes
1582 adding file changes
1591 adding abc.txt revisions
1583 adding abc.txt revisions
1592 files: 1/4 chunks (25.00%)
1584 files: 1/4 chunks (25.00%)
1593 adding foo/Bar/file.txt revisions
1585 adding foo/Bar/file.txt revisions
1594 files: 2/4 chunks (50.00%)
1586 files: 2/4 chunks (50.00%)
1595 adding foo/file.txt revisions
1587 adding foo/file.txt revisions
1596 files: 3/4 chunks (75.00%)
1588 files: 3/4 chunks (75.00%)
1597 adding quux/file.py revisions
1589 adding quux/file.py revisions
1598 files: 4/4 chunks (100.00%)
1590 files: 4/4 chunks (100.00%)
1599 added 4 changesets with 4 changes to 4 files (+1 heads)
1591 added 4 changesets with 4 changes to 4 files (+1 heads)
1600 calling hook pretxnchangegroup.acl: hgext.acl.hook
1592 calling hook pretxnchangegroup.acl: hgext.acl.hook
1601 acl: acl.allow.branches enabled, 0 entries for user astro
1593 acl: acl.allow.branches enabled, 0 entries for user astro
1602 acl: acl.deny.branches not enabled
1594 acl: acl.deny.branches not enabled
1603 acl: acl.allow not enabled
1595 acl: acl.allow not enabled
1604 acl: acl.deny not enabled
1596 acl: acl.deny not enabled
1605 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1597 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1606 transaction abort!
1598 transaction abort!
1607 rollback completed
1599 rollback completed
1608 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1600 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1609 no rollback information available
1601 no rollback information available
1610 2:fb35475503ef
1602 2:fb35475503ef
1611
1603
1612
1604
1613 Branch acl allow other
1605 Branch acl allow other
1614
1606
1615 $ init_config
1607 $ init_config
1616 $ echo "[acl.allow.branches]" >> $config
1608 $ echo "[acl.allow.branches]" >> $config
1617 $ echo "* = george" >> $config
1609 $ echo "* = george" >> $config
1618 $ do_push astro
1610 $ do_push astro
1619 Pushing as user astro
1611 Pushing as user astro
1620 hgrc = """
1612 hgrc = """
1621 [acl]
1613 [acl]
1622 sources = push
1614 sources = push
1623 [extensions]
1615 [extensions]
1624 [acl.allow.branches]
1616 [acl.allow.branches]
1625 * = george
1617 * = george
1626 """
1618 """
1627 pushing to ../b
1619 pushing to ../b
1628 query 1; heads
1620 query 1; heads
1629 searching for changes
1621 searching for changes
1630 all remote heads known locally
1622 all remote heads known locally
1631 4 changesets found
1623 4 changesets found
1632 list of changesets:
1624 list of changesets:
1633 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1625 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1634 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1626 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1635 911600dab2ae7a9baff75958b84fe606851ce955
1627 911600dab2ae7a9baff75958b84fe606851ce955
1636 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1628 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1637 adding changesets
1629 adding changesets
1638 bundling: 1/4 changesets (25.00%)
1630 bundling: 1/4 changesets (25.00%)
1639 bundling: 2/4 changesets (50.00%)
1631 bundling: 2/4 changesets (50.00%)
1640 bundling: 3/4 changesets (75.00%)
1632 bundling: 3/4 changesets (75.00%)
1641 bundling: 4/4 changesets (100.00%)
1633 bundling: 4/4 changesets (100.00%)
1642 bundling: 1/4 manifests (25.00%)
1634 bundling: 1/4 manifests (25.00%)
1643 bundling: 2/4 manifests (50.00%)
1635 bundling: 2/4 manifests (50.00%)
1644 bundling: 3/4 manifests (75.00%)
1636 bundling: 3/4 manifests (75.00%)
1645 bundling: 4/4 manifests (100.00%)
1637 bundling: 4/4 manifests (100.00%)
1646 bundling: abc.txt 1/4 files (25.00%)
1638 bundling: abc.txt 1/4 files (25.00%)
1647 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1639 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1648 bundling: foo/file.txt 3/4 files (75.00%)
1640 bundling: foo/file.txt 3/4 files (75.00%)
1649 bundling: quux/file.py 4/4 files (100.00%)
1641 bundling: quux/file.py 4/4 files (100.00%)
1650 changesets: 1 chunks
1642 changesets: 1 chunks
1651 add changeset ef1ea85a6374
1643 add changeset ef1ea85a6374
1652 changesets: 2 chunks
1644 changesets: 2 chunks
1653 add changeset f9cafe1212c8
1645 add changeset f9cafe1212c8
1654 changesets: 3 chunks
1646 changesets: 3 chunks
1655 add changeset 911600dab2ae
1647 add changeset 911600dab2ae
1656 changesets: 4 chunks
1648 changesets: 4 chunks
1657 add changeset e8fc755d4d82
1649 add changeset e8fc755d4d82
1658 adding manifests
1650 adding manifests
1659 manifests: 1/4 chunks (25.00%)
1651 manifests: 1/4 chunks (25.00%)
1660 manifests: 2/4 chunks (50.00%)
1652 manifests: 2/4 chunks (50.00%)
1661 manifests: 3/4 chunks (75.00%)
1653 manifests: 3/4 chunks (75.00%)
1662 manifests: 4/4 chunks (100.00%)
1654 manifests: 4/4 chunks (100.00%)
1663 adding file changes
1655 adding file changes
1664 adding abc.txt revisions
1656 adding abc.txt revisions
1665 files: 1/4 chunks (25.00%)
1657 files: 1/4 chunks (25.00%)
1666 adding foo/Bar/file.txt revisions
1658 adding foo/Bar/file.txt revisions
1667 files: 2/4 chunks (50.00%)
1659 files: 2/4 chunks (50.00%)
1668 adding foo/file.txt revisions
1660 adding foo/file.txt revisions
1669 files: 3/4 chunks (75.00%)
1661 files: 3/4 chunks (75.00%)
1670 adding quux/file.py revisions
1662 adding quux/file.py revisions
1671 files: 4/4 chunks (100.00%)
1663 files: 4/4 chunks (100.00%)
1672 added 4 changesets with 4 changes to 4 files (+1 heads)
1664 added 4 changesets with 4 changes to 4 files (+1 heads)
1673 calling hook pretxnchangegroup.acl: hgext.acl.hook
1665 calling hook pretxnchangegroup.acl: hgext.acl.hook
1674 acl: acl.allow.branches enabled, 0 entries for user astro
1666 acl: acl.allow.branches enabled, 0 entries for user astro
1675 acl: acl.deny.branches not enabled
1667 acl: acl.deny.branches not enabled
1676 acl: acl.allow not enabled
1668 acl: acl.allow not enabled
1677 acl: acl.deny not enabled
1669 acl: acl.deny not enabled
1678 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1670 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1679 transaction abort!
1671 transaction abort!
1680 rollback completed
1672 rollback completed
1681 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1673 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1682 no rollback information available
1674 no rollback information available
1683 2:fb35475503ef
1675 2:fb35475503ef
1684
1676
1685 $ do_push george
1677 $ do_push george
1686 Pushing as user george
1678 Pushing as user george
1687 hgrc = """
1679 hgrc = """
1688 [acl]
1680 [acl]
1689 sources = push
1681 sources = push
1690 [extensions]
1682 [extensions]
1691 [acl.allow.branches]
1683 [acl.allow.branches]
1692 * = george
1684 * = george
1693 """
1685 """
1694 pushing to ../b
1686 pushing to ../b
1695 query 1; heads
1687 query 1; heads
1696 searching for changes
1688 searching for changes
1697 all remote heads known locally
1689 all remote heads known locally
1698 4 changesets found
1690 4 changesets found
1699 list of changesets:
1691 list of changesets:
1700 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1692 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1701 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1693 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1702 911600dab2ae7a9baff75958b84fe606851ce955
1694 911600dab2ae7a9baff75958b84fe606851ce955
1703 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1695 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1704 adding changesets
1696 adding changesets
1705 bundling: 1/4 changesets (25.00%)
1697 bundling: 1/4 changesets (25.00%)
1706 bundling: 2/4 changesets (50.00%)
1698 bundling: 2/4 changesets (50.00%)
1707 bundling: 3/4 changesets (75.00%)
1699 bundling: 3/4 changesets (75.00%)
1708 bundling: 4/4 changesets (100.00%)
1700 bundling: 4/4 changesets (100.00%)
1709 bundling: 1/4 manifests (25.00%)
1701 bundling: 1/4 manifests (25.00%)
1710 bundling: 2/4 manifests (50.00%)
1702 bundling: 2/4 manifests (50.00%)
1711 bundling: 3/4 manifests (75.00%)
1703 bundling: 3/4 manifests (75.00%)
1712 bundling: 4/4 manifests (100.00%)
1704 bundling: 4/4 manifests (100.00%)
1713 bundling: abc.txt 1/4 files (25.00%)
1705 bundling: abc.txt 1/4 files (25.00%)
1714 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1706 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1715 bundling: foo/file.txt 3/4 files (75.00%)
1707 bundling: foo/file.txt 3/4 files (75.00%)
1716 bundling: quux/file.py 4/4 files (100.00%)
1708 bundling: quux/file.py 4/4 files (100.00%)
1717 changesets: 1 chunks
1709 changesets: 1 chunks
1718 add changeset ef1ea85a6374
1710 add changeset ef1ea85a6374
1719 changesets: 2 chunks
1711 changesets: 2 chunks
1720 add changeset f9cafe1212c8
1712 add changeset f9cafe1212c8
1721 changesets: 3 chunks
1713 changesets: 3 chunks
1722 add changeset 911600dab2ae
1714 add changeset 911600dab2ae
1723 changesets: 4 chunks
1715 changesets: 4 chunks
1724 add changeset e8fc755d4d82
1716 add changeset e8fc755d4d82
1725 adding manifests
1717 adding manifests
1726 manifests: 1/4 chunks (25.00%)
1718 manifests: 1/4 chunks (25.00%)
1727 manifests: 2/4 chunks (50.00%)
1719 manifests: 2/4 chunks (50.00%)
1728 manifests: 3/4 chunks (75.00%)
1720 manifests: 3/4 chunks (75.00%)
1729 manifests: 4/4 chunks (100.00%)
1721 manifests: 4/4 chunks (100.00%)
1730 adding file changes
1722 adding file changes
1731 adding abc.txt revisions
1723 adding abc.txt revisions
1732 files: 1/4 chunks (25.00%)
1724 files: 1/4 chunks (25.00%)
1733 adding foo/Bar/file.txt revisions
1725 adding foo/Bar/file.txt revisions
1734 files: 2/4 chunks (50.00%)
1726 files: 2/4 chunks (50.00%)
1735 adding foo/file.txt revisions
1727 adding foo/file.txt revisions
1736 files: 3/4 chunks (75.00%)
1728 files: 3/4 chunks (75.00%)
1737 adding quux/file.py revisions
1729 adding quux/file.py revisions
1738 files: 4/4 chunks (100.00%)
1730 files: 4/4 chunks (100.00%)
1739 added 4 changesets with 4 changes to 4 files (+1 heads)
1731 added 4 changesets with 4 changes to 4 files (+1 heads)
1740 calling hook pretxnchangegroup.acl: hgext.acl.hook
1732 calling hook pretxnchangegroup.acl: hgext.acl.hook
1741 acl: acl.allow.branches enabled, 1 entries for user george
1733 acl: acl.allow.branches enabled, 1 entries for user george
1742 acl: acl.deny.branches not enabled
1734 acl: acl.deny.branches not enabled
1743 acl: acl.allow not enabled
1735 acl: acl.allow not enabled
1744 acl: acl.deny not enabled
1736 acl: acl.deny not enabled
1745 acl: branch access granted: "ef1ea85a6374" on branch "default"
1737 acl: branch access granted: "ef1ea85a6374" on branch "default"
1746 acl: allowing changeset ef1ea85a6374
1738 acl: allowing changeset ef1ea85a6374
1747 acl: branch access granted: "f9cafe1212c8" on branch "default"
1739 acl: branch access granted: "f9cafe1212c8" on branch "default"
1748 acl: allowing changeset f9cafe1212c8
1740 acl: allowing changeset f9cafe1212c8
1749 acl: branch access granted: "911600dab2ae" on branch "default"
1741 acl: branch access granted: "911600dab2ae" on branch "default"
1750 acl: allowing changeset 911600dab2ae
1742 acl: allowing changeset 911600dab2ae
1751 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1743 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1752 acl: allowing changeset e8fc755d4d82
1744 acl: allowing changeset e8fc755d4d82
1753 updating the branch cache
1745 updating the branch cache
1754 checking for updated bookmarks
1746 checking for updated bookmarks
1755 repository tip rolled back to revision 2 (undo push)
1747 repository tip rolled back to revision 2 (undo push)
1756 working directory now based on revision 2
1757 2:fb35475503ef
1748 2:fb35475503ef
1758
1749
1759
1750
1760 Branch acl conflicting allow
1751 Branch acl conflicting allow
1761 asterisk ends up applying to all branches and allowing george to
1752 asterisk ends up applying to all branches and allowing george to
1762 push foobar into the remote
1753 push foobar into the remote
1763
1754
1764 $ init_config
1755 $ init_config
1765 $ echo "[acl.allow.branches]" >> $config
1756 $ echo "[acl.allow.branches]" >> $config
1766 $ echo "foobar = astro" >> $config
1757 $ echo "foobar = astro" >> $config
1767 $ echo "* = george" >> $config
1758 $ echo "* = george" >> $config
1768 $ do_push george
1759 $ do_push george
1769 Pushing as user george
1760 Pushing as user george
1770 hgrc = """
1761 hgrc = """
1771 [acl]
1762 [acl]
1772 sources = push
1763 sources = push
1773 [extensions]
1764 [extensions]
1774 [acl.allow.branches]
1765 [acl.allow.branches]
1775 foobar = astro
1766 foobar = astro
1776 * = george
1767 * = george
1777 """
1768 """
1778 pushing to ../b
1769 pushing to ../b
1779 query 1; heads
1770 query 1; heads
1780 searching for changes
1771 searching for changes
1781 all remote heads known locally
1772 all remote heads known locally
1782 invalidating branch cache (tip differs)
1773 invalidating branch cache (tip differs)
1783 4 changesets found
1774 4 changesets found
1784 list of changesets:
1775 list of changesets:
1785 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1776 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1786 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1777 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1787 911600dab2ae7a9baff75958b84fe606851ce955
1778 911600dab2ae7a9baff75958b84fe606851ce955
1788 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1779 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1789 adding changesets
1780 adding changesets
1790 bundling: 1/4 changesets (25.00%)
1781 bundling: 1/4 changesets (25.00%)
1791 bundling: 2/4 changesets (50.00%)
1782 bundling: 2/4 changesets (50.00%)
1792 bundling: 3/4 changesets (75.00%)
1783 bundling: 3/4 changesets (75.00%)
1793 bundling: 4/4 changesets (100.00%)
1784 bundling: 4/4 changesets (100.00%)
1794 bundling: 1/4 manifests (25.00%)
1785 bundling: 1/4 manifests (25.00%)
1795 bundling: 2/4 manifests (50.00%)
1786 bundling: 2/4 manifests (50.00%)
1796 bundling: 3/4 manifests (75.00%)
1787 bundling: 3/4 manifests (75.00%)
1797 bundling: 4/4 manifests (100.00%)
1788 bundling: 4/4 manifests (100.00%)
1798 bundling: abc.txt 1/4 files (25.00%)
1789 bundling: abc.txt 1/4 files (25.00%)
1799 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1790 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1800 bundling: foo/file.txt 3/4 files (75.00%)
1791 bundling: foo/file.txt 3/4 files (75.00%)
1801 bundling: quux/file.py 4/4 files (100.00%)
1792 bundling: quux/file.py 4/4 files (100.00%)
1802 changesets: 1 chunks
1793 changesets: 1 chunks
1803 add changeset ef1ea85a6374
1794 add changeset ef1ea85a6374
1804 changesets: 2 chunks
1795 changesets: 2 chunks
1805 add changeset f9cafe1212c8
1796 add changeset f9cafe1212c8
1806 changesets: 3 chunks
1797 changesets: 3 chunks
1807 add changeset 911600dab2ae
1798 add changeset 911600dab2ae
1808 changesets: 4 chunks
1799 changesets: 4 chunks
1809 add changeset e8fc755d4d82
1800 add changeset e8fc755d4d82
1810 adding manifests
1801 adding manifests
1811 manifests: 1/4 chunks (25.00%)
1802 manifests: 1/4 chunks (25.00%)
1812 manifests: 2/4 chunks (50.00%)
1803 manifests: 2/4 chunks (50.00%)
1813 manifests: 3/4 chunks (75.00%)
1804 manifests: 3/4 chunks (75.00%)
1814 manifests: 4/4 chunks (100.00%)
1805 manifests: 4/4 chunks (100.00%)
1815 adding file changes
1806 adding file changes
1816 adding abc.txt revisions
1807 adding abc.txt revisions
1817 files: 1/4 chunks (25.00%)
1808 files: 1/4 chunks (25.00%)
1818 adding foo/Bar/file.txt revisions
1809 adding foo/Bar/file.txt revisions
1819 files: 2/4 chunks (50.00%)
1810 files: 2/4 chunks (50.00%)
1820 adding foo/file.txt revisions
1811 adding foo/file.txt revisions
1821 files: 3/4 chunks (75.00%)
1812 files: 3/4 chunks (75.00%)
1822 adding quux/file.py revisions
1813 adding quux/file.py revisions
1823 files: 4/4 chunks (100.00%)
1814 files: 4/4 chunks (100.00%)
1824 added 4 changesets with 4 changes to 4 files (+1 heads)
1815 added 4 changesets with 4 changes to 4 files (+1 heads)
1825 calling hook pretxnchangegroup.acl: hgext.acl.hook
1816 calling hook pretxnchangegroup.acl: hgext.acl.hook
1826 acl: acl.allow.branches enabled, 1 entries for user george
1817 acl: acl.allow.branches enabled, 1 entries for user george
1827 acl: acl.deny.branches not enabled
1818 acl: acl.deny.branches not enabled
1828 acl: acl.allow not enabled
1819 acl: acl.allow not enabled
1829 acl: acl.deny not enabled
1820 acl: acl.deny not enabled
1830 acl: branch access granted: "ef1ea85a6374" on branch "default"
1821 acl: branch access granted: "ef1ea85a6374" on branch "default"
1831 acl: allowing changeset ef1ea85a6374
1822 acl: allowing changeset ef1ea85a6374
1832 acl: branch access granted: "f9cafe1212c8" on branch "default"
1823 acl: branch access granted: "f9cafe1212c8" on branch "default"
1833 acl: allowing changeset f9cafe1212c8
1824 acl: allowing changeset f9cafe1212c8
1834 acl: branch access granted: "911600dab2ae" on branch "default"
1825 acl: branch access granted: "911600dab2ae" on branch "default"
1835 acl: allowing changeset 911600dab2ae
1826 acl: allowing changeset 911600dab2ae
1836 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1827 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1837 acl: allowing changeset e8fc755d4d82
1828 acl: allowing changeset e8fc755d4d82
1838 updating the branch cache
1829 updating the branch cache
1839 checking for updated bookmarks
1830 checking for updated bookmarks
1840 repository tip rolled back to revision 2 (undo push)
1831 repository tip rolled back to revision 2 (undo push)
1841 working directory now based on revision 2
1842 2:fb35475503ef
1832 2:fb35475503ef
1843
1833
1844 Branch acl conflicting deny
1834 Branch acl conflicting deny
1845
1835
1846 $ init_config
1836 $ init_config
1847 $ echo "[acl.deny.branches]" >> $config
1837 $ echo "[acl.deny.branches]" >> $config
1848 $ echo "foobar = astro" >> $config
1838 $ echo "foobar = astro" >> $config
1849 $ echo "default = astro" >> $config
1839 $ echo "default = astro" >> $config
1850 $ echo "* = george" >> $config
1840 $ echo "* = george" >> $config
1851 $ do_push george
1841 $ do_push george
1852 Pushing as user george
1842 Pushing as user george
1853 hgrc = """
1843 hgrc = """
1854 [acl]
1844 [acl]
1855 sources = push
1845 sources = push
1856 [extensions]
1846 [extensions]
1857 [acl.deny.branches]
1847 [acl.deny.branches]
1858 foobar = astro
1848 foobar = astro
1859 default = astro
1849 default = astro
1860 * = george
1850 * = george
1861 """
1851 """
1862 pushing to ../b
1852 pushing to ../b
1863 query 1; heads
1853 query 1; heads
1864 searching for changes
1854 searching for changes
1865 all remote heads known locally
1855 all remote heads known locally
1866 invalidating branch cache (tip differs)
1856 invalidating branch cache (tip differs)
1867 4 changesets found
1857 4 changesets found
1868 list of changesets:
1858 list of changesets:
1869 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1859 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1870 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1860 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1871 911600dab2ae7a9baff75958b84fe606851ce955
1861 911600dab2ae7a9baff75958b84fe606851ce955
1872 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1862 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1873 adding changesets
1863 adding changesets
1874 bundling: 1/4 changesets (25.00%)
1864 bundling: 1/4 changesets (25.00%)
1875 bundling: 2/4 changesets (50.00%)
1865 bundling: 2/4 changesets (50.00%)
1876 bundling: 3/4 changesets (75.00%)
1866 bundling: 3/4 changesets (75.00%)
1877 bundling: 4/4 changesets (100.00%)
1867 bundling: 4/4 changesets (100.00%)
1878 bundling: 1/4 manifests (25.00%)
1868 bundling: 1/4 manifests (25.00%)
1879 bundling: 2/4 manifests (50.00%)
1869 bundling: 2/4 manifests (50.00%)
1880 bundling: 3/4 manifests (75.00%)
1870 bundling: 3/4 manifests (75.00%)
1881 bundling: 4/4 manifests (100.00%)
1871 bundling: 4/4 manifests (100.00%)
1882 bundling: abc.txt 1/4 files (25.00%)
1872 bundling: abc.txt 1/4 files (25.00%)
1883 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1873 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1884 bundling: foo/file.txt 3/4 files (75.00%)
1874 bundling: foo/file.txt 3/4 files (75.00%)
1885 bundling: quux/file.py 4/4 files (100.00%)
1875 bundling: quux/file.py 4/4 files (100.00%)
1886 changesets: 1 chunks
1876 changesets: 1 chunks
1887 add changeset ef1ea85a6374
1877 add changeset ef1ea85a6374
1888 changesets: 2 chunks
1878 changesets: 2 chunks
1889 add changeset f9cafe1212c8
1879 add changeset f9cafe1212c8
1890 changesets: 3 chunks
1880 changesets: 3 chunks
1891 add changeset 911600dab2ae
1881 add changeset 911600dab2ae
1892 changesets: 4 chunks
1882 changesets: 4 chunks
1893 add changeset e8fc755d4d82
1883 add changeset e8fc755d4d82
1894 adding manifests
1884 adding manifests
1895 manifests: 1/4 chunks (25.00%)
1885 manifests: 1/4 chunks (25.00%)
1896 manifests: 2/4 chunks (50.00%)
1886 manifests: 2/4 chunks (50.00%)
1897 manifests: 3/4 chunks (75.00%)
1887 manifests: 3/4 chunks (75.00%)
1898 manifests: 4/4 chunks (100.00%)
1888 manifests: 4/4 chunks (100.00%)
1899 adding file changes
1889 adding file changes
1900 adding abc.txt revisions
1890 adding abc.txt revisions
1901 files: 1/4 chunks (25.00%)
1891 files: 1/4 chunks (25.00%)
1902 adding foo/Bar/file.txt revisions
1892 adding foo/Bar/file.txt revisions
1903 files: 2/4 chunks (50.00%)
1893 files: 2/4 chunks (50.00%)
1904 adding foo/file.txt revisions
1894 adding foo/file.txt revisions
1905 files: 3/4 chunks (75.00%)
1895 files: 3/4 chunks (75.00%)
1906 adding quux/file.py revisions
1896 adding quux/file.py revisions
1907 files: 4/4 chunks (100.00%)
1897 files: 4/4 chunks (100.00%)
1908 added 4 changesets with 4 changes to 4 files (+1 heads)
1898 added 4 changesets with 4 changes to 4 files (+1 heads)
1909 calling hook pretxnchangegroup.acl: hgext.acl.hook
1899 calling hook pretxnchangegroup.acl: hgext.acl.hook
1910 acl: acl.allow.branches not enabled
1900 acl: acl.allow.branches not enabled
1911 acl: acl.deny.branches enabled, 1 entries for user george
1901 acl: acl.deny.branches enabled, 1 entries for user george
1912 acl: acl.allow not enabled
1902 acl: acl.allow not enabled
1913 acl: acl.deny not enabled
1903 acl: acl.deny not enabled
1914 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
1904 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
1915 transaction abort!
1905 transaction abort!
1916 rollback completed
1906 rollback completed
1917 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
1907 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
1918 no rollback information available
1908 no rollback information available
1919 2:fb35475503ef
1909 2:fb35475503ef
1920
1910
@@ -1,330 +1,326 b''
1 $ hg init test
1 $ hg init test
2 $ cd test
2 $ cd test
3 $ hg unbundle $TESTDIR/bundles/remote.hg
3 $ hg unbundle $TESTDIR/bundles/remote.hg
4 adding changesets
4 adding changesets
5 adding manifests
5 adding manifests
6 adding file changes
6 adding file changes
7 added 9 changesets with 7 changes to 4 files (+1 heads)
7 added 9 changesets with 7 changes to 4 files (+1 heads)
8 (run 'hg heads' to see heads, 'hg merge' to merge)
8 (run 'hg heads' to see heads, 'hg merge' to merge)
9 $ hg up tip
9 $ hg up tip
10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 $ cd ..
11 $ cd ..
12
12
13 $ for i in 0 1 2 3 4 5 6 7 8; do
13 $ for i in 0 1 2 3 4 5 6 7 8; do
14 > mkdir test-"$i"
14 > mkdir test-"$i"
15 > hg --cwd test-"$i" init
15 > hg --cwd test-"$i" init
16 > hg -R test bundle -r "$i" test-"$i".hg test-"$i"
16 > hg -R test bundle -r "$i" test-"$i".hg test-"$i"
17 > cd test-"$i"
17 > cd test-"$i"
18 > hg unbundle ../test-"$i".hg
18 > hg unbundle ../test-"$i".hg
19 > hg verify
19 > hg verify
20 > hg tip -q
20 > hg tip -q
21 > cd ..
21 > cd ..
22 > done
22 > done
23 searching for changes
23 searching for changes
24 1 changesets found
24 1 changesets found
25 adding changesets
25 adding changesets
26 adding manifests
26 adding manifests
27 adding file changes
27 adding file changes
28 added 1 changesets with 1 changes to 1 files
28 added 1 changesets with 1 changes to 1 files
29 (run 'hg update' to get a working copy)
29 (run 'hg update' to get a working copy)
30 checking changesets
30 checking changesets
31 checking manifests
31 checking manifests
32 crosschecking files in changesets and manifests
32 crosschecking files in changesets and manifests
33 checking files
33 checking files
34 1 files, 1 changesets, 1 total revisions
34 1 files, 1 changesets, 1 total revisions
35 0:bfaf4b5cbf01
35 0:bfaf4b5cbf01
36 searching for changes
36 searching for changes
37 2 changesets found
37 2 changesets found
38 adding changesets
38 adding changesets
39 adding manifests
39 adding manifests
40 adding file changes
40 adding file changes
41 added 2 changesets with 2 changes to 1 files
41 added 2 changesets with 2 changes to 1 files
42 (run 'hg update' to get a working copy)
42 (run 'hg update' to get a working copy)
43 checking changesets
43 checking changesets
44 checking manifests
44 checking manifests
45 crosschecking files in changesets and manifests
45 crosschecking files in changesets and manifests
46 checking files
46 checking files
47 1 files, 2 changesets, 2 total revisions
47 1 files, 2 changesets, 2 total revisions
48 1:21f32785131f
48 1:21f32785131f
49 searching for changes
49 searching for changes
50 3 changesets found
50 3 changesets found
51 adding changesets
51 adding changesets
52 adding manifests
52 adding manifests
53 adding file changes
53 adding file changes
54 added 3 changesets with 3 changes to 1 files
54 added 3 changesets with 3 changes to 1 files
55 (run 'hg update' to get a working copy)
55 (run 'hg update' to get a working copy)
56 checking changesets
56 checking changesets
57 checking manifests
57 checking manifests
58 crosschecking files in changesets and manifests
58 crosschecking files in changesets and manifests
59 checking files
59 checking files
60 1 files, 3 changesets, 3 total revisions
60 1 files, 3 changesets, 3 total revisions
61 2:4ce51a113780
61 2:4ce51a113780
62 searching for changes
62 searching for changes
63 4 changesets found
63 4 changesets found
64 adding changesets
64 adding changesets
65 adding manifests
65 adding manifests
66 adding file changes
66 adding file changes
67 added 4 changesets with 4 changes to 1 files
67 added 4 changesets with 4 changes to 1 files
68 (run 'hg update' to get a working copy)
68 (run 'hg update' to get a working copy)
69 checking changesets
69 checking changesets
70 checking manifests
70 checking manifests
71 crosschecking files in changesets and manifests
71 crosschecking files in changesets and manifests
72 checking files
72 checking files
73 1 files, 4 changesets, 4 total revisions
73 1 files, 4 changesets, 4 total revisions
74 3:93ee6ab32777
74 3:93ee6ab32777
75 searching for changes
75 searching for changes
76 2 changesets found
76 2 changesets found
77 adding changesets
77 adding changesets
78 adding manifests
78 adding manifests
79 adding file changes
79 adding file changes
80 added 2 changesets with 2 changes to 1 files
80 added 2 changesets with 2 changes to 1 files
81 (run 'hg update' to get a working copy)
81 (run 'hg update' to get a working copy)
82 checking changesets
82 checking changesets
83 checking manifests
83 checking manifests
84 crosschecking files in changesets and manifests
84 crosschecking files in changesets and manifests
85 checking files
85 checking files
86 1 files, 2 changesets, 2 total revisions
86 1 files, 2 changesets, 2 total revisions
87 1:c70afb1ee985
87 1:c70afb1ee985
88 searching for changes
88 searching for changes
89 3 changesets found
89 3 changesets found
90 adding changesets
90 adding changesets
91 adding manifests
91 adding manifests
92 adding file changes
92 adding file changes
93 added 3 changesets with 3 changes to 1 files
93 added 3 changesets with 3 changes to 1 files
94 (run 'hg update' to get a working copy)
94 (run 'hg update' to get a working copy)
95 checking changesets
95 checking changesets
96 checking manifests
96 checking manifests
97 crosschecking files in changesets and manifests
97 crosschecking files in changesets and manifests
98 checking files
98 checking files
99 1 files, 3 changesets, 3 total revisions
99 1 files, 3 changesets, 3 total revisions
100 2:f03ae5a9b979
100 2:f03ae5a9b979
101 searching for changes
101 searching for changes
102 4 changesets found
102 4 changesets found
103 adding changesets
103 adding changesets
104 adding manifests
104 adding manifests
105 adding file changes
105 adding file changes
106 added 4 changesets with 5 changes to 2 files
106 added 4 changesets with 5 changes to 2 files
107 (run 'hg update' to get a working copy)
107 (run 'hg update' to get a working copy)
108 checking changesets
108 checking changesets
109 checking manifests
109 checking manifests
110 crosschecking files in changesets and manifests
110 crosschecking files in changesets and manifests
111 checking files
111 checking files
112 2 files, 4 changesets, 5 total revisions
112 2 files, 4 changesets, 5 total revisions
113 3:095cb14b1b4d
113 3:095cb14b1b4d
114 searching for changes
114 searching for changes
115 5 changesets found
115 5 changesets found
116 adding changesets
116 adding changesets
117 adding manifests
117 adding manifests
118 adding file changes
118 adding file changes
119 added 5 changesets with 6 changes to 3 files
119 added 5 changesets with 6 changes to 3 files
120 (run 'hg update' to get a working copy)
120 (run 'hg update' to get a working copy)
121 checking changesets
121 checking changesets
122 checking manifests
122 checking manifests
123 crosschecking files in changesets and manifests
123 crosschecking files in changesets and manifests
124 checking files
124 checking files
125 3 files, 5 changesets, 6 total revisions
125 3 files, 5 changesets, 6 total revisions
126 4:faa2e4234c7a
126 4:faa2e4234c7a
127 searching for changes
127 searching for changes
128 5 changesets found
128 5 changesets found
129 adding changesets
129 adding changesets
130 adding manifests
130 adding manifests
131 adding file changes
131 adding file changes
132 added 5 changesets with 5 changes to 2 files
132 added 5 changesets with 5 changes to 2 files
133 (run 'hg update' to get a working copy)
133 (run 'hg update' to get a working copy)
134 checking changesets
134 checking changesets
135 checking manifests
135 checking manifests
136 crosschecking files in changesets and manifests
136 crosschecking files in changesets and manifests
137 checking files
137 checking files
138 2 files, 5 changesets, 5 total revisions
138 2 files, 5 changesets, 5 total revisions
139 4:916f1afdef90
139 4:916f1afdef90
140 $ cd test-8
140 $ cd test-8
141 $ hg pull ../test-7
141 $ hg pull ../test-7
142 pulling from ../test-7
142 pulling from ../test-7
143 searching for changes
143 searching for changes
144 adding changesets
144 adding changesets
145 adding manifests
145 adding manifests
146 adding file changes
146 adding file changes
147 added 4 changesets with 2 changes to 3 files (+1 heads)
147 added 4 changesets with 2 changes to 3 files (+1 heads)
148 (run 'hg heads' to see heads, 'hg merge' to merge)
148 (run 'hg heads' to see heads, 'hg merge' to merge)
149 $ hg verify
149 $ hg verify
150 checking changesets
150 checking changesets
151 checking manifests
151 checking manifests
152 crosschecking files in changesets and manifests
152 crosschecking files in changesets and manifests
153 checking files
153 checking files
154 4 files, 9 changesets, 7 total revisions
154 4 files, 9 changesets, 7 total revisions
155 $ hg rollback
155 $ hg rollback
156 repository tip rolled back to revision 4 (undo pull)
156 repository tip rolled back to revision 4 (undo pull)
157 working directory now based on revision -1
158 $ cd ..
157 $ cd ..
159
158
160 should fail
159 should fail
161
160
162 $ hg -R test bundle --base 2 -r tip test-bundle-branch1.hg test-3
161 $ hg -R test bundle --base 2 -r tip test-bundle-branch1.hg test-3
163 abort: --base is incompatible with specifying a destination
162 abort: --base is incompatible with specifying a destination
164 [255]
163 [255]
165 $ hg -R test bundle -r tip test-bundle-branch1.hg
164 $ hg -R test bundle -r tip test-bundle-branch1.hg
166 abort: repository default-push not found!
165 abort: repository default-push not found!
167 [255]
166 [255]
168
167
169 $ hg -R test bundle --base 2 -r tip test-bundle-branch1.hg
168 $ hg -R test bundle --base 2 -r tip test-bundle-branch1.hg
170 2 changesets found
169 2 changesets found
171 $ hg -R test bundle --base 2 -r 7 test-bundle-branch2.hg
170 $ hg -R test bundle --base 2 -r 7 test-bundle-branch2.hg
172 4 changesets found
171 4 changesets found
173 $ hg -R test bundle --base 2 test-bundle-all.hg
172 $ hg -R test bundle --base 2 test-bundle-all.hg
174 6 changesets found
173 6 changesets found
175 $ hg -R test bundle --base 3 -r tip test-bundle-should-fail.hg
174 $ hg -R test bundle --base 3 -r tip test-bundle-should-fail.hg
176 1 changesets found
175 1 changesets found
177
176
178 empty bundle
177 empty bundle
179
178
180 $ hg -R test bundle --base 7 --base 8 test-bundle-empty.hg
179 $ hg -R test bundle --base 7 --base 8 test-bundle-empty.hg
181 no changes found
180 no changes found
182 [1]
181 [1]
183
182
184 issue76 msg2163
183 issue76 msg2163
185
184
186 $ hg -R test bundle --base 3 -r 3 -r 3 test-bundle-cset-3.hg
185 $ hg -R test bundle --base 3 -r 3 -r 3 test-bundle-cset-3.hg
187 no changes found
186 no changes found
188 [1]
187 [1]
189
188
190 Issue1910: 'hg bundle --base $head' does not exclude $head from
189 Issue1910: 'hg bundle --base $head' does not exclude $head from
191 result
190 result
192
191
193 $ hg -R test bundle --base 7 test-bundle-cset-7.hg
192 $ hg -R test bundle --base 7 test-bundle-cset-7.hg
194 4 changesets found
193 4 changesets found
195
194
196 $ hg clone test-2 test-9
195 $ hg clone test-2 test-9
197 updating to branch default
196 updating to branch default
198 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 $ cd test-9
198 $ cd test-9
200
199
201 revision 2
200 revision 2
202
201
203 $ hg tip -q
202 $ hg tip -q
204 2:4ce51a113780
203 2:4ce51a113780
205 $ hg unbundle ../test-bundle-should-fail.hg
204 $ hg unbundle ../test-bundle-should-fail.hg
206 adding changesets
205 adding changesets
207 transaction abort!
206 transaction abort!
208 rollback completed
207 rollback completed
209 abort: 00changelog.i@93ee6ab32777: unknown parent!
208 abort: 00changelog.i@93ee6ab32777: unknown parent!
210 [255]
209 [255]
211
210
212 revision 2
211 revision 2
213
212
214 $ hg tip -q
213 $ hg tip -q
215 2:4ce51a113780
214 2:4ce51a113780
216 $ hg unbundle ../test-bundle-all.hg
215 $ hg unbundle ../test-bundle-all.hg
217 adding changesets
216 adding changesets
218 adding manifests
217 adding manifests
219 adding file changes
218 adding file changes
220 added 6 changesets with 4 changes to 4 files (+1 heads)
219 added 6 changesets with 4 changes to 4 files (+1 heads)
221 (run 'hg heads' to see heads, 'hg merge' to merge)
220 (run 'hg heads' to see heads, 'hg merge' to merge)
222
221
223 revision 8
222 revision 8
224
223
225 $ hg tip -q
224 $ hg tip -q
226 8:916f1afdef90
225 8:916f1afdef90
227 $ hg verify
226 $ hg verify
228 checking changesets
227 checking changesets
229 checking manifests
228 checking manifests
230 crosschecking files in changesets and manifests
229 crosschecking files in changesets and manifests
231 checking files
230 checking files
232 4 files, 9 changesets, 7 total revisions
231 4 files, 9 changesets, 7 total revisions
233 $ hg rollback
232 $ hg rollback
234 repository tip rolled back to revision 2 (undo unbundle)
233 repository tip rolled back to revision 2 (undo unbundle)
235 working directory now based on revision 2
236
234
237 revision 2
235 revision 2
238
236
239 $ hg tip -q
237 $ hg tip -q
240 2:4ce51a113780
238 2:4ce51a113780
241 $ hg unbundle ../test-bundle-branch1.hg
239 $ hg unbundle ../test-bundle-branch1.hg
242 adding changesets
240 adding changesets
243 adding manifests
241 adding manifests
244 adding file changes
242 adding file changes
245 added 2 changesets with 2 changes to 2 files
243 added 2 changesets with 2 changes to 2 files
246 (run 'hg update' to get a working copy)
244 (run 'hg update' to get a working copy)
247
245
248 revision 4
246 revision 4
249
247
250 $ hg tip -q
248 $ hg tip -q
251 4:916f1afdef90
249 4:916f1afdef90
252 $ hg verify
250 $ hg verify
253 checking changesets
251 checking changesets
254 checking manifests
252 checking manifests
255 crosschecking files in changesets and manifests
253 crosschecking files in changesets and manifests
256 checking files
254 checking files
257 2 files, 5 changesets, 5 total revisions
255 2 files, 5 changesets, 5 total revisions
258 $ hg rollback
256 $ hg rollback
259 repository tip rolled back to revision 2 (undo unbundle)
257 repository tip rolled back to revision 2 (undo unbundle)
260 working directory now based on revision 2
261 $ hg unbundle ../test-bundle-branch2.hg
258 $ hg unbundle ../test-bundle-branch2.hg
262 adding changesets
259 adding changesets
263 adding manifests
260 adding manifests
264 adding file changes
261 adding file changes
265 added 4 changesets with 3 changes to 3 files (+1 heads)
262 added 4 changesets with 3 changes to 3 files (+1 heads)
266 (run 'hg heads' to see heads, 'hg merge' to merge)
263 (run 'hg heads' to see heads, 'hg merge' to merge)
267
264
268 revision 6
265 revision 6
269
266
270 $ hg tip -q
267 $ hg tip -q
271 6:faa2e4234c7a
268 6:faa2e4234c7a
272 $ hg verify
269 $ hg verify
273 checking changesets
270 checking changesets
274 checking manifests
271 checking manifests
275 crosschecking files in changesets and manifests
272 crosschecking files in changesets and manifests
276 checking files
273 checking files
277 3 files, 7 changesets, 6 total revisions
274 3 files, 7 changesets, 6 total revisions
278 $ hg rollback
275 $ hg rollback
279 repository tip rolled back to revision 2 (undo unbundle)
276 repository tip rolled back to revision 2 (undo unbundle)
280 working directory now based on revision 2
281 $ hg unbundle ../test-bundle-cset-7.hg
277 $ hg unbundle ../test-bundle-cset-7.hg
282 adding changesets
278 adding changesets
283 adding manifests
279 adding manifests
284 adding file changes
280 adding file changes
285 added 2 changesets with 2 changes to 2 files
281 added 2 changesets with 2 changes to 2 files
286 (run 'hg update' to get a working copy)
282 (run 'hg update' to get a working copy)
287
283
288 revision 4
284 revision 4
289
285
290 $ hg tip -q
286 $ hg tip -q
291 4:916f1afdef90
287 4:916f1afdef90
292 $ hg verify
288 $ hg verify
293 checking changesets
289 checking changesets
294 checking manifests
290 checking manifests
295 crosschecking files in changesets and manifests
291 crosschecking files in changesets and manifests
296 checking files
292 checking files
297 2 files, 5 changesets, 5 total revisions
293 2 files, 5 changesets, 5 total revisions
298
294
299 $ cd ../test
295 $ cd ../test
300 $ hg merge 7
296 $ hg merge 7
301 note: possible conflict - afile was renamed multiple times to:
297 note: possible conflict - afile was renamed multiple times to:
302 anotherfile
298 anotherfile
303 adifferentfile
299 adifferentfile
304 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
305 (branch merge, don't forget to commit)
301 (branch merge, don't forget to commit)
306 $ hg ci -m merge
302 $ hg ci -m merge
307 $ cd ..
303 $ cd ..
308 $ hg -R test bundle --base 2 test-bundle-head.hg
304 $ hg -R test bundle --base 2 test-bundle-head.hg
309 7 changesets found
305 7 changesets found
310 $ hg clone test-2 test-10
306 $ hg clone test-2 test-10
311 updating to branch default
307 updating to branch default
312 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
313 $ cd test-10
309 $ cd test-10
314 $ hg unbundle ../test-bundle-head.hg
310 $ hg unbundle ../test-bundle-head.hg
315 adding changesets
311 adding changesets
316 adding manifests
312 adding manifests
317 adding file changes
313 adding file changes
318 added 7 changesets with 4 changes to 4 files
314 added 7 changesets with 4 changes to 4 files
319 (run 'hg update' to get a working copy)
315 (run 'hg update' to get a working copy)
320
316
321 revision 9
317 revision 9
322
318
323 $ hg tip -q
319 $ hg tip -q
324 9:03fc0b0e347c
320 9:03fc0b0e347c
325 $ hg verify
321 $ hg verify
326 checking changesets
322 checking changesets
327 checking manifests
323 checking manifests
328 crosschecking files in changesets and manifests
324 crosschecking files in changesets and manifests
329 checking files
325 checking files
330 4 files, 10 changesets, 7 total revisions
326 4 files, 10 changesets, 7 total revisions
@@ -1,577 +1,574 b''
1 Setting up test
1 Setting up test
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo 0 > afile
5 $ echo 0 > afile
6 $ hg add afile
6 $ hg add afile
7 $ hg commit -m "0.0"
7 $ hg commit -m "0.0"
8 $ echo 1 >> afile
8 $ echo 1 >> afile
9 $ hg commit -m "0.1"
9 $ hg commit -m "0.1"
10 $ echo 2 >> afile
10 $ echo 2 >> afile
11 $ hg commit -m "0.2"
11 $ hg commit -m "0.2"
12 $ echo 3 >> afile
12 $ echo 3 >> afile
13 $ hg commit -m "0.3"
13 $ hg commit -m "0.3"
14 $ hg update -C 0
14 $ hg update -C 0
15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 $ echo 1 >> afile
16 $ echo 1 >> afile
17 $ hg commit -m "1.1"
17 $ hg commit -m "1.1"
18 created new head
18 created new head
19 $ echo 2 >> afile
19 $ echo 2 >> afile
20 $ hg commit -m "1.2"
20 $ hg commit -m "1.2"
21 $ echo "a line" > fred
21 $ echo "a line" > fred
22 $ echo 3 >> afile
22 $ echo 3 >> afile
23 $ hg add fred
23 $ hg add fred
24 $ hg commit -m "1.3"
24 $ hg commit -m "1.3"
25 $ hg mv afile adifferentfile
25 $ hg mv afile adifferentfile
26 $ hg commit -m "1.3m"
26 $ hg commit -m "1.3m"
27 $ hg update -C 3
27 $ hg update -C 3
28 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
28 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
29 $ hg mv afile anotherfile
29 $ hg mv afile anotherfile
30 $ hg commit -m "0.3m"
30 $ hg commit -m "0.3m"
31 $ hg verify
31 $ hg verify
32 checking changesets
32 checking changesets
33 checking manifests
33 checking manifests
34 crosschecking files in changesets and manifests
34 crosschecking files in changesets and manifests
35 checking files
35 checking files
36 4 files, 9 changesets, 7 total revisions
36 4 files, 9 changesets, 7 total revisions
37 $ cd ..
37 $ cd ..
38 $ hg init empty
38 $ hg init empty
39
39
40 Bundle --all
40 Bundle --all
41
41
42 $ hg -R test bundle --all all.hg
42 $ hg -R test bundle --all all.hg
43 9 changesets found
43 9 changesets found
44
44
45 Bundle test to full.hg
45 Bundle test to full.hg
46
46
47 $ hg -R test bundle full.hg empty
47 $ hg -R test bundle full.hg empty
48 searching for changes
48 searching for changes
49 9 changesets found
49 9 changesets found
50
50
51 Unbundle full.hg in test
51 Unbundle full.hg in test
52
52
53 $ hg -R test unbundle full.hg
53 $ hg -R test unbundle full.hg
54 adding changesets
54 adding changesets
55 adding manifests
55 adding manifests
56 adding file changes
56 adding file changes
57 added 0 changesets with 0 changes to 4 files
57 added 0 changesets with 0 changes to 4 files
58 (run 'hg update' to get a working copy)
58 (run 'hg update' to get a working copy)
59
59
60 Verify empty
60 Verify empty
61
61
62 $ hg -R empty heads
62 $ hg -R empty heads
63 [1]
63 [1]
64 $ hg -R empty verify
64 $ hg -R empty verify
65 checking changesets
65 checking changesets
66 checking manifests
66 checking manifests
67 crosschecking files in changesets and manifests
67 crosschecking files in changesets and manifests
68 checking files
68 checking files
69 0 files, 0 changesets, 0 total revisions
69 0 files, 0 changesets, 0 total revisions
70
70
71 Pull full.hg into test (using --cwd)
71 Pull full.hg into test (using --cwd)
72
72
73 $ hg --cwd test pull ../full.hg
73 $ hg --cwd test pull ../full.hg
74 pulling from ../full.hg
74 pulling from ../full.hg
75 searching for changes
75 searching for changes
76 no changes found
76 no changes found
77
77
78 Pull full.hg into empty (using --cwd)
78 Pull full.hg into empty (using --cwd)
79
79
80 $ hg --cwd empty pull ../full.hg
80 $ hg --cwd empty pull ../full.hg
81 pulling from ../full.hg
81 pulling from ../full.hg
82 requesting all changes
82 requesting all changes
83 adding changesets
83 adding changesets
84 adding manifests
84 adding manifests
85 adding file changes
85 adding file changes
86 added 9 changesets with 7 changes to 4 files (+1 heads)
86 added 9 changesets with 7 changes to 4 files (+1 heads)
87 (run 'hg heads' to see heads, 'hg merge' to merge)
87 (run 'hg heads' to see heads, 'hg merge' to merge)
88
88
89 Rollback empty
89 Rollback empty
90
90
91 $ hg -R empty rollback
91 $ hg -R empty rollback
92 repository tip rolled back to revision -1 (undo pull)
92 repository tip rolled back to revision -1 (undo pull)
93 working directory now based on revision -1
94
93
95 Pull full.hg into empty again (using --cwd)
94 Pull full.hg into empty again (using --cwd)
96
95
97 $ hg --cwd empty pull ../full.hg
96 $ hg --cwd empty pull ../full.hg
98 pulling from ../full.hg
97 pulling from ../full.hg
99 requesting all changes
98 requesting all changes
100 adding changesets
99 adding changesets
101 adding manifests
100 adding manifests
102 adding file changes
101 adding file changes
103 added 9 changesets with 7 changes to 4 files (+1 heads)
102 added 9 changesets with 7 changes to 4 files (+1 heads)
104 (run 'hg heads' to see heads, 'hg merge' to merge)
103 (run 'hg heads' to see heads, 'hg merge' to merge)
105
104
106 Pull full.hg into test (using -R)
105 Pull full.hg into test (using -R)
107
106
108 $ hg -R test pull full.hg
107 $ hg -R test pull full.hg
109 pulling from full.hg
108 pulling from full.hg
110 searching for changes
109 searching for changes
111 no changes found
110 no changes found
112
111
113 Pull full.hg into empty (using -R)
112 Pull full.hg into empty (using -R)
114
113
115 $ hg -R empty pull full.hg
114 $ hg -R empty pull full.hg
116 pulling from full.hg
115 pulling from full.hg
117 searching for changes
116 searching for changes
118 no changes found
117 no changes found
119
118
120 Rollback empty
119 Rollback empty
121
120
122 $ hg -R empty rollback
121 $ hg -R empty rollback
123 repository tip rolled back to revision -1 (undo pull)
122 repository tip rolled back to revision -1 (undo pull)
124 working directory now based on revision -1
125
123
126 Pull full.hg into empty again (using -R)
124 Pull full.hg into empty again (using -R)
127
125
128 $ hg -R empty pull full.hg
126 $ hg -R empty pull full.hg
129 pulling from full.hg
127 pulling from full.hg
130 requesting all changes
128 requesting all changes
131 adding changesets
129 adding changesets
132 adding manifests
130 adding manifests
133 adding file changes
131 adding file changes
134 added 9 changesets with 7 changes to 4 files (+1 heads)
132 added 9 changesets with 7 changes to 4 files (+1 heads)
135 (run 'hg heads' to see heads, 'hg merge' to merge)
133 (run 'hg heads' to see heads, 'hg merge' to merge)
136
134
137 Log -R full.hg in fresh empty
135 Log -R full.hg in fresh empty
138
136
139 $ rm -r empty
137 $ rm -r empty
140 $ hg init empty
138 $ hg init empty
141 $ cd empty
139 $ cd empty
142 $ hg -R bundle://../full.hg log
140 $ hg -R bundle://../full.hg log
143 changeset: 8:aa35859c02ea
141 changeset: 8:aa35859c02ea
144 tag: tip
142 tag: tip
145 parent: 3:eebf5a27f8ca
143 parent: 3:eebf5a27f8ca
146 user: test
144 user: test
147 date: Thu Jan 01 00:00:00 1970 +0000
145 date: Thu Jan 01 00:00:00 1970 +0000
148 summary: 0.3m
146 summary: 0.3m
149
147
150 changeset: 7:a6a34bfa0076
148 changeset: 7:a6a34bfa0076
151 user: test
149 user: test
152 date: Thu Jan 01 00:00:00 1970 +0000
150 date: Thu Jan 01 00:00:00 1970 +0000
153 summary: 1.3m
151 summary: 1.3m
154
152
155 changeset: 6:7373c1169842
153 changeset: 6:7373c1169842
156 user: test
154 user: test
157 date: Thu Jan 01 00:00:00 1970 +0000
155 date: Thu Jan 01 00:00:00 1970 +0000
158 summary: 1.3
156 summary: 1.3
159
157
160 changeset: 5:1bb50a9436a7
158 changeset: 5:1bb50a9436a7
161 user: test
159 user: test
162 date: Thu Jan 01 00:00:00 1970 +0000
160 date: Thu Jan 01 00:00:00 1970 +0000
163 summary: 1.2
161 summary: 1.2
164
162
165 changeset: 4:095197eb4973
163 changeset: 4:095197eb4973
166 parent: 0:f9ee2f85a263
164 parent: 0:f9ee2f85a263
167 user: test
165 user: test
168 date: Thu Jan 01 00:00:00 1970 +0000
166 date: Thu Jan 01 00:00:00 1970 +0000
169 summary: 1.1
167 summary: 1.1
170
168
171 changeset: 3:eebf5a27f8ca
169 changeset: 3:eebf5a27f8ca
172 user: test
170 user: test
173 date: Thu Jan 01 00:00:00 1970 +0000
171 date: Thu Jan 01 00:00:00 1970 +0000
174 summary: 0.3
172 summary: 0.3
175
173
176 changeset: 2:e38ba6f5b7e0
174 changeset: 2:e38ba6f5b7e0
177 user: test
175 user: test
178 date: Thu Jan 01 00:00:00 1970 +0000
176 date: Thu Jan 01 00:00:00 1970 +0000
179 summary: 0.2
177 summary: 0.2
180
178
181 changeset: 1:34c2bf6b0626
179 changeset: 1:34c2bf6b0626
182 user: test
180 user: test
183 date: Thu Jan 01 00:00:00 1970 +0000
181 date: Thu Jan 01 00:00:00 1970 +0000
184 summary: 0.1
182 summary: 0.1
185
183
186 changeset: 0:f9ee2f85a263
184 changeset: 0:f9ee2f85a263
187 user: test
185 user: test
188 date: Thu Jan 01 00:00:00 1970 +0000
186 date: Thu Jan 01 00:00:00 1970 +0000
189 summary: 0.0
187 summary: 0.0
190
188
191 Make sure bundlerepo doesn't leak tempfiles (issue2491)
189 Make sure bundlerepo doesn't leak tempfiles (issue2491)
192
190
193 $ ls .hg
191 $ ls .hg
194 00changelog.i
192 00changelog.i
195 cache
193 cache
196 requires
194 requires
197 store
195 store
198
196
199 Pull ../full.hg into empty (with hook)
197 Pull ../full.hg into empty (with hook)
200
198
201 $ echo '[hooks]' >> .hg/hgrc
199 $ echo '[hooks]' >> .hg/hgrc
202 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
200 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
203
201
204 doesn't work (yet ?)
202 doesn't work (yet ?)
205
203
206 hg -R bundle://../full.hg verify
204 hg -R bundle://../full.hg verify
207
205
208 $ hg pull bundle://../full.hg
206 $ hg pull bundle://../full.hg
209 pulling from bundle:../full.hg
207 pulling from bundle:../full.hg
210 requesting all changes
208 requesting all changes
211 adding changesets
209 adding changesets
212 adding manifests
210 adding manifests
213 adding file changes
211 adding file changes
214 added 9 changesets with 7 changes to 4 files (+1 heads)
212 added 9 changesets with 7 changes to 4 files (+1 heads)
215 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_SOURCE=pull HG_URL=bundle:../full.hg
213 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_SOURCE=pull HG_URL=bundle:../full.hg
216 (run 'hg heads' to see heads, 'hg merge' to merge)
214 (run 'hg heads' to see heads, 'hg merge' to merge)
217
215
218 Rollback empty
216 Rollback empty
219
217
220 $ hg rollback
218 $ hg rollback
221 repository tip rolled back to revision -1 (undo pull)
219 repository tip rolled back to revision -1 (undo pull)
222 working directory now based on revision -1
223 $ cd ..
220 $ cd ..
224
221
225 Log -R bundle:empty+full.hg
222 Log -R bundle:empty+full.hg
226
223
227 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
224 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
228 8 7 6 5 4 3 2 1 0
225 8 7 6 5 4 3 2 1 0
229
226
230 Pull full.hg into empty again (using -R; with hook)
227 Pull full.hg into empty again (using -R; with hook)
231
228
232 $ hg -R empty pull full.hg
229 $ hg -R empty pull full.hg
233 pulling from full.hg
230 pulling from full.hg
234 requesting all changes
231 requesting all changes
235 adding changesets
232 adding changesets
236 adding manifests
233 adding manifests
237 adding file changes
234 adding file changes
238 added 9 changesets with 7 changes to 4 files (+1 heads)
235 added 9 changesets with 7 changes to 4 files (+1 heads)
239 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_SOURCE=pull HG_URL=bundle:empty+full.hg
236 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_SOURCE=pull HG_URL=bundle:empty+full.hg
240 (run 'hg heads' to see heads, 'hg merge' to merge)
237 (run 'hg heads' to see heads, 'hg merge' to merge)
241
238
242 Create partial clones
239 Create partial clones
243
240
244 $ rm -r empty
241 $ rm -r empty
245 $ hg init empty
242 $ hg init empty
246 $ hg clone -r 3 test partial
243 $ hg clone -r 3 test partial
247 adding changesets
244 adding changesets
248 adding manifests
245 adding manifests
249 adding file changes
246 adding file changes
250 added 4 changesets with 4 changes to 1 files
247 added 4 changesets with 4 changes to 1 files
251 updating to branch default
248 updating to branch default
252 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
249 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 $ hg clone partial partial2
250 $ hg clone partial partial2
254 updating to branch default
251 updating to branch default
255 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
256 $ cd partial
253 $ cd partial
257
254
258 Log -R full.hg in partial
255 Log -R full.hg in partial
259
256
260 $ hg -R bundle://../full.hg log
257 $ hg -R bundle://../full.hg log
261 changeset: 8:aa35859c02ea
258 changeset: 8:aa35859c02ea
262 tag: tip
259 tag: tip
263 parent: 3:eebf5a27f8ca
260 parent: 3:eebf5a27f8ca
264 user: test
261 user: test
265 date: Thu Jan 01 00:00:00 1970 +0000
262 date: Thu Jan 01 00:00:00 1970 +0000
266 summary: 0.3m
263 summary: 0.3m
267
264
268 changeset: 7:a6a34bfa0076
265 changeset: 7:a6a34bfa0076
269 user: test
266 user: test
270 date: Thu Jan 01 00:00:00 1970 +0000
267 date: Thu Jan 01 00:00:00 1970 +0000
271 summary: 1.3m
268 summary: 1.3m
272
269
273 changeset: 6:7373c1169842
270 changeset: 6:7373c1169842
274 user: test
271 user: test
275 date: Thu Jan 01 00:00:00 1970 +0000
272 date: Thu Jan 01 00:00:00 1970 +0000
276 summary: 1.3
273 summary: 1.3
277
274
278 changeset: 5:1bb50a9436a7
275 changeset: 5:1bb50a9436a7
279 user: test
276 user: test
280 date: Thu Jan 01 00:00:00 1970 +0000
277 date: Thu Jan 01 00:00:00 1970 +0000
281 summary: 1.2
278 summary: 1.2
282
279
283 changeset: 4:095197eb4973
280 changeset: 4:095197eb4973
284 parent: 0:f9ee2f85a263
281 parent: 0:f9ee2f85a263
285 user: test
282 user: test
286 date: Thu Jan 01 00:00:00 1970 +0000
283 date: Thu Jan 01 00:00:00 1970 +0000
287 summary: 1.1
284 summary: 1.1
288
285
289 changeset: 3:eebf5a27f8ca
286 changeset: 3:eebf5a27f8ca
290 user: test
287 user: test
291 date: Thu Jan 01 00:00:00 1970 +0000
288 date: Thu Jan 01 00:00:00 1970 +0000
292 summary: 0.3
289 summary: 0.3
293
290
294 changeset: 2:e38ba6f5b7e0
291 changeset: 2:e38ba6f5b7e0
295 user: test
292 user: test
296 date: Thu Jan 01 00:00:00 1970 +0000
293 date: Thu Jan 01 00:00:00 1970 +0000
297 summary: 0.2
294 summary: 0.2
298
295
299 changeset: 1:34c2bf6b0626
296 changeset: 1:34c2bf6b0626
300 user: test
297 user: test
301 date: Thu Jan 01 00:00:00 1970 +0000
298 date: Thu Jan 01 00:00:00 1970 +0000
302 summary: 0.1
299 summary: 0.1
303
300
304 changeset: 0:f9ee2f85a263
301 changeset: 0:f9ee2f85a263
305 user: test
302 user: test
306 date: Thu Jan 01 00:00:00 1970 +0000
303 date: Thu Jan 01 00:00:00 1970 +0000
307 summary: 0.0
304 summary: 0.0
308
305
309
306
310 Incoming full.hg in partial
307 Incoming full.hg in partial
311
308
312 $ hg incoming bundle://../full.hg
309 $ hg incoming bundle://../full.hg
313 comparing with bundle:../full.hg
310 comparing with bundle:../full.hg
314 searching for changes
311 searching for changes
315 changeset: 4:095197eb4973
312 changeset: 4:095197eb4973
316 parent: 0:f9ee2f85a263
313 parent: 0:f9ee2f85a263
317 user: test
314 user: test
318 date: Thu Jan 01 00:00:00 1970 +0000
315 date: Thu Jan 01 00:00:00 1970 +0000
319 summary: 1.1
316 summary: 1.1
320
317
321 changeset: 5:1bb50a9436a7
318 changeset: 5:1bb50a9436a7
322 user: test
319 user: test
323 date: Thu Jan 01 00:00:00 1970 +0000
320 date: Thu Jan 01 00:00:00 1970 +0000
324 summary: 1.2
321 summary: 1.2
325
322
326 changeset: 6:7373c1169842
323 changeset: 6:7373c1169842
327 user: test
324 user: test
328 date: Thu Jan 01 00:00:00 1970 +0000
325 date: Thu Jan 01 00:00:00 1970 +0000
329 summary: 1.3
326 summary: 1.3
330
327
331 changeset: 7:a6a34bfa0076
328 changeset: 7:a6a34bfa0076
332 user: test
329 user: test
333 date: Thu Jan 01 00:00:00 1970 +0000
330 date: Thu Jan 01 00:00:00 1970 +0000
334 summary: 1.3m
331 summary: 1.3m
335
332
336 changeset: 8:aa35859c02ea
333 changeset: 8:aa35859c02ea
337 tag: tip
334 tag: tip
338 parent: 3:eebf5a27f8ca
335 parent: 3:eebf5a27f8ca
339 user: test
336 user: test
340 date: Thu Jan 01 00:00:00 1970 +0000
337 date: Thu Jan 01 00:00:00 1970 +0000
341 summary: 0.3m
338 summary: 0.3m
342
339
343
340
344 Outgoing -R full.hg vs partial2 in partial
341 Outgoing -R full.hg vs partial2 in partial
345
342
346 $ hg -R bundle://../full.hg outgoing ../partial2
343 $ hg -R bundle://../full.hg outgoing ../partial2
347 comparing with ../partial2
344 comparing with ../partial2
348 searching for changes
345 searching for changes
349 changeset: 4:095197eb4973
346 changeset: 4:095197eb4973
350 parent: 0:f9ee2f85a263
347 parent: 0:f9ee2f85a263
351 user: test
348 user: test
352 date: Thu Jan 01 00:00:00 1970 +0000
349 date: Thu Jan 01 00:00:00 1970 +0000
353 summary: 1.1
350 summary: 1.1
354
351
355 changeset: 5:1bb50a9436a7
352 changeset: 5:1bb50a9436a7
356 user: test
353 user: test
357 date: Thu Jan 01 00:00:00 1970 +0000
354 date: Thu Jan 01 00:00:00 1970 +0000
358 summary: 1.2
355 summary: 1.2
359
356
360 changeset: 6:7373c1169842
357 changeset: 6:7373c1169842
361 user: test
358 user: test
362 date: Thu Jan 01 00:00:00 1970 +0000
359 date: Thu Jan 01 00:00:00 1970 +0000
363 summary: 1.3
360 summary: 1.3
364
361
365 changeset: 7:a6a34bfa0076
362 changeset: 7:a6a34bfa0076
366 user: test
363 user: test
367 date: Thu Jan 01 00:00:00 1970 +0000
364 date: Thu Jan 01 00:00:00 1970 +0000
368 summary: 1.3m
365 summary: 1.3m
369
366
370 changeset: 8:aa35859c02ea
367 changeset: 8:aa35859c02ea
371 tag: tip
368 tag: tip
372 parent: 3:eebf5a27f8ca
369 parent: 3:eebf5a27f8ca
373 user: test
370 user: test
374 date: Thu Jan 01 00:00:00 1970 +0000
371 date: Thu Jan 01 00:00:00 1970 +0000
375 summary: 0.3m
372 summary: 0.3m
376
373
377
374
378 Outgoing -R does-not-exist.hg vs partial2 in partial
375 Outgoing -R does-not-exist.hg vs partial2 in partial
379
376
380 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
377 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
381 abort: No such file or directory: ../does-not-exist.hg
378 abort: No such file or directory: ../does-not-exist.hg
382 [255]
379 [255]
383 $ cd ..
380 $ cd ..
384
381
385 Direct clone from bundle (all-history)
382 Direct clone from bundle (all-history)
386
383
387 $ hg clone full.hg full-clone
384 $ hg clone full.hg full-clone
388 requesting all changes
385 requesting all changes
389 adding changesets
386 adding changesets
390 adding manifests
387 adding manifests
391 adding file changes
388 adding file changes
392 added 9 changesets with 7 changes to 4 files (+1 heads)
389 added 9 changesets with 7 changes to 4 files (+1 heads)
393 updating to branch default
390 updating to branch default
394 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 $ hg -R full-clone heads
392 $ hg -R full-clone heads
396 changeset: 8:aa35859c02ea
393 changeset: 8:aa35859c02ea
397 tag: tip
394 tag: tip
398 parent: 3:eebf5a27f8ca
395 parent: 3:eebf5a27f8ca
399 user: test
396 user: test
400 date: Thu Jan 01 00:00:00 1970 +0000
397 date: Thu Jan 01 00:00:00 1970 +0000
401 summary: 0.3m
398 summary: 0.3m
402
399
403 changeset: 7:a6a34bfa0076
400 changeset: 7:a6a34bfa0076
404 user: test
401 user: test
405 date: Thu Jan 01 00:00:00 1970 +0000
402 date: Thu Jan 01 00:00:00 1970 +0000
406 summary: 1.3m
403 summary: 1.3m
407
404
408 $ rm -r full-clone
405 $ rm -r full-clone
409
406
410 When cloning from a non-copiable repository into '', do not
407 When cloning from a non-copiable repository into '', do not
411 recurse infinitely (issue 2528)
408 recurse infinitely (issue 2528)
412
409
413 $ hg clone full.hg ''
410 $ hg clone full.hg ''
414 abort: No such file or directory
411 abort: No such file or directory
415 [255]
412 [255]
416
413
417 test for http://mercurial.selenic.com/bts/issue216
414 test for http://mercurial.selenic.com/bts/issue216
418
415
419 Unbundle incremental bundles into fresh empty in one go
416 Unbundle incremental bundles into fresh empty in one go
420
417
421 $ rm -r empty
418 $ rm -r empty
422 $ hg init empty
419 $ hg init empty
423 $ hg -R test bundle --base null -r 0 ../0.hg
420 $ hg -R test bundle --base null -r 0 ../0.hg
424 1 changesets found
421 1 changesets found
425 $ hg -R test bundle --base 0 -r 1 ../1.hg
422 $ hg -R test bundle --base 0 -r 1 ../1.hg
426 1 changesets found
423 1 changesets found
427 $ hg -R empty unbundle -u ../0.hg ../1.hg
424 $ hg -R empty unbundle -u ../0.hg ../1.hg
428 adding changesets
425 adding changesets
429 adding manifests
426 adding manifests
430 adding file changes
427 adding file changes
431 added 1 changesets with 1 changes to 1 files
428 added 1 changesets with 1 changes to 1 files
432 adding changesets
429 adding changesets
433 adding manifests
430 adding manifests
434 adding file changes
431 adding file changes
435 added 1 changesets with 1 changes to 1 files
432 added 1 changesets with 1 changes to 1 files
436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
433 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437
434
438 test for 540d1059c802
435 test for 540d1059c802
439
436
440 test for 540d1059c802
437 test for 540d1059c802
441
438
442 $ hg init orig
439 $ hg init orig
443 $ cd orig
440 $ cd orig
444 $ echo foo > foo
441 $ echo foo > foo
445 $ hg add foo
442 $ hg add foo
446 $ hg ci -m 'add foo'
443 $ hg ci -m 'add foo'
447
444
448 $ hg clone . ../copy
445 $ hg clone . ../copy
449 updating to branch default
446 updating to branch default
450 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
447 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
451 $ hg tag foo
448 $ hg tag foo
452
449
453 $ cd ../copy
450 $ cd ../copy
454 $ echo >> foo
451 $ echo >> foo
455 $ hg ci -m 'change foo'
452 $ hg ci -m 'change foo'
456 $ hg bundle ../bundle.hg ../orig
453 $ hg bundle ../bundle.hg ../orig
457 searching for changes
454 searching for changes
458 1 changesets found
455 1 changesets found
459
456
460 $ cd ../orig
457 $ cd ../orig
461 $ hg incoming ../bundle.hg
458 $ hg incoming ../bundle.hg
462 comparing with ../bundle.hg
459 comparing with ../bundle.hg
463 searching for changes
460 searching for changes
464 changeset: 2:ed1b79f46b9a
461 changeset: 2:ed1b79f46b9a
465 tag: tip
462 tag: tip
466 parent: 0:bbd179dfa0a7
463 parent: 0:bbd179dfa0a7
467 user: test
464 user: test
468 date: Thu Jan 01 00:00:00 1970 +0000
465 date: Thu Jan 01 00:00:00 1970 +0000
469 summary: change foo
466 summary: change foo
470
467
471 $ cd ..
468 $ cd ..
472
469
473 test bundle with # in the filename (issue2154):
470 test bundle with # in the filename (issue2154):
474
471
475 $ cp bundle.hg 'test#bundle.hg'
472 $ cp bundle.hg 'test#bundle.hg'
476 $ cd orig
473 $ cd orig
477 $ hg incoming '../test#bundle.hg'
474 $ hg incoming '../test#bundle.hg'
478 comparing with ../test
475 comparing with ../test
479 abort: unknown revision 'bundle.hg'!
476 abort: unknown revision 'bundle.hg'!
480 [255]
477 [255]
481
478
482 note that percent encoding is not handled:
479 note that percent encoding is not handled:
483
480
484 $ hg incoming ../test%23bundle.hg
481 $ hg incoming ../test%23bundle.hg
485 abort: repository ../test%23bundle.hg not found!
482 abort: repository ../test%23bundle.hg not found!
486 [255]
483 [255]
487 $ cd ..
484 $ cd ..
488
485
489 test for http://mercurial.selenic.com/bts/issue1144
486 test for http://mercurial.selenic.com/bts/issue1144
490
487
491 test that verify bundle does not traceback
488 test that verify bundle does not traceback
492
489
493 partial history bundle, fails w/ unkown parent
490 partial history bundle, fails w/ unkown parent
494
491
495 $ hg -R bundle.hg verify
492 $ hg -R bundle.hg verify
496 abort: 00changelog.i@bbd179dfa0a7: unknown parent!
493 abort: 00changelog.i@bbd179dfa0a7: unknown parent!
497 [255]
494 [255]
498
495
499 full history bundle, refuses to verify non-local repo
496 full history bundle, refuses to verify non-local repo
500
497
501 $ hg -R all.hg verify
498 $ hg -R all.hg verify
502 abort: cannot verify bundle or remote repos
499 abort: cannot verify bundle or remote repos
503 [255]
500 [255]
504
501
505 but, regular verify must continue to work
502 but, regular verify must continue to work
506
503
507 $ hg -R orig verify
504 $ hg -R orig verify
508 checking changesets
505 checking changesets
509 checking manifests
506 checking manifests
510 crosschecking files in changesets and manifests
507 crosschecking files in changesets and manifests
511 checking files
508 checking files
512 2 files, 2 changesets, 2 total revisions
509 2 files, 2 changesets, 2 total revisions
513
510
514 diff against bundle
511 diff against bundle
515
512
516 $ hg init b
513 $ hg init b
517 $ cd b
514 $ cd b
518 $ hg -R ../all.hg diff -r tip
515 $ hg -R ../all.hg diff -r tip
519 diff -r aa35859c02ea anotherfile
516 diff -r aa35859c02ea anotherfile
520 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
517 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
521 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
518 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
522 @@ -1,4 +0,0 @@
519 @@ -1,4 +0,0 @@
523 -0
520 -0
524 -1
521 -1
525 -2
522 -2
526 -3
523 -3
527 $ cd ..
524 $ cd ..
528
525
529 bundle single branch
526 bundle single branch
530
527
531 $ hg init branchy
528 $ hg init branchy
532 $ cd branchy
529 $ cd branchy
533 $ echo a >a
530 $ echo a >a
534 $ hg ci -Ama
531 $ hg ci -Ama
535 adding a
532 adding a
536 $ echo b >b
533 $ echo b >b
537 $ hg ci -Amb
534 $ hg ci -Amb
538 adding b
535 adding b
539 $ echo b1 >b1
536 $ echo b1 >b1
540 $ hg ci -Amb1
537 $ hg ci -Amb1
541 adding b1
538 adding b1
542 $ hg up 0
539 $ hg up 0
543 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
540 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
544 $ echo c >c
541 $ echo c >c
545 $ hg ci -Amc
542 $ hg ci -Amc
546 adding c
543 adding c
547 created new head
544 created new head
548 $ echo c1 >c1
545 $ echo c1 >c1
549 $ hg ci -Amc1
546 $ hg ci -Amc1
550 adding c1
547 adding c1
551 $ hg clone -q .#tip part
548 $ hg clone -q .#tip part
552
549
553 == bundling via incoming
550 == bundling via incoming
554
551
555 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
552 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
556 comparing with .
553 comparing with .
557 searching for changes
554 searching for changes
558 d2ae7f538514cd87c17547b0de4cea71fe1af9fb
555 d2ae7f538514cd87c17547b0de4cea71fe1af9fb
559 5ece8e77363e2b5269e27c66828b72da29e4341a
556 5ece8e77363e2b5269e27c66828b72da29e4341a
560
557
561 == bundling
558 == bundling
562
559
563 $ hg bundle bundle.hg part --debug
560 $ hg bundle bundle.hg part --debug
564 query 1; heads
561 query 1; heads
565 searching for changes
562 searching for changes
566 all remote heads known locally
563 all remote heads known locally
567 2 changesets found
564 2 changesets found
568 list of changesets:
565 list of changesets:
569 d2ae7f538514cd87c17547b0de4cea71fe1af9fb
566 d2ae7f538514cd87c17547b0de4cea71fe1af9fb
570 5ece8e77363e2b5269e27c66828b72da29e4341a
567 5ece8e77363e2b5269e27c66828b72da29e4341a
571 bundling: 1/2 changesets (50.00%)
568 bundling: 1/2 changesets (50.00%)
572 bundling: 2/2 changesets (100.00%)
569 bundling: 2/2 changesets (100.00%)
573 bundling: 1/2 manifests (50.00%)
570 bundling: 1/2 manifests (50.00%)
574 bundling: 2/2 manifests (100.00%)
571 bundling: 2/2 manifests (100.00%)
575 bundling: b 1/2 files (50.00%)
572 bundling: b 1/2 files (50.00%)
576 bundling: b1 2/2 files (100.00%)
573 bundling: b1 2/2 files (100.00%)
577
574
@@ -1,461 +1,460 b''
1
1
2 $ "$TESTDIR/hghave" cvs || exit 80
2 $ "$TESTDIR/hghave" cvs || exit 80
3 $ cvscall()
3 $ cvscall()
4 > {
4 > {
5 > cvs -f "$@"
5 > cvs -f "$@"
6 > }
6 > }
7 $ hgcat()
7 $ hgcat()
8 > {
8 > {
9 > hg --cwd src-hg cat -r tip "$1"
9 > hg --cwd src-hg cat -r tip "$1"
10 > }
10 > }
11 $ echo "[extensions]" >> $HGRCPATH
11 $ echo "[extensions]" >> $HGRCPATH
12 $ echo "convert = " >> $HGRCPATH
12 $ echo "convert = " >> $HGRCPATH
13 $ echo "graphlog = " >> $HGRCPATH
13 $ echo "graphlog = " >> $HGRCPATH
14 $ cat > cvshooks.py <<EOF
14 $ cat > cvshooks.py <<EOF
15 > def cvslog(ui,repo,hooktype,log):
15 > def cvslog(ui,repo,hooktype,log):
16 > print "%s hook: %d entries"%(hooktype,len(log))
16 > print "%s hook: %d entries"%(hooktype,len(log))
17 >
17 >
18 > def cvschangesets(ui,repo,hooktype,changesets):
18 > def cvschangesets(ui,repo,hooktype,changesets):
19 > print "%s hook: %d changesets"%(hooktype,len(changesets))
19 > print "%s hook: %d changesets"%(hooktype,len(changesets))
20 > EOF
20 > EOF
21 $ hookpath=`pwd`
21 $ hookpath=`pwd`
22 $ echo "[hooks]" >> $HGRCPATH
22 $ echo "[hooks]" >> $HGRCPATH
23 $ echo "cvslog=python:$hookpath/cvshooks.py:cvslog" >> $HGRCPATH
23 $ echo "cvslog=python:$hookpath/cvshooks.py:cvslog" >> $HGRCPATH
24 $ echo "cvschangesets=python:$hookpath/cvshooks.py:cvschangesets" >> $HGRCPATH
24 $ echo "cvschangesets=python:$hookpath/cvshooks.py:cvschangesets" >> $HGRCPATH
25
25
26 create cvs repository
26 create cvs repository
27
27
28 $ mkdir cvsrepo
28 $ mkdir cvsrepo
29 $ cd cvsrepo
29 $ cd cvsrepo
30 $ CVSROOT=`pwd`
30 $ CVSROOT=`pwd`
31 $ export CVSROOT
31 $ export CVSROOT
32 $ CVS_OPTIONS=-f
32 $ CVS_OPTIONS=-f
33 $ export CVS_OPTIONS
33 $ export CVS_OPTIONS
34 $ cd ..
34 $ cd ..
35 $ cvscall -q -d "$CVSROOT" init
35 $ cvscall -q -d "$CVSROOT" init
36
36
37 create source directory
37 create source directory
38
38
39 $ mkdir src-temp
39 $ mkdir src-temp
40 $ cd src-temp
40 $ cd src-temp
41 $ echo a > a
41 $ echo a > a
42 $ mkdir b
42 $ mkdir b
43 $ cd b
43 $ cd b
44 $ echo c > c
44 $ echo c > c
45 $ cd ..
45 $ cd ..
46
46
47 import source directory
47 import source directory
48
48
49 $ cvscall -q import -m import src INITIAL start
49 $ cvscall -q import -m import src INITIAL start
50 N src/a
50 N src/a
51 N src/b/c
51 N src/b/c
52
52
53 No conflicts created by this import
53 No conflicts created by this import
54
54
55 $ cd ..
55 $ cd ..
56
56
57 checkout source directory
57 checkout source directory
58
58
59 $ cvscall -q checkout src
59 $ cvscall -q checkout src
60 U src/a
60 U src/a
61 U src/b/c
61 U src/b/c
62
62
63 commit a new revision changing b/c
63 commit a new revision changing b/c
64
64
65 $ cd src
65 $ cd src
66 $ sleep 1
66 $ sleep 1
67 $ echo c >> b/c
67 $ echo c >> b/c
68 $ cvscall -q commit -mci0 . | grep '<--'
68 $ cvscall -q commit -mci0 . | grep '<--'
69 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
69 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
70 $ cd ..
70 $ cd ..
71
71
72 convert fresh repo
72 convert fresh repo
73
73
74 $ hg convert src src-hg
74 $ hg convert src src-hg
75 initializing destination src-hg repository
75 initializing destination src-hg repository
76 connecting to $TESTTMP/cvsrepo
76 connecting to $TESTTMP/cvsrepo
77 scanning source...
77 scanning source...
78 collecting CVS rlog
78 collecting CVS rlog
79 5 log entries
79 5 log entries
80 cvslog hook: 5 entries
80 cvslog hook: 5 entries
81 creating changesets
81 creating changesets
82 3 changeset entries
82 3 changeset entries
83 cvschangesets hook: 3 changesets
83 cvschangesets hook: 3 changesets
84 sorting...
84 sorting...
85 converting...
85 converting...
86 2 Initial revision
86 2 Initial revision
87 1 import
87 1 import
88 0 ci0
88 0 ci0
89 updating tags
89 updating tags
90 $ hgcat a
90 $ hgcat a
91 a
91 a
92 $ hgcat b/c
92 $ hgcat b/c
93 c
93 c
94 c
94 c
95
95
96 convert fresh repo with --filemap
96 convert fresh repo with --filemap
97
97
98 $ echo include b/c > filemap
98 $ echo include b/c > filemap
99 $ hg convert --filemap filemap src src-filemap
99 $ hg convert --filemap filemap src src-filemap
100 initializing destination src-filemap repository
100 initializing destination src-filemap repository
101 connecting to $TESTTMP/cvsrepo
101 connecting to $TESTTMP/cvsrepo
102 scanning source...
102 scanning source...
103 collecting CVS rlog
103 collecting CVS rlog
104 5 log entries
104 5 log entries
105 cvslog hook: 5 entries
105 cvslog hook: 5 entries
106 creating changesets
106 creating changesets
107 3 changeset entries
107 3 changeset entries
108 cvschangesets hook: 3 changesets
108 cvschangesets hook: 3 changesets
109 sorting...
109 sorting...
110 converting...
110 converting...
111 2 Initial revision
111 2 Initial revision
112 1 import
112 1 import
113 filtering out empty revision
113 filtering out empty revision
114 repository tip rolled back to revision 0 (undo commit)
114 repository tip rolled back to revision 0 (undo commit)
115 working directory now based on revision -1
116 0 ci0
115 0 ci0
117 updating tags
116 updating tags
118 $ hgcat b/c
117 $ hgcat b/c
119 c
118 c
120 c
119 c
121 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
120 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
122 2 update tags files: .hgtags
121 2 update tags files: .hgtags
123 1 ci0 files: b/c
122 1 ci0 files: b/c
124 0 Initial revision files: b/c
123 0 Initial revision files: b/c
125
124
126 convert full repository (issue1649)
125 convert full repository (issue1649)
127
126
128 $ cvscall -q -d "$CVSROOT" checkout -d srcfull "." | grep -v CVSROOT
127 $ cvscall -q -d "$CVSROOT" checkout -d srcfull "." | grep -v CVSROOT
129 U srcfull/src/a
128 U srcfull/src/a
130 U srcfull/src/b/c
129 U srcfull/src/b/c
131 $ ls srcfull
130 $ ls srcfull
132 CVS
131 CVS
133 CVSROOT
132 CVSROOT
134 src
133 src
135 $ hg convert srcfull srcfull-hg \
134 $ hg convert srcfull srcfull-hg \
136 > | grep -v 'log entries' | grep -v 'hook:' \
135 > | grep -v 'log entries' | grep -v 'hook:' \
137 > | grep -v '^[0-3] .*' # filter instable changeset order
136 > | grep -v '^[0-3] .*' # filter instable changeset order
138 initializing destination srcfull-hg repository
137 initializing destination srcfull-hg repository
139 connecting to $TESTTMP/cvsrepo
138 connecting to $TESTTMP/cvsrepo
140 scanning source...
139 scanning source...
141 collecting CVS rlog
140 collecting CVS rlog
142 creating changesets
141 creating changesets
143 4 changeset entries
142 4 changeset entries
144 sorting...
143 sorting...
145 converting...
144 converting...
146 updating tags
145 updating tags
147 $ hg cat -r tip srcfull-hg/src/a
146 $ hg cat -r tip srcfull-hg/src/a
148 a
147 a
149 $ hg cat -r tip srcfull-hg/src/b/c
148 $ hg cat -r tip srcfull-hg/src/b/c
150 c
149 c
151 c
150 c
152
151
153 commit new file revisions
152 commit new file revisions
154
153
155 $ cd src
154 $ cd src
156 $ echo a >> a
155 $ echo a >> a
157 $ echo c >> b/c
156 $ echo c >> b/c
158 $ cvscall -q commit -mci1 . | grep '<--'
157 $ cvscall -q commit -mci1 . | grep '<--'
159 $TESTTMP/cvsrepo/src/a,v <-- a
158 $TESTTMP/cvsrepo/src/a,v <-- a
160 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
159 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
161 $ cd ..
160 $ cd ..
162
161
163 convert again
162 convert again
164
163
165 $ hg convert src src-hg
164 $ hg convert src src-hg
166 connecting to $TESTTMP/cvsrepo
165 connecting to $TESTTMP/cvsrepo
167 scanning source...
166 scanning source...
168 collecting CVS rlog
167 collecting CVS rlog
169 7 log entries
168 7 log entries
170 cvslog hook: 7 entries
169 cvslog hook: 7 entries
171 creating changesets
170 creating changesets
172 4 changeset entries
171 4 changeset entries
173 cvschangesets hook: 4 changesets
172 cvschangesets hook: 4 changesets
174 sorting...
173 sorting...
175 converting...
174 converting...
176 0 ci1
175 0 ci1
177 $ hgcat a
176 $ hgcat a
178 a
177 a
179 a
178 a
180 $ hgcat b/c
179 $ hgcat b/c
181 c
180 c
182 c
181 c
183 c
182 c
184
183
185 convert again with --filemap
184 convert again with --filemap
186
185
187 $ hg convert --filemap filemap src src-filemap
186 $ hg convert --filemap filemap src src-filemap
188 connecting to $TESTTMP/cvsrepo
187 connecting to $TESTTMP/cvsrepo
189 scanning source...
188 scanning source...
190 collecting CVS rlog
189 collecting CVS rlog
191 7 log entries
190 7 log entries
192 cvslog hook: 7 entries
191 cvslog hook: 7 entries
193 creating changesets
192 creating changesets
194 4 changeset entries
193 4 changeset entries
195 cvschangesets hook: 4 changesets
194 cvschangesets hook: 4 changesets
196 sorting...
195 sorting...
197 converting...
196 converting...
198 0 ci1
197 0 ci1
199 $ hgcat b/c
198 $ hgcat b/c
200 c
199 c
201 c
200 c
202 c
201 c
203 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
202 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
204 3 ci1 files: b/c
203 3 ci1 files: b/c
205 2 update tags files: .hgtags
204 2 update tags files: .hgtags
206 1 ci0 files: b/c
205 1 ci0 files: b/c
207 0 Initial revision files: b/c
206 0 Initial revision files: b/c
208
207
209 commit branch
208 commit branch
210
209
211 $ cd src
210 $ cd src
212 $ cvs -q update -r1.1 b/c
211 $ cvs -q update -r1.1 b/c
213 U b/c
212 U b/c
214 $ cvs -q tag -b branch
213 $ cvs -q tag -b branch
215 T a
214 T a
216 T b/c
215 T b/c
217 $ cvs -q update -r branch > /dev/null
216 $ cvs -q update -r branch > /dev/null
218 $ echo d >> b/c
217 $ echo d >> b/c
219 $ cvs -q commit -mci2 . | grep '<--'
218 $ cvs -q commit -mci2 . | grep '<--'
220 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
219 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
221 $ cd ..
220 $ cd ..
222
221
223 convert again
222 convert again
224
223
225 $ hg convert src src-hg
224 $ hg convert src src-hg
226 connecting to $TESTTMP/cvsrepo
225 connecting to $TESTTMP/cvsrepo
227 scanning source...
226 scanning source...
228 collecting CVS rlog
227 collecting CVS rlog
229 8 log entries
228 8 log entries
230 cvslog hook: 8 entries
229 cvslog hook: 8 entries
231 creating changesets
230 creating changesets
232 5 changeset entries
231 5 changeset entries
233 cvschangesets hook: 5 changesets
232 cvschangesets hook: 5 changesets
234 sorting...
233 sorting...
235 converting...
234 converting...
236 0 ci2
235 0 ci2
237 $ hgcat b/c
236 $ hgcat b/c
238 c
237 c
239 d
238 d
240
239
241 convert again with --filemap
240 convert again with --filemap
242
241
243 $ hg convert --filemap filemap src src-filemap
242 $ hg convert --filemap filemap src src-filemap
244 connecting to $TESTTMP/cvsrepo
243 connecting to $TESTTMP/cvsrepo
245 scanning source...
244 scanning source...
246 collecting CVS rlog
245 collecting CVS rlog
247 8 log entries
246 8 log entries
248 cvslog hook: 8 entries
247 cvslog hook: 8 entries
249 creating changesets
248 creating changesets
250 5 changeset entries
249 5 changeset entries
251 cvschangesets hook: 5 changesets
250 cvschangesets hook: 5 changesets
252 sorting...
251 sorting...
253 converting...
252 converting...
254 0 ci2
253 0 ci2
255 $ hgcat b/c
254 $ hgcat b/c
256 c
255 c
257 d
256 d
258 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
257 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
259 4 ci2 files: b/c
258 4 ci2 files: b/c
260 3 ci1 files: b/c
259 3 ci1 files: b/c
261 2 update tags files: .hgtags
260 2 update tags files: .hgtags
262 1 ci0 files: b/c
261 1 ci0 files: b/c
263 0 Initial revision files: b/c
262 0 Initial revision files: b/c
264
263
265 commit a new revision with funny log message
264 commit a new revision with funny log message
266
265
267 $ cd src
266 $ cd src
268 $ sleep 1
267 $ sleep 1
269 $ echo e >> a
268 $ echo e >> a
270 $ cvscall -q commit -m'funny
269 $ cvscall -q commit -m'funny
271 > ----------------------------
270 > ----------------------------
272 > log message' . | grep '<--' |\
271 > log message' . | grep '<--' |\
273 > sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
272 > sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
274 checking in src/a,v
273 checking in src/a,v
275
274
276 commit new file revisions with some fuzz
275 commit new file revisions with some fuzz
277
276
278 $ sleep 1
277 $ sleep 1
279 $ echo f >> a
278 $ echo f >> a
280 $ cvscall -q commit -mfuzzy . | grep '<--'
279 $ cvscall -q commit -mfuzzy . | grep '<--'
281 $TESTTMP/cvsrepo/src/a,v <-- a
280 $TESTTMP/cvsrepo/src/a,v <-- a
282 $ sleep 4 # the two changes will be split if fuzz < 4
281 $ sleep 4 # the two changes will be split if fuzz < 4
283 $ echo g >> b/c
282 $ echo g >> b/c
284 $ cvscall -q commit -mfuzzy . | grep '<--'
283 $ cvscall -q commit -mfuzzy . | grep '<--'
285 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
284 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
286 $ cd ..
285 $ cd ..
287
286
288 convert again
287 convert again
289
288
290 $ hg convert --config convert.cvsps.fuzz=2 src src-hg
289 $ hg convert --config convert.cvsps.fuzz=2 src src-hg
291 connecting to $TESTTMP/cvsrepo
290 connecting to $TESTTMP/cvsrepo
292 scanning source...
291 scanning source...
293 collecting CVS rlog
292 collecting CVS rlog
294 11 log entries
293 11 log entries
295 cvslog hook: 11 entries
294 cvslog hook: 11 entries
296 creating changesets
295 creating changesets
297 8 changeset entries
296 8 changeset entries
298 cvschangesets hook: 8 changesets
297 cvschangesets hook: 8 changesets
299 sorting...
298 sorting...
300 converting...
299 converting...
301 2 funny
300 2 funny
302 1 fuzzy
301 1 fuzzy
303 0 fuzzy
302 0 fuzzy
304 $ hg -R src-hg glog --template '{rev} ({branches}) {desc} files: {files}\n'
303 $ hg -R src-hg glog --template '{rev} ({branches}) {desc} files: {files}\n'
305 o 8 (branch) fuzzy files: b/c
304 o 8 (branch) fuzzy files: b/c
306 |
305 |
307 o 7 (branch) fuzzy files: a
306 o 7 (branch) fuzzy files: a
308 |
307 |
309 o 6 (branch) funny
308 o 6 (branch) funny
310 | ----------------------------
309 | ----------------------------
311 | log message files: a
310 | log message files: a
312 o 5 (branch) ci2 files: b/c
311 o 5 (branch) ci2 files: b/c
313
312
314 o 4 () ci1 files: a b/c
313 o 4 () ci1 files: a b/c
315 |
314 |
316 o 3 () update tags files: .hgtags
315 o 3 () update tags files: .hgtags
317 |
316 |
318 o 2 () ci0 files: b/c
317 o 2 () ci0 files: b/c
319 |
318 |
320 | o 1 (INITIAL) import files:
319 | o 1 (INITIAL) import files:
321 |/
320 |/
322 o 0 () Initial revision files: a b/c
321 o 0 () Initial revision files: a b/c
323
322
324
323
325 testing debugcvsps
324 testing debugcvsps
326
325
327 $ cd src
326 $ cd src
328 $ hg debugcvsps --fuzz=2
327 $ hg debugcvsps --fuzz=2
329 collecting CVS rlog
328 collecting CVS rlog
330 11 log entries
329 11 log entries
331 cvslog hook: 11 entries
330 cvslog hook: 11 entries
332 creating changesets
331 creating changesets
333 10 changeset entries
332 10 changeset entries
334 cvschangesets hook: 10 changesets
333 cvschangesets hook: 10 changesets
335 ---------------------
334 ---------------------
336 PatchSet 1
335 PatchSet 1
337 Date: * (glob)
336 Date: * (glob)
338 Author: * (glob)
337 Author: * (glob)
339 Branch: HEAD
338 Branch: HEAD
340 Tag: (none)
339 Tag: (none)
341 Branchpoints: INITIAL
340 Branchpoints: INITIAL
342 Log:
341 Log:
343 Initial revision
342 Initial revision
344
343
345 Members:
344 Members:
346 a:INITIAL->1.1
345 a:INITIAL->1.1
347
346
348 ---------------------
347 ---------------------
349 PatchSet 2
348 PatchSet 2
350 Date: * (glob)
349 Date: * (glob)
351 Author: * (glob)
350 Author: * (glob)
352 Branch: HEAD
351 Branch: HEAD
353 Tag: (none)
352 Tag: (none)
354 Branchpoints: INITIAL, branch
353 Branchpoints: INITIAL, branch
355 Log:
354 Log:
356 Initial revision
355 Initial revision
357
356
358 Members:
357 Members:
359 b/c:INITIAL->1.1
358 b/c:INITIAL->1.1
360
359
361 ---------------------
360 ---------------------
362 PatchSet 3
361 PatchSet 3
363 Date: * (glob)
362 Date: * (glob)
364 Author: * (glob)
363 Author: * (glob)
365 Branch: INITIAL
364 Branch: INITIAL
366 Tag: start
365 Tag: start
367 Log:
366 Log:
368 import
367 import
369
368
370 Members:
369 Members:
371 a:1.1->1.1.1.1
370 a:1.1->1.1.1.1
372 b/c:1.1->1.1.1.1
371 b/c:1.1->1.1.1.1
373
372
374 ---------------------
373 ---------------------
375 PatchSet 4
374 PatchSet 4
376 Date: * (glob)
375 Date: * (glob)
377 Author: * (glob)
376 Author: * (glob)
378 Branch: HEAD
377 Branch: HEAD
379 Tag: (none)
378 Tag: (none)
380 Log:
379 Log:
381 ci0
380 ci0
382
381
383 Members:
382 Members:
384 b/c:1.1->1.2
383 b/c:1.1->1.2
385
384
386 ---------------------
385 ---------------------
387 PatchSet 5
386 PatchSet 5
388 Date: * (glob)
387 Date: * (glob)
389 Author: * (glob)
388 Author: * (glob)
390 Branch: HEAD
389 Branch: HEAD
391 Tag: (none)
390 Tag: (none)
392 Branchpoints: branch
391 Branchpoints: branch
393 Log:
392 Log:
394 ci1
393 ci1
395
394
396 Members:
395 Members:
397 a:1.1->1.2
396 a:1.1->1.2
398
397
399 ---------------------
398 ---------------------
400 PatchSet 6
399 PatchSet 6
401 Date: * (glob)
400 Date: * (glob)
402 Author: * (glob)
401 Author: * (glob)
403 Branch: HEAD
402 Branch: HEAD
404 Tag: (none)
403 Tag: (none)
405 Log:
404 Log:
406 ci1
405 ci1
407
406
408 Members:
407 Members:
409 b/c:1.2->1.3
408 b/c:1.2->1.3
410
409
411 ---------------------
410 ---------------------
412 PatchSet 7
411 PatchSet 7
413 Date: * (glob)
412 Date: * (glob)
414 Author: * (glob)
413 Author: * (glob)
415 Branch: branch
414 Branch: branch
416 Tag: (none)
415 Tag: (none)
417 Log:
416 Log:
418 ci2
417 ci2
419
418
420 Members:
419 Members:
421 b/c:1.1->1.1.2.1
420 b/c:1.1->1.1.2.1
422
421
423 ---------------------
422 ---------------------
424 PatchSet 8
423 PatchSet 8
425 Date: * (glob)
424 Date: * (glob)
426 Author: * (glob)
425 Author: * (glob)
427 Branch: branch
426 Branch: branch
428 Tag: (none)
427 Tag: (none)
429 Log:
428 Log:
430 funny
429 funny
431 ----------------------------
430 ----------------------------
432 log message
431 log message
433
432
434 Members:
433 Members:
435 a:1.2->1.2.2.1
434 a:1.2->1.2.2.1
436
435
437 ---------------------
436 ---------------------
438 PatchSet 9
437 PatchSet 9
439 Date: * (glob)
438 Date: * (glob)
440 Author: * (glob)
439 Author: * (glob)
441 Branch: branch
440 Branch: branch
442 Tag: (none)
441 Tag: (none)
443 Log:
442 Log:
444 fuzzy
443 fuzzy
445
444
446 Members:
445 Members:
447 a:1.2.2.1->1.2.2.2
446 a:1.2.2.1->1.2.2.2
448
447
449 ---------------------
448 ---------------------
450 PatchSet 10
449 PatchSet 10
451 Date: * (glob)
450 Date: * (glob)
452 Author: * (glob)
451 Author: * (glob)
453 Branch: branch
452 Branch: branch
454 Tag: (none)
453 Tag: (none)
455 Log:
454 Log:
456 fuzzy
455 fuzzy
457
456
458 Members:
457 Members:
459 b/c:1.1.2.1->1.1.2.2
458 b/c:1.1.2.1->1.1.2.2
460
459
461
460
@@ -1,217 +1,216 b''
1 Test the EOL hook
1 Test the EOL hook
2
2
3 $ hg init main
3 $ hg init main
4 $ cat > main/.hg/hgrc <<EOF
4 $ cat > main/.hg/hgrc <<EOF
5 > [hooks]
5 > [hooks]
6 > pretxnchangegroup = python:hgext.eol.hook
6 > pretxnchangegroup = python:hgext.eol.hook
7 > EOF
7 > EOF
8 $ hg clone main fork
8 $ hg clone main fork
9 updating to branch default
9 updating to branch default
10 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
10 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 $ cd fork
11 $ cd fork
12
12
13 Create repo
13 Create repo
14 $ cat > .hgeol <<EOF
14 $ cat > .hgeol <<EOF
15 > [patterns]
15 > [patterns]
16 > mixed.txt = BIN
16 > mixed.txt = BIN
17 > crlf.txt = CRLF
17 > crlf.txt = CRLF
18 > **.txt = native
18 > **.txt = native
19 > EOF
19 > EOF
20 $ hg add .hgeol
20 $ hg add .hgeol
21 $ hg commit -m 'Commit .hgeol'
21 $ hg commit -m 'Commit .hgeol'
22
22
23 $ printf "first\nsecond\nthird\n" > a.txt
23 $ printf "first\nsecond\nthird\n" > a.txt
24 $ hg add a.txt
24 $ hg add a.txt
25 $ hg commit -m 'LF a.txt'
25 $ hg commit -m 'LF a.txt'
26 $ hg push ../main
26 $ hg push ../main
27 pushing to ../main
27 pushing to ../main
28 searching for changes
28 searching for changes
29 adding changesets
29 adding changesets
30 adding manifests
30 adding manifests
31 adding file changes
31 adding file changes
32 added 2 changesets with 2 changes to 2 files
32 added 2 changesets with 2 changes to 2 files
33
33
34 $ printf "first\r\nsecond\r\nthird\n" > a.txt
34 $ printf "first\r\nsecond\r\nthird\n" > a.txt
35 $ hg commit -m 'CRLF a.txt'
35 $ hg commit -m 'CRLF a.txt'
36 $ hg push ../main
36 $ hg push ../main
37 pushing to ../main
37 pushing to ../main
38 searching for changes
38 searching for changes
39 adding changesets
39 adding changesets
40 adding manifests
40 adding manifests
41 adding file changes
41 adding file changes
42 added 1 changesets with 1 changes to 1 files
42 added 1 changesets with 1 changes to 1 files
43 error: pretxnchangegroup hook failed: end-of-line check failed:
43 error: pretxnchangegroup hook failed: end-of-line check failed:
44 a.txt in a8ee6548cd86 should not have CRLF line endings
44 a.txt in a8ee6548cd86 should not have CRLF line endings
45 transaction abort!
45 transaction abort!
46 rollback completed
46 rollback completed
47 abort: end-of-line check failed:
47 abort: end-of-line check failed:
48 a.txt in a8ee6548cd86 should not have CRLF line endings
48 a.txt in a8ee6548cd86 should not have CRLF line endings
49 [255]
49 [255]
50
50
51 $ printf "first\nsecond\nthird\n" > a.txt
51 $ printf "first\nsecond\nthird\n" > a.txt
52 $ hg commit -m 'LF a.txt (fixed)'
52 $ hg commit -m 'LF a.txt (fixed)'
53 $ hg push ../main
53 $ hg push ../main
54 pushing to ../main
54 pushing to ../main
55 searching for changes
55 searching for changes
56 adding changesets
56 adding changesets
57 adding manifests
57 adding manifests
58 adding file changes
58 adding file changes
59 added 2 changesets with 2 changes to 1 files
59 added 2 changesets with 2 changes to 1 files
60
60
61 $ printf "first\nsecond\nthird\n" > crlf.txt
61 $ printf "first\nsecond\nthird\n" > crlf.txt
62 $ hg add crlf.txt
62 $ hg add crlf.txt
63 $ hg commit -m 'LF crlf.txt'
63 $ hg commit -m 'LF crlf.txt'
64 $ hg push ../main
64 $ hg push ../main
65 pushing to ../main
65 pushing to ../main
66 searching for changes
66 searching for changes
67 adding changesets
67 adding changesets
68 adding manifests
68 adding manifests
69 adding file changes
69 adding file changes
70 added 1 changesets with 1 changes to 1 files
70 added 1 changesets with 1 changes to 1 files
71 error: pretxnchangegroup hook failed: end-of-line check failed:
71 error: pretxnchangegroup hook failed: end-of-line check failed:
72 crlf.txt in 004ba2132725 should not have LF line endings
72 crlf.txt in 004ba2132725 should not have LF line endings
73 transaction abort!
73 transaction abort!
74 rollback completed
74 rollback completed
75 abort: end-of-line check failed:
75 abort: end-of-line check failed:
76 crlf.txt in 004ba2132725 should not have LF line endings
76 crlf.txt in 004ba2132725 should not have LF line endings
77 [255]
77 [255]
78
78
79 $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
79 $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
80 $ hg commit -m 'CRLF crlf.txt (fixed)'
80 $ hg commit -m 'CRLF crlf.txt (fixed)'
81 $ hg push ../main
81 $ hg push ../main
82 pushing to ../main
82 pushing to ../main
83 searching for changes
83 searching for changes
84 adding changesets
84 adding changesets
85 adding manifests
85 adding manifests
86 adding file changes
86 adding file changes
87 added 2 changesets with 2 changes to 1 files
87 added 2 changesets with 2 changes to 1 files
88
88
89 $ printf "first\r\nsecond" > b.txt
89 $ printf "first\r\nsecond" > b.txt
90 $ hg add b.txt
90 $ hg add b.txt
91 $ hg commit -m 'CRLF b.txt'
91 $ hg commit -m 'CRLF b.txt'
92 $ hg push ../main
92 $ hg push ../main
93 pushing to ../main
93 pushing to ../main
94 searching for changes
94 searching for changes
95 adding changesets
95 adding changesets
96 adding manifests
96 adding manifests
97 adding file changes
97 adding file changes
98 added 1 changesets with 1 changes to 1 files
98 added 1 changesets with 1 changes to 1 files
99 error: pretxnchangegroup hook failed: end-of-line check failed:
99 error: pretxnchangegroup hook failed: end-of-line check failed:
100 b.txt in fbcf9b1025f5 should not have CRLF line endings
100 b.txt in fbcf9b1025f5 should not have CRLF line endings
101 transaction abort!
101 transaction abort!
102 rollback completed
102 rollback completed
103 abort: end-of-line check failed:
103 abort: end-of-line check failed:
104 b.txt in fbcf9b1025f5 should not have CRLF line endings
104 b.txt in fbcf9b1025f5 should not have CRLF line endings
105 [255]
105 [255]
106
106
107 $ hg up -r -2
107 $ hg up -r -2
108 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
108 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
109 $ printf "some\nother\nfile" > c.txt
109 $ printf "some\nother\nfile" > c.txt
110 $ hg add c.txt
110 $ hg add c.txt
111 $ hg commit -m "LF c.txt, b.txt doesn't exist here"
111 $ hg commit -m "LF c.txt, b.txt doesn't exist here"
112 created new head
112 created new head
113 $ hg push -f ../main
113 $ hg push -f ../main
114 pushing to ../main
114 pushing to ../main
115 searching for changes
115 searching for changes
116 adding changesets
116 adding changesets
117 adding manifests
117 adding manifests
118 adding file changes
118 adding file changes
119 added 2 changesets with 2 changes to 2 files (+1 heads)
119 added 2 changesets with 2 changes to 2 files (+1 heads)
120 error: pretxnchangegroup hook failed: end-of-line check failed:
120 error: pretxnchangegroup hook failed: end-of-line check failed:
121 b.txt in fbcf9b1025f5 should not have CRLF line endings
121 b.txt in fbcf9b1025f5 should not have CRLF line endings
122 transaction abort!
122 transaction abort!
123 rollback completed
123 rollback completed
124 abort: end-of-line check failed:
124 abort: end-of-line check failed:
125 b.txt in fbcf9b1025f5 should not have CRLF line endings
125 b.txt in fbcf9b1025f5 should not have CRLF line endings
126 [255]
126 [255]
127
127
128 Test checkheadshook alias
128 Test checkheadshook alias
129
129
130 $ cat > ../main/.hg/hgrc <<EOF
130 $ cat > ../main/.hg/hgrc <<EOF
131 > [hooks]
131 > [hooks]
132 > pretxnchangegroup = python:hgext.eol.checkheadshook
132 > pretxnchangegroup = python:hgext.eol.checkheadshook
133 > EOF
133 > EOF
134 $ hg push -f ../main
134 $ hg push -f ../main
135 pushing to ../main
135 pushing to ../main
136 searching for changes
136 searching for changes
137 adding changesets
137 adding changesets
138 adding manifests
138 adding manifests
139 adding file changes
139 adding file changes
140 added 2 changesets with 2 changes to 2 files (+1 heads)
140 added 2 changesets with 2 changes to 2 files (+1 heads)
141 error: pretxnchangegroup hook failed: end-of-line check failed:
141 error: pretxnchangegroup hook failed: end-of-line check failed:
142 b.txt in fbcf9b1025f5 should not have CRLF line endings
142 b.txt in fbcf9b1025f5 should not have CRLF line endings
143 transaction abort!
143 transaction abort!
144 rollback completed
144 rollback completed
145 abort: end-of-line check failed:
145 abort: end-of-line check failed:
146 b.txt in fbcf9b1025f5 should not have CRLF line endings
146 b.txt in fbcf9b1025f5 should not have CRLF line endings
147 [255]
147 [255]
148
148
149 We can fix the head and push again
149 We can fix the head and push again
150
150
151 $ hg up 6
151 $ hg up 6
152 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
152 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
153 $ printf "first\nsecond" > b.txt
153 $ printf "first\nsecond" > b.txt
154 $ hg ci -m "remove CRLF from b.txt"
154 $ hg ci -m "remove CRLF from b.txt"
155 $ hg push -f ../main
155 $ hg push -f ../main
156 pushing to ../main
156 pushing to ../main
157 searching for changes
157 searching for changes
158 adding changesets
158 adding changesets
159 adding manifests
159 adding manifests
160 adding file changes
160 adding file changes
161 added 3 changesets with 3 changes to 2 files (+1 heads)
161 added 3 changesets with 3 changes to 2 files (+1 heads)
162 $ hg -R ../main rollback
162 $ hg -R ../main rollback
163 repository tip rolled back to revision 5 (undo push)
163 repository tip rolled back to revision 5 (undo push)
164 working directory now based on revision -1
165
164
166 Test it still fails with checkallhook
165 Test it still fails with checkallhook
167
166
168 $ cat > ../main/.hg/hgrc <<EOF
167 $ cat > ../main/.hg/hgrc <<EOF
169 > [hooks]
168 > [hooks]
170 > pretxnchangegroup = python:hgext.eol.checkallhook
169 > pretxnchangegroup = python:hgext.eol.checkallhook
171 > EOF
170 > EOF
172 $ hg push -f ../main
171 $ hg push -f ../main
173 pushing to ../main
172 pushing to ../main
174 searching for changes
173 searching for changes
175 adding changesets
174 adding changesets
176 adding manifests
175 adding manifests
177 adding file changes
176 adding file changes
178 added 3 changesets with 3 changes to 2 files (+1 heads)
177 added 3 changesets with 3 changes to 2 files (+1 heads)
179 error: pretxnchangegroup hook failed: end-of-line check failed:
178 error: pretxnchangegroup hook failed: end-of-line check failed:
180 b.txt in fbcf9b1025f5 should not have CRLF line endings
179 b.txt in fbcf9b1025f5 should not have CRLF line endings
181 transaction abort!
180 transaction abort!
182 rollback completed
181 rollback completed
183 abort: end-of-line check failed:
182 abort: end-of-line check failed:
184 b.txt in fbcf9b1025f5 should not have CRLF line endings
183 b.txt in fbcf9b1025f5 should not have CRLF line endings
185 [255]
184 [255]
186
185
187 But we can push the clean head
186 But we can push the clean head
188
187
189 $ hg push -r7 -f ../main
188 $ hg push -r7 -f ../main
190 pushing to ../main
189 pushing to ../main
191 searching for changes
190 searching for changes
192 adding changesets
191 adding changesets
193 adding manifests
192 adding manifests
194 adding file changes
193 adding file changes
195 added 1 changesets with 1 changes to 1 files
194 added 1 changesets with 1 changes to 1 files
196
195
197 Test multiple files/revisions output
196 Test multiple files/revisions output
198
197
199 $ printf "another\r\nbad\r\none" > d.txt
198 $ printf "another\r\nbad\r\none" > d.txt
200 $ hg add d.txt
199 $ hg add d.txt
201 $ hg ci -m "add d.txt"
200 $ hg ci -m "add d.txt"
202 $ hg push -f ../main
201 $ hg push -f ../main
203 pushing to ../main
202 pushing to ../main
204 searching for changes
203 searching for changes
205 adding changesets
204 adding changesets
206 adding manifests
205 adding manifests
207 adding file changes
206 adding file changes
208 added 3 changesets with 3 changes to 2 files (+1 heads)
207 added 3 changesets with 3 changes to 2 files (+1 heads)
209 error: pretxnchangegroup hook failed: end-of-line check failed:
208 error: pretxnchangegroup hook failed: end-of-line check failed:
210 d.txt in a7040e68714f should not have CRLF line endings
209 d.txt in a7040e68714f should not have CRLF line endings
211 b.txt in fbcf9b1025f5 should not have CRLF line endings
210 b.txt in fbcf9b1025f5 should not have CRLF line endings
212 transaction abort!
211 transaction abort!
213 rollback completed
212 rollback completed
214 abort: end-of-line check failed:
213 abort: end-of-line check failed:
215 d.txt in a7040e68714f should not have CRLF line endings
214 d.txt in a7040e68714f should not have CRLF line endings
216 b.txt in fbcf9b1025f5 should not have CRLF line endings
215 b.txt in fbcf9b1025f5 should not have CRLF line endings
217 [255]
216 [255]
@@ -1,551 +1,550 b''
1 commit hooks can see env vars
1 commit hooks can see env vars
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ echo "[hooks]" > .hg/hgrc
5 $ echo "[hooks]" > .hg/hgrc
6 $ echo 'commit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit' >> .hg/hgrc
6 $ echo 'commit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit' >> .hg/hgrc
7 $ echo 'commit.b = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit.b' >> .hg/hgrc
7 $ echo 'commit.b = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit.b' >> .hg/hgrc
8 $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python "$TESTDIR"/printenv.py precommit' >> .hg/hgrc
8 $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python "$TESTDIR"/printenv.py precommit' >> .hg/hgrc
9 $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py pretxncommit' >> .hg/hgrc
9 $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py pretxncommit' >> .hg/hgrc
10 $ echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
10 $ echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
11 $ echo 'pre-identify = python "$TESTDIR"/printenv.py pre-identify 1' >> .hg/hgrc
11 $ echo 'pre-identify = python "$TESTDIR"/printenv.py pre-identify 1' >> .hg/hgrc
12 $ echo 'pre-cat = python "$TESTDIR"/printenv.py pre-cat' >> .hg/hgrc
12 $ echo 'pre-cat = python "$TESTDIR"/printenv.py pre-cat' >> .hg/hgrc
13 $ echo 'post-cat = python "$TESTDIR"/printenv.py post-cat' >> .hg/hgrc
13 $ echo 'post-cat = python "$TESTDIR"/printenv.py post-cat' >> .hg/hgrc
14 $ echo a > a
14 $ echo a > a
15 $ hg add a
15 $ hg add a
16 $ hg commit -m a
16 $ hg commit -m a
17 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
17 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
18 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
18 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
19 0:cb9a9f314b8b
19 0:cb9a9f314b8b
20 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
20 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
21 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
21 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
22
22
23 $ hg clone . ../b
23 $ hg clone . ../b
24 updating to branch default
24 updating to branch default
25 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
25 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
26 $ cd ../b
26 $ cd ../b
27
27
28 changegroup hooks can see env vars
28 changegroup hooks can see env vars
29
29
30 $ echo '[hooks]' > .hg/hgrc
30 $ echo '[hooks]' > .hg/hgrc
31 $ echo 'prechangegroup = python "$TESTDIR"/printenv.py prechangegroup' >> .hg/hgrc
31 $ echo 'prechangegroup = python "$TESTDIR"/printenv.py prechangegroup' >> .hg/hgrc
32 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
32 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
33 $ echo 'incoming = python "$TESTDIR"/printenv.py incoming' >> .hg/hgrc
33 $ echo 'incoming = python "$TESTDIR"/printenv.py incoming' >> .hg/hgrc
34
34
35 pretxncommit and commit hooks can see both parents of merge
35 pretxncommit and commit hooks can see both parents of merge
36
36
37 $ cd ../a
37 $ cd ../a
38 $ echo b >> a
38 $ echo b >> a
39 $ hg commit -m a1 -d "1 0"
39 $ hg commit -m a1 -d "1 0"
40 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
40 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
41 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
41 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
42 1:ab228980c14d
42 1:ab228980c14d
43 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
43 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
44 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
44 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
45 $ hg update -C 0
45 $ hg update -C 0
46 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
47 $ echo b > b
47 $ echo b > b
48 $ hg add b
48 $ hg add b
49 $ hg commit -m b -d '1 0'
49 $ hg commit -m b -d '1 0'
50 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
50 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
51 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
51 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
52 2:ee9deb46ab31
52 2:ee9deb46ab31
53 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
53 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
54 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
54 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
55 created new head
55 created new head
56 $ hg merge 1
56 $ hg merge 1
57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 (branch merge, don't forget to commit)
58 (branch merge, don't forget to commit)
59 $ hg commit -m merge -d '2 0'
59 $ hg commit -m merge -d '2 0'
60 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
60 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
61 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
61 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
62 3:07f3376c1e65
62 3:07f3376c1e65
63 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
63 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
64 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
64 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
65
65
66 test generic hooks
66 test generic hooks
67
67
68 $ hg id
68 $ hg id
69 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'num': None, 'rev': '', 'tags': None} HG_PATS=[]
69 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'num': None, 'rev': '', 'tags': None} HG_PATS=[]
70 warning: pre-identify hook exited with status 1
70 warning: pre-identify hook exited with status 1
71 [1]
71 [1]
72 $ hg cat b
72 $ hg cat b
73 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
73 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
74 b
74 b
75 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
75 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
76
76
77 $ cd ../b
77 $ cd ../b
78 $ hg pull ../a
78 $ hg pull ../a
79 pulling from ../a
79 pulling from ../a
80 searching for changes
80 searching for changes
81 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
81 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
82 adding changesets
82 adding changesets
83 adding manifests
83 adding manifests
84 adding file changes
84 adding file changes
85 added 3 changesets with 2 changes to 2 files
85 added 3 changesets with 2 changes to 2 files
86 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
86 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
87 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
87 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
88 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
88 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
89 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
89 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
90 (run 'hg update' to get a working copy)
90 (run 'hg update' to get a working copy)
91
91
92 tag hooks can see env vars
92 tag hooks can see env vars
93
93
94 $ cd ../a
94 $ cd ../a
95 $ echo 'pretag = python "$TESTDIR"/printenv.py pretag' >> .hg/hgrc
95 $ echo 'pretag = python "$TESTDIR"/printenv.py pretag' >> .hg/hgrc
96 $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python "$TESTDIR"/printenv.py tag' >> .hg/hgrc
96 $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python "$TESTDIR"/printenv.py tag' >> .hg/hgrc
97 $ hg tag -d '3 0' a
97 $ hg tag -d '3 0' a
98 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
98 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
99 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
99 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
100 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
100 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
101 4:539e4b31b6dc
101 4:539e4b31b6dc
102 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
102 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
103 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
103 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
104 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
104 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
105 $ hg tag -l la
105 $ hg tag -l la
106 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
106 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
107 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
107 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
108
108
109 pretag hook can forbid tagging
109 pretag hook can forbid tagging
110
110
111 $ echo 'pretag.forbid = python "$TESTDIR"/printenv.py pretag.forbid 1' >> .hg/hgrc
111 $ echo 'pretag.forbid = python "$TESTDIR"/printenv.py pretag.forbid 1' >> .hg/hgrc
112 $ hg tag -d '4 0' fa
112 $ hg tag -d '4 0' fa
113 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
113 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
114 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
114 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
115 abort: pretag.forbid hook exited with status 1
115 abort: pretag.forbid hook exited with status 1
116 [255]
116 [255]
117 $ hg tag -l fla
117 $ hg tag -l fla
118 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
118 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
119 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
119 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
120 abort: pretag.forbid hook exited with status 1
120 abort: pretag.forbid hook exited with status 1
121 [255]
121 [255]
122
122
123 pretxncommit hook can see changeset, can roll back txn, changeset no
123 pretxncommit hook can see changeset, can roll back txn, changeset no
124 more there after
124 more there after
125
125
126 $ echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
126 $ echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
127 $ echo 'pretxncommit.forbid1 = python "$TESTDIR"/printenv.py pretxncommit.forbid 1' >> .hg/hgrc
127 $ echo 'pretxncommit.forbid1 = python "$TESTDIR"/printenv.py pretxncommit.forbid 1' >> .hg/hgrc
128 $ echo z > z
128 $ echo z > z
129 $ hg add z
129 $ hg add z
130 $ hg -q tip
130 $ hg -q tip
131 4:539e4b31b6dc
131 4:539e4b31b6dc
132 $ hg commit -m 'fail' -d '4 0'
132 $ hg commit -m 'fail' -d '4 0'
133 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
133 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
134 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
134 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
135 5:6f611f8018c1
135 5:6f611f8018c1
136 5:6f611f8018c1
136 5:6f611f8018c1
137 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
137 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
138 transaction abort!
138 transaction abort!
139 rollback completed
139 rollback completed
140 abort: pretxncommit.forbid1 hook exited with status 1
140 abort: pretxncommit.forbid1 hook exited with status 1
141 [255]
141 [255]
142 $ hg -q tip
142 $ hg -q tip
143 4:539e4b31b6dc
143 4:539e4b31b6dc
144
144
145 precommit hook can prevent commit
145 precommit hook can prevent commit
146
146
147 $ echo 'precommit.forbid = python "$TESTDIR"/printenv.py precommit.forbid 1' >> .hg/hgrc
147 $ echo 'precommit.forbid = python "$TESTDIR"/printenv.py precommit.forbid 1' >> .hg/hgrc
148 $ hg commit -m 'fail' -d '4 0'
148 $ hg commit -m 'fail' -d '4 0'
149 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
149 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
150 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
150 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
151 abort: precommit.forbid hook exited with status 1
151 abort: precommit.forbid hook exited with status 1
152 [255]
152 [255]
153 $ hg -q tip
153 $ hg -q tip
154 4:539e4b31b6dc
154 4:539e4b31b6dc
155
155
156 preupdate hook can prevent update
156 preupdate hook can prevent update
157
157
158 $ echo 'preupdate = python "$TESTDIR"/printenv.py preupdate' >> .hg/hgrc
158 $ echo 'preupdate = python "$TESTDIR"/printenv.py preupdate' >> .hg/hgrc
159 $ hg update 1
159 $ hg update 1
160 preupdate hook: HG_PARENT1=ab228980c14d
160 preupdate hook: HG_PARENT1=ab228980c14d
161 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
161 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
162
162
163 update hook
163 update hook
164
164
165 $ echo 'update = python "$TESTDIR"/printenv.py update' >> .hg/hgrc
165 $ echo 'update = python "$TESTDIR"/printenv.py update' >> .hg/hgrc
166 $ hg update
166 $ hg update
167 preupdate hook: HG_PARENT1=539e4b31b6dc
167 preupdate hook: HG_PARENT1=539e4b31b6dc
168 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
168 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
169 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
170
170
171 pushkey hook
171 pushkey hook
172
172
173 $ echo 'pushkey = python "$TESTDIR"/printenv.py pushkey' >> .hg/hgrc
173 $ echo 'pushkey = python "$TESTDIR"/printenv.py pushkey' >> .hg/hgrc
174 $ cd ../b
174 $ cd ../b
175 $ hg bookmark -r null foo
175 $ hg bookmark -r null foo
176 $ hg push -B foo ../a
176 $ hg push -B foo ../a
177 pushing to ../a
177 pushing to ../a
178 searching for changes
178 searching for changes
179 no changes found
179 no changes found
180 exporting bookmark foo
180 exporting bookmark foo
181 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
181 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
182 $ cd ../a
182 $ cd ../a
183
183
184 listkeys hook
184 listkeys hook
185
185
186 $ echo 'listkeys = python "$TESTDIR"/printenv.py listkeys' >> .hg/hgrc
186 $ echo 'listkeys = python "$TESTDIR"/printenv.py listkeys' >> .hg/hgrc
187 $ hg bookmark -r null bar
187 $ hg bookmark -r null bar
188 $ cd ../b
188 $ cd ../b
189 $ hg pull -B bar ../a
189 $ hg pull -B bar ../a
190 pulling from ../a
190 pulling from ../a
191 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
191 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
192 no changes found
192 no changes found
193 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
193 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
194 importing bookmark bar
194 importing bookmark bar
195 $ cd ../a
195 $ cd ../a
196
196
197 test that prepushkey can prevent incoming keys
197 test that prepushkey can prevent incoming keys
198
198
199 $ echo 'prepushkey = python "$TESTDIR"/printenv.py prepushkey.forbid 1' >> .hg/hgrc
199 $ echo 'prepushkey = python "$TESTDIR"/printenv.py prepushkey.forbid 1' >> .hg/hgrc
200 $ cd ../b
200 $ cd ../b
201 $ hg bookmark -r null baz
201 $ hg bookmark -r null baz
202 $ hg push -B baz ../a
202 $ hg push -B baz ../a
203 pushing to ../a
203 pushing to ../a
204 searching for changes
204 searching for changes
205 no changes found
205 no changes found
206 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
206 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
207 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
207 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
208 exporting bookmark baz
208 exporting bookmark baz
209 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
209 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
210 abort: prepushkey hook exited with status 1
210 abort: prepushkey hook exited with status 1
211 [255]
211 [255]
212 $ cd ../a
212 $ cd ../a
213
213
214 test that prelistkeys can prevent listing keys
214 test that prelistkeys can prevent listing keys
215
215
216 $ echo 'prelistkeys = python "$TESTDIR"/printenv.py prelistkeys.forbid 1' >> .hg/hgrc
216 $ echo 'prelistkeys = python "$TESTDIR"/printenv.py prelistkeys.forbid 1' >> .hg/hgrc
217 $ hg bookmark -r null quux
217 $ hg bookmark -r null quux
218 $ cd ../b
218 $ cd ../b
219 $ hg pull -B quux ../a
219 $ hg pull -B quux ../a
220 pulling from ../a
220 pulling from ../a
221 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
221 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
222 abort: prelistkeys hook exited with status 1
222 abort: prelistkeys hook exited with status 1
223 [255]
223 [255]
224 $ cd ../a
224 $ cd ../a
225
225
226 prechangegroup hook can prevent incoming changes
226 prechangegroup hook can prevent incoming changes
227
227
228 $ cd ../b
228 $ cd ../b
229 $ hg -q tip
229 $ hg -q tip
230 3:07f3376c1e65
230 3:07f3376c1e65
231 $ echo '[hooks]' > .hg/hgrc
231 $ echo '[hooks]' > .hg/hgrc
232 $ echo 'prechangegroup.forbid = python "$TESTDIR"/printenv.py prechangegroup.forbid 1' >> .hg/hgrc
232 $ echo 'prechangegroup.forbid = python "$TESTDIR"/printenv.py prechangegroup.forbid 1' >> .hg/hgrc
233 $ hg pull ../a
233 $ hg pull ../a
234 pulling from ../a
234 pulling from ../a
235 searching for changes
235 searching for changes
236 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
236 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
237 abort: prechangegroup.forbid hook exited with status 1
237 abort: prechangegroup.forbid hook exited with status 1
238 [255]
238 [255]
239
239
240 pretxnchangegroup hook can see incoming changes, can roll back txn,
240 pretxnchangegroup hook can see incoming changes, can roll back txn,
241 incoming changes no longer there after
241 incoming changes no longer there after
242
242
243 $ echo '[hooks]' > .hg/hgrc
243 $ echo '[hooks]' > .hg/hgrc
244 $ echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
244 $ echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
245 $ echo 'pretxnchangegroup.forbid1 = python "$TESTDIR"/printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
245 $ echo 'pretxnchangegroup.forbid1 = python "$TESTDIR"/printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
246 $ hg pull ../a
246 $ hg pull ../a
247 pulling from ../a
247 pulling from ../a
248 searching for changes
248 searching for changes
249 adding changesets
249 adding changesets
250 adding manifests
250 adding manifests
251 adding file changes
251 adding file changes
252 added 1 changesets with 1 changes to 1 files
252 added 1 changesets with 1 changes to 1 files
253 4:539e4b31b6dc
253 4:539e4b31b6dc
254 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
254 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
255 transaction abort!
255 transaction abort!
256 rollback completed
256 rollback completed
257 abort: pretxnchangegroup.forbid1 hook exited with status 1
257 abort: pretxnchangegroup.forbid1 hook exited with status 1
258 [255]
258 [255]
259 $ hg -q tip
259 $ hg -q tip
260 3:07f3376c1e65
260 3:07f3376c1e65
261
261
262 outgoing hooks can see env vars
262 outgoing hooks can see env vars
263
263
264 $ rm .hg/hgrc
264 $ rm .hg/hgrc
265 $ echo '[hooks]' > ../a/.hg/hgrc
265 $ echo '[hooks]' > ../a/.hg/hgrc
266 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> ../a/.hg/hgrc
266 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> ../a/.hg/hgrc
267 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> ../a/.hg/hgrc
267 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> ../a/.hg/hgrc
268 $ hg pull ../a
268 $ hg pull ../a
269 pulling from ../a
269 pulling from ../a
270 searching for changes
270 searching for changes
271 preoutgoing hook: HG_SOURCE=pull
271 preoutgoing hook: HG_SOURCE=pull
272 adding changesets
272 adding changesets
273 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
273 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
274 adding manifests
274 adding manifests
275 adding file changes
275 adding file changes
276 added 1 changesets with 1 changes to 1 files
276 added 1 changesets with 1 changes to 1 files
277 (run 'hg update' to get a working copy)
277 (run 'hg update' to get a working copy)
278 $ hg rollback
278 $ hg rollback
279 repository tip rolled back to revision 3 (undo pull)
279 repository tip rolled back to revision 3 (undo pull)
280 working directory now based on revision 0
281
280
282 preoutgoing hook can prevent outgoing changes
281 preoutgoing hook can prevent outgoing changes
283
282
284 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
283 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
285 $ hg pull ../a
284 $ hg pull ../a
286 pulling from ../a
285 pulling from ../a
287 searching for changes
286 searching for changes
288 preoutgoing hook: HG_SOURCE=pull
287 preoutgoing hook: HG_SOURCE=pull
289 preoutgoing.forbid hook: HG_SOURCE=pull
288 preoutgoing.forbid hook: HG_SOURCE=pull
290 abort: preoutgoing.forbid hook exited with status 1
289 abort: preoutgoing.forbid hook exited with status 1
291 [255]
290 [255]
292
291
293 outgoing hooks work for local clones
292 outgoing hooks work for local clones
294
293
295 $ cd ..
294 $ cd ..
296 $ echo '[hooks]' > a/.hg/hgrc
295 $ echo '[hooks]' > a/.hg/hgrc
297 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> a/.hg/hgrc
296 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> a/.hg/hgrc
298 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> a/.hg/hgrc
297 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> a/.hg/hgrc
299 $ hg clone a c
298 $ hg clone a c
300 preoutgoing hook: HG_SOURCE=clone
299 preoutgoing hook: HG_SOURCE=clone
301 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
300 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
302 updating to branch default
301 updating to branch default
303 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
302 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 $ rm -rf c
303 $ rm -rf c
305
304
306 preoutgoing hook can prevent outgoing changes for local clones
305 preoutgoing hook can prevent outgoing changes for local clones
307
306
308 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
307 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
309 $ hg clone a zzz
308 $ hg clone a zzz
310 preoutgoing hook: HG_SOURCE=clone
309 preoutgoing hook: HG_SOURCE=clone
311 preoutgoing.forbid hook: HG_SOURCE=clone
310 preoutgoing.forbid hook: HG_SOURCE=clone
312 abort: preoutgoing.forbid hook exited with status 1
311 abort: preoutgoing.forbid hook exited with status 1
313 [255]
312 [255]
314 $ cd b
313 $ cd b
315
314
316 $ cat > hooktests.py <<EOF
315 $ cat > hooktests.py <<EOF
317 > from mercurial import util
316 > from mercurial import util
318 >
317 >
319 > uncallable = 0
318 > uncallable = 0
320 >
319 >
321 > def printargs(args):
320 > def printargs(args):
322 > args.pop('ui', None)
321 > args.pop('ui', None)
323 > args.pop('repo', None)
322 > args.pop('repo', None)
324 > a = list(args.items())
323 > a = list(args.items())
325 > a.sort()
324 > a.sort()
326 > print 'hook args:'
325 > print 'hook args:'
327 > for k, v in a:
326 > for k, v in a:
328 > print ' ', k, v
327 > print ' ', k, v
329 >
328 >
330 > def passhook(**args):
329 > def passhook(**args):
331 > printargs(args)
330 > printargs(args)
332 >
331 >
333 > def failhook(**args):
332 > def failhook(**args):
334 > printargs(args)
333 > printargs(args)
335 > return True
334 > return True
336 >
335 >
337 > class LocalException(Exception):
336 > class LocalException(Exception):
338 > pass
337 > pass
339 >
338 >
340 > def raisehook(**args):
339 > def raisehook(**args):
341 > raise LocalException('exception from hook')
340 > raise LocalException('exception from hook')
342 >
341 >
343 > def aborthook(**args):
342 > def aborthook(**args):
344 > raise util.Abort('raise abort from hook')
343 > raise util.Abort('raise abort from hook')
345 >
344 >
346 > def brokenhook(**args):
345 > def brokenhook(**args):
347 > return 1 + {}
346 > return 1 + {}
348 >
347 >
349 > def verbosehook(ui, **args):
348 > def verbosehook(ui, **args):
350 > ui.note('verbose output from hook\n')
349 > ui.note('verbose output from hook\n')
351 >
350 >
352 > class container:
351 > class container:
353 > unreachable = 1
352 > unreachable = 1
354 > EOF
353 > EOF
355
354
356 test python hooks
355 test python hooks
357
356
358 $ PYTHONPATH="`pwd`:$PYTHONPATH"
357 $ PYTHONPATH="`pwd`:$PYTHONPATH"
359 $ export PYTHONPATH
358 $ export PYTHONPATH
360
359
361 $ echo '[hooks]' > ../a/.hg/hgrc
360 $ echo '[hooks]' > ../a/.hg/hgrc
362 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
361 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
363 $ hg pull ../a 2>&1 | grep 'raised an exception'
362 $ hg pull ../a 2>&1 | grep 'raised an exception'
364 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
363 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
365
364
366 $ echo '[hooks]' > ../a/.hg/hgrc
365 $ echo '[hooks]' > ../a/.hg/hgrc
367 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
366 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
368 $ hg pull ../a 2>&1 | grep 'raised an exception'
367 $ hg pull ../a 2>&1 | grep 'raised an exception'
369 error: preoutgoing.raise hook raised an exception: exception from hook
368 error: preoutgoing.raise hook raised an exception: exception from hook
370
369
371 $ echo '[hooks]' > ../a/.hg/hgrc
370 $ echo '[hooks]' > ../a/.hg/hgrc
372 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
371 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
373 $ hg pull ../a
372 $ hg pull ../a
374 pulling from ../a
373 pulling from ../a
375 searching for changes
374 searching for changes
376 error: preoutgoing.abort hook failed: raise abort from hook
375 error: preoutgoing.abort hook failed: raise abort from hook
377 abort: raise abort from hook
376 abort: raise abort from hook
378 [255]
377 [255]
379
378
380 $ echo '[hooks]' > ../a/.hg/hgrc
379 $ echo '[hooks]' > ../a/.hg/hgrc
381 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
380 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
382 $ hg pull ../a
381 $ hg pull ../a
383 pulling from ../a
382 pulling from ../a
384 searching for changes
383 searching for changes
385 hook args:
384 hook args:
386 hooktype preoutgoing
385 hooktype preoutgoing
387 source pull
386 source pull
388 abort: preoutgoing.fail hook failed
387 abort: preoutgoing.fail hook failed
389 [255]
388 [255]
390
389
391 $ echo '[hooks]' > ../a/.hg/hgrc
390 $ echo '[hooks]' > ../a/.hg/hgrc
392 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
391 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
393 $ hg pull ../a
392 $ hg pull ../a
394 pulling from ../a
393 pulling from ../a
395 searching for changes
394 searching for changes
396 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
395 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
397 [255]
396 [255]
398
397
399 $ echo '[hooks]' > ../a/.hg/hgrc
398 $ echo '[hooks]' > ../a/.hg/hgrc
400 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
399 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
401 $ hg pull ../a
400 $ hg pull ../a
402 pulling from ../a
401 pulling from ../a
403 searching for changes
402 searching for changes
404 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
403 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
405 [255]
404 [255]
406
405
407 $ echo '[hooks]' > ../a/.hg/hgrc
406 $ echo '[hooks]' > ../a/.hg/hgrc
408 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
407 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
409 $ hg pull ../a
408 $ hg pull ../a
410 pulling from ../a
409 pulling from ../a
411 searching for changes
410 searching for changes
412 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
411 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
413 [255]
412 [255]
414
413
415 $ echo '[hooks]' > ../a/.hg/hgrc
414 $ echo '[hooks]' > ../a/.hg/hgrc
416 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
415 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
417 $ hg pull ../a
416 $ hg pull ../a
418 pulling from ../a
417 pulling from ../a
419 searching for changes
418 searching for changes
420 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
419 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
421 [255]
420 [255]
422
421
423 $ echo '[hooks]' > ../a/.hg/hgrc
422 $ echo '[hooks]' > ../a/.hg/hgrc
424 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
423 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
425 $ hg pull ../a
424 $ hg pull ../a
426 pulling from ../a
425 pulling from ../a
427 searching for changes
426 searching for changes
428 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
427 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
429 [255]
428 [255]
430
429
431 $ echo '[hooks]' > ../a/.hg/hgrc
430 $ echo '[hooks]' > ../a/.hg/hgrc
432 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
431 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
433 $ hg pull ../a
432 $ hg pull ../a
434 pulling from ../a
433 pulling from ../a
435 searching for changes
434 searching for changes
436 hook args:
435 hook args:
437 hooktype preoutgoing
436 hooktype preoutgoing
438 source pull
437 source pull
439 adding changesets
438 adding changesets
440 adding manifests
439 adding manifests
441 adding file changes
440 adding file changes
442 added 1 changesets with 1 changes to 1 files
441 added 1 changesets with 1 changes to 1 files
443 (run 'hg update' to get a working copy)
442 (run 'hg update' to get a working copy)
444
443
445 make sure --traceback works
444 make sure --traceback works
446
445
447 $ echo '[hooks]' > .hg/hgrc
446 $ echo '[hooks]' > .hg/hgrc
448 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
447 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
449
448
450 $ echo aa > a
449 $ echo aa > a
451 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
450 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
452 Traceback (most recent call last):
451 Traceback (most recent call last):
453
452
454 $ cd ..
453 $ cd ..
455 $ hg init c
454 $ hg init c
456 $ cd c
455 $ cd c
457
456
458 $ cat > hookext.py <<EOF
457 $ cat > hookext.py <<EOF
459 > def autohook(**args):
458 > def autohook(**args):
460 > print "Automatically installed hook"
459 > print "Automatically installed hook"
461 >
460 >
462 > def reposetup(ui, repo):
461 > def reposetup(ui, repo):
463 > repo.ui.setconfig("hooks", "commit.auto", autohook)
462 > repo.ui.setconfig("hooks", "commit.auto", autohook)
464 > EOF
463 > EOF
465 $ echo '[extensions]' >> .hg/hgrc
464 $ echo '[extensions]' >> .hg/hgrc
466 $ echo 'hookext = hookext.py' >> .hg/hgrc
465 $ echo 'hookext = hookext.py' >> .hg/hgrc
467
466
468 $ touch foo
467 $ touch foo
469 $ hg add foo
468 $ hg add foo
470 $ hg ci -d '0 0' -m 'add foo'
469 $ hg ci -d '0 0' -m 'add foo'
471 Automatically installed hook
470 Automatically installed hook
472 $ echo >> foo
471 $ echo >> foo
473 $ hg ci --debug -d '0 0' -m 'change foo'
472 $ hg ci --debug -d '0 0' -m 'change foo'
474 foo
473 foo
475 calling hook commit.auto: <function autohook at *> (glob)
474 calling hook commit.auto: <function autohook at *> (glob)
476 Automatically installed hook
475 Automatically installed hook
477 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
476 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
478
477
479 $ hg showconfig hooks
478 $ hg showconfig hooks
480 hooks.commit.auto=<function autohook at *> (glob)
479 hooks.commit.auto=<function autohook at *> (glob)
481
480
482 test python hook configured with python:[file]:[hook] syntax
481 test python hook configured with python:[file]:[hook] syntax
483
482
484 $ cd ..
483 $ cd ..
485 $ mkdir d
484 $ mkdir d
486 $ cd d
485 $ cd d
487 $ hg init repo
486 $ hg init repo
488 $ mkdir hooks
487 $ mkdir hooks
489
488
490 $ cd hooks
489 $ cd hooks
491 $ cat > testhooks.py <<EOF
490 $ cat > testhooks.py <<EOF
492 > def testhook(**args):
491 > def testhook(**args):
493 > print 'hook works'
492 > print 'hook works'
494 > EOF
493 > EOF
495 $ echo '[hooks]' > ../repo/.hg/hgrc
494 $ echo '[hooks]' > ../repo/.hg/hgrc
496 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
495 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
497
496
498 $ cd ../repo
497 $ cd ../repo
499 $ hg commit -d '0 0'
498 $ hg commit -d '0 0'
500 hook works
499 hook works
501 nothing changed
500 nothing changed
502 [1]
501 [1]
503
502
504 $ cd ../../b
503 $ cd ../../b
505
504
506 make sure --traceback works on hook import failure
505 make sure --traceback works on hook import failure
507
506
508 $ cat > importfail.py <<EOF
507 $ cat > importfail.py <<EOF
509 > import somebogusmodule
508 > import somebogusmodule
510 > # dereference something in the module to force demandimport to load it
509 > # dereference something in the module to force demandimport to load it
511 > somebogusmodule.whatever
510 > somebogusmodule.whatever
512 > EOF
511 > EOF
513
512
514 $ echo '[hooks]' > .hg/hgrc
513 $ echo '[hooks]' > .hg/hgrc
515 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
514 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
516
515
517 $ echo a >> a
516 $ echo a >> a
518 $ hg --traceback commit -ma 2>&1 | egrep '^(exception|Traceback|ImportError)'
517 $ hg --traceback commit -ma 2>&1 | egrep '^(exception|Traceback|ImportError)'
519 exception from first failed import attempt:
518 exception from first failed import attempt:
520 Traceback (most recent call last):
519 Traceback (most recent call last):
521 ImportError: No module named somebogusmodule
520 ImportError: No module named somebogusmodule
522 exception from second failed import attempt:
521 exception from second failed import attempt:
523 Traceback (most recent call last):
522 Traceback (most recent call last):
524 ImportError: No module named hgext_importfail
523 ImportError: No module named hgext_importfail
525 Traceback (most recent call last):
524 Traceback (most recent call last):
526
525
527 Issue1827: Hooks Update & Commit not completely post operation
526 Issue1827: Hooks Update & Commit not completely post operation
528
527
529 commit and update hooks should run after command completion
528 commit and update hooks should run after command completion
530
529
531 $ echo '[hooks]' > .hg/hgrc
530 $ echo '[hooks]' > .hg/hgrc
532 $ echo 'commit = hg id' >> .hg/hgrc
531 $ echo 'commit = hg id' >> .hg/hgrc
533 $ echo 'update = hg id' >> .hg/hgrc
532 $ echo 'update = hg id' >> .hg/hgrc
534 $ echo bb > a
533 $ echo bb > a
535 $ hg ci -ma
534 $ hg ci -ma
536 223eafe2750c tip
535 223eafe2750c tip
537 $ hg up 0
536 $ hg up 0
538 cb9a9f314b8b
537 cb9a9f314b8b
539 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
540
539
541 make sure --verbose (and --quiet/--debug etc.) are propogated to the local ui
540 make sure --verbose (and --quiet/--debug etc.) are propogated to the local ui
542 that is passed to pre/post hooks
541 that is passed to pre/post hooks
543
542
544 $ echo '[hooks]' > .hg/hgrc
543 $ echo '[hooks]' > .hg/hgrc
545 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
544 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
546 $ hg id
545 $ hg id
547 cb9a9f314b8b
546 cb9a9f314b8b
548 $ hg id --verbose
547 $ hg id --verbose
549 calling hook pre-identify: hooktests.verbosehook
548 calling hook pre-identify: hooktests.verbosehook
550 verbose output from hook
549 verbose output from hook
551 cb9a9f314b8b
550 cb9a9f314b8b
@@ -1,261 +1,258 b''
1 $ echo "[extensions]" >> $HGRCPATH
1 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "purge=" >> $HGRCPATH
2 $ echo "purge=" >> $HGRCPATH
3 $ echo "graphlog=" >> $HGRCPATH
3 $ echo "graphlog=" >> $HGRCPATH
4
4
5 $ shortlog() {
5 $ shortlog() {
6 > hg glog --template '{rev}:{node|short} {author} {date|hgdate} - {branch} - {desc|firstline}\n'
6 > hg glog --template '{rev}:{node|short} {author} {date|hgdate} - {branch} - {desc|firstline}\n'
7 > }
7 > }
8
8
9 Test --bypass with other options
9 Test --bypass with other options
10
10
11 $ hg init repo-options
11 $ hg init repo-options
12 $ cd repo-options
12 $ cd repo-options
13 $ echo a > a
13 $ echo a > a
14 $ hg ci -Am adda
14 $ hg ci -Am adda
15 adding a
15 adding a
16 $ echo a >> a
16 $ echo a >> a
17 $ hg branch foo
17 $ hg branch foo
18 marked working directory as branch foo
18 marked working directory as branch foo
19 $ hg ci -Am changea
19 $ hg ci -Am changea
20 $ hg export . > ../test.diff
20 $ hg export . > ../test.diff
21 $ hg up null
21 $ hg up null
22 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
22 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
23
23
24 Test importing an existing revision
24 Test importing an existing revision
25
25
26 $ hg import --bypass --exact ../test.diff
26 $ hg import --bypass --exact ../test.diff
27 applying ../test.diff
27 applying ../test.diff
28 $ shortlog
28 $ shortlog
29 o 1:4e322f7ce8e3 test 0 0 - foo - changea
29 o 1:4e322f7ce8e3 test 0 0 - foo - changea
30 |
30 |
31 o 0:07f494440405 test 0 0 - default - adda
31 o 0:07f494440405 test 0 0 - default - adda
32
32
33
33
34 Test failure without --exact
34 Test failure without --exact
35
35
36 $ hg import --bypass ../test.diff
36 $ hg import --bypass ../test.diff
37 applying ../test.diff
37 applying ../test.diff
38 unable to find 'a' for patching
38 unable to find 'a' for patching
39 abort: patch failed to apply
39 abort: patch failed to apply
40 [255]
40 [255]
41 $ hg st
41 $ hg st
42 $ shortlog
42 $ shortlog
43 o 1:4e322f7ce8e3 test 0 0 - foo - changea
43 o 1:4e322f7ce8e3 test 0 0 - foo - changea
44 |
44 |
45 o 0:07f494440405 test 0 0 - default - adda
45 o 0:07f494440405 test 0 0 - default - adda
46
46
47
47
48 Test --user, --date and --message
48 Test --user, --date and --message
49
49
50 $ hg up 0
50 $ hg up 0
51 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 $ hg import --bypass --u test2 -d '1 0' -m patch2 ../test.diff
52 $ hg import --bypass --u test2 -d '1 0' -m patch2 ../test.diff
53 applying ../test.diff
53 applying ../test.diff
54 $ cat .hg/last-message.txt
54 $ cat .hg/last-message.txt
55 patch2 (no-eol)
55 patch2 (no-eol)
56 $ shortlog
56 $ shortlog
57 o 2:2e127d1da504 test2 1 0 - default - patch2
57 o 2:2e127d1da504 test2 1 0 - default - patch2
58 |
58 |
59 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
59 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
60 |/
60 |/
61 @ 0:07f494440405 test 0 0 - default - adda
61 @ 0:07f494440405 test 0 0 - default - adda
62
62
63 $ hg rollback
63 $ hg rollback
64 repository tip rolled back to revision 1 (undo commit)
64 repository tip rolled back to revision 1 (undo commit)
65 working directory now based on revision 0
66
65
67 Test --import-branch
66 Test --import-branch
68
67
69 $ hg import --bypass --import-branch ../test.diff
68 $ hg import --bypass --import-branch ../test.diff
70 applying ../test.diff
69 applying ../test.diff
71 $ shortlog
70 $ shortlog
72 o 1:4e322f7ce8e3 test 0 0 - foo - changea
71 o 1:4e322f7ce8e3 test 0 0 - foo - changea
73 |
72 |
74 @ 0:07f494440405 test 0 0 - default - adda
73 @ 0:07f494440405 test 0 0 - default - adda
75
74
76 $ hg rollback
75 $ hg rollback
77 repository tip rolled back to revision 1 (undo commit)
76 repository tip rolled back to revision 1 (undo commit)
78 working directory now based on revision 0
79
77
80 Test --strip
78 Test --strip
81
79
82 $ hg import --bypass --strip 0 - <<EOF
80 $ hg import --bypass --strip 0 - <<EOF
83 > # HG changeset patch
81 > # HG changeset patch
84 > # User test
82 > # User test
85 > # Date 0 0
83 > # Date 0 0
86 > # Branch foo
84 > # Branch foo
87 > # Node ID 4e322f7ce8e3e4203950eac9ece27bf7e45ffa6c
85 > # Node ID 4e322f7ce8e3e4203950eac9ece27bf7e45ffa6c
88 > # Parent 07f4944404050f47db2e5c5071e0e84e7a27bba9
86 > # Parent 07f4944404050f47db2e5c5071e0e84e7a27bba9
89 > changea
87 > changea
90 >
88 >
91 > diff -r 07f494440405 -r 4e322f7ce8e3 a
89 > diff -r 07f494440405 -r 4e322f7ce8e3 a
92 > --- a Thu Jan 01 00:00:00 1970 +0000
90 > --- a Thu Jan 01 00:00:00 1970 +0000
93 > +++ a Thu Jan 01 00:00:00 1970 +0000
91 > +++ a Thu Jan 01 00:00:00 1970 +0000
94 > @@ -1,1 +1,2 @@
92 > @@ -1,1 +1,2 @@
95 > a
93 > a
96 > +a
94 > +a
97 > EOF
95 > EOF
98 applying patch from stdin
96 applying patch from stdin
99 $ hg rollback
97 $ hg rollback
100 repository tip rolled back to revision 1 (undo commit)
98 repository tip rolled back to revision 1 (undo commit)
101 working directory now based on revision 0
102
99
103 Test unsupported combinations
100 Test unsupported combinations
104
101
105 $ hg import --bypass --no-commit ../test.diff
102 $ hg import --bypass --no-commit ../test.diff
106 abort: cannot use --no-commit with --bypass
103 abort: cannot use --no-commit with --bypass
107 [255]
104 [255]
108 $ hg import --bypass --similarity 50 ../test.diff
105 $ hg import --bypass --similarity 50 ../test.diff
109 abort: cannot use --similarity with --bypass
106 abort: cannot use --similarity with --bypass
110 [255]
107 [255]
111
108
112 Test commit editor
109 Test commit editor
113
110
114 $ hg diff -c 1 > ../test.diff
111 $ hg diff -c 1 > ../test.diff
115 $ HGEDITOR=cat hg import --bypass ../test.diff
112 $ HGEDITOR=cat hg import --bypass ../test.diff
116 applying ../test.diff
113 applying ../test.diff
117
114
118
115
119 HG: Enter commit message. Lines beginning with 'HG:' are removed.
116 HG: Enter commit message. Lines beginning with 'HG:' are removed.
120 HG: Leave message empty to abort commit.
117 HG: Leave message empty to abort commit.
121 HG: --
118 HG: --
122 HG: user: test
119 HG: user: test
123 HG: branch 'default'
120 HG: branch 'default'
124 HG: changed a
121 HG: changed a
125 abort: empty commit message
122 abort: empty commit message
126 [255]
123 [255]
127
124
128 Test patch.eol is handled
125 Test patch.eol is handled
129
126
130 $ python -c 'file("a", "wb").write("a\r\n")'
127 $ python -c 'file("a", "wb").write("a\r\n")'
131 $ hg ci -m makeacrlf
128 $ hg ci -m makeacrlf
132 $ hg import -m 'should fail because of eol' --bypass ../test.diff
129 $ hg import -m 'should fail because of eol' --bypass ../test.diff
133 applying ../test.diff
130 applying ../test.diff
134 patching file a
131 patching file a
135 Hunk #1 FAILED at 0
132 Hunk #1 FAILED at 0
136 abort: patch failed to apply
133 abort: patch failed to apply
137 [255]
134 [255]
138 $ hg --config patch.eol=auto import -d '0 0' -m 'test patch.eol' --bypass ../test.diff
135 $ hg --config patch.eol=auto import -d '0 0' -m 'test patch.eol' --bypass ../test.diff
139 applying ../test.diff
136 applying ../test.diff
140 $ shortlog
137 $ shortlog
141 o 3:d7805b4d2cb3 test 0 0 - default - test patch.eol
138 o 3:d7805b4d2cb3 test 0 0 - default - test patch.eol
142 |
139 |
143 @ 2:872023de769d test 0 0 - default - makeacrlf
140 @ 2:872023de769d test 0 0 - default - makeacrlf
144 |
141 |
145 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
142 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
146 |/
143 |/
147 o 0:07f494440405 test 0 0 - default - adda
144 o 0:07f494440405 test 0 0 - default - adda
148
145
149
146
150 Test applying multiple patches
147 Test applying multiple patches
151
148
152 $ hg up -qC 0
149 $ hg up -qC 0
153 $ echo e > e
150 $ echo e > e
154 $ hg ci -Am adde
151 $ hg ci -Am adde
155 adding e
152 adding e
156 created new head
153 created new head
157 $ hg export . > ../patch1.diff
154 $ hg export . > ../patch1.diff
158 $ hg up -qC 1
155 $ hg up -qC 1
159 $ echo f > f
156 $ echo f > f
160 $ hg ci -Am addf
157 $ hg ci -Am addf
161 adding f
158 adding f
162 $ hg export . > ../patch2.diff
159 $ hg export . > ../patch2.diff
163 $ cd ..
160 $ cd ..
164 $ hg clone -r1 repo-options repo-multi1
161 $ hg clone -r1 repo-options repo-multi1
165 adding changesets
162 adding changesets
166 adding manifests
163 adding manifests
167 adding file changes
164 adding file changes
168 added 2 changesets with 2 changes to 1 files
165 added 2 changesets with 2 changes to 1 files
169 updating to branch foo
166 updating to branch foo
170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
167 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 $ cd repo-multi1
168 $ cd repo-multi1
172 $ hg up 0
169 $ hg up 0
173 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 $ hg import --bypass ../patch1.diff ../patch2.diff
171 $ hg import --bypass ../patch1.diff ../patch2.diff
175 applying ../patch1.diff
172 applying ../patch1.diff
176 applying ../patch2.diff
173 applying ../patch2.diff
177 applied 16581080145e
174 applied 16581080145e
178 $ shortlog
175 $ shortlog
179 o 3:bc8ca3f8a7c4 test 0 0 - default - addf
176 o 3:bc8ca3f8a7c4 test 0 0 - default - addf
180 |
177 |
181 o 2:16581080145e test 0 0 - default - adde
178 o 2:16581080145e test 0 0 - default - adde
182 |
179 |
183 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
180 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
184 |/
181 |/
185 @ 0:07f494440405 test 0 0 - default - adda
182 @ 0:07f494440405 test 0 0 - default - adda
186
183
187
184
188 Test applying multiple patches with --exact
185 Test applying multiple patches with --exact
189
186
190 $ cd ..
187 $ cd ..
191 $ hg clone -r1 repo-options repo-multi2
188 $ hg clone -r1 repo-options repo-multi2
192 adding changesets
189 adding changesets
193 adding manifests
190 adding manifests
194 adding file changes
191 adding file changes
195 added 2 changesets with 2 changes to 1 files
192 added 2 changesets with 2 changes to 1 files
196 updating to branch foo
193 updating to branch foo
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
194 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 $ cd repo-multi2
195 $ cd repo-multi2
199 $ hg import --bypass --exact ../patch1.diff ../patch2.diff
196 $ hg import --bypass --exact ../patch1.diff ../patch2.diff
200 applying ../patch1.diff
197 applying ../patch1.diff
201 applying ../patch2.diff
198 applying ../patch2.diff
202 applied 16581080145e
199 applied 16581080145e
203 $ shortlog
200 $ shortlog
204 o 3:d60cb8989666 test 0 0 - foo - addf
201 o 3:d60cb8989666 test 0 0 - foo - addf
205 |
202 |
206 | o 2:16581080145e test 0 0 - default - adde
203 | o 2:16581080145e test 0 0 - default - adde
207 | |
204 | |
208 @ | 1:4e322f7ce8e3 test 0 0 - foo - changea
205 @ | 1:4e322f7ce8e3 test 0 0 - foo - changea
209 |/
206 |/
210 o 0:07f494440405 test 0 0 - default - adda
207 o 0:07f494440405 test 0 0 - default - adda
211
208
212
209
213 $ cd ..
210 $ cd ..
214
211
215 Test complicated patch with --exact
212 Test complicated patch with --exact
216
213
217 $ hg init repo-exact
214 $ hg init repo-exact
218 $ cd repo-exact
215 $ cd repo-exact
219 $ echo a > a
216 $ echo a > a
220 $ echo c > c
217 $ echo c > c
221 $ echo d > d
218 $ echo d > d
222 $ echo e > e
219 $ echo e > e
223 $ echo f > f
220 $ echo f > f
224 $ chmod +x f
221 $ chmod +x f
225 $ ln -s c linkc
222 $ ln -s c linkc
226 $ hg ci -Am t
223 $ hg ci -Am t
227 adding a
224 adding a
228 adding c
225 adding c
229 adding d
226 adding d
230 adding e
227 adding e
231 adding f
228 adding f
232 adding linkc
229 adding linkc
233 $ hg cp a aa1
230 $ hg cp a aa1
234 $ echo b >> a
231 $ echo b >> a
235 $ echo b > b
232 $ echo b > b
236 $ hg add b
233 $ hg add b
237 $ hg cp a aa2
234 $ hg cp a aa2
238 $ echo aa >> aa2
235 $ echo aa >> aa2
239 $ chmod +x e
236 $ chmod +x e
240 $ chmod -x f
237 $ chmod -x f
241 $ ln -s a linka
238 $ ln -s a linka
242 $ hg rm d
239 $ hg rm d
243 $ hg rm linkc
240 $ hg rm linkc
244 $ hg mv c cc
241 $ hg mv c cc
245 $ hg ci -m patch
242 $ hg ci -m patch
246 $ hg export --git . > ../test.diff
243 $ hg export --git . > ../test.diff
247 $ hg up -C null
244 $ hg up -C null
248 0 files updated, 0 files merged, 7 files removed, 0 files unresolved
245 0 files updated, 0 files merged, 7 files removed, 0 files unresolved
249 $ hg purge
246 $ hg purge
250 $ hg st
247 $ hg st
251 $ hg import --bypass --exact ../test.diff
248 $ hg import --bypass --exact ../test.diff
252 applying ../test.diff
249 applying ../test.diff
253
250
254 The patch should have matched the exported revision and generated no additional
251 The patch should have matched the exported revision and generated no additional
255 data. If not, diff both heads to debug it.
252 data. If not, diff both heads to debug it.
256
253
257 $ shortlog
254 $ shortlog
258 o 1:2978fd5c8aa4 test 0 0 - default - patch
255 o 1:2978fd5c8aa4 test 0 0 - default - patch
259 |
256 |
260 o 0:a0e19e636a43 test 0 0 - default - t
257 o 0:a0e19e636a43 test 0 0 - default - t
261
258
@@ -1,128 +1,126 b''
1
1
2 $ cat <<EOF >> $HGRCPATH
2 $ cat <<EOF >> $HGRCPATH
3 > [extensions]
3 > [extensions]
4 > notify=
4 > notify=
5 >
5 >
6 > [hooks]
6 > [hooks]
7 > changegroup.notify = python:hgext.notify.hook
7 > changegroup.notify = python:hgext.notify.hook
8 >
8 >
9 > [notify]
9 > [notify]
10 > sources = push
10 > sources = push
11 > diffstat = False
11 > diffstat = False
12 > maxsubject = 10
12 > maxsubject = 10
13 >
13 >
14 > [usersubs]
14 > [usersubs]
15 > foo@bar = *
15 > foo@bar = *
16 >
16 >
17 > [reposubs]
17 > [reposubs]
18 > * = baz
18 > * = baz
19 > EOF
19 > EOF
20 $ hg init a
20 $ hg init a
21
21
22 clone
22 clone
23
23
24 $ hg --traceback clone a b
24 $ hg --traceback clone a b
25 updating to branch default
25 updating to branch default
26 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
26 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 $ echo a > b/a
27 $ echo a > b/a
28
28
29 commit
29 commit
30
30
31 $ hg --traceback --cwd b commit -Ama
31 $ hg --traceback --cwd b commit -Ama
32 adding a
32 adding a
33 $ echo a >> b/a
33 $ echo a >> b/a
34
34
35 commit
35 commit
36
36
37 $ hg --traceback --cwd b commit -Amb
37 $ hg --traceback --cwd b commit -Amb
38
38
39 push
39 push
40
40
41 $ hg --traceback --cwd b push ../a 2>&1 |
41 $ hg --traceback --cwd b push ../a 2>&1 |
42 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
42 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
43 pushing to ../a
43 pushing to ../a
44 searching for changes
44 searching for changes
45 adding changesets
45 adding changesets
46 adding manifests
46 adding manifests
47 adding file changes
47 adding file changes
48 added 2 changesets with 2 changes to 1 files
48 added 2 changesets with 2 changes to 1 files
49 Content-Type: text/plain; charset="us-ascii"
49 Content-Type: text/plain; charset="us-ascii"
50 MIME-Version: 1.0
50 MIME-Version: 1.0
51 Content-Transfer-Encoding: 7bit
51 Content-Transfer-Encoding: 7bit
52 Date: * (glob)
52 Date: * (glob)
53 Subject: * (glob)
53 Subject: * (glob)
54 From: test
54 From: test
55 X-Hg-Notification: changeset cb9a9f314b8b
55 X-Hg-Notification: changeset cb9a9f314b8b
56 Message-Id: <*> (glob)
56 Message-Id: <*> (glob)
57 To: baz, foo@bar
57 To: baz, foo@bar
58
58
59 changeset cb9a9f314b8b in $TESTTMP/a
59 changeset cb9a9f314b8b in $TESTTMP/a
60 details: $TESTTMP/a?cmd=changeset;node=cb9a9f314b8b
60 details: $TESTTMP/a?cmd=changeset;node=cb9a9f314b8b
61 summary: a
61 summary: a
62
62
63 changeset ba677d0156c1 in $TESTTMP/a
63 changeset ba677d0156c1 in $TESTTMP/a
64 details: $TESTTMP/a?cmd=changeset;node=ba677d0156c1
64 details: $TESTTMP/a?cmd=changeset;node=ba677d0156c1
65 summary: b
65 summary: b
66
66
67 diffs (6 lines):
67 diffs (6 lines):
68
68
69 diff -r 000000000000 -r ba677d0156c1 a
69 diff -r 000000000000 -r ba677d0156c1 a
70 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
70 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
71 +++ b/a Thu Jan 01 00:00:00 1970 +0000
71 +++ b/a Thu Jan 01 00:00:00 1970 +0000
72 @@ -0,0 +1,2 @@
72 @@ -0,0 +1,2 @@
73 +a
73 +a
74 +a
74 +a
75 $ hg --cwd a rollback
75 $ hg --cwd a rollback
76 repository tip rolled back to revision -1 (undo push)
76 repository tip rolled back to revision -1 (undo push)
77 working directory now based on revision -1
78
77
79 unbundle with unrelated source
78 unbundle with unrelated source
80
79
81 $ hg --cwd b bundle ../test.hg ../a
80 $ hg --cwd b bundle ../test.hg ../a
82 searching for changes
81 searching for changes
83 2 changesets found
82 2 changesets found
84 $ hg --cwd a unbundle ../test.hg
83 $ hg --cwd a unbundle ../test.hg
85 adding changesets
84 adding changesets
86 adding manifests
85 adding manifests
87 adding file changes
86 adding file changes
88 added 2 changesets with 2 changes to 1 files
87 added 2 changesets with 2 changes to 1 files
89 (run 'hg update' to get a working copy)
88 (run 'hg update' to get a working copy)
90 $ hg --cwd a rollback
89 $ hg --cwd a rollback
91 repository tip rolled back to revision -1 (undo unbundle)
90 repository tip rolled back to revision -1 (undo unbundle)
92 working directory now based on revision -1
93
91
94 unbundle with correct source
92 unbundle with correct source
95
93
96 $ hg --config notify.sources=unbundle --cwd a unbundle ../test.hg 2>&1 |
94 $ hg --config notify.sources=unbundle --cwd a unbundle ../test.hg 2>&1 |
97 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
95 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
98 adding changesets
96 adding changesets
99 adding manifests
97 adding manifests
100 adding file changes
98 adding file changes
101 added 2 changesets with 2 changes to 1 files
99 added 2 changesets with 2 changes to 1 files
102 Content-Type: text/plain; charset="us-ascii"
100 Content-Type: text/plain; charset="us-ascii"
103 MIME-Version: 1.0
101 MIME-Version: 1.0
104 Content-Transfer-Encoding: 7bit
102 Content-Transfer-Encoding: 7bit
105 Date: * (glob)
103 Date: * (glob)
106 Subject: * (glob)
104 Subject: * (glob)
107 From: test
105 From: test
108 X-Hg-Notification: changeset cb9a9f314b8b
106 X-Hg-Notification: changeset cb9a9f314b8b
109 Message-Id: <*> (glob)
107 Message-Id: <*> (glob)
110 To: baz, foo@bar
108 To: baz, foo@bar
111
109
112 changeset cb9a9f314b8b in $TESTTMP/a
110 changeset cb9a9f314b8b in $TESTTMP/a
113 details: $TESTTMP/a?cmd=changeset;node=cb9a9f314b8b
111 details: $TESTTMP/a?cmd=changeset;node=cb9a9f314b8b
114 summary: a
112 summary: a
115
113
116 changeset ba677d0156c1 in $TESTTMP/a
114 changeset ba677d0156c1 in $TESTTMP/a
117 details: $TESTTMP/a?cmd=changeset;node=ba677d0156c1
115 details: $TESTTMP/a?cmd=changeset;node=ba677d0156c1
118 summary: b
116 summary: b
119
117
120 diffs (6 lines):
118 diffs (6 lines):
121
119
122 diff -r 000000000000 -r ba677d0156c1 a
120 diff -r 000000000000 -r ba677d0156c1 a
123 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
121 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124 +++ b/a Thu Jan 01 00:00:00 1970 +0000
122 +++ b/a Thu Jan 01 00:00:00 1970 +0000
125 @@ -0,0 +1,2 @@
123 @@ -0,0 +1,2 @@
126 +a
124 +a
127 +a
125 +a
128 (run 'hg update' to get a working copy)
126 (run 'hg update' to get a working copy)
@@ -1,400 +1,397 b''
1
1
2 $ cat <<EOF >> $HGRCPATH
2 $ cat <<EOF >> $HGRCPATH
3 > [extensions]
3 > [extensions]
4 > notify=
4 > notify=
5 >
5 >
6 > [hooks]
6 > [hooks]
7 > incoming.notify = python:hgext.notify.hook
7 > incoming.notify = python:hgext.notify.hook
8 >
8 >
9 > [notify]
9 > [notify]
10 > sources = pull
10 > sources = pull
11 > diffstat = False
11 > diffstat = False
12 >
12 >
13 > [usersubs]
13 > [usersubs]
14 > foo@bar = *
14 > foo@bar = *
15 >
15 >
16 > [reposubs]
16 > [reposubs]
17 > * = baz
17 > * = baz
18 > EOF
18 > EOF
19 $ hg help notify
19 $ hg help notify
20 notify extension - hooks for sending email push notifications
20 notify extension - hooks for sending email push notifications
21
21
22 This extension let you run hooks sending email notifications when changesets
22 This extension let you run hooks sending email notifications when changesets
23 are being pushed, from the sending or receiving side.
23 are being pushed, from the sending or receiving side.
24
24
25 First, enable the extension as explained in "hg help extensions", and register
25 First, enable the extension as explained in "hg help extensions", and register
26 the hook you want to run. "incoming" and "outgoing" hooks are run by the
26 the hook you want to run. "incoming" and "outgoing" hooks are run by the
27 changesets receiver while the "outgoing" one is for the sender:
27 changesets receiver while the "outgoing" one is for the sender:
28
28
29 [hooks]
29 [hooks]
30 # one email for each incoming changeset
30 # one email for each incoming changeset
31 incoming.notify = python:hgext.notify.hook
31 incoming.notify = python:hgext.notify.hook
32 # one email for all incoming changesets
32 # one email for all incoming changesets
33 changegroup.notify = python:hgext.notify.hook
33 changegroup.notify = python:hgext.notify.hook
34
34
35 # one email for all outgoing changesets
35 # one email for all outgoing changesets
36 outgoing.notify = python:hgext.notify.hook
36 outgoing.notify = python:hgext.notify.hook
37
37
38 Now the hooks are running, subscribers must be assigned to repositories. Use
38 Now the hooks are running, subscribers must be assigned to repositories. Use
39 the "[usersubs]" section to map repositories to a given email or the
39 the "[usersubs]" section to map repositories to a given email or the
40 "[reposubs]" section to map emails to a single repository:
40 "[reposubs]" section to map emails to a single repository:
41
41
42 [usersubs]
42 [usersubs]
43 # key is subscriber email, value is a comma-separated list of glob
43 # key is subscriber email, value is a comma-separated list of glob
44 # patterns
44 # patterns
45 user@host = pattern
45 user@host = pattern
46
46
47 [reposubs]
47 [reposubs]
48 # key is glob pattern, value is a comma-separated list of subscriber
48 # key is glob pattern, value is a comma-separated list of subscriber
49 # emails
49 # emails
50 pattern = user@host
50 pattern = user@host
51
51
52 Glob patterns are matched against absolute path to repository root. The
52 Glob patterns are matched against absolute path to repository root. The
53 subscriptions can be defined in their own file and referenced with:
53 subscriptions can be defined in their own file and referenced with:
54
54
55 [notify]
55 [notify]
56 config = /path/to/subscriptionsfile
56 config = /path/to/subscriptionsfile
57
57
58 Alternatively, they can be added to Mercurial configuration files by setting
58 Alternatively, they can be added to Mercurial configuration files by setting
59 the previous entry to an empty value.
59 the previous entry to an empty value.
60
60
61 At this point, notifications should be generated but will not be sent until
61 At this point, notifications should be generated but will not be sent until
62 you set the "notify.test" entry to "False".
62 you set the "notify.test" entry to "False".
63
63
64 Notifications content can be tweaked with the following configuration entries:
64 Notifications content can be tweaked with the following configuration entries:
65
65
66 notify.test
66 notify.test
67 If "True", print messages to stdout instead of sending them. Default: True.
67 If "True", print messages to stdout instead of sending them. Default: True.
68
68
69 notify.sources
69 notify.sources
70 Space separated list of change sources. Notifications are sent only if it
70 Space separated list of change sources. Notifications are sent only if it
71 includes the incoming or outgoing changes source. Incoming sources can be
71 includes the incoming or outgoing changes source. Incoming sources can be
72 "serve" for changes coming from http or ssh, "pull" for pulled changes,
72 "serve" for changes coming from http or ssh, "pull" for pulled changes,
73 "unbundle" for changes added by "hg unbundle" or "push" for changes being
73 "unbundle" for changes added by "hg unbundle" or "push" for changes being
74 pushed locally. Outgoing sources are the same except for "unbundle" which is
74 pushed locally. Outgoing sources are the same except for "unbundle" which is
75 replaced by "bundle". Default: serve.
75 replaced by "bundle". Default: serve.
76
76
77 notify.strip
77 notify.strip
78 Number of leading slashes to strip from url paths. By default, notifications
78 Number of leading slashes to strip from url paths. By default, notifications
79 references repositories with their absolute path. "notify.strip" let you
79 references repositories with their absolute path. "notify.strip" let you
80 turn them into relative paths. For example, "notify.strip=3" will change
80 turn them into relative paths. For example, "notify.strip=3" will change
81 "/long/path/repository" into "repository". Default: 0.
81 "/long/path/repository" into "repository". Default: 0.
82
82
83 notify.domain
83 notify.domain
84 If subscribers emails or the from email have no domain set, complete them
84 If subscribers emails or the from email have no domain set, complete them
85 with this value.
85 with this value.
86
86
87 notify.style
87 notify.style
88 Style file to use when formatting emails.
88 Style file to use when formatting emails.
89
89
90 notify.template
90 notify.template
91 Template to use when formatting emails.
91 Template to use when formatting emails.
92
92
93 notify.incoming
93 notify.incoming
94 Template to use when run as incoming hook, override "notify.template".
94 Template to use when run as incoming hook, override "notify.template".
95
95
96 notify.outgoing
96 notify.outgoing
97 Template to use when run as outgoing hook, override "notify.template".
97 Template to use when run as outgoing hook, override "notify.template".
98
98
99 notify.changegroup
99 notify.changegroup
100 Template to use when running as changegroup hook, override
100 Template to use when running as changegroup hook, override
101 "notify.template".
101 "notify.template".
102
102
103 notify.maxdiff
103 notify.maxdiff
104 Maximum number of diff lines to include in notification email. Set to 0 to
104 Maximum number of diff lines to include in notification email. Set to 0 to
105 disable the diff, -1 to include all of it. Default: 300.
105 disable the diff, -1 to include all of it. Default: 300.
106
106
107 notify.maxsubject
107 notify.maxsubject
108 Maximum number of characters in emails subject line. Default: 67.
108 Maximum number of characters in emails subject line. Default: 67.
109
109
110 notify.diffstat
110 notify.diffstat
111 Set to True to include a diffstat before diff content. Default: True.
111 Set to True to include a diffstat before diff content. Default: True.
112
112
113 notify.merge
113 notify.merge
114 If True, send notifications for merge changesets. Default: True.
114 If True, send notifications for merge changesets. Default: True.
115
115
116 If set, the following entries will also be used to customize the
116 If set, the following entries will also be used to customize the
117 notifications:
117 notifications:
118
118
119 email.from
119 email.from
120 Email "From" address to use if none can be found in generated email content.
120 Email "From" address to use if none can be found in generated email content.
121
121
122 web.baseurl
122 web.baseurl
123 Root repository browsing URL to combine with repository paths when making
123 Root repository browsing URL to combine with repository paths when making
124 references. See also "notify.strip".
124 references. See also "notify.strip".
125
125
126 no commands defined
126 no commands defined
127 $ hg init a
127 $ hg init a
128 $ echo a > a/a
128 $ echo a > a/a
129
129
130 commit
130 commit
131
131
132 $ hg --cwd a commit -Ama -d '0 0'
132 $ hg --cwd a commit -Ama -d '0 0'
133 adding a
133 adding a
134
134
135
135
136 clone
136 clone
137
137
138 $ hg --traceback clone a b
138 $ hg --traceback clone a b
139 updating to branch default
139 updating to branch default
140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 $ echo a >> a/a
141 $ echo a >> a/a
142
142
143 commit
143 commit
144
144
145 $ hg --traceback --cwd a commit -Amb -d '1 0'
145 $ hg --traceback --cwd a commit -Amb -d '1 0'
146
146
147 on Mac OS X 10.5 the tmp path is very long so would get stripped in the subject line
147 on Mac OS X 10.5 the tmp path is very long so would get stripped in the subject line
148
148
149 $ cat <<EOF >> $HGRCPATH
149 $ cat <<EOF >> $HGRCPATH
150 > [notify]
150 > [notify]
151 > maxsubject = 200
151 > maxsubject = 200
152 > EOF
152 > EOF
153
153
154 the python call below wraps continuation lines, which appear on Mac OS X 10.5 because
154 the python call below wraps continuation lines, which appear on Mac OS X 10.5 because
155 of the very long subject line
155 of the very long subject line
156 pull (minimal config)
156 pull (minimal config)
157
157
158 $ hg --traceback --cwd b pull ../a | \
158 $ hg --traceback --cwd b pull ../a | \
159 > python -c 'import sys,re; print re.sub("\n[\t ]", " ", sys.stdin.read()),'
159 > python -c 'import sys,re; print re.sub("\n[\t ]", " ", sys.stdin.read()),'
160 pulling from ../a
160 pulling from ../a
161 searching for changes
161 searching for changes
162 adding changesets
162 adding changesets
163 adding manifests
163 adding manifests
164 adding file changes
164 adding file changes
165 added 1 changesets with 1 changes to 1 files
165 added 1 changesets with 1 changes to 1 files
166 Content-Type: text/plain; charset="us-ascii"
166 Content-Type: text/plain; charset="us-ascii"
167 MIME-Version: 1.0
167 MIME-Version: 1.0
168 Content-Transfer-Encoding: 7bit
168 Content-Transfer-Encoding: 7bit
169 Date: * (glob)
169 Date: * (glob)
170 Subject: changeset in $TESTTMP/b: b
170 Subject: changeset in $TESTTMP/b: b
171 From: test
171 From: test
172 X-Hg-Notification: changeset 0647d048b600
172 X-Hg-Notification: changeset 0647d048b600
173 Message-Id: <*> (glob)
173 Message-Id: <*> (glob)
174 To: baz, foo@bar
174 To: baz, foo@bar
175
175
176 changeset 0647d048b600 in $TESTTMP/b
176 changeset 0647d048b600 in $TESTTMP/b
177 details: $TESTTMP/b?cmd=changeset;node=0647d048b600
177 details: $TESTTMP/b?cmd=changeset;node=0647d048b600
178 description: b
178 description: b
179
179
180 diffs (6 lines):
180 diffs (6 lines):
181
181
182 diff -r cb9a9f314b8b -r 0647d048b600 a
182 diff -r cb9a9f314b8b -r 0647d048b600 a
183 --- a/a Thu Jan 01 00:00:00 1970 +0000
183 --- a/a Thu Jan 01 00:00:00 1970 +0000
184 +++ b/a Thu Jan 01 00:00:01 1970 +0000
184 +++ b/a Thu Jan 01 00:00:01 1970 +0000
185 @@ -1,1 +1,2 @@ a
185 @@ -1,1 +1,2 @@ a
186 +a
186 +a
187 (run 'hg update' to get a working copy)
187 (run 'hg update' to get a working copy)
188 $ cat <<EOF >> $HGRCPATH
188 $ cat <<EOF >> $HGRCPATH
189 > [notify]
189 > [notify]
190 > config = `pwd`/.notify.conf
190 > config = `pwd`/.notify.conf
191 > domain = test.com
191 > domain = test.com
192 > strip = 42
192 > strip = 42
193 > template = Subject: {desc|firstline|strip}\nFrom: {author}\nX-Test: foo\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
193 > template = Subject: {desc|firstline|strip}\nFrom: {author}\nX-Test: foo\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
194 >
194 >
195 > [web]
195 > [web]
196 > baseurl = http://test/
196 > baseurl = http://test/
197 > EOF
197 > EOF
198
198
199 fail for config file is missing
199 fail for config file is missing
200
200
201 $ hg --cwd b rollback
201 $ hg --cwd b rollback
202 repository tip rolled back to revision 0 (undo pull)
202 repository tip rolled back to revision 0 (undo pull)
203 working directory now based on revision 0
204 $ hg --cwd b pull ../a 2>&1 | grep 'error.*\.notify\.conf' > /dev/null && echo pull failed
203 $ hg --cwd b pull ../a 2>&1 | grep 'error.*\.notify\.conf' > /dev/null && echo pull failed
205 pull failed
204 pull failed
206 $ touch ".notify.conf"
205 $ touch ".notify.conf"
207
206
208 pull
207 pull
209
208
210 $ hg --cwd b rollback
209 $ hg --cwd b rollback
211 repository tip rolled back to revision 0 (undo pull)
210 repository tip rolled back to revision 0 (undo pull)
212 working directory now based on revision 0
213 $ hg --traceback --cwd b pull ../a | \
211 $ hg --traceback --cwd b pull ../a | \
214 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
212 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
215 pulling from ../a
213 pulling from ../a
216 searching for changes
214 searching for changes
217 adding changesets
215 adding changesets
218 adding manifests
216 adding manifests
219 adding file changes
217 adding file changes
220 added 1 changesets with 1 changes to 1 files
218 added 1 changesets with 1 changes to 1 files
221 Content-Type: text/plain; charset="us-ascii"
219 Content-Type: text/plain; charset="us-ascii"
222 MIME-Version: 1.0
220 MIME-Version: 1.0
223 Content-Transfer-Encoding: 7bit
221 Content-Transfer-Encoding: 7bit
224 X-Test: foo
222 X-Test: foo
225 Date: * (glob)
223 Date: * (glob)
226 Subject: b
224 Subject: b
227 From: test@test.com
225 From: test@test.com
228 X-Hg-Notification: changeset 0647d048b600
226 X-Hg-Notification: changeset 0647d048b600
229 Message-Id: <*> (glob)
227 Message-Id: <*> (glob)
230 To: baz@test.com, foo@bar
228 To: baz@test.com, foo@bar
231
229
232 changeset 0647d048b600 in b
230 changeset 0647d048b600 in b
233 description: b
231 description: b
234 diffs (6 lines):
232 diffs (6 lines):
235
233
236 diff -r cb9a9f314b8b -r 0647d048b600 a
234 diff -r cb9a9f314b8b -r 0647d048b600 a
237 --- a/a Thu Jan 01 00:00:00 1970 +0000
235 --- a/a Thu Jan 01 00:00:00 1970 +0000
238 +++ b/a Thu Jan 01 00:00:01 1970 +0000
236 +++ b/a Thu Jan 01 00:00:01 1970 +0000
239 @@ -1,1 +1,2 @@
237 @@ -1,1 +1,2 @@
240 a
238 a
241 +a
239 +a
242 (run 'hg update' to get a working copy)
240 (run 'hg update' to get a working copy)
243
241
244 $ cat << EOF >> $HGRCPATH
242 $ cat << EOF >> $HGRCPATH
245 > [hooks]
243 > [hooks]
246 > incoming.notify = python:hgext.notify.hook
244 > incoming.notify = python:hgext.notify.hook
247 >
245 >
248 > [notify]
246 > [notify]
249 > sources = pull
247 > sources = pull
250 > diffstat = True
248 > diffstat = True
251 > EOF
249 > EOF
252
250
253 pull
251 pull
254
252
255 $ hg --cwd b rollback
253 $ hg --cwd b rollback
256 repository tip rolled back to revision 0 (undo pull)
254 repository tip rolled back to revision 0 (undo pull)
257 working directory now based on revision 0
258 $ hg --traceback --cwd b pull ../a | \
255 $ hg --traceback --cwd b pull ../a | \
259 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
256 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
260 pulling from ../a
257 pulling from ../a
261 searching for changes
258 searching for changes
262 adding changesets
259 adding changesets
263 adding manifests
260 adding manifests
264 adding file changes
261 adding file changes
265 added 1 changesets with 1 changes to 1 files
262 added 1 changesets with 1 changes to 1 files
266 Content-Type: text/plain; charset="us-ascii"
263 Content-Type: text/plain; charset="us-ascii"
267 MIME-Version: 1.0
264 MIME-Version: 1.0
268 Content-Transfer-Encoding: 7bit
265 Content-Transfer-Encoding: 7bit
269 X-Test: foo
266 X-Test: foo
270 Date: * (glob)
267 Date: * (glob)
271 Subject: b
268 Subject: b
272 From: test@test.com
269 From: test@test.com
273 X-Hg-Notification: changeset 0647d048b600
270 X-Hg-Notification: changeset 0647d048b600
274 Message-Id: <*> (glob)
271 Message-Id: <*> (glob)
275 To: baz@test.com, foo@bar
272 To: baz@test.com, foo@bar
276
273
277 changeset 0647d048b600 in b
274 changeset 0647d048b600 in b
278 description: b
275 description: b
279 diffstat:
276 diffstat:
280
277
281 a | 1 +
278 a | 1 +
282 1 files changed, 1 insertions(+), 0 deletions(-)
279 1 files changed, 1 insertions(+), 0 deletions(-)
283
280
284 diffs (6 lines):
281 diffs (6 lines):
285
282
286 diff -r cb9a9f314b8b -r 0647d048b600 a
283 diff -r cb9a9f314b8b -r 0647d048b600 a
287 --- a/a Thu Jan 01 00:00:00 1970 +0000
284 --- a/a Thu Jan 01 00:00:00 1970 +0000
288 +++ b/a Thu Jan 01 00:00:01 1970 +0000
285 +++ b/a Thu Jan 01 00:00:01 1970 +0000
289 @@ -1,1 +1,2 @@
286 @@ -1,1 +1,2 @@
290 a
287 a
291 +a
288 +a
292 (run 'hg update' to get a working copy)
289 (run 'hg update' to get a working copy)
293
290
294 test merge
291 test merge
295
292
296 $ cd a
293 $ cd a
297 $ hg up -C 0
294 $ hg up -C 0
298 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
295 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 $ echo a >> a
296 $ echo a >> a
300 $ hg ci -Am adda2 -d '2 0'
297 $ hg ci -Am adda2 -d '2 0'
301 created new head
298 created new head
302 $ hg merge
299 $ hg merge
303 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 (branch merge, don't forget to commit)
301 (branch merge, don't forget to commit)
305 $ hg ci -m merge -d '3 0'
302 $ hg ci -m merge -d '3 0'
306 $ cd ..
303 $ cd ..
307 $ hg --traceback --cwd b pull ../a | \
304 $ hg --traceback --cwd b pull ../a | \
308 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
305 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
309 pulling from ../a
306 pulling from ../a
310 searching for changes
307 searching for changes
311 adding changesets
308 adding changesets
312 adding manifests
309 adding manifests
313 adding file changes
310 adding file changes
314 added 2 changesets with 0 changes to 0 files
311 added 2 changesets with 0 changes to 0 files
315 Content-Type: text/plain; charset="us-ascii"
312 Content-Type: text/plain; charset="us-ascii"
316 MIME-Version: 1.0
313 MIME-Version: 1.0
317 Content-Transfer-Encoding: 7bit
314 Content-Transfer-Encoding: 7bit
318 X-Test: foo
315 X-Test: foo
319 Date: * (glob)
316 Date: * (glob)
320 Subject: adda2
317 Subject: adda2
321 From: test@test.com
318 From: test@test.com
322 X-Hg-Notification: changeset 0a184ce6067f
319 X-Hg-Notification: changeset 0a184ce6067f
323 Message-Id: <*> (glob)
320 Message-Id: <*> (glob)
324 To: baz@test.com, foo@bar
321 To: baz@test.com, foo@bar
325
322
326 changeset 0a184ce6067f in b
323 changeset 0a184ce6067f in b
327 description: adda2
324 description: adda2
328 diffstat:
325 diffstat:
329
326
330 a | 1 +
327 a | 1 +
331 1 files changed, 1 insertions(+), 0 deletions(-)
328 1 files changed, 1 insertions(+), 0 deletions(-)
332
329
333 diffs (6 lines):
330 diffs (6 lines):
334
331
335 diff -r cb9a9f314b8b -r 0a184ce6067f a
332 diff -r cb9a9f314b8b -r 0a184ce6067f a
336 --- a/a Thu Jan 01 00:00:00 1970 +0000
333 --- a/a Thu Jan 01 00:00:00 1970 +0000
337 +++ b/a Thu Jan 01 00:00:02 1970 +0000
334 +++ b/a Thu Jan 01 00:00:02 1970 +0000
338 @@ -1,1 +1,2 @@
335 @@ -1,1 +1,2 @@
339 a
336 a
340 +a
337 +a
341 Content-Type: text/plain; charset="us-ascii"
338 Content-Type: text/plain; charset="us-ascii"
342 MIME-Version: 1.0
339 MIME-Version: 1.0
343 Content-Transfer-Encoding: 7bit
340 Content-Transfer-Encoding: 7bit
344 X-Test: foo
341 X-Test: foo
345 Date: * (glob)
342 Date: * (glob)
346 Subject: merge
343 Subject: merge
347 From: test@test.com
344 From: test@test.com
348 X-Hg-Notification: changeset 6a0cf76b2701
345 X-Hg-Notification: changeset 6a0cf76b2701
349 Message-Id: <*> (glob)
346 Message-Id: <*> (glob)
350 To: baz@test.com, foo@bar
347 To: baz@test.com, foo@bar
351
348
352 changeset 6a0cf76b2701 in b
349 changeset 6a0cf76b2701 in b
353 description: merge
350 description: merge
354 (run 'hg update' to get a working copy)
351 (run 'hg update' to get a working copy)
355
352
356 truncate multi-byte subject
353 truncate multi-byte subject
357
354
358 $ cat <<EOF >> $HGRCPATH
355 $ cat <<EOF >> $HGRCPATH
359 > [notify]
356 > [notify]
360 > maxsubject = 4
357 > maxsubject = 4
361 > EOF
358 > EOF
362 $ echo a >> a/a
359 $ echo a >> a/a
363 $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
360 $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
364 > -m `python -c 'print "\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4"'`
361 > -m `python -c 'print "\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4"'`
365 $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
362 $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
366 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
363 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
367 pulling from ../a
364 pulling from ../a
368 searching for changes
365 searching for changes
369 adding changesets
366 adding changesets
370 adding manifests
367 adding manifests
371 adding file changes
368 adding file changes
372 added 1 changesets with 1 changes to 1 files
369 added 1 changesets with 1 changes to 1 files
373 Content-Type: text/plain; charset="us-ascii"
370 Content-Type: text/plain; charset="us-ascii"
374 MIME-Version: 1.0
371 MIME-Version: 1.0
375 Content-Transfer-Encoding: 8bit
372 Content-Transfer-Encoding: 8bit
376 X-Test: foo
373 X-Test: foo
377 Date: * (glob)
374 Date: * (glob)
378 Subject: \xc3\xa0... (esc)
375 Subject: \xc3\xa0... (esc)
379 From: test@test.com
376 From: test@test.com
380 X-Hg-Notification: changeset 7ea05ad269dc
377 X-Hg-Notification: changeset 7ea05ad269dc
381 Message-Id: <*> (glob)
378 Message-Id: <*> (glob)
382 To: baz@test.com, foo@bar
379 To: baz@test.com, foo@bar
383
380
384 changeset 7ea05ad269dc in b
381 changeset 7ea05ad269dc in b
385 description: \xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4 (esc)
382 description: \xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4 (esc)
386 diffstat:
383 diffstat:
387
384
388 a | 1 +
385 a | 1 +
389 1 files changed, 1 insertions(+), 0 deletions(-)
386 1 files changed, 1 insertions(+), 0 deletions(-)
390
387
391 diffs (7 lines):
388 diffs (7 lines):
392
389
393 diff -r 6a0cf76b2701 -r 7ea05ad269dc a
390 diff -r 6a0cf76b2701 -r 7ea05ad269dc a
394 --- a/a Thu Jan 01 00:00:03 1970 +0000
391 --- a/a Thu Jan 01 00:00:03 1970 +0000
395 +++ b/a Thu Jan 01 00:00:00 1970 +0000
392 +++ b/a Thu Jan 01 00:00:00 1970 +0000
396 @@ -1,2 +1,3 @@
393 @@ -1,2 +1,3 @@
397 a
394 a
398 a
395 a
399 +a
396 +a
400 (run 'hg update' to get a working copy)
397 (run 'hg update' to get a working copy)
@@ -1,121 +1,118 b''
1
1
2 $ hg init test
2 $ hg init test
3 $ cd test
3 $ cd test
4 $ echo a > a
4 $ echo a > a
5 $ hg ci -Ama
5 $ hg ci -Ama
6 adding a
6 adding a
7 $ cd ..
7 $ cd ..
8 $ hg clone test test2
8 $ hg clone test test2
9 updating to branch default
9 updating to branch default
10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 $ cd test2
11 $ cd test2
12 $ echo a >> a
12 $ echo a >> a
13 $ hg ci -mb
13 $ hg ci -mb
14 $ req() {
14 $ req() {
15 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
15 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
16 > cat hg.pid >> $DAEMON_PIDS
16 > cat hg.pid >> $DAEMON_PIDS
17 > hg --cwd ../test2 push http://localhost:$HGPORT/
17 > hg --cwd ../test2 push http://localhost:$HGPORT/
18 > "$TESTDIR/killdaemons.py"
18 > "$TESTDIR/killdaemons.py"
19 > echo % serve errors
19 > echo % serve errors
20 > cat errors.log
20 > cat errors.log
21 > }
21 > }
22 $ cd ../test
22 $ cd ../test
23
23
24 expect ssl error
24 expect ssl error
25
25
26 $ req
26 $ req
27 pushing to http://localhost:$HGPORT/
27 pushing to http://localhost:$HGPORT/
28 searching for changes
28 searching for changes
29 remote: ssl required
29 remote: ssl required
30 % serve errors
30 % serve errors
31
31
32 expect authorization error
32 expect authorization error
33
33
34 $ echo '[web]' > .hg/hgrc
34 $ echo '[web]' > .hg/hgrc
35 $ echo 'push_ssl = false' >> .hg/hgrc
35 $ echo 'push_ssl = false' >> .hg/hgrc
36 $ req
36 $ req
37 pushing to http://localhost:$HGPORT/
37 pushing to http://localhost:$HGPORT/
38 searching for changes
38 searching for changes
39 abort: authorization failed
39 abort: authorization failed
40 % serve errors
40 % serve errors
41
41
42 expect authorization error: must have authorized user
42 expect authorization error: must have authorized user
43
43
44 $ echo 'allow_push = unperson' >> .hg/hgrc
44 $ echo 'allow_push = unperson' >> .hg/hgrc
45 $ req
45 $ req
46 pushing to http://localhost:$HGPORT/
46 pushing to http://localhost:$HGPORT/
47 searching for changes
47 searching for changes
48 abort: authorization failed
48 abort: authorization failed
49 % serve errors
49 % serve errors
50
50
51 expect success
51 expect success
52
52
53 $ echo 'allow_push = *' >> .hg/hgrc
53 $ echo 'allow_push = *' >> .hg/hgrc
54 $ echo '[hooks]' >> .hg/hgrc
54 $ echo '[hooks]' >> .hg/hgrc
55 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup 0' >> .hg/hgrc
55 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup 0' >> .hg/hgrc
56 $ req
56 $ req
57 pushing to http://localhost:$HGPORT/
57 pushing to http://localhost:$HGPORT/
58 searching for changes
58 searching for changes
59 remote: adding changesets
59 remote: adding changesets
60 remote: adding manifests
60 remote: adding manifests
61 remote: adding file changes
61 remote: adding file changes
62 remote: added 1 changesets with 1 changes to 1 files
62 remote: added 1 changesets with 1 changes to 1 files
63 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
63 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
64 % serve errors
64 % serve errors
65 $ hg rollback
65 $ hg rollback
66 repository tip rolled back to revision 0 (undo serve)
66 repository tip rolled back to revision 0 (undo serve)
67 working directory now based on revision 0
68
67
69 expect success, server lacks the httpheader capability
68 expect success, server lacks the httpheader capability
70
69
71 $ CAP=httpheader
70 $ CAP=httpheader
72 $ . "$TESTDIR/notcapable"
71 $ . "$TESTDIR/notcapable"
73 $ req
72 $ req
74 pushing to http://localhost:$HGPORT/
73 pushing to http://localhost:$HGPORT/
75 searching for changes
74 searching for changes
76 remote: adding changesets
75 remote: adding changesets
77 remote: adding manifests
76 remote: adding manifests
78 remote: adding file changes
77 remote: adding file changes
79 remote: added 1 changesets with 1 changes to 1 files
78 remote: added 1 changesets with 1 changes to 1 files
80 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
79 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
81 % serve errors
80 % serve errors
82 $ hg rollback
81 $ hg rollback
83 repository tip rolled back to revision 0 (undo serve)
82 repository tip rolled back to revision 0 (undo serve)
84 working directory now based on revision 0
85
83
86 expect success, server lacks the unbundlehash capability
84 expect success, server lacks the unbundlehash capability
87
85
88 $ CAP=unbundlehash
86 $ CAP=unbundlehash
89 $ . "$TESTDIR/notcapable"
87 $ . "$TESTDIR/notcapable"
90 $ req
88 $ req
91 pushing to http://localhost:$HGPORT/
89 pushing to http://localhost:$HGPORT/
92 searching for changes
90 searching for changes
93 remote: adding changesets
91 remote: adding changesets
94 remote: adding manifests
92 remote: adding manifests
95 remote: adding file changes
93 remote: adding file changes
96 remote: added 1 changesets with 1 changes to 1 files
94 remote: added 1 changesets with 1 changes to 1 files
97 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
95 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
98 % serve errors
96 % serve errors
99 $ hg rollback
97 $ hg rollback
100 repository tip rolled back to revision 0 (undo serve)
98 repository tip rolled back to revision 0 (undo serve)
101 working directory now based on revision 0
102
99
103 expect authorization error: all users denied
100 expect authorization error: all users denied
104
101
105 $ echo '[web]' > .hg/hgrc
102 $ echo '[web]' > .hg/hgrc
106 $ echo 'push_ssl = false' >> .hg/hgrc
103 $ echo 'push_ssl = false' >> .hg/hgrc
107 $ echo 'deny_push = *' >> .hg/hgrc
104 $ echo 'deny_push = *' >> .hg/hgrc
108 $ req
105 $ req
109 pushing to http://localhost:$HGPORT/
106 pushing to http://localhost:$HGPORT/
110 searching for changes
107 searching for changes
111 abort: authorization failed
108 abort: authorization failed
112 % serve errors
109 % serve errors
113
110
114 expect authorization error: some users denied, users must be authenticated
111 expect authorization error: some users denied, users must be authenticated
115
112
116 $ echo 'deny_push = unperson' >> .hg/hgrc
113 $ echo 'deny_push = unperson' >> .hg/hgrc
117 $ req
114 $ req
118 pushing to http://localhost:$HGPORT/
115 pushing to http://localhost:$HGPORT/
119 searching for changes
116 searching for changes
120 abort: authorization failed
117 abort: authorization failed
121 % serve errors
118 % serve errors
@@ -1,119 +1,148 b''
1 setup repo
1 setup repo
2 $ hg init t
2 $ hg init t
3 $ cd t
3 $ cd t
4 $ echo a > a
4 $ echo a > a
5 $ hg commit -Am'add a'
5 $ hg commit -Am'add a'
6 adding a
6 adding a
7 $ hg verify
7 $ hg verify
8 checking changesets
8 checking changesets
9 checking manifests
9 checking manifests
10 crosschecking files in changesets and manifests
10 crosschecking files in changesets and manifests
11 checking files
11 checking files
12 1 files, 1 changesets, 1 total revisions
12 1 files, 1 changesets, 1 total revisions
13 $ hg parents
13 $ hg parents
14 changeset: 0:1f0dee641bb7
14 changeset: 0:1f0dee641bb7
15 tag: tip
15 tag: tip
16 user: test
16 user: test
17 date: Thu Jan 01 00:00:00 1970 +0000
17 date: Thu Jan 01 00:00:00 1970 +0000
18 summary: add a
18 summary: add a
19
19
20
20
21 rollback to null revision
21 rollback to null revision
22 $ hg status
22 $ hg status
23 $ hg rollback
23 $ hg rollback
24 repository tip rolled back to revision -1 (undo commit)
24 repository tip rolled back to revision -1 (undo commit)
25 working directory now based on revision -1
25 working directory now based on revision -1
26 $ hg verify
26 $ hg verify
27 checking changesets
27 checking changesets
28 checking manifests
28 checking manifests
29 crosschecking files in changesets and manifests
29 crosschecking files in changesets and manifests
30 checking files
30 checking files
31 0 files, 0 changesets, 0 total revisions
31 0 files, 0 changesets, 0 total revisions
32 $ hg parents
32 $ hg parents
33 $ hg status
33 $ hg status
34 A a
34 A a
35
35
36 Two changesets this time so we rollback to a real changeset
36 Two changesets this time so we rollback to a real changeset
37 $ hg commit -m'add a again'
37 $ hg commit -m'add a again'
38 $ echo a >> a
38 $ echo a >> a
39 $ hg commit -m'modify a'
39 $ hg commit -m'modify a'
40
40
41 Test issue 902 (current branch is preserved)
41 Test issue 902 (current branch is preserved)
42 $ hg branch test
42 $ hg branch test
43 marked working directory as branch test
43 marked working directory as branch test
44 $ hg rollback
44 $ hg rollback
45 repository tip rolled back to revision 0 (undo commit)
45 repository tip rolled back to revision 0 (undo commit)
46 working directory now based on revision 0
46 working directory now based on revision 0
47 $ hg branch
47 $ hg branch
48 default
48 default
49
49
50 Test issue 1635 (commit message saved)
50 Test issue 1635 (commit message saved)
51 $ cat .hg/last-message.txt ; echo
51 $ cat .hg/last-message.txt ; echo
52 modify a
52 modify a
53
53
54 Test rollback of hg before issue 902 was fixed
54 Test rollback of hg before issue 902 was fixed
55
55
56 $ hg commit -m "test3"
56 $ hg commit -m "test3"
57 $ hg branch test
57 $ hg branch test
58 marked working directory as branch test
58 marked working directory as branch test
59 $ rm .hg/undo.branch
59 $ rm .hg/undo.branch
60 $ hg rollback
60 $ hg rollback
61 repository tip rolled back to revision 0 (undo commit)
61 repository tip rolled back to revision 0 (undo commit)
62 named branch could not be reset: current branch is still 'test'
62 named branch could not be reset: current branch is still 'test'
63 working directory now based on revision 0
63 working directory now based on revision 0
64 $ hg branch
64 $ hg branch
65 test
65 test
66
66
67 working dir unaffected by rollback: do not restore dirstate et. al.
68 $ hg log --template '{rev} {branch} {desc|firstline}\n'
69 0 default add a again
70 $ hg status
71 M a
72 $ hg bookmark foo
73 $ hg commit -m'modify a again'
74 $ echo b > b
75 $ hg commit -Am'add b'
76 adding b
77 $ hg log --template '{rev} {branch} {desc|firstline}\n'
78 2 test add b
79 1 test modify a again
80 0 default add a again
81 $ hg update default
82 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 $ hg bookmark bar
84 $ cat .hg/undo.branch ; echo
85 test
86 $ hg rollback
87 repository tip rolled back to revision 1 (undo commit)
88 $ hg id -n
89 0
90 $ hg branch
91 default
92 $ cat .hg/bookmarks.current ; echo
93 bar
94 $ hg bookmark --delete foo
95
67 rollback by pretxncommit saves commit message (issue 1635)
96 rollback by pretxncommit saves commit message (issue 1635)
68
97
69 $ echo a >> a
98 $ echo a >> a
70 $ hg --config hooks.pretxncommit=false commit -m"precious commit message"
99 $ hg --config hooks.pretxncommit=false commit -m"precious commit message"
71 transaction abort!
100 transaction abort!
72 rollback completed
101 rollback completed
73 abort: pretxncommit hook exited with status * (glob)
102 abort: pretxncommit hook exited with status * (glob)
74 [255]
103 [255]
75 $ cat .hg/last-message.txt ; echo
104 $ cat .hg/last-message.txt ; echo
76 precious commit message
105 precious commit message
77
106
78 same thing, but run $EDITOR
107 same thing, but run $EDITOR
79
108
80 $ cat > editor << '__EOF__'
109 $ cat > editor << '__EOF__'
81 > #!/bin/sh
110 > #!/bin/sh
82 > echo "another precious commit message" > "$1"
111 > echo "another precious commit message" > "$1"
83 > __EOF__
112 > __EOF__
84 $ chmod +x editor
113 $ chmod +x editor
85 $ HGEDITOR="'`pwd`'"/editor hg --config hooks.pretxncommit=false commit 2>&1
114 $ HGEDITOR="'`pwd`'"/editor hg --config hooks.pretxncommit=false commit 2>&1
86 transaction abort!
115 transaction abort!
87 rollback completed
116 rollback completed
88 note: commit message saved in .hg/last-message.txt
117 note: commit message saved in .hg/last-message.txt
89 abort: pretxncommit hook exited with status * (glob)
118 abort: pretxncommit hook exited with status * (glob)
90 [255]
119 [255]
91 $ cat .hg/last-message.txt
120 $ cat .hg/last-message.txt
92 another precious commit message
121 another precious commit message
93
122
94 test rollback on served repository
123 test rollback on served repository
95
124
96 $ hg commit -m "precious commit message"
125 $ hg commit -m "precious commit message"
97 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
126 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
98 $ cat hg.pid >> $DAEMON_PIDS
127 $ cat hg.pid >> $DAEMON_PIDS
99 $ cd ..
128 $ cd ..
100 $ hg clone http://localhost:$HGPORT u
129 $ hg clone http://localhost:$HGPORT u
101 requesting all changes
130 requesting all changes
102 adding changesets
131 adding changesets
103 adding manifests
132 adding manifests
104 adding file changes
133 adding file changes
105 added 2 changesets with 2 changes to 1 files
134 added 3 changesets with 2 changes to 1 files (+1 heads)
106 updating to branch default
135 updating to branch default
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
136 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 $ cd u
137 $ cd u
109 $ hg id default
138 $ hg id default
110 8902593132ae
139 068774709090
111
140
112 now rollback and observe that 'hg serve' reloads the repository and
141 now rollback and observe that 'hg serve' reloads the repository and
113 presents the correct tip changeset:
142 presents the correct tip changeset:
114
143
115 $ hg -R ../t rollback
144 $ hg -R ../t rollback
116 repository tip rolled back to revision 0 (undo commit)
145 repository tip rolled back to revision 1 (undo commit)
117 working directory now based on revision 0
146 working directory now based on revision 0
118 $ hg id default
147 $ hg id default
119 23b0221f3370
148 791dd2169706
@@ -1,208 +1,203 b''
1 Test basic functionality of url#rev syntax
1 Test basic functionality of url#rev syntax
2
2
3 $ hg init repo
3 $ hg init repo
4 $ cd repo
4 $ cd repo
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -qAm 'add a'
6 $ hg ci -qAm 'add a'
7 $ hg branch foo
7 $ hg branch foo
8 marked working directory as branch foo
8 marked working directory as branch foo
9 $ echo >> a
9 $ echo >> a
10 $ hg ci -m 'change a'
10 $ hg ci -m 'change a'
11 $ cd ..
11 $ cd ..
12
12
13 $ hg clone 'repo#foo' clone
13 $ hg clone 'repo#foo' clone
14 adding changesets
14 adding changesets
15 adding manifests
15 adding manifests
16 adding file changes
16 adding file changes
17 added 2 changesets with 2 changes to 1 files
17 added 2 changesets with 2 changes to 1 files
18 updating to branch foo
18 updating to branch foo
19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20
20
21 $ hg --cwd clone heads
21 $ hg --cwd clone heads
22 changeset: 1:cd2a86ecc814
22 changeset: 1:cd2a86ecc814
23 branch: foo
23 branch: foo
24 tag: tip
24 tag: tip
25 user: test
25 user: test
26 date: Thu Jan 01 00:00:00 1970 +0000
26 date: Thu Jan 01 00:00:00 1970 +0000
27 summary: change a
27 summary: change a
28
28
29 changeset: 0:1f0dee641bb7
29 changeset: 0:1f0dee641bb7
30 user: test
30 user: test
31 date: Thu Jan 01 00:00:00 1970 +0000
31 date: Thu Jan 01 00:00:00 1970 +0000
32 summary: add a
32 summary: add a
33
33
34 $ hg --cwd clone parents
34 $ hg --cwd clone parents
35 changeset: 1:cd2a86ecc814
35 changeset: 1:cd2a86ecc814
36 branch: foo
36 branch: foo
37 tag: tip
37 tag: tip
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:00 1970 +0000
39 date: Thu Jan 01 00:00:00 1970 +0000
40 summary: change a
40 summary: change a
41
41
42 $ cat clone/.hg/hgrc
42 $ cat clone/.hg/hgrc
43 [paths]
43 [paths]
44 default = $TESTTMP/repo#foo
44 default = $TESTTMP/repo#foo
45
45
46 Changing original repo:
46 Changing original repo:
47
47
48 $ cd repo
48 $ cd repo
49
49
50 $ echo >> a
50 $ echo >> a
51 $ hg ci -m 'new head of branch foo'
51 $ hg ci -m 'new head of branch foo'
52
52
53 $ hg up -qC default
53 $ hg up -qC default
54 $ echo bar > bar
54 $ echo bar > bar
55 $ hg ci -qAm 'add bar'
55 $ hg ci -qAm 'add bar'
56
56
57 $ hg log
57 $ hg log
58 changeset: 3:4cd725637392
58 changeset: 3:4cd725637392
59 tag: tip
59 tag: tip
60 parent: 0:1f0dee641bb7
60 parent: 0:1f0dee641bb7
61 user: test
61 user: test
62 date: Thu Jan 01 00:00:00 1970 +0000
62 date: Thu Jan 01 00:00:00 1970 +0000
63 summary: add bar
63 summary: add bar
64
64
65 changeset: 2:faba9097cad4
65 changeset: 2:faba9097cad4
66 branch: foo
66 branch: foo
67 user: test
67 user: test
68 date: Thu Jan 01 00:00:00 1970 +0000
68 date: Thu Jan 01 00:00:00 1970 +0000
69 summary: new head of branch foo
69 summary: new head of branch foo
70
70
71 changeset: 1:cd2a86ecc814
71 changeset: 1:cd2a86ecc814
72 branch: foo
72 branch: foo
73 user: test
73 user: test
74 date: Thu Jan 01 00:00:00 1970 +0000
74 date: Thu Jan 01 00:00:00 1970 +0000
75 summary: change a
75 summary: change a
76
76
77 changeset: 0:1f0dee641bb7
77 changeset: 0:1f0dee641bb7
78 user: test
78 user: test
79 date: Thu Jan 01 00:00:00 1970 +0000
79 date: Thu Jan 01 00:00:00 1970 +0000
80 summary: add a
80 summary: add a
81
81
82 $ hg -q outgoing '../clone#foo'
82 $ hg -q outgoing '../clone#foo'
83 2:faba9097cad4
83 2:faba9097cad4
84
84
85 $ hg -q push '../clone#foo'
85 $ hg -q push '../clone#foo'
86
86
87 $ hg --cwd ../clone heads
87 $ hg --cwd ../clone heads
88 changeset: 2:faba9097cad4
88 changeset: 2:faba9097cad4
89 branch: foo
89 branch: foo
90 tag: tip
90 tag: tip
91 user: test
91 user: test
92 date: Thu Jan 01 00:00:00 1970 +0000
92 date: Thu Jan 01 00:00:00 1970 +0000
93 summary: new head of branch foo
93 summary: new head of branch foo
94
94
95 changeset: 0:1f0dee641bb7
95 changeset: 0:1f0dee641bb7
96 user: test
96 user: test
97 date: Thu Jan 01 00:00:00 1970 +0000
97 date: Thu Jan 01 00:00:00 1970 +0000
98 summary: add a
98 summary: add a
99
99
100 $ cd ..
100 $ cd ..
101
101
102 $ cd clone
102 $ cd clone
103 $ hg rollback
103 $ hg rollback
104 repository tip rolled back to revision 1 (undo push)
104 repository tip rolled back to revision 1 (undo push)
105 working directory now based on revision 1
106
105
107 $ hg -q incoming
106 $ hg -q incoming
108 2:faba9097cad4
107 2:faba9097cad4
109
108
110 $ hg -q pull
109 $ hg -q pull
111
110
112 $ hg heads
111 $ hg heads
113 changeset: 2:faba9097cad4
112 changeset: 2:faba9097cad4
114 branch: foo
113 branch: foo
115 tag: tip
114 tag: tip
116 user: test
115 user: test
117 date: Thu Jan 01 00:00:00 1970 +0000
116 date: Thu Jan 01 00:00:00 1970 +0000
118 summary: new head of branch foo
117 summary: new head of branch foo
119
118
120 changeset: 0:1f0dee641bb7
119 changeset: 0:1f0dee641bb7
121 user: test
120 user: test
122 date: Thu Jan 01 00:00:00 1970 +0000
121 date: Thu Jan 01 00:00:00 1970 +0000
123 summary: add a
122 summary: add a
124
123
125 Pull should not have updated:
124 Pull should not have updated:
126
125
127 $ hg parents -q
126 $ hg parents -q
128 1:cd2a86ecc814
127 1:cd2a86ecc814
129
128
130 Going back to the default branch:
129 Going back to the default branch:
131
130
132 $ hg up -C 0
131 $ hg up -C 0
133 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
134
133
135 $ hg parents
134 $ hg parents
136 changeset: 0:1f0dee641bb7
135 changeset: 0:1f0dee641bb7
137 user: test
136 user: test
138 date: Thu Jan 01 00:00:00 1970 +0000
137 date: Thu Jan 01 00:00:00 1970 +0000
139 summary: add a
138 summary: add a
140
139
141 No new revs, no update:
140 No new revs, no update:
142
141
143 $ hg pull -qu
142 $ hg pull -qu
144
143
145 $ hg parents -q
144 $ hg parents -q
146 0:1f0dee641bb7
145 0:1f0dee641bb7
147
146
148 $ hg rollback
147 $ hg rollback
149 repository tip rolled back to revision 1 (undo pull)
148 repository tip rolled back to revision 1 (undo pull)
150 working directory now based on revision 1
151
152 $ hg up -C 0
153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154
149
155 $ hg parents -q
150 $ hg parents -q
156 0:1f0dee641bb7
151 0:1f0dee641bb7
157
152
158 Pull -u takes us back to branch foo:
153 Pull -u takes us back to branch foo:
159
154
160 $ hg pull -qu
155 $ hg pull -qu
161
156
162 $ hg parents
157 $ hg parents
163 changeset: 2:faba9097cad4
158 changeset: 2:faba9097cad4
164 branch: foo
159 branch: foo
165 tag: tip
160 tag: tip
166 user: test
161 user: test
167 date: Thu Jan 01 00:00:00 1970 +0000
162 date: Thu Jan 01 00:00:00 1970 +0000
168 summary: new head of branch foo
163 summary: new head of branch foo
169
164
170 $ hg rollback
165 $ hg rollback
171 repository tip rolled back to revision 1 (undo pull)
166 repository tip rolled back to revision 1 (undo pull)
172 working directory now based on revision 0
167 working directory now based on revision 0
173
168
174 $ hg up -C 0
169 $ hg up -C 0
175 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
176
171
177 $ hg parents -q
172 $ hg parents -q
178 0:1f0dee641bb7
173 0:1f0dee641bb7
179
174
180 $ hg heads -q
175 $ hg heads -q
181 1:cd2a86ecc814
176 1:cd2a86ecc814
182 0:1f0dee641bb7
177 0:1f0dee641bb7
183
178
184 $ hg pull -qur default default
179 $ hg pull -qur default default
185
180
186 $ hg parents
181 $ hg parents
187 changeset: 3:4cd725637392
182 changeset: 3:4cd725637392
188 tag: tip
183 tag: tip
189 parent: 0:1f0dee641bb7
184 parent: 0:1f0dee641bb7
190 user: test
185 user: test
191 date: Thu Jan 01 00:00:00 1970 +0000
186 date: Thu Jan 01 00:00:00 1970 +0000
192 summary: add bar
187 summary: add bar
193
188
194 $ hg heads
189 $ hg heads
195 changeset: 3:4cd725637392
190 changeset: 3:4cd725637392
196 tag: tip
191 tag: tip
197 parent: 0:1f0dee641bb7
192 parent: 0:1f0dee641bb7
198 user: test
193 user: test
199 date: Thu Jan 01 00:00:00 1970 +0000
194 date: Thu Jan 01 00:00:00 1970 +0000
200 summary: add bar
195 summary: add bar
201
196
202 changeset: 2:faba9097cad4
197 changeset: 2:faba9097cad4
203 branch: foo
198 branch: foo
204 user: test
199 user: test
205 date: Thu Jan 01 00:00:00 1970 +0000
200 date: Thu Jan 01 00:00:00 1970 +0000
206 summary: new head of branch foo
201 summary: new head of branch foo
207
202
208
203
General Comments 0
You need to be logged in to leave comments. Login now