##// END OF EJS Templates
outgoing: fix possible filtering crash in outgoing (issue3814)...
Pierre-Yves David -
r18617:227479f6 stable
parent child Browse files
Show More
@@ -1,990 +1,994 b''
1 # scmutil.py - Mercurial core utility functions
1 # scmutil.py - Mercurial core utility functions
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com>
3 # Copyright 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 i18n import _
8 from i18n import _
9 from mercurial.node import nullrev
9 from mercurial.node import nullrev
10 import util, error, osutil, revset, similar, encoding, phases
10 import util, error, osutil, revset, similar, encoding, phases
11 import match as matchmod
11 import match as matchmod
12 import os, errno, re, stat, sys, glob
12 import os, errno, re, stat, sys, glob
13
13
14 def nochangesfound(ui, repo, excluded=None):
14 def nochangesfound(ui, repo, excluded=None):
15 '''Report no changes for push/pull, excluded is None or a list of
15 '''Report no changes for push/pull, excluded is None or a list of
16 nodes excluded from the push/pull.
16 nodes excluded from the push/pull.
17 '''
17 '''
18 secretlist = []
18 secretlist = []
19 if excluded:
19 if excluded:
20 for n in excluded:
20 for n in excluded:
21 if n not in repo:
22 # discovery should not have included the filtered revision,
23 # we have to explicitly exclude it until discovery is cleanup.
24 continue
21 ctx = repo[n]
25 ctx = repo[n]
22 if ctx.phase() >= phases.secret and not ctx.extinct():
26 if ctx.phase() >= phases.secret and not ctx.extinct():
23 secretlist.append(n)
27 secretlist.append(n)
24
28
25 if secretlist:
29 if secretlist:
26 ui.status(_("no changes found (ignored %d secret changesets)\n")
30 ui.status(_("no changes found (ignored %d secret changesets)\n")
27 % len(secretlist))
31 % len(secretlist))
28 else:
32 else:
29 ui.status(_("no changes found\n"))
33 ui.status(_("no changes found\n"))
30
34
31 def checknewlabel(repo, lbl, kind):
35 def checknewlabel(repo, lbl, kind):
32 if lbl in ['tip', '.', 'null']:
36 if lbl in ['tip', '.', 'null']:
33 raise util.Abort(_("the name '%s' is reserved") % lbl)
37 raise util.Abort(_("the name '%s' is reserved") % lbl)
34 for c in (':', '\0', '\n', '\r'):
38 for c in (':', '\0', '\n', '\r'):
35 if c in lbl:
39 if c in lbl:
36 raise util.Abort(_("%r cannot be used in a name") % c)
40 raise util.Abort(_("%r cannot be used in a name") % c)
37
41
38 def checkfilename(f):
42 def checkfilename(f):
39 '''Check that the filename f is an acceptable filename for a tracked file'''
43 '''Check that the filename f is an acceptable filename for a tracked file'''
40 if '\r' in f or '\n' in f:
44 if '\r' in f or '\n' in f:
41 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
45 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
42
46
43 def checkportable(ui, f):
47 def checkportable(ui, f):
44 '''Check if filename f is portable and warn or abort depending on config'''
48 '''Check if filename f is portable and warn or abort depending on config'''
45 checkfilename(f)
49 checkfilename(f)
46 abort, warn = checkportabilityalert(ui)
50 abort, warn = checkportabilityalert(ui)
47 if abort or warn:
51 if abort or warn:
48 msg = util.checkwinfilename(f)
52 msg = util.checkwinfilename(f)
49 if msg:
53 if msg:
50 msg = "%s: %r" % (msg, f)
54 msg = "%s: %r" % (msg, f)
51 if abort:
55 if abort:
52 raise util.Abort(msg)
56 raise util.Abort(msg)
53 ui.warn(_("warning: %s\n") % msg)
57 ui.warn(_("warning: %s\n") % msg)
54
58
55 def checkportabilityalert(ui):
59 def checkportabilityalert(ui):
56 '''check if the user's config requests nothing, a warning, or abort for
60 '''check if the user's config requests nothing, a warning, or abort for
57 non-portable filenames'''
61 non-portable filenames'''
58 val = ui.config('ui', 'portablefilenames', 'warn')
62 val = ui.config('ui', 'portablefilenames', 'warn')
59 lval = val.lower()
63 lval = val.lower()
60 bval = util.parsebool(val)
64 bval = util.parsebool(val)
61 abort = os.name == 'nt' or lval == 'abort'
65 abort = os.name == 'nt' or lval == 'abort'
62 warn = bval or lval == 'warn'
66 warn = bval or lval == 'warn'
63 if bval is None and not (warn or abort or lval == 'ignore'):
67 if bval is None and not (warn or abort or lval == 'ignore'):
64 raise error.ConfigError(
68 raise error.ConfigError(
65 _("ui.portablefilenames value is invalid ('%s')") % val)
69 _("ui.portablefilenames value is invalid ('%s')") % val)
66 return abort, warn
70 return abort, warn
67
71
68 class casecollisionauditor(object):
72 class casecollisionauditor(object):
69 def __init__(self, ui, abort, dirstate):
73 def __init__(self, ui, abort, dirstate):
70 self._ui = ui
74 self._ui = ui
71 self._abort = abort
75 self._abort = abort
72 allfiles = '\0'.join(dirstate._map)
76 allfiles = '\0'.join(dirstate._map)
73 self._loweredfiles = set(encoding.lower(allfiles).split('\0'))
77 self._loweredfiles = set(encoding.lower(allfiles).split('\0'))
74 self._dirstate = dirstate
78 self._dirstate = dirstate
75 # The purpose of _newfiles is so that we don't complain about
79 # The purpose of _newfiles is so that we don't complain about
76 # case collisions if someone were to call this object with the
80 # case collisions if someone were to call this object with the
77 # same filename twice.
81 # same filename twice.
78 self._newfiles = set()
82 self._newfiles = set()
79
83
80 def __call__(self, f):
84 def __call__(self, f):
81 fl = encoding.lower(f)
85 fl = encoding.lower(f)
82 if (fl in self._loweredfiles and f not in self._dirstate and
86 if (fl in self._loweredfiles and f not in self._dirstate and
83 f not in self._newfiles):
87 f not in self._newfiles):
84 msg = _('possible case-folding collision for %s') % f
88 msg = _('possible case-folding collision for %s') % f
85 if self._abort:
89 if self._abort:
86 raise util.Abort(msg)
90 raise util.Abort(msg)
87 self._ui.warn(_("warning: %s\n") % msg)
91 self._ui.warn(_("warning: %s\n") % msg)
88 self._loweredfiles.add(fl)
92 self._loweredfiles.add(fl)
89 self._newfiles.add(f)
93 self._newfiles.add(f)
90
94
91 class pathauditor(object):
95 class pathauditor(object):
92 '''ensure that a filesystem path contains no banned components.
96 '''ensure that a filesystem path contains no banned components.
93 the following properties of a path are checked:
97 the following properties of a path are checked:
94
98
95 - ends with a directory separator
99 - ends with a directory separator
96 - under top-level .hg
100 - under top-level .hg
97 - starts at the root of a windows drive
101 - starts at the root of a windows drive
98 - contains ".."
102 - contains ".."
99 - traverses a symlink (e.g. a/symlink_here/b)
103 - traverses a symlink (e.g. a/symlink_here/b)
100 - inside a nested repository (a callback can be used to approve
104 - inside a nested repository (a callback can be used to approve
101 some nested repositories, e.g., subrepositories)
105 some nested repositories, e.g., subrepositories)
102 '''
106 '''
103
107
104 def __init__(self, root, callback=None):
108 def __init__(self, root, callback=None):
105 self.audited = set()
109 self.audited = set()
106 self.auditeddir = set()
110 self.auditeddir = set()
107 self.root = root
111 self.root = root
108 self.callback = callback
112 self.callback = callback
109 if os.path.lexists(root) and not util.checkcase(root):
113 if os.path.lexists(root) and not util.checkcase(root):
110 self.normcase = util.normcase
114 self.normcase = util.normcase
111 else:
115 else:
112 self.normcase = lambda x: x
116 self.normcase = lambda x: x
113
117
114 def __call__(self, path):
118 def __call__(self, path):
115 '''Check the relative path.
119 '''Check the relative path.
116 path may contain a pattern (e.g. foodir/**.txt)'''
120 path may contain a pattern (e.g. foodir/**.txt)'''
117
121
118 path = util.localpath(path)
122 path = util.localpath(path)
119 normpath = self.normcase(path)
123 normpath = self.normcase(path)
120 if normpath in self.audited:
124 if normpath in self.audited:
121 return
125 return
122 # AIX ignores "/" at end of path, others raise EISDIR.
126 # AIX ignores "/" at end of path, others raise EISDIR.
123 if util.endswithsep(path):
127 if util.endswithsep(path):
124 raise util.Abort(_("path ends in directory separator: %s") % path)
128 raise util.Abort(_("path ends in directory separator: %s") % path)
125 parts = util.splitpath(path)
129 parts = util.splitpath(path)
126 if (os.path.splitdrive(path)[0]
130 if (os.path.splitdrive(path)[0]
127 or parts[0].lower() in ('.hg', '.hg.', '')
131 or parts[0].lower() in ('.hg', '.hg.', '')
128 or os.pardir in parts):
132 or os.pardir in parts):
129 raise util.Abort(_("path contains illegal component: %s") % path)
133 raise util.Abort(_("path contains illegal component: %s") % path)
130 if '.hg' in path.lower():
134 if '.hg' in path.lower():
131 lparts = [p.lower() for p in parts]
135 lparts = [p.lower() for p in parts]
132 for p in '.hg', '.hg.':
136 for p in '.hg', '.hg.':
133 if p in lparts[1:]:
137 if p in lparts[1:]:
134 pos = lparts.index(p)
138 pos = lparts.index(p)
135 base = os.path.join(*parts[:pos])
139 base = os.path.join(*parts[:pos])
136 raise util.Abort(_("path '%s' is inside nested repo %r")
140 raise util.Abort(_("path '%s' is inside nested repo %r")
137 % (path, base))
141 % (path, base))
138
142
139 normparts = util.splitpath(normpath)
143 normparts = util.splitpath(normpath)
140 assert len(parts) == len(normparts)
144 assert len(parts) == len(normparts)
141
145
142 parts.pop()
146 parts.pop()
143 normparts.pop()
147 normparts.pop()
144 prefixes = []
148 prefixes = []
145 while parts:
149 while parts:
146 prefix = os.sep.join(parts)
150 prefix = os.sep.join(parts)
147 normprefix = os.sep.join(normparts)
151 normprefix = os.sep.join(normparts)
148 if normprefix in self.auditeddir:
152 if normprefix in self.auditeddir:
149 break
153 break
150 curpath = os.path.join(self.root, prefix)
154 curpath = os.path.join(self.root, prefix)
151 try:
155 try:
152 st = os.lstat(curpath)
156 st = os.lstat(curpath)
153 except OSError, err:
157 except OSError, err:
154 # EINVAL can be raised as invalid path syntax under win32.
158 # EINVAL can be raised as invalid path syntax under win32.
155 # They must be ignored for patterns can be checked too.
159 # They must be ignored for patterns can be checked too.
156 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
160 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
157 raise
161 raise
158 else:
162 else:
159 if stat.S_ISLNK(st.st_mode):
163 if stat.S_ISLNK(st.st_mode):
160 raise util.Abort(
164 raise util.Abort(
161 _('path %r traverses symbolic link %r')
165 _('path %r traverses symbolic link %r')
162 % (path, prefix))
166 % (path, prefix))
163 elif (stat.S_ISDIR(st.st_mode) and
167 elif (stat.S_ISDIR(st.st_mode) and
164 os.path.isdir(os.path.join(curpath, '.hg'))):
168 os.path.isdir(os.path.join(curpath, '.hg'))):
165 if not self.callback or not self.callback(curpath):
169 if not self.callback or not self.callback(curpath):
166 raise util.Abort(_("path '%s' is inside nested "
170 raise util.Abort(_("path '%s' is inside nested "
167 "repo %r")
171 "repo %r")
168 % (path, prefix))
172 % (path, prefix))
169 prefixes.append(normprefix)
173 prefixes.append(normprefix)
170 parts.pop()
174 parts.pop()
171 normparts.pop()
175 normparts.pop()
172
176
173 self.audited.add(normpath)
177 self.audited.add(normpath)
174 # only add prefixes to the cache after checking everything: we don't
178 # only add prefixes to the cache after checking everything: we don't
175 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
179 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
176 self.auditeddir.update(prefixes)
180 self.auditeddir.update(prefixes)
177
181
178 class abstractvfs(object):
182 class abstractvfs(object):
179 """Abstract base class; cannot be instantiated"""
183 """Abstract base class; cannot be instantiated"""
180
184
181 def __init__(self, *args, **kwargs):
185 def __init__(self, *args, **kwargs):
182 '''Prevent instantiation; don't call this from subclasses.'''
186 '''Prevent instantiation; don't call this from subclasses.'''
183 raise NotImplementedError('attempted instantiating ' + str(type(self)))
187 raise NotImplementedError('attempted instantiating ' + str(type(self)))
184
188
185 def tryread(self, path):
189 def tryread(self, path):
186 '''gracefully return an empty string for missing files'''
190 '''gracefully return an empty string for missing files'''
187 try:
191 try:
188 return self.read(path)
192 return self.read(path)
189 except IOError, inst:
193 except IOError, inst:
190 if inst.errno != errno.ENOENT:
194 if inst.errno != errno.ENOENT:
191 raise
195 raise
192 return ""
196 return ""
193
197
194 def read(self, path):
198 def read(self, path):
195 fp = self(path, 'rb')
199 fp = self(path, 'rb')
196 try:
200 try:
197 return fp.read()
201 return fp.read()
198 finally:
202 finally:
199 fp.close()
203 fp.close()
200
204
201 def write(self, path, data):
205 def write(self, path, data):
202 fp = self(path, 'wb')
206 fp = self(path, 'wb')
203 try:
207 try:
204 return fp.write(data)
208 return fp.write(data)
205 finally:
209 finally:
206 fp.close()
210 fp.close()
207
211
208 def append(self, path, data):
212 def append(self, path, data):
209 fp = self(path, 'ab')
213 fp = self(path, 'ab')
210 try:
214 try:
211 return fp.write(data)
215 return fp.write(data)
212 finally:
216 finally:
213 fp.close()
217 fp.close()
214
218
215 def exists(self, path=None):
219 def exists(self, path=None):
216 return os.path.exists(self.join(path))
220 return os.path.exists(self.join(path))
217
221
218 def isdir(self, path=None):
222 def isdir(self, path=None):
219 return os.path.isdir(self.join(path))
223 return os.path.isdir(self.join(path))
220
224
221 def makedir(self, path=None, notindexed=True):
225 def makedir(self, path=None, notindexed=True):
222 return util.makedir(self.join(path), notindexed)
226 return util.makedir(self.join(path), notindexed)
223
227
224 def makedirs(self, path=None, mode=None):
228 def makedirs(self, path=None, mode=None):
225 return util.makedirs(self.join(path), mode)
229 return util.makedirs(self.join(path), mode)
226
230
227 def mkdir(self, path=None):
231 def mkdir(self, path=None):
228 return os.mkdir(self.join(path))
232 return os.mkdir(self.join(path))
229
233
230 def readdir(self, path=None, stat=None, skip=None):
234 def readdir(self, path=None, stat=None, skip=None):
231 return osutil.listdir(self.join(path), stat, skip)
235 return osutil.listdir(self.join(path), stat, skip)
232
236
233 def stat(self, path=None):
237 def stat(self, path=None):
234 return os.stat(self.join(path))
238 return os.stat(self.join(path))
235
239
236 class vfs(abstractvfs):
240 class vfs(abstractvfs):
237 '''Operate files relative to a base directory
241 '''Operate files relative to a base directory
238
242
239 This class is used to hide the details of COW semantics and
243 This class is used to hide the details of COW semantics and
240 remote file access from higher level code.
244 remote file access from higher level code.
241 '''
245 '''
242 def __init__(self, base, audit=True, expand=False):
246 def __init__(self, base, audit=True, expand=False):
243 if expand:
247 if expand:
244 base = os.path.realpath(util.expandpath(base))
248 base = os.path.realpath(util.expandpath(base))
245 self.base = base
249 self.base = base
246 self._setmustaudit(audit)
250 self._setmustaudit(audit)
247 self.createmode = None
251 self.createmode = None
248 self._trustnlink = None
252 self._trustnlink = None
249
253
250 def _getmustaudit(self):
254 def _getmustaudit(self):
251 return self._audit
255 return self._audit
252
256
253 def _setmustaudit(self, onoff):
257 def _setmustaudit(self, onoff):
254 self._audit = onoff
258 self._audit = onoff
255 if onoff:
259 if onoff:
256 self.audit = pathauditor(self.base)
260 self.audit = pathauditor(self.base)
257 else:
261 else:
258 self.audit = util.always
262 self.audit = util.always
259
263
260 mustaudit = property(_getmustaudit, _setmustaudit)
264 mustaudit = property(_getmustaudit, _setmustaudit)
261
265
262 @util.propertycache
266 @util.propertycache
263 def _cansymlink(self):
267 def _cansymlink(self):
264 return util.checklink(self.base)
268 return util.checklink(self.base)
265
269
266 @util.propertycache
270 @util.propertycache
267 def _chmod(self):
271 def _chmod(self):
268 return util.checkexec(self.base)
272 return util.checkexec(self.base)
269
273
270 def _fixfilemode(self, name):
274 def _fixfilemode(self, name):
271 if self.createmode is None or not self._chmod:
275 if self.createmode is None or not self._chmod:
272 return
276 return
273 os.chmod(name, self.createmode & 0666)
277 os.chmod(name, self.createmode & 0666)
274
278
275 def __call__(self, path, mode="r", text=False, atomictemp=False):
279 def __call__(self, path, mode="r", text=False, atomictemp=False):
276 if self._audit:
280 if self._audit:
277 r = util.checkosfilename(path)
281 r = util.checkosfilename(path)
278 if r:
282 if r:
279 raise util.Abort("%s: %r" % (r, path))
283 raise util.Abort("%s: %r" % (r, path))
280 self.audit(path)
284 self.audit(path)
281 f = self.join(path)
285 f = self.join(path)
282
286
283 if not text and "b" not in mode:
287 if not text and "b" not in mode:
284 mode += "b" # for that other OS
288 mode += "b" # for that other OS
285
289
286 nlink = -1
290 nlink = -1
287 if mode not in ('r', 'rb'):
291 if mode not in ('r', 'rb'):
288 dirname, basename = util.split(f)
292 dirname, basename = util.split(f)
289 # If basename is empty, then the path is malformed because it points
293 # If basename is empty, then the path is malformed because it points
290 # to a directory. Let the posixfile() call below raise IOError.
294 # to a directory. Let the posixfile() call below raise IOError.
291 if basename:
295 if basename:
292 if atomictemp:
296 if atomictemp:
293 if not os.path.isdir(dirname):
297 if not os.path.isdir(dirname):
294 util.makedirs(dirname, self.createmode)
298 util.makedirs(dirname, self.createmode)
295 return util.atomictempfile(f, mode, self.createmode)
299 return util.atomictempfile(f, mode, self.createmode)
296 try:
300 try:
297 if 'w' in mode:
301 if 'w' in mode:
298 util.unlink(f)
302 util.unlink(f)
299 nlink = 0
303 nlink = 0
300 else:
304 else:
301 # nlinks() may behave differently for files on Windows
305 # nlinks() may behave differently for files on Windows
302 # shares if the file is open.
306 # shares if the file is open.
303 fd = util.posixfile(f)
307 fd = util.posixfile(f)
304 nlink = util.nlinks(f)
308 nlink = util.nlinks(f)
305 if nlink < 1:
309 if nlink < 1:
306 nlink = 2 # force mktempcopy (issue1922)
310 nlink = 2 # force mktempcopy (issue1922)
307 fd.close()
311 fd.close()
308 except (OSError, IOError), e:
312 except (OSError, IOError), e:
309 if e.errno != errno.ENOENT:
313 if e.errno != errno.ENOENT:
310 raise
314 raise
311 nlink = 0
315 nlink = 0
312 if not os.path.isdir(dirname):
316 if not os.path.isdir(dirname):
313 util.makedirs(dirname, self.createmode)
317 util.makedirs(dirname, self.createmode)
314 if nlink > 0:
318 if nlink > 0:
315 if self._trustnlink is None:
319 if self._trustnlink is None:
316 self._trustnlink = nlink > 1 or util.checknlink(f)
320 self._trustnlink = nlink > 1 or util.checknlink(f)
317 if nlink > 1 or not self._trustnlink:
321 if nlink > 1 or not self._trustnlink:
318 util.rename(util.mktempcopy(f), f)
322 util.rename(util.mktempcopy(f), f)
319 fp = util.posixfile(f, mode)
323 fp = util.posixfile(f, mode)
320 if nlink == 0:
324 if nlink == 0:
321 self._fixfilemode(f)
325 self._fixfilemode(f)
322 return fp
326 return fp
323
327
324 def symlink(self, src, dst):
328 def symlink(self, src, dst):
325 self.audit(dst)
329 self.audit(dst)
326 linkname = self.join(dst)
330 linkname = self.join(dst)
327 try:
331 try:
328 os.unlink(linkname)
332 os.unlink(linkname)
329 except OSError:
333 except OSError:
330 pass
334 pass
331
335
332 dirname = os.path.dirname(linkname)
336 dirname = os.path.dirname(linkname)
333 if not os.path.exists(dirname):
337 if not os.path.exists(dirname):
334 util.makedirs(dirname, self.createmode)
338 util.makedirs(dirname, self.createmode)
335
339
336 if self._cansymlink:
340 if self._cansymlink:
337 try:
341 try:
338 os.symlink(src, linkname)
342 os.symlink(src, linkname)
339 except OSError, err:
343 except OSError, err:
340 raise OSError(err.errno, _('could not symlink to %r: %s') %
344 raise OSError(err.errno, _('could not symlink to %r: %s') %
341 (src, err.strerror), linkname)
345 (src, err.strerror), linkname)
342 else:
346 else:
343 self.write(dst, src)
347 self.write(dst, src)
344
348
345 def join(self, path):
349 def join(self, path):
346 if path:
350 if path:
347 return os.path.join(self.base, path)
351 return os.path.join(self.base, path)
348 else:
352 else:
349 return self.base
353 return self.base
350
354
351 opener = vfs
355 opener = vfs
352
356
353 class auditvfs(object):
357 class auditvfs(object):
354 def __init__(self, vfs):
358 def __init__(self, vfs):
355 self.vfs = vfs
359 self.vfs = vfs
356
360
357 def _getmustaudit(self):
361 def _getmustaudit(self):
358 return self.vfs.mustaudit
362 return self.vfs.mustaudit
359
363
360 def _setmustaudit(self, onoff):
364 def _setmustaudit(self, onoff):
361 self.vfs.mustaudit = onoff
365 self.vfs.mustaudit = onoff
362
366
363 mustaudit = property(_getmustaudit, _setmustaudit)
367 mustaudit = property(_getmustaudit, _setmustaudit)
364
368
365 class filtervfs(abstractvfs, auditvfs):
369 class filtervfs(abstractvfs, auditvfs):
366 '''Wrapper vfs for filtering filenames with a function.'''
370 '''Wrapper vfs for filtering filenames with a function.'''
367
371
368 def __init__(self, vfs, filter):
372 def __init__(self, vfs, filter):
369 auditvfs.__init__(self, vfs)
373 auditvfs.__init__(self, vfs)
370 self._filter = filter
374 self._filter = filter
371
375
372 def __call__(self, path, *args, **kwargs):
376 def __call__(self, path, *args, **kwargs):
373 return self.vfs(self._filter(path), *args, **kwargs)
377 return self.vfs(self._filter(path), *args, **kwargs)
374
378
375 def join(self, path):
379 def join(self, path):
376 if path:
380 if path:
377 return self.vfs.join(self._filter(path))
381 return self.vfs.join(self._filter(path))
378 else:
382 else:
379 return self.vfs.join(path)
383 return self.vfs.join(path)
380
384
381 filteropener = filtervfs
385 filteropener = filtervfs
382
386
383 class readonlyvfs(abstractvfs, auditvfs):
387 class readonlyvfs(abstractvfs, auditvfs):
384 '''Wrapper vfs preventing any writing.'''
388 '''Wrapper vfs preventing any writing.'''
385
389
386 def __init__(self, vfs):
390 def __init__(self, vfs):
387 auditvfs.__init__(self, vfs)
391 auditvfs.__init__(self, vfs)
388
392
389 def __call__(self, path, mode='r', *args, **kw):
393 def __call__(self, path, mode='r', *args, **kw):
390 if mode not in ('r', 'rb'):
394 if mode not in ('r', 'rb'):
391 raise util.Abort('this vfs is read only')
395 raise util.Abort('this vfs is read only')
392 return self.vfs(path, mode, *args, **kw)
396 return self.vfs(path, mode, *args, **kw)
393
397
394
398
395 def canonpath(root, cwd, myname, auditor=None):
399 def canonpath(root, cwd, myname, auditor=None):
396 '''return the canonical path of myname, given cwd and root'''
400 '''return the canonical path of myname, given cwd and root'''
397 if util.endswithsep(root):
401 if util.endswithsep(root):
398 rootsep = root
402 rootsep = root
399 else:
403 else:
400 rootsep = root + os.sep
404 rootsep = root + os.sep
401 name = myname
405 name = myname
402 if not os.path.isabs(name):
406 if not os.path.isabs(name):
403 name = os.path.join(root, cwd, name)
407 name = os.path.join(root, cwd, name)
404 name = os.path.normpath(name)
408 name = os.path.normpath(name)
405 if auditor is None:
409 if auditor is None:
406 auditor = pathauditor(root)
410 auditor = pathauditor(root)
407 if name != rootsep and name.startswith(rootsep):
411 if name != rootsep and name.startswith(rootsep):
408 name = name[len(rootsep):]
412 name = name[len(rootsep):]
409 auditor(name)
413 auditor(name)
410 return util.pconvert(name)
414 return util.pconvert(name)
411 elif name == root:
415 elif name == root:
412 return ''
416 return ''
413 else:
417 else:
414 # Determine whether `name' is in the hierarchy at or beneath `root',
418 # Determine whether `name' is in the hierarchy at or beneath `root',
415 # by iterating name=dirname(name) until that causes no change (can't
419 # by iterating name=dirname(name) until that causes no change (can't
416 # check name == '/', because that doesn't work on windows). The list
420 # check name == '/', because that doesn't work on windows). The list
417 # `rel' holds the reversed list of components making up the relative
421 # `rel' holds the reversed list of components making up the relative
418 # file name we want.
422 # file name we want.
419 rel = []
423 rel = []
420 while True:
424 while True:
421 try:
425 try:
422 s = util.samefile(name, root)
426 s = util.samefile(name, root)
423 except OSError:
427 except OSError:
424 s = False
428 s = False
425 if s:
429 if s:
426 if not rel:
430 if not rel:
427 # name was actually the same as root (maybe a symlink)
431 # name was actually the same as root (maybe a symlink)
428 return ''
432 return ''
429 rel.reverse()
433 rel.reverse()
430 name = os.path.join(*rel)
434 name = os.path.join(*rel)
431 auditor(name)
435 auditor(name)
432 return util.pconvert(name)
436 return util.pconvert(name)
433 dirname, basename = util.split(name)
437 dirname, basename = util.split(name)
434 rel.append(basename)
438 rel.append(basename)
435 if dirname == name:
439 if dirname == name:
436 break
440 break
437 name = dirname
441 name = dirname
438
442
439 raise util.Abort(_("%s not under root '%s'") % (myname, root))
443 raise util.Abort(_("%s not under root '%s'") % (myname, root))
440
444
441 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
445 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
442 '''yield every hg repository under path, always recursively.
446 '''yield every hg repository under path, always recursively.
443 The recurse flag will only control recursion into repo working dirs'''
447 The recurse flag will only control recursion into repo working dirs'''
444 def errhandler(err):
448 def errhandler(err):
445 if err.filename == path:
449 if err.filename == path:
446 raise err
450 raise err
447 samestat = getattr(os.path, 'samestat', None)
451 samestat = getattr(os.path, 'samestat', None)
448 if followsym and samestat is not None:
452 if followsym and samestat is not None:
449 def adddir(dirlst, dirname):
453 def adddir(dirlst, dirname):
450 match = False
454 match = False
451 dirstat = os.stat(dirname)
455 dirstat = os.stat(dirname)
452 for lstdirstat in dirlst:
456 for lstdirstat in dirlst:
453 if samestat(dirstat, lstdirstat):
457 if samestat(dirstat, lstdirstat):
454 match = True
458 match = True
455 break
459 break
456 if not match:
460 if not match:
457 dirlst.append(dirstat)
461 dirlst.append(dirstat)
458 return not match
462 return not match
459 else:
463 else:
460 followsym = False
464 followsym = False
461
465
462 if (seen_dirs is None) and followsym:
466 if (seen_dirs is None) and followsym:
463 seen_dirs = []
467 seen_dirs = []
464 adddir(seen_dirs, path)
468 adddir(seen_dirs, path)
465 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
469 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
466 dirs.sort()
470 dirs.sort()
467 if '.hg' in dirs:
471 if '.hg' in dirs:
468 yield root # found a repository
472 yield root # found a repository
469 qroot = os.path.join(root, '.hg', 'patches')
473 qroot = os.path.join(root, '.hg', 'patches')
470 if os.path.isdir(os.path.join(qroot, '.hg')):
474 if os.path.isdir(os.path.join(qroot, '.hg')):
471 yield qroot # we have a patch queue repo here
475 yield qroot # we have a patch queue repo here
472 if recurse:
476 if recurse:
473 # avoid recursing inside the .hg directory
477 # avoid recursing inside the .hg directory
474 dirs.remove('.hg')
478 dirs.remove('.hg')
475 else:
479 else:
476 dirs[:] = [] # don't descend further
480 dirs[:] = [] # don't descend further
477 elif followsym:
481 elif followsym:
478 newdirs = []
482 newdirs = []
479 for d in dirs:
483 for d in dirs:
480 fname = os.path.join(root, d)
484 fname = os.path.join(root, d)
481 if adddir(seen_dirs, fname):
485 if adddir(seen_dirs, fname):
482 if os.path.islink(fname):
486 if os.path.islink(fname):
483 for hgname in walkrepos(fname, True, seen_dirs):
487 for hgname in walkrepos(fname, True, seen_dirs):
484 yield hgname
488 yield hgname
485 else:
489 else:
486 newdirs.append(d)
490 newdirs.append(d)
487 dirs[:] = newdirs
491 dirs[:] = newdirs
488
492
489 def osrcpath():
493 def osrcpath():
490 '''return default os-specific hgrc search path'''
494 '''return default os-specific hgrc search path'''
491 path = systemrcpath()
495 path = systemrcpath()
492 path.extend(userrcpath())
496 path.extend(userrcpath())
493 path = [os.path.normpath(f) for f in path]
497 path = [os.path.normpath(f) for f in path]
494 return path
498 return path
495
499
496 _rcpath = None
500 _rcpath = None
497
501
498 def rcpath():
502 def rcpath():
499 '''return hgrc search path. if env var HGRCPATH is set, use it.
503 '''return hgrc search path. if env var HGRCPATH is set, use it.
500 for each item in path, if directory, use files ending in .rc,
504 for each item in path, if directory, use files ending in .rc,
501 else use item.
505 else use item.
502 make HGRCPATH empty to only look in .hg/hgrc of current repo.
506 make HGRCPATH empty to only look in .hg/hgrc of current repo.
503 if no HGRCPATH, use default os-specific path.'''
507 if no HGRCPATH, use default os-specific path.'''
504 global _rcpath
508 global _rcpath
505 if _rcpath is None:
509 if _rcpath is None:
506 if 'HGRCPATH' in os.environ:
510 if 'HGRCPATH' in os.environ:
507 _rcpath = []
511 _rcpath = []
508 for p in os.environ['HGRCPATH'].split(os.pathsep):
512 for p in os.environ['HGRCPATH'].split(os.pathsep):
509 if not p:
513 if not p:
510 continue
514 continue
511 p = util.expandpath(p)
515 p = util.expandpath(p)
512 if os.path.isdir(p):
516 if os.path.isdir(p):
513 for f, kind in osutil.listdir(p):
517 for f, kind in osutil.listdir(p):
514 if f.endswith('.rc'):
518 if f.endswith('.rc'):
515 _rcpath.append(os.path.join(p, f))
519 _rcpath.append(os.path.join(p, f))
516 else:
520 else:
517 _rcpath.append(p)
521 _rcpath.append(p)
518 else:
522 else:
519 _rcpath = osrcpath()
523 _rcpath = osrcpath()
520 return _rcpath
524 return _rcpath
521
525
522 if os.name != 'nt':
526 if os.name != 'nt':
523
527
524 def rcfiles(path):
528 def rcfiles(path):
525 rcs = [os.path.join(path, 'hgrc')]
529 rcs = [os.path.join(path, 'hgrc')]
526 rcdir = os.path.join(path, 'hgrc.d')
530 rcdir = os.path.join(path, 'hgrc.d')
527 try:
531 try:
528 rcs.extend([os.path.join(rcdir, f)
532 rcs.extend([os.path.join(rcdir, f)
529 for f, kind in osutil.listdir(rcdir)
533 for f, kind in osutil.listdir(rcdir)
530 if f.endswith(".rc")])
534 if f.endswith(".rc")])
531 except OSError:
535 except OSError:
532 pass
536 pass
533 return rcs
537 return rcs
534
538
535 def systemrcpath():
539 def systemrcpath():
536 path = []
540 path = []
537 if sys.platform == 'plan9':
541 if sys.platform == 'plan9':
538 root = 'lib/mercurial'
542 root = 'lib/mercurial'
539 else:
543 else:
540 root = 'etc/mercurial'
544 root = 'etc/mercurial'
541 # old mod_python does not set sys.argv
545 # old mod_python does not set sys.argv
542 if len(getattr(sys, 'argv', [])) > 0:
546 if len(getattr(sys, 'argv', [])) > 0:
543 p = os.path.dirname(os.path.dirname(sys.argv[0]))
547 p = os.path.dirname(os.path.dirname(sys.argv[0]))
544 path.extend(rcfiles(os.path.join(p, root)))
548 path.extend(rcfiles(os.path.join(p, root)))
545 path.extend(rcfiles('/' + root))
549 path.extend(rcfiles('/' + root))
546 return path
550 return path
547
551
548 def userrcpath():
552 def userrcpath():
549 if sys.platform == 'plan9':
553 if sys.platform == 'plan9':
550 return [os.environ['home'] + '/lib/hgrc']
554 return [os.environ['home'] + '/lib/hgrc']
551 else:
555 else:
552 return [os.path.expanduser('~/.hgrc')]
556 return [os.path.expanduser('~/.hgrc')]
553
557
554 else:
558 else:
555
559
556 import _winreg
560 import _winreg
557
561
558 def systemrcpath():
562 def systemrcpath():
559 '''return default os-specific hgrc search path'''
563 '''return default os-specific hgrc search path'''
560 rcpath = []
564 rcpath = []
561 filename = util.executablepath()
565 filename = util.executablepath()
562 # Use mercurial.ini found in directory with hg.exe
566 # Use mercurial.ini found in directory with hg.exe
563 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
567 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
564 if os.path.isfile(progrc):
568 if os.path.isfile(progrc):
565 rcpath.append(progrc)
569 rcpath.append(progrc)
566 return rcpath
570 return rcpath
567 # Use hgrc.d found in directory with hg.exe
571 # Use hgrc.d found in directory with hg.exe
568 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
572 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
569 if os.path.isdir(progrcd):
573 if os.path.isdir(progrcd):
570 for f, kind in osutil.listdir(progrcd):
574 for f, kind in osutil.listdir(progrcd):
571 if f.endswith('.rc'):
575 if f.endswith('.rc'):
572 rcpath.append(os.path.join(progrcd, f))
576 rcpath.append(os.path.join(progrcd, f))
573 return rcpath
577 return rcpath
574 # else look for a system rcpath in the registry
578 # else look for a system rcpath in the registry
575 value = util.lookupreg('SOFTWARE\\Mercurial', None,
579 value = util.lookupreg('SOFTWARE\\Mercurial', None,
576 _winreg.HKEY_LOCAL_MACHINE)
580 _winreg.HKEY_LOCAL_MACHINE)
577 if not isinstance(value, str) or not value:
581 if not isinstance(value, str) or not value:
578 return rcpath
582 return rcpath
579 value = util.localpath(value)
583 value = util.localpath(value)
580 for p in value.split(os.pathsep):
584 for p in value.split(os.pathsep):
581 if p.lower().endswith('mercurial.ini'):
585 if p.lower().endswith('mercurial.ini'):
582 rcpath.append(p)
586 rcpath.append(p)
583 elif os.path.isdir(p):
587 elif os.path.isdir(p):
584 for f, kind in osutil.listdir(p):
588 for f, kind in osutil.listdir(p):
585 if f.endswith('.rc'):
589 if f.endswith('.rc'):
586 rcpath.append(os.path.join(p, f))
590 rcpath.append(os.path.join(p, f))
587 return rcpath
591 return rcpath
588
592
589 def userrcpath():
593 def userrcpath():
590 '''return os-specific hgrc search path to the user dir'''
594 '''return os-specific hgrc search path to the user dir'''
591 home = os.path.expanduser('~')
595 home = os.path.expanduser('~')
592 path = [os.path.join(home, 'mercurial.ini'),
596 path = [os.path.join(home, 'mercurial.ini'),
593 os.path.join(home, '.hgrc')]
597 os.path.join(home, '.hgrc')]
594 userprofile = os.environ.get('USERPROFILE')
598 userprofile = os.environ.get('USERPROFILE')
595 if userprofile:
599 if userprofile:
596 path.append(os.path.join(userprofile, 'mercurial.ini'))
600 path.append(os.path.join(userprofile, 'mercurial.ini'))
597 path.append(os.path.join(userprofile, '.hgrc'))
601 path.append(os.path.join(userprofile, '.hgrc'))
598 return path
602 return path
599
603
600 def revsingle(repo, revspec, default='.'):
604 def revsingle(repo, revspec, default='.'):
601 if not revspec:
605 if not revspec:
602 return repo[default]
606 return repo[default]
603
607
604 l = revrange(repo, [revspec])
608 l = revrange(repo, [revspec])
605 if len(l) < 1:
609 if len(l) < 1:
606 raise util.Abort(_('empty revision set'))
610 raise util.Abort(_('empty revision set'))
607 return repo[l[-1]]
611 return repo[l[-1]]
608
612
609 def revpair(repo, revs):
613 def revpair(repo, revs):
610 if not revs:
614 if not revs:
611 return repo.dirstate.p1(), None
615 return repo.dirstate.p1(), None
612
616
613 l = revrange(repo, revs)
617 l = revrange(repo, revs)
614
618
615 if len(l) == 0:
619 if len(l) == 0:
616 if revs:
620 if revs:
617 raise util.Abort(_('empty revision range'))
621 raise util.Abort(_('empty revision range'))
618 return repo.dirstate.p1(), None
622 return repo.dirstate.p1(), None
619
623
620 if len(l) == 1 and len(revs) == 1 and _revrangesep not in revs[0]:
624 if len(l) == 1 and len(revs) == 1 and _revrangesep not in revs[0]:
621 return repo.lookup(l[0]), None
625 return repo.lookup(l[0]), None
622
626
623 return repo.lookup(l[0]), repo.lookup(l[-1])
627 return repo.lookup(l[0]), repo.lookup(l[-1])
624
628
625 _revrangesep = ':'
629 _revrangesep = ':'
626
630
627 def revrange(repo, revs):
631 def revrange(repo, revs):
628 """Yield revision as strings from a list of revision specifications."""
632 """Yield revision as strings from a list of revision specifications."""
629
633
630 def revfix(repo, val, defval):
634 def revfix(repo, val, defval):
631 if not val and val != 0 and defval is not None:
635 if not val and val != 0 and defval is not None:
632 return defval
636 return defval
633 return repo[val].rev()
637 return repo[val].rev()
634
638
635 seen, l = set(), []
639 seen, l = set(), []
636 for spec in revs:
640 for spec in revs:
637 if l and not seen:
641 if l and not seen:
638 seen = set(l)
642 seen = set(l)
639 # attempt to parse old-style ranges first to deal with
643 # attempt to parse old-style ranges first to deal with
640 # things like old-tag which contain query metacharacters
644 # things like old-tag which contain query metacharacters
641 try:
645 try:
642 if isinstance(spec, int):
646 if isinstance(spec, int):
643 seen.add(spec)
647 seen.add(spec)
644 l.append(spec)
648 l.append(spec)
645 continue
649 continue
646
650
647 if _revrangesep in spec:
651 if _revrangesep in spec:
648 start, end = spec.split(_revrangesep, 1)
652 start, end = spec.split(_revrangesep, 1)
649 start = revfix(repo, start, 0)
653 start = revfix(repo, start, 0)
650 end = revfix(repo, end, len(repo) - 1)
654 end = revfix(repo, end, len(repo) - 1)
651 if end == nullrev and start <= 0:
655 if end == nullrev and start <= 0:
652 start = nullrev
656 start = nullrev
653 rangeiter = repo.changelog.revs(start, end)
657 rangeiter = repo.changelog.revs(start, end)
654 if not seen and not l:
658 if not seen and not l:
655 # by far the most common case: revs = ["-1:0"]
659 # by far the most common case: revs = ["-1:0"]
656 l = list(rangeiter)
660 l = list(rangeiter)
657 # defer syncing seen until next iteration
661 # defer syncing seen until next iteration
658 continue
662 continue
659 newrevs = set(rangeiter)
663 newrevs = set(rangeiter)
660 if seen:
664 if seen:
661 newrevs.difference_update(seen)
665 newrevs.difference_update(seen)
662 seen.update(newrevs)
666 seen.update(newrevs)
663 else:
667 else:
664 seen = newrevs
668 seen = newrevs
665 l.extend(sorted(newrevs, reverse=start > end))
669 l.extend(sorted(newrevs, reverse=start > end))
666 continue
670 continue
667 elif spec and spec in repo: # single unquoted rev
671 elif spec and spec in repo: # single unquoted rev
668 rev = revfix(repo, spec, None)
672 rev = revfix(repo, spec, None)
669 if rev in seen:
673 if rev in seen:
670 continue
674 continue
671 seen.add(rev)
675 seen.add(rev)
672 l.append(rev)
676 l.append(rev)
673 continue
677 continue
674 except error.RepoLookupError:
678 except error.RepoLookupError:
675 pass
679 pass
676
680
677 # fall through to new-style queries if old-style fails
681 # fall through to new-style queries if old-style fails
678 m = revset.match(repo.ui, spec)
682 m = revset.match(repo.ui, spec)
679 dl = [r for r in m(repo, list(repo)) if r not in seen]
683 dl = [r for r in m(repo, list(repo)) if r not in seen]
680 l.extend(dl)
684 l.extend(dl)
681 seen.update(dl)
685 seen.update(dl)
682
686
683 return l
687 return l
684
688
685 def expandpats(pats):
689 def expandpats(pats):
686 if not util.expandglobs:
690 if not util.expandglobs:
687 return list(pats)
691 return list(pats)
688 ret = []
692 ret = []
689 for p in pats:
693 for p in pats:
690 kind, name = matchmod._patsplit(p, None)
694 kind, name = matchmod._patsplit(p, None)
691 if kind is None:
695 if kind is None:
692 try:
696 try:
693 globbed = glob.glob(name)
697 globbed = glob.glob(name)
694 except re.error:
698 except re.error:
695 globbed = [name]
699 globbed = [name]
696 if globbed:
700 if globbed:
697 ret.extend(globbed)
701 ret.extend(globbed)
698 continue
702 continue
699 ret.append(p)
703 ret.append(p)
700 return ret
704 return ret
701
705
702 def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
706 def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
703 if pats == ("",):
707 if pats == ("",):
704 pats = []
708 pats = []
705 if not globbed and default == 'relpath':
709 if not globbed and default == 'relpath':
706 pats = expandpats(pats or [])
710 pats = expandpats(pats or [])
707
711
708 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
712 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
709 default)
713 default)
710 def badfn(f, msg):
714 def badfn(f, msg):
711 ctx._repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
715 ctx._repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
712 m.bad = badfn
716 m.bad = badfn
713 return m, pats
717 return m, pats
714
718
715 def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
719 def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
716 return matchandpats(ctx, pats, opts, globbed, default)[0]
720 return matchandpats(ctx, pats, opts, globbed, default)[0]
717
721
718 def matchall(repo):
722 def matchall(repo):
719 return matchmod.always(repo.root, repo.getcwd())
723 return matchmod.always(repo.root, repo.getcwd())
720
724
721 def matchfiles(repo, files):
725 def matchfiles(repo, files):
722 return matchmod.exact(repo.root, repo.getcwd(), files)
726 return matchmod.exact(repo.root, repo.getcwd(), files)
723
727
724 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
728 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
725 if dry_run is None:
729 if dry_run is None:
726 dry_run = opts.get('dry_run')
730 dry_run = opts.get('dry_run')
727 if similarity is None:
731 if similarity is None:
728 similarity = float(opts.get('similarity') or 0)
732 similarity = float(opts.get('similarity') or 0)
729 # we'd use status here, except handling of symlinks and ignore is tricky
733 # we'd use status here, except handling of symlinks and ignore is tricky
730 added, unknown, deleted, removed = [], [], [], []
734 added, unknown, deleted, removed = [], [], [], []
731 audit_path = pathauditor(repo.root)
735 audit_path = pathauditor(repo.root)
732 m = match(repo[None], pats, opts)
736 m = match(repo[None], pats, opts)
733 rejected = []
737 rejected = []
734 m.bad = lambda x, y: rejected.append(x)
738 m.bad = lambda x, y: rejected.append(x)
735
739
736 for abs in repo.walk(m):
740 for abs in repo.walk(m):
737 target = repo.wjoin(abs)
741 target = repo.wjoin(abs)
738 good = True
742 good = True
739 try:
743 try:
740 audit_path(abs)
744 audit_path(abs)
741 except (OSError, util.Abort):
745 except (OSError, util.Abort):
742 good = False
746 good = False
743 rel = m.rel(abs)
747 rel = m.rel(abs)
744 exact = m.exact(abs)
748 exact = m.exact(abs)
745 if good and abs not in repo.dirstate:
749 if good and abs not in repo.dirstate:
746 unknown.append(abs)
750 unknown.append(abs)
747 if repo.ui.verbose or not exact:
751 if repo.ui.verbose or not exact:
748 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
752 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
749 elif (repo.dirstate[abs] != 'r' and
753 elif (repo.dirstate[abs] != 'r' and
750 (not good or not os.path.lexists(target) or
754 (not good or not os.path.lexists(target) or
751 (os.path.isdir(target) and not os.path.islink(target)))):
755 (os.path.isdir(target) and not os.path.islink(target)))):
752 deleted.append(abs)
756 deleted.append(abs)
753 if repo.ui.verbose or not exact:
757 if repo.ui.verbose or not exact:
754 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
758 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
755 # for finding renames
759 # for finding renames
756 elif repo.dirstate[abs] == 'r':
760 elif repo.dirstate[abs] == 'r':
757 removed.append(abs)
761 removed.append(abs)
758 elif repo.dirstate[abs] == 'a':
762 elif repo.dirstate[abs] == 'a':
759 added.append(abs)
763 added.append(abs)
760 copies = {}
764 copies = {}
761 if similarity > 0:
765 if similarity > 0:
762 for old, new, score in similar.findrenames(repo,
766 for old, new, score in similar.findrenames(repo,
763 added + unknown, removed + deleted, similarity):
767 added + unknown, removed + deleted, similarity):
764 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
768 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
765 repo.ui.status(_('recording removal of %s as rename to %s '
769 repo.ui.status(_('recording removal of %s as rename to %s '
766 '(%d%% similar)\n') %
770 '(%d%% similar)\n') %
767 (m.rel(old), m.rel(new), score * 100))
771 (m.rel(old), m.rel(new), score * 100))
768 copies[new] = old
772 copies[new] = old
769
773
770 if not dry_run:
774 if not dry_run:
771 wctx = repo[None]
775 wctx = repo[None]
772 wlock = repo.wlock()
776 wlock = repo.wlock()
773 try:
777 try:
774 wctx.forget(deleted)
778 wctx.forget(deleted)
775 wctx.add(unknown)
779 wctx.add(unknown)
776 for new, old in copies.iteritems():
780 for new, old in copies.iteritems():
777 wctx.copy(old, new)
781 wctx.copy(old, new)
778 finally:
782 finally:
779 wlock.release()
783 wlock.release()
780
784
781 for f in rejected:
785 for f in rejected:
782 if f in m.files():
786 if f in m.files():
783 return 1
787 return 1
784 return 0
788 return 0
785
789
786 def updatedir(ui, repo, patches, similarity=0):
790 def updatedir(ui, repo, patches, similarity=0):
787 '''Update dirstate after patch application according to metadata'''
791 '''Update dirstate after patch application according to metadata'''
788 if not patches:
792 if not patches:
789 return []
793 return []
790 copies = []
794 copies = []
791 removes = set()
795 removes = set()
792 cfiles = patches.keys()
796 cfiles = patches.keys()
793 cwd = repo.getcwd()
797 cwd = repo.getcwd()
794 if cwd:
798 if cwd:
795 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
799 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
796 for f in patches:
800 for f in patches:
797 gp = patches[f]
801 gp = patches[f]
798 if not gp:
802 if not gp:
799 continue
803 continue
800 if gp.op == 'RENAME':
804 if gp.op == 'RENAME':
801 copies.append((gp.oldpath, gp.path))
805 copies.append((gp.oldpath, gp.path))
802 removes.add(gp.oldpath)
806 removes.add(gp.oldpath)
803 elif gp.op == 'COPY':
807 elif gp.op == 'COPY':
804 copies.append((gp.oldpath, gp.path))
808 copies.append((gp.oldpath, gp.path))
805 elif gp.op == 'DELETE':
809 elif gp.op == 'DELETE':
806 removes.add(gp.path)
810 removes.add(gp.path)
807
811
808 wctx = repo[None]
812 wctx = repo[None]
809 for src, dst in copies:
813 for src, dst in copies:
810 dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd)
814 dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd)
811 if (not similarity) and removes:
815 if (not similarity) and removes:
812 wctx.remove(sorted(removes), True)
816 wctx.remove(sorted(removes), True)
813
817
814 for f in patches:
818 for f in patches:
815 gp = patches[f]
819 gp = patches[f]
816 if gp and gp.mode:
820 if gp and gp.mode:
817 islink, isexec = gp.mode
821 islink, isexec = gp.mode
818 dst = repo.wjoin(gp.path)
822 dst = repo.wjoin(gp.path)
819 # patch won't create empty files
823 # patch won't create empty files
820 if gp.op == 'ADD' and not os.path.lexists(dst):
824 if gp.op == 'ADD' and not os.path.lexists(dst):
821 flags = (isexec and 'x' or '') + (islink and 'l' or '')
825 flags = (isexec and 'x' or '') + (islink and 'l' or '')
822 repo.wwrite(gp.path, '', flags)
826 repo.wwrite(gp.path, '', flags)
823 util.setflags(dst, islink, isexec)
827 util.setflags(dst, islink, isexec)
824 addremove(repo, cfiles, similarity=similarity)
828 addremove(repo, cfiles, similarity=similarity)
825 files = patches.keys()
829 files = patches.keys()
826 files.extend([r for r in removes if r not in files])
830 files.extend([r for r in removes if r not in files])
827 return sorted(files)
831 return sorted(files)
828
832
829 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
833 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
830 """Update the dirstate to reflect the intent of copying src to dst. For
834 """Update the dirstate to reflect the intent of copying src to dst. For
831 different reasons it might not end with dst being marked as copied from src.
835 different reasons it might not end with dst being marked as copied from src.
832 """
836 """
833 origsrc = repo.dirstate.copied(src) or src
837 origsrc = repo.dirstate.copied(src) or src
834 if dst == origsrc: # copying back a copy?
838 if dst == origsrc: # copying back a copy?
835 if repo.dirstate[dst] not in 'mn' and not dryrun:
839 if repo.dirstate[dst] not in 'mn' and not dryrun:
836 repo.dirstate.normallookup(dst)
840 repo.dirstate.normallookup(dst)
837 else:
841 else:
838 if repo.dirstate[origsrc] == 'a' and origsrc == src:
842 if repo.dirstate[origsrc] == 'a' and origsrc == src:
839 if not ui.quiet:
843 if not ui.quiet:
840 ui.warn(_("%s has not been committed yet, so no copy "
844 ui.warn(_("%s has not been committed yet, so no copy "
841 "data will be stored for %s.\n")
845 "data will be stored for %s.\n")
842 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
846 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
843 if repo.dirstate[dst] in '?r' and not dryrun:
847 if repo.dirstate[dst] in '?r' and not dryrun:
844 wctx.add([dst])
848 wctx.add([dst])
845 elif not dryrun:
849 elif not dryrun:
846 wctx.copy(origsrc, dst)
850 wctx.copy(origsrc, dst)
847
851
848 def readrequires(opener, supported):
852 def readrequires(opener, supported):
849 '''Reads and parses .hg/requires and checks if all entries found
853 '''Reads and parses .hg/requires and checks if all entries found
850 are in the list of supported features.'''
854 are in the list of supported features.'''
851 requirements = set(opener.read("requires").splitlines())
855 requirements = set(opener.read("requires").splitlines())
852 missings = []
856 missings = []
853 for r in requirements:
857 for r in requirements:
854 if r not in supported:
858 if r not in supported:
855 if not r or not r[0].isalnum():
859 if not r or not r[0].isalnum():
856 raise error.RequirementError(_(".hg/requires file is corrupt"))
860 raise error.RequirementError(_(".hg/requires file is corrupt"))
857 missings.append(r)
861 missings.append(r)
858 missings.sort()
862 missings.sort()
859 if missings:
863 if missings:
860 raise error.RequirementError(
864 raise error.RequirementError(
861 _("unknown repository format: requires features '%s' (upgrade "
865 _("unknown repository format: requires features '%s' (upgrade "
862 "Mercurial)") % "', '".join(missings))
866 "Mercurial)") % "', '".join(missings))
863 return requirements
867 return requirements
864
868
865 class filecacheentry(object):
869 class filecacheentry(object):
866 def __init__(self, path, stat=True):
870 def __init__(self, path, stat=True):
867 self.path = path
871 self.path = path
868 self.cachestat = None
872 self.cachestat = None
869 self._cacheable = None
873 self._cacheable = None
870
874
871 if stat:
875 if stat:
872 self.cachestat = filecacheentry.stat(self.path)
876 self.cachestat = filecacheentry.stat(self.path)
873
877
874 if self.cachestat:
878 if self.cachestat:
875 self._cacheable = self.cachestat.cacheable()
879 self._cacheable = self.cachestat.cacheable()
876 else:
880 else:
877 # None means we don't know yet
881 # None means we don't know yet
878 self._cacheable = None
882 self._cacheable = None
879
883
880 def refresh(self):
884 def refresh(self):
881 if self.cacheable():
885 if self.cacheable():
882 self.cachestat = filecacheentry.stat(self.path)
886 self.cachestat = filecacheentry.stat(self.path)
883
887
884 def cacheable(self):
888 def cacheable(self):
885 if self._cacheable is not None:
889 if self._cacheable is not None:
886 return self._cacheable
890 return self._cacheable
887
891
888 # we don't know yet, assume it is for now
892 # we don't know yet, assume it is for now
889 return True
893 return True
890
894
891 def changed(self):
895 def changed(self):
892 # no point in going further if we can't cache it
896 # no point in going further if we can't cache it
893 if not self.cacheable():
897 if not self.cacheable():
894 return True
898 return True
895
899
896 newstat = filecacheentry.stat(self.path)
900 newstat = filecacheentry.stat(self.path)
897
901
898 # we may not know if it's cacheable yet, check again now
902 # we may not know if it's cacheable yet, check again now
899 if newstat and self._cacheable is None:
903 if newstat and self._cacheable is None:
900 self._cacheable = newstat.cacheable()
904 self._cacheable = newstat.cacheable()
901
905
902 # check again
906 # check again
903 if not self._cacheable:
907 if not self._cacheable:
904 return True
908 return True
905
909
906 if self.cachestat != newstat:
910 if self.cachestat != newstat:
907 self.cachestat = newstat
911 self.cachestat = newstat
908 return True
912 return True
909 else:
913 else:
910 return False
914 return False
911
915
912 @staticmethod
916 @staticmethod
913 def stat(path):
917 def stat(path):
914 try:
918 try:
915 return util.cachestat(path)
919 return util.cachestat(path)
916 except OSError, e:
920 except OSError, e:
917 if e.errno != errno.ENOENT:
921 if e.errno != errno.ENOENT:
918 raise
922 raise
919
923
920 class filecache(object):
924 class filecache(object):
921 '''A property like decorator that tracks a file under .hg/ for updates.
925 '''A property like decorator that tracks a file under .hg/ for updates.
922
926
923 Records stat info when called in _filecache.
927 Records stat info when called in _filecache.
924
928
925 On subsequent calls, compares old stat info with new info, and recreates
929 On subsequent calls, compares old stat info with new info, and recreates
926 the object when needed, updating the new stat info in _filecache.
930 the object when needed, updating the new stat info in _filecache.
927
931
928 Mercurial either atomic renames or appends for files under .hg,
932 Mercurial either atomic renames or appends for files under .hg,
929 so to ensure the cache is reliable we need the filesystem to be able
933 so to ensure the cache is reliable we need the filesystem to be able
930 to tell us if a file has been replaced. If it can't, we fallback to
934 to tell us if a file has been replaced. If it can't, we fallback to
931 recreating the object on every call (essentially the same behaviour as
935 recreating the object on every call (essentially the same behaviour as
932 propertycache).'''
936 propertycache).'''
933 def __init__(self, path):
937 def __init__(self, path):
934 self.path = path
938 self.path = path
935
939
936 def join(self, obj, fname):
940 def join(self, obj, fname):
937 """Used to compute the runtime path of the cached file.
941 """Used to compute the runtime path of the cached file.
938
942
939 Users should subclass filecache and provide their own version of this
943 Users should subclass filecache and provide their own version of this
940 function to call the appropriate join function on 'obj' (an instance
944 function to call the appropriate join function on 'obj' (an instance
941 of the class that its member function was decorated).
945 of the class that its member function was decorated).
942 """
946 """
943 return obj.join(fname)
947 return obj.join(fname)
944
948
945 def __call__(self, func):
949 def __call__(self, func):
946 self.func = func
950 self.func = func
947 self.name = func.__name__
951 self.name = func.__name__
948 return self
952 return self
949
953
950 def __get__(self, obj, type=None):
954 def __get__(self, obj, type=None):
951 # do we need to check if the file changed?
955 # do we need to check if the file changed?
952 if self.name in obj.__dict__:
956 if self.name in obj.__dict__:
953 assert self.name in obj._filecache, self.name
957 assert self.name in obj._filecache, self.name
954 return obj.__dict__[self.name]
958 return obj.__dict__[self.name]
955
959
956 entry = obj._filecache.get(self.name)
960 entry = obj._filecache.get(self.name)
957
961
958 if entry:
962 if entry:
959 if entry.changed():
963 if entry.changed():
960 entry.obj = self.func(obj)
964 entry.obj = self.func(obj)
961 else:
965 else:
962 path = self.join(obj, self.path)
966 path = self.join(obj, self.path)
963
967
964 # We stat -before- creating the object so our cache doesn't lie if
968 # We stat -before- creating the object so our cache doesn't lie if
965 # a writer modified between the time we read and stat
969 # a writer modified between the time we read and stat
966 entry = filecacheentry(path)
970 entry = filecacheentry(path)
967 entry.obj = self.func(obj)
971 entry.obj = self.func(obj)
968
972
969 obj._filecache[self.name] = entry
973 obj._filecache[self.name] = entry
970
974
971 obj.__dict__[self.name] = entry.obj
975 obj.__dict__[self.name] = entry.obj
972 return entry.obj
976 return entry.obj
973
977
974 def __set__(self, obj, value):
978 def __set__(self, obj, value):
975 if self.name not in obj._filecache:
979 if self.name not in obj._filecache:
976 # we add an entry for the missing value because X in __dict__
980 # we add an entry for the missing value because X in __dict__
977 # implies X in _filecache
981 # implies X in _filecache
978 ce = filecacheentry(self.join(obj, self.path), False)
982 ce = filecacheentry(self.join(obj, self.path), False)
979 obj._filecache[self.name] = ce
983 obj._filecache[self.name] = ce
980 else:
984 else:
981 ce = obj._filecache[self.name]
985 ce = obj._filecache[self.name]
982
986
983 ce.obj = value # update cached copy
987 ce.obj = value # update cached copy
984 obj.__dict__[self.name] = value # update copy returned by obj.x
988 obj.__dict__[self.name] = value # update copy returned by obj.x
985
989
986 def __delete__(self, obj):
990 def __delete__(self, obj):
987 try:
991 try:
988 del obj.__dict__[self.name]
992 del obj.__dict__[self.name]
989 except KeyError:
993 except KeyError:
990 raise AttributeError(self.name)
994 raise AttributeError(self.name)
@@ -1,867 +1,889 b''
1 $ cat >> $HGRCPATH << EOF
1 $ cat >> $HGRCPATH << EOF
2 > [extensions]
2 > [extensions]
3 > graphlog=
3 > graphlog=
4 > [phases]
4 > [phases]
5 > # public changeset are not obsolete
5 > # public changeset are not obsolete
6 > publish=false
6 > publish=false
7 > EOF
7 > EOF
8 $ mkcommit() {
8 $ mkcommit() {
9 > echo "$1" > "$1"
9 > echo "$1" > "$1"
10 > hg add "$1"
10 > hg add "$1"
11 > hg ci -m "add $1"
11 > hg ci -m "add $1"
12 > }
12 > }
13 $ getid() {
13 $ getid() {
14 > hg id --debug --hidden -ir "desc('$1')"
14 > hg id --debug --hidden -ir "desc('$1')"
15 > }
15 > }
16
16
17 $ cat > debugkeys.py <<EOF
17 $ cat > debugkeys.py <<EOF
18 > def reposetup(ui, repo):
18 > def reposetup(ui, repo):
19 > class debugkeysrepo(repo.__class__):
19 > class debugkeysrepo(repo.__class__):
20 > def listkeys(self, namespace):
20 > def listkeys(self, namespace):
21 > ui.write('listkeys %s\n' % (namespace,))
21 > ui.write('listkeys %s\n' % (namespace,))
22 > return super(debugkeysrepo, self).listkeys(namespace)
22 > return super(debugkeysrepo, self).listkeys(namespace)
23 >
23 >
24 > if repo.local():
24 > if repo.local():
25 > repo.__class__ = debugkeysrepo
25 > repo.__class__ = debugkeysrepo
26 > EOF
26 > EOF
27
27
28 $ hg init tmpa
28 $ hg init tmpa
29 $ cd tmpa
29 $ cd tmpa
30 $ mkcommit kill_me
30 $ mkcommit kill_me
31
31
32 Checking that the feature is properly disabled
32 Checking that the feature is properly disabled
33
33
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
35 abort: obsolete feature is not enabled on this repo
35 abort: obsolete feature is not enabled on this repo
36 [255]
36 [255]
37
37
38 Enabling it
38 Enabling it
39
39
40 $ cat > ../obs.py << EOF
40 $ cat > ../obs.py << EOF
41 > import mercurial.obsolete
41 > import mercurial.obsolete
42 > mercurial.obsolete._enabled = True
42 > mercurial.obsolete._enabled = True
43 > EOF
43 > EOF
44 $ echo '[extensions]' >> $HGRCPATH
44 $ echo '[extensions]' >> $HGRCPATH
45 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
45 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
46
46
47 Killing a single changeset without replacement
47 Killing a single changeset without replacement
48
48
49 $ hg debugobsolete 0
49 $ hg debugobsolete 0
50 abort: changeset references must be full hexadecimal node identifiers
50 abort: changeset references must be full hexadecimal node identifiers
51 [255]
51 [255]
52 $ hg debugobsolete '00'
52 $ hg debugobsolete '00'
53 abort: changeset references must be full hexadecimal node identifiers
53 abort: changeset references must be full hexadecimal node identifiers
54 [255]
54 [255]
55 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
55 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
56 $ hg debugobsolete
56 $ hg debugobsolete
57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'}
57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'}
58
58
59 (test that mercurial is not confused)
59 (test that mercurial is not confused)
60
60
61 $ hg up null --quiet # having 0 as parent prevents it to be hidden
61 $ hg up null --quiet # having 0 as parent prevents it to be hidden
62 $ hg tip
62 $ hg tip
63 changeset: -1:000000000000
63 changeset: -1:000000000000
64 tag: tip
64 tag: tip
65 user:
65 user:
66 date: Thu Jan 01 00:00:00 1970 +0000
66 date: Thu Jan 01 00:00:00 1970 +0000
67
67
68 $ hg up --hidden tip --quiet
68 $ hg up --hidden tip --quiet
69 $ cd ..
69 $ cd ..
70
70
71 Killing a single changeset with replacement
71 Killing a single changeset with replacement
72
72
73 $ hg init tmpb
73 $ hg init tmpb
74 $ cd tmpb
74 $ cd tmpb
75 $ mkcommit a
75 $ mkcommit a
76 $ mkcommit b
76 $ mkcommit b
77 $ mkcommit original_c
77 $ mkcommit original_c
78 $ hg up "desc('b')"
78 $ hg up "desc('b')"
79 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
79 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
80 $ mkcommit new_c
80 $ mkcommit new_c
81 created new head
81 created new head
82 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
82 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
83 $ hg debugobsolete --flag 12 `getid original_c` `getid new_c` -d '56 12'
83 $ hg debugobsolete --flag 12 `getid original_c` `getid new_c` -d '56 12'
84 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
84 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
85 2:245bde4270cd add original_c
85 2:245bde4270cd add original_c
86 $ hg debugobsolete
86 $ hg debugobsolete
87 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
87 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
88
88
89 do it again (it read the obsstore before adding new changeset)
89 do it again (it read the obsstore before adding new changeset)
90
90
91 $ hg up '.^'
91 $ hg up '.^'
92 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
92 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
93 $ mkcommit new_2_c
93 $ mkcommit new_2_c
94 created new head
94 created new head
95 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
95 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
96 $ hg debugobsolete
96 $ hg debugobsolete
97 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
97 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
98 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
98 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
99
99
100 Register two markers with a missing node
100 Register two markers with a missing node
101
101
102 $ hg up '.^'
102 $ hg up '.^'
103 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
103 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
104 $ mkcommit new_3_c
104 $ mkcommit new_3_c
105 created new head
105 created new head
106 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
106 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
107 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
107 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
108 $ hg debugobsolete
108 $ hg debugobsolete
109 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
109 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
110 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
110 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
111 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
111 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
112 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
112 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
113
113
114 Refuse pathological nullid successors
114 Refuse pathological nullid successors
115 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
115 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
116 transaction abort!
116 transaction abort!
117 rollback completed
117 rollback completed
118 abort: bad obsolescence marker detected: invalid successors nullid
118 abort: bad obsolescence marker detected: invalid successors nullid
119 [255]
119 [255]
120
120
121 Check that graphlog detect that a changeset is obsolete:
121 Check that graphlog detect that a changeset is obsolete:
122
122
123 $ hg glog
123 $ hg glog
124 @ changeset: 5:5601fb93a350
124 @ changeset: 5:5601fb93a350
125 | tag: tip
125 | tag: tip
126 | parent: 1:7c3bad9141dc
126 | parent: 1:7c3bad9141dc
127 | user: test
127 | user: test
128 | date: Thu Jan 01 00:00:00 1970 +0000
128 | date: Thu Jan 01 00:00:00 1970 +0000
129 | summary: add new_3_c
129 | summary: add new_3_c
130 |
130 |
131 o changeset: 1:7c3bad9141dc
131 o changeset: 1:7c3bad9141dc
132 | user: test
132 | user: test
133 | date: Thu Jan 01 00:00:00 1970 +0000
133 | date: Thu Jan 01 00:00:00 1970 +0000
134 | summary: add b
134 | summary: add b
135 |
135 |
136 o changeset: 0:1f0dee641bb7
136 o changeset: 0:1f0dee641bb7
137 user: test
137 user: test
138 date: Thu Jan 01 00:00:00 1970 +0000
138 date: Thu Jan 01 00:00:00 1970 +0000
139 summary: add a
139 summary: add a
140
140
141
141
142 check that heads does not report them
142 check that heads does not report them
143
143
144 $ hg heads
144 $ hg heads
145 changeset: 5:5601fb93a350
145 changeset: 5:5601fb93a350
146 tag: tip
146 tag: tip
147 parent: 1:7c3bad9141dc
147 parent: 1:7c3bad9141dc
148 user: test
148 user: test
149 date: Thu Jan 01 00:00:00 1970 +0000
149 date: Thu Jan 01 00:00:00 1970 +0000
150 summary: add new_3_c
150 summary: add new_3_c
151
151
152 $ hg heads --hidden
152 $ hg heads --hidden
153 changeset: 5:5601fb93a350
153 changeset: 5:5601fb93a350
154 tag: tip
154 tag: tip
155 parent: 1:7c3bad9141dc
155 parent: 1:7c3bad9141dc
156 user: test
156 user: test
157 date: Thu Jan 01 00:00:00 1970 +0000
157 date: Thu Jan 01 00:00:00 1970 +0000
158 summary: add new_3_c
158 summary: add new_3_c
159
159
160 changeset: 4:ca819180edb9
160 changeset: 4:ca819180edb9
161 parent: 1:7c3bad9141dc
161 parent: 1:7c3bad9141dc
162 user: test
162 user: test
163 date: Thu Jan 01 00:00:00 1970 +0000
163 date: Thu Jan 01 00:00:00 1970 +0000
164 summary: add new_2_c
164 summary: add new_2_c
165
165
166 changeset: 3:cdbce2fbb163
166 changeset: 3:cdbce2fbb163
167 parent: 1:7c3bad9141dc
167 parent: 1:7c3bad9141dc
168 user: test
168 user: test
169 date: Thu Jan 01 00:00:00 1970 +0000
169 date: Thu Jan 01 00:00:00 1970 +0000
170 summary: add new_c
170 summary: add new_c
171
171
172 changeset: 2:245bde4270cd
172 changeset: 2:245bde4270cd
173 user: test
173 user: test
174 date: Thu Jan 01 00:00:00 1970 +0000
174 date: Thu Jan 01 00:00:00 1970 +0000
175 summary: add original_c
175 summary: add original_c
176
176
177
177
178
178
179 check that summary does not report them
179 check that summary does not report them
180
180
181 $ hg init ../sink
181 $ hg init ../sink
182 $ echo '[paths]' >> .hg/hgrc
182 $ echo '[paths]' >> .hg/hgrc
183 $ echo 'default=../sink' >> .hg/hgrc
183 $ echo 'default=../sink' >> .hg/hgrc
184 $ hg summary --remote
184 $ hg summary --remote
185 parent: 5:5601fb93a350 tip
185 parent: 5:5601fb93a350 tip
186 add new_3_c
186 add new_3_c
187 branch: default
187 branch: default
188 commit: (clean)
188 commit: (clean)
189 update: (current)
189 update: (current)
190 remote: 3 outgoing
190 remote: 3 outgoing
191
191
192 $ hg summary --remote --hidden
192 $ hg summary --remote --hidden
193 parent: 5:5601fb93a350 tip
193 parent: 5:5601fb93a350 tip
194 add new_3_c
194 add new_3_c
195 branch: default
195 branch: default
196 commit: (clean)
196 commit: (clean)
197 update: 3 new changesets, 4 branch heads (merge)
197 update: 3 new changesets, 4 branch heads (merge)
198 remote: 3 outgoing
198 remote: 3 outgoing
199
199
200 check that various commands work well with filtering
200 check that various commands work well with filtering
201
201
202 $ hg tip
202 $ hg tip
203 changeset: 5:5601fb93a350
203 changeset: 5:5601fb93a350
204 tag: tip
204 tag: tip
205 parent: 1:7c3bad9141dc
205 parent: 1:7c3bad9141dc
206 user: test
206 user: test
207 date: Thu Jan 01 00:00:00 1970 +0000
207 date: Thu Jan 01 00:00:00 1970 +0000
208 summary: add new_3_c
208 summary: add new_3_c
209
209
210 $ hg log -r 6
210 $ hg log -r 6
211 abort: unknown revision '6'!
211 abort: unknown revision '6'!
212 [255]
212 [255]
213 $ hg log -r 4
213 $ hg log -r 4
214 abort: unknown revision '4'!
214 abort: unknown revision '4'!
215 [255]
215 [255]
216
216
217 Check that public changeset are not accounted as obsolete:
217 Check that public changeset are not accounted as obsolete:
218
218
219 $ hg --hidden phase --public 2
219 $ hg --hidden phase --public 2
220 $ hg --config 'extensions.graphlog=' glog
220 $ hg --config 'extensions.graphlog=' glog
221 @ changeset: 5:5601fb93a350
221 @ changeset: 5:5601fb93a350
222 | tag: tip
222 | tag: tip
223 | parent: 1:7c3bad9141dc
223 | parent: 1:7c3bad9141dc
224 | user: test
224 | user: test
225 | date: Thu Jan 01 00:00:00 1970 +0000
225 | date: Thu Jan 01 00:00:00 1970 +0000
226 | summary: add new_3_c
226 | summary: add new_3_c
227 |
227 |
228 | o changeset: 2:245bde4270cd
228 | o changeset: 2:245bde4270cd
229 |/ user: test
229 |/ user: test
230 | date: Thu Jan 01 00:00:00 1970 +0000
230 | date: Thu Jan 01 00:00:00 1970 +0000
231 | summary: add original_c
231 | summary: add original_c
232 |
232 |
233 o changeset: 1:7c3bad9141dc
233 o changeset: 1:7c3bad9141dc
234 | user: test
234 | user: test
235 | date: Thu Jan 01 00:00:00 1970 +0000
235 | date: Thu Jan 01 00:00:00 1970 +0000
236 | summary: add b
236 | summary: add b
237 |
237 |
238 o changeset: 0:1f0dee641bb7
238 o changeset: 0:1f0dee641bb7
239 user: test
239 user: test
240 date: Thu Jan 01 00:00:00 1970 +0000
240 date: Thu Jan 01 00:00:00 1970 +0000
241 summary: add a
241 summary: add a
242
242
243
243
244 And that bumped changeset are detected
244 And that bumped changeset are detected
245 --------------------------------------
245 --------------------------------------
246
246
247 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
247 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
248 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
248 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
249 the public changeset
249 the public changeset
250
250
251 $ hg log --hidden -r 'bumped()'
251 $ hg log --hidden -r 'bumped()'
252 changeset: 5:5601fb93a350
252 changeset: 5:5601fb93a350
253 tag: tip
253 tag: tip
254 parent: 1:7c3bad9141dc
254 parent: 1:7c3bad9141dc
255 user: test
255 user: test
256 date: Thu Jan 01 00:00:00 1970 +0000
256 date: Thu Jan 01 00:00:00 1970 +0000
257 summary: add new_3_c
257 summary: add new_3_c
258
258
259
259
260 And that we can't push bumped changeset
260 And that we can't push bumped changeset
261
261
262 $ hg push ../tmpa -r 0 --force #(make repo related)
262 $ hg push ../tmpa -r 0 --force #(make repo related)
263 pushing to ../tmpa
263 pushing to ../tmpa
264 searching for changes
264 searching for changes
265 warning: repository is unrelated
265 warning: repository is unrelated
266 adding changesets
266 adding changesets
267 adding manifests
267 adding manifests
268 adding file changes
268 adding file changes
269 added 1 changesets with 1 changes to 1 files (+1 heads)
269 added 1 changesets with 1 changes to 1 files (+1 heads)
270 $ hg push ../tmpa
270 $ hg push ../tmpa
271 pushing to ../tmpa
271 pushing to ../tmpa
272 searching for changes
272 searching for changes
273 abort: push includes bumped changeset: 5601fb93a350!
273 abort: push includes bumped changeset: 5601fb93a350!
274 [255]
274 [255]
275
275
276 Fixing "bumped" situation
276 Fixing "bumped" situation
277 We need to create a clone of 5 and add a special marker with a flag
277 We need to create a clone of 5 and add a special marker with a flag
278
278
279 $ hg up '5^'
279 $ hg up '5^'
280 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
280 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
281 $ hg revert -ar 5
281 $ hg revert -ar 5
282 adding new_3_c
282 adding new_3_c
283 $ hg ci -m 'add n3w_3_c'
283 $ hg ci -m 'add n3w_3_c'
284 created new head
284 created new head
285 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
285 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
286 $ hg log -r 'bumped()'
286 $ hg log -r 'bumped()'
287 $ hg log -G
287 $ hg log -G
288 @ changeset: 6:6f9641995072
288 @ changeset: 6:6f9641995072
289 | tag: tip
289 | tag: tip
290 | parent: 1:7c3bad9141dc
290 | parent: 1:7c3bad9141dc
291 | user: test
291 | user: test
292 | date: Thu Jan 01 00:00:00 1970 +0000
292 | date: Thu Jan 01 00:00:00 1970 +0000
293 | summary: add n3w_3_c
293 | summary: add n3w_3_c
294 |
294 |
295 | o changeset: 2:245bde4270cd
295 | o changeset: 2:245bde4270cd
296 |/ user: test
296 |/ user: test
297 | date: Thu Jan 01 00:00:00 1970 +0000
297 | date: Thu Jan 01 00:00:00 1970 +0000
298 | summary: add original_c
298 | summary: add original_c
299 |
299 |
300 o changeset: 1:7c3bad9141dc
300 o changeset: 1:7c3bad9141dc
301 | user: test
301 | user: test
302 | date: Thu Jan 01 00:00:00 1970 +0000
302 | date: Thu Jan 01 00:00:00 1970 +0000
303 | summary: add b
303 | summary: add b
304 |
304 |
305 o changeset: 0:1f0dee641bb7
305 o changeset: 0:1f0dee641bb7
306 user: test
306 user: test
307 date: Thu Jan 01 00:00:00 1970 +0000
307 date: Thu Jan 01 00:00:00 1970 +0000
308 summary: add a
308 summary: add a
309
309
310
310
311
311
312
312
313 $ cd ..
313 $ cd ..
314
314
315 Exchange Test
315 Exchange Test
316 ============================
316 ============================
317
317
318 Destination repo does not have any data
318 Destination repo does not have any data
319 ---------------------------------------
319 ---------------------------------------
320
320
321 Simple incoming test
321 Simple incoming test
322
322
323 $ hg init tmpc
323 $ hg init tmpc
324 $ cd tmpc
324 $ cd tmpc
325 $ hg incoming ../tmpb
325 $ hg incoming ../tmpb
326 comparing with ../tmpb
326 comparing with ../tmpb
327 changeset: 0:1f0dee641bb7
327 changeset: 0:1f0dee641bb7
328 user: test
328 user: test
329 date: Thu Jan 01 00:00:00 1970 +0000
329 date: Thu Jan 01 00:00:00 1970 +0000
330 summary: add a
330 summary: add a
331
331
332 changeset: 1:7c3bad9141dc
332 changeset: 1:7c3bad9141dc
333 user: test
333 user: test
334 date: Thu Jan 01 00:00:00 1970 +0000
334 date: Thu Jan 01 00:00:00 1970 +0000
335 summary: add b
335 summary: add b
336
336
337 changeset: 2:245bde4270cd
337 changeset: 2:245bde4270cd
338 user: test
338 user: test
339 date: Thu Jan 01 00:00:00 1970 +0000
339 date: Thu Jan 01 00:00:00 1970 +0000
340 summary: add original_c
340 summary: add original_c
341
341
342 changeset: 6:6f9641995072
342 changeset: 6:6f9641995072
343 tag: tip
343 tag: tip
344 parent: 1:7c3bad9141dc
344 parent: 1:7c3bad9141dc
345 user: test
345 user: test
346 date: Thu Jan 01 00:00:00 1970 +0000
346 date: Thu Jan 01 00:00:00 1970 +0000
347 summary: add n3w_3_c
347 summary: add n3w_3_c
348
348
349
349
350 Try to pull markers
350 Try to pull markers
351 (extinct changeset are excluded but marker are pushed)
351 (extinct changeset are excluded but marker are pushed)
352
352
353 $ hg pull ../tmpb
353 $ hg pull ../tmpb
354 pulling from ../tmpb
354 pulling from ../tmpb
355 requesting all changes
355 requesting all changes
356 adding changesets
356 adding changesets
357 adding manifests
357 adding manifests
358 adding file changes
358 adding file changes
359 added 4 changesets with 4 changes to 4 files (+1 heads)
359 added 4 changesets with 4 changes to 4 files (+1 heads)
360 (run 'hg heads' to see heads, 'hg merge' to merge)
360 (run 'hg heads' to see heads, 'hg merge' to merge)
361 $ hg debugobsolete
361 $ hg debugobsolete
362 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
362 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
363 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
363 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
364 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
364 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
365 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
365 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
366 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
366 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
367
367
368 Rollback//Transaction support
368 Rollback//Transaction support
369
369
370 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
370 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
371 $ hg debugobsolete
371 $ hg debugobsolete
372 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
372 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
373 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
373 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
374 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
374 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
375 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
375 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
376 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
376 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
377 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'}
377 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'}
378 $ hg rollback -n
378 $ hg rollback -n
379 repository tip rolled back to revision 3 (undo debugobsolete)
379 repository tip rolled back to revision 3 (undo debugobsolete)
380 $ hg rollback
380 $ hg rollback
381 repository tip rolled back to revision 3 (undo debugobsolete)
381 repository tip rolled back to revision 3 (undo debugobsolete)
382 $ hg debugobsolete
382 $ hg debugobsolete
383 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
383 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
384 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
384 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
385 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
385 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
386 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
386 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
387 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
387 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
388
388
389 $ cd ..
389 $ cd ..
390
390
391 Try to push markers
391 Try to push markers
392
392
393 $ hg init tmpd
393 $ hg init tmpd
394 $ hg -R tmpb push tmpd
394 $ hg -R tmpb push tmpd
395 pushing to tmpd
395 pushing to tmpd
396 searching for changes
396 searching for changes
397 adding changesets
397 adding changesets
398 adding manifests
398 adding manifests
399 adding file changes
399 adding file changes
400 added 4 changesets with 4 changes to 4 files (+1 heads)
400 added 4 changesets with 4 changes to 4 files (+1 heads)
401 $ hg -R tmpd debugobsolete
401 $ hg -R tmpd debugobsolete
402 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
402 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
403 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
403 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
404 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
404 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
405 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
405 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
406 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
406 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
407
407
408 Check obsolete keys are exchanged only if source has an obsolete store
408 Check obsolete keys are exchanged only if source has an obsolete store
409
409
410 $ hg init empty
410 $ hg init empty
411 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
411 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
412 pushing to tmpd
412 pushing to tmpd
413 no changes found
413 no changes found
414 listkeys phases
414 listkeys phases
415 listkeys bookmarks
415 listkeys bookmarks
416 [1]
416 [1]
417
417
418 clone support
418 clone support
419 (markers are copied and extinct changesets are included to allow hardlinks)
419 (markers are copied and extinct changesets are included to allow hardlinks)
420
420
421 $ hg clone tmpb clone-dest
421 $ hg clone tmpb clone-dest
422 updating to branch default
422 updating to branch default
423 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 $ hg -R clone-dest log -G --hidden
424 $ hg -R clone-dest log -G --hidden
425 @ changeset: 6:6f9641995072
425 @ changeset: 6:6f9641995072
426 | tag: tip
426 | tag: tip
427 | parent: 1:7c3bad9141dc
427 | parent: 1:7c3bad9141dc
428 | user: test
428 | user: test
429 | date: Thu Jan 01 00:00:00 1970 +0000
429 | date: Thu Jan 01 00:00:00 1970 +0000
430 | summary: add n3w_3_c
430 | summary: add n3w_3_c
431 |
431 |
432 | x changeset: 5:5601fb93a350
432 | x changeset: 5:5601fb93a350
433 |/ parent: 1:7c3bad9141dc
433 |/ parent: 1:7c3bad9141dc
434 | user: test
434 | user: test
435 | date: Thu Jan 01 00:00:00 1970 +0000
435 | date: Thu Jan 01 00:00:00 1970 +0000
436 | summary: add new_3_c
436 | summary: add new_3_c
437 |
437 |
438 | x changeset: 4:ca819180edb9
438 | x changeset: 4:ca819180edb9
439 |/ parent: 1:7c3bad9141dc
439 |/ parent: 1:7c3bad9141dc
440 | user: test
440 | user: test
441 | date: Thu Jan 01 00:00:00 1970 +0000
441 | date: Thu Jan 01 00:00:00 1970 +0000
442 | summary: add new_2_c
442 | summary: add new_2_c
443 |
443 |
444 | x changeset: 3:cdbce2fbb163
444 | x changeset: 3:cdbce2fbb163
445 |/ parent: 1:7c3bad9141dc
445 |/ parent: 1:7c3bad9141dc
446 | user: test
446 | user: test
447 | date: Thu Jan 01 00:00:00 1970 +0000
447 | date: Thu Jan 01 00:00:00 1970 +0000
448 | summary: add new_c
448 | summary: add new_c
449 |
449 |
450 | o changeset: 2:245bde4270cd
450 | o changeset: 2:245bde4270cd
451 |/ user: test
451 |/ user: test
452 | date: Thu Jan 01 00:00:00 1970 +0000
452 | date: Thu Jan 01 00:00:00 1970 +0000
453 | summary: add original_c
453 | summary: add original_c
454 |
454 |
455 o changeset: 1:7c3bad9141dc
455 o changeset: 1:7c3bad9141dc
456 | user: test
456 | user: test
457 | date: Thu Jan 01 00:00:00 1970 +0000
457 | date: Thu Jan 01 00:00:00 1970 +0000
458 | summary: add b
458 | summary: add b
459 |
459 |
460 o changeset: 0:1f0dee641bb7
460 o changeset: 0:1f0dee641bb7
461 user: test
461 user: test
462 date: Thu Jan 01 00:00:00 1970 +0000
462 date: Thu Jan 01 00:00:00 1970 +0000
463 summary: add a
463 summary: add a
464
464
465 $ hg -R clone-dest debugobsolete
465 $ hg -R clone-dest debugobsolete
466 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
466 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
467 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
467 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
468 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
468 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
469 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
469 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
470 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
470 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
471
471
472
472
473 Destination repo have existing data
473 Destination repo have existing data
474 ---------------------------------------
474 ---------------------------------------
475
475
476 On pull
476 On pull
477
477
478 $ hg init tmpe
478 $ hg init tmpe
479 $ cd tmpe
479 $ cd tmpe
480 $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339
480 $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339
481 $ hg pull ../tmpb
481 $ hg pull ../tmpb
482 pulling from ../tmpb
482 pulling from ../tmpb
483 requesting all changes
483 requesting all changes
484 adding changesets
484 adding changesets
485 adding manifests
485 adding manifests
486 adding file changes
486 adding file changes
487 added 4 changesets with 4 changes to 4 files (+1 heads)
487 added 4 changesets with 4 changes to 4 files (+1 heads)
488 (run 'hg heads' to see heads, 'hg merge' to merge)
488 (run 'hg heads' to see heads, 'hg merge' to merge)
489 $ hg debugobsolete
489 $ hg debugobsolete
490 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
490 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
491 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
491 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
492 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
492 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
493 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
493 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
494 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
494 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
495 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
495 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
496
496
497
497
498 On push
498 On push
499
499
500 $ hg push ../tmpc
500 $ hg push ../tmpc
501 pushing to ../tmpc
501 pushing to ../tmpc
502 searching for changes
502 searching for changes
503 no changes found
503 no changes found
504 [1]
504 [1]
505 $ hg -R ../tmpc debugobsolete
505 $ hg -R ../tmpc debugobsolete
506 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
506 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
507 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
507 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
508 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
508 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
509 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
509 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
510 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
510 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
511 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
511 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
512
512
513 detect outgoing obsolete and unstable
513 detect outgoing obsolete and unstable
514 ---------------------------------------
514 ---------------------------------------
515
515
516
516
517 $ hg glog
517 $ hg glog
518 o changeset: 3:6f9641995072
518 o changeset: 3:6f9641995072
519 | tag: tip
519 | tag: tip
520 | parent: 1:7c3bad9141dc
520 | parent: 1:7c3bad9141dc
521 | user: test
521 | user: test
522 | date: Thu Jan 01 00:00:00 1970 +0000
522 | date: Thu Jan 01 00:00:00 1970 +0000
523 | summary: add n3w_3_c
523 | summary: add n3w_3_c
524 |
524 |
525 | o changeset: 2:245bde4270cd
525 | o changeset: 2:245bde4270cd
526 |/ user: test
526 |/ user: test
527 | date: Thu Jan 01 00:00:00 1970 +0000
527 | date: Thu Jan 01 00:00:00 1970 +0000
528 | summary: add original_c
528 | summary: add original_c
529 |
529 |
530 o changeset: 1:7c3bad9141dc
530 o changeset: 1:7c3bad9141dc
531 | user: test
531 | user: test
532 | date: Thu Jan 01 00:00:00 1970 +0000
532 | date: Thu Jan 01 00:00:00 1970 +0000
533 | summary: add b
533 | summary: add b
534 |
534 |
535 o changeset: 0:1f0dee641bb7
535 o changeset: 0:1f0dee641bb7
536 user: test
536 user: test
537 date: Thu Jan 01 00:00:00 1970 +0000
537 date: Thu Jan 01 00:00:00 1970 +0000
538 summary: add a
538 summary: add a
539
539
540 $ hg up 'desc("n3w_3_c")'
540 $ hg up 'desc("n3w_3_c")'
541 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
541 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
542 $ mkcommit original_d
542 $ mkcommit original_d
543 $ mkcommit original_e
543 $ mkcommit original_e
544 $ hg debugobsolete `getid original_d` -d '0 0'
544 $ hg debugobsolete `getid original_d` -d '0 0'
545 $ hg log -r 'obsolete()'
545 $ hg log -r 'obsolete()'
546 changeset: 4:94b33453f93b
546 changeset: 4:94b33453f93b
547 user: test
547 user: test
548 date: Thu Jan 01 00:00:00 1970 +0000
548 date: Thu Jan 01 00:00:00 1970 +0000
549 summary: add original_d
549 summary: add original_d
550
550
551 $ hg glog -r '::unstable()'
551 $ hg glog -r '::unstable()'
552 @ changeset: 5:cda648ca50f5
552 @ changeset: 5:cda648ca50f5
553 | tag: tip
553 | tag: tip
554 | user: test
554 | user: test
555 | date: Thu Jan 01 00:00:00 1970 +0000
555 | date: Thu Jan 01 00:00:00 1970 +0000
556 | summary: add original_e
556 | summary: add original_e
557 |
557 |
558 x changeset: 4:94b33453f93b
558 x changeset: 4:94b33453f93b
559 | user: test
559 | user: test
560 | date: Thu Jan 01 00:00:00 1970 +0000
560 | date: Thu Jan 01 00:00:00 1970 +0000
561 | summary: add original_d
561 | summary: add original_d
562 |
562 |
563 o changeset: 3:6f9641995072
563 o changeset: 3:6f9641995072
564 | parent: 1:7c3bad9141dc
564 | parent: 1:7c3bad9141dc
565 | user: test
565 | user: test
566 | date: Thu Jan 01 00:00:00 1970 +0000
566 | date: Thu Jan 01 00:00:00 1970 +0000
567 | summary: add n3w_3_c
567 | summary: add n3w_3_c
568 |
568 |
569 o changeset: 1:7c3bad9141dc
569 o changeset: 1:7c3bad9141dc
570 | user: test
570 | user: test
571 | date: Thu Jan 01 00:00:00 1970 +0000
571 | date: Thu Jan 01 00:00:00 1970 +0000
572 | summary: add b
572 | summary: add b
573 |
573 |
574 o changeset: 0:1f0dee641bb7
574 o changeset: 0:1f0dee641bb7
575 user: test
575 user: test
576 date: Thu Jan 01 00:00:00 1970 +0000
576 date: Thu Jan 01 00:00:00 1970 +0000
577 summary: add a
577 summary: add a
578
578
579
579
580 refuse to push obsolete changeset
580 refuse to push obsolete changeset
581
581
582 $ hg push ../tmpc/ -r 'desc("original_d")'
582 $ hg push ../tmpc/ -r 'desc("original_d")'
583 pushing to ../tmpc/
583 pushing to ../tmpc/
584 searching for changes
584 searching for changes
585 abort: push includes obsolete changeset: 94b33453f93b!
585 abort: push includes obsolete changeset: 94b33453f93b!
586 [255]
586 [255]
587
587
588 refuse to push unstable changeset
588 refuse to push unstable changeset
589
589
590 $ hg push ../tmpc/
590 $ hg push ../tmpc/
591 pushing to ../tmpc/
591 pushing to ../tmpc/
592 searching for changes
592 searching for changes
593 abort: push includes unstable changeset: cda648ca50f5!
593 abort: push includes unstable changeset: cda648ca50f5!
594 [255]
594 [255]
595
595
596 Test that extinct changeset are properly detected
596 Test that extinct changeset are properly detected
597
597
598 $ hg log -r 'extinct()'
598 $ hg log -r 'extinct()'
599
599
600 Don't try to push extinct changeset
600 Don't try to push extinct changeset
601
601
602 $ hg init ../tmpf
602 $ hg init ../tmpf
603 $ hg out ../tmpf
603 $ hg out ../tmpf
604 comparing with ../tmpf
604 comparing with ../tmpf
605 searching for changes
605 searching for changes
606 changeset: 0:1f0dee641bb7
606 changeset: 0:1f0dee641bb7
607 user: test
607 user: test
608 date: Thu Jan 01 00:00:00 1970 +0000
608 date: Thu Jan 01 00:00:00 1970 +0000
609 summary: add a
609 summary: add a
610
610
611 changeset: 1:7c3bad9141dc
611 changeset: 1:7c3bad9141dc
612 user: test
612 user: test
613 date: Thu Jan 01 00:00:00 1970 +0000
613 date: Thu Jan 01 00:00:00 1970 +0000
614 summary: add b
614 summary: add b
615
615
616 changeset: 2:245bde4270cd
616 changeset: 2:245bde4270cd
617 user: test
617 user: test
618 date: Thu Jan 01 00:00:00 1970 +0000
618 date: Thu Jan 01 00:00:00 1970 +0000
619 summary: add original_c
619 summary: add original_c
620
620
621 changeset: 3:6f9641995072
621 changeset: 3:6f9641995072
622 parent: 1:7c3bad9141dc
622 parent: 1:7c3bad9141dc
623 user: test
623 user: test
624 date: Thu Jan 01 00:00:00 1970 +0000
624 date: Thu Jan 01 00:00:00 1970 +0000
625 summary: add n3w_3_c
625 summary: add n3w_3_c
626
626
627 changeset: 4:94b33453f93b
627 changeset: 4:94b33453f93b
628 user: test
628 user: test
629 date: Thu Jan 01 00:00:00 1970 +0000
629 date: Thu Jan 01 00:00:00 1970 +0000
630 summary: add original_d
630 summary: add original_d
631
631
632 changeset: 5:cda648ca50f5
632 changeset: 5:cda648ca50f5
633 tag: tip
633 tag: tip
634 user: test
634 user: test
635 date: Thu Jan 01 00:00:00 1970 +0000
635 date: Thu Jan 01 00:00:00 1970 +0000
636 summary: add original_e
636 summary: add original_e
637
637
638 $ hg push ../tmpf -f # -f because be push unstable too
638 $ hg push ../tmpf -f # -f because be push unstable too
639 pushing to ../tmpf
639 pushing to ../tmpf
640 searching for changes
640 searching for changes
641 adding changesets
641 adding changesets
642 adding manifests
642 adding manifests
643 adding file changes
643 adding file changes
644 added 6 changesets with 6 changes to 6 files (+1 heads)
644 added 6 changesets with 6 changes to 6 files (+1 heads)
645
645
646 no warning displayed
646 no warning displayed
647
647
648 $ hg push ../tmpf
648 $ hg push ../tmpf
649 pushing to ../tmpf
649 pushing to ../tmpf
650 searching for changes
650 searching for changes
651 no changes found
651 no changes found
652 [1]
652 [1]
653
653
654 Do not warn about new head when the new head is a successors of a remote one
654 Do not warn about new head when the new head is a successors of a remote one
655
655
656 $ hg glog
656 $ hg glog
657 @ changeset: 5:cda648ca50f5
657 @ changeset: 5:cda648ca50f5
658 | tag: tip
658 | tag: tip
659 | user: test
659 | user: test
660 | date: Thu Jan 01 00:00:00 1970 +0000
660 | date: Thu Jan 01 00:00:00 1970 +0000
661 | summary: add original_e
661 | summary: add original_e
662 |
662 |
663 x changeset: 4:94b33453f93b
663 x changeset: 4:94b33453f93b
664 | user: test
664 | user: test
665 | date: Thu Jan 01 00:00:00 1970 +0000
665 | date: Thu Jan 01 00:00:00 1970 +0000
666 | summary: add original_d
666 | summary: add original_d
667 |
667 |
668 o changeset: 3:6f9641995072
668 o changeset: 3:6f9641995072
669 | parent: 1:7c3bad9141dc
669 | parent: 1:7c3bad9141dc
670 | user: test
670 | user: test
671 | date: Thu Jan 01 00:00:00 1970 +0000
671 | date: Thu Jan 01 00:00:00 1970 +0000
672 | summary: add n3w_3_c
672 | summary: add n3w_3_c
673 |
673 |
674 | o changeset: 2:245bde4270cd
674 | o changeset: 2:245bde4270cd
675 |/ user: test
675 |/ user: test
676 | date: Thu Jan 01 00:00:00 1970 +0000
676 | date: Thu Jan 01 00:00:00 1970 +0000
677 | summary: add original_c
677 | summary: add original_c
678 |
678 |
679 o changeset: 1:7c3bad9141dc
679 o changeset: 1:7c3bad9141dc
680 | user: test
680 | user: test
681 | date: Thu Jan 01 00:00:00 1970 +0000
681 | date: Thu Jan 01 00:00:00 1970 +0000
682 | summary: add b
682 | summary: add b
683 |
683 |
684 o changeset: 0:1f0dee641bb7
684 o changeset: 0:1f0dee641bb7
685 user: test
685 user: test
686 date: Thu Jan 01 00:00:00 1970 +0000
686 date: Thu Jan 01 00:00:00 1970 +0000
687 summary: add a
687 summary: add a
688
688
689 $ hg up -q 'desc(n3w_3_c)'
689 $ hg up -q 'desc(n3w_3_c)'
690 $ mkcommit obsolete_e
690 $ mkcommit obsolete_e
691 created new head
691 created new head
692 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
692 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
693 $ hg outgoing ../tmpf # parasite hg outgoing testin
693 $ hg outgoing ../tmpf # parasite hg outgoing testin
694 comparing with ../tmpf
694 comparing with ../tmpf
695 searching for changes
695 searching for changes
696 changeset: 6:3de5eca88c00
696 changeset: 6:3de5eca88c00
697 tag: tip
697 tag: tip
698 parent: 3:6f9641995072
698 parent: 3:6f9641995072
699 user: test
699 user: test
700 date: Thu Jan 01 00:00:00 1970 +0000
700 date: Thu Jan 01 00:00:00 1970 +0000
701 summary: add obsolete_e
701 summary: add obsolete_e
702
702
703 $ hg push ../tmpf
703 $ hg push ../tmpf
704 pushing to ../tmpf
704 pushing to ../tmpf
705 searching for changes
705 searching for changes
706 adding changesets
706 adding changesets
707 adding manifests
707 adding manifests
708 adding file changes
708 adding file changes
709 added 1 changesets with 1 changes to 1 files (+1 heads)
709 added 1 changesets with 1 changes to 1 files (+1 heads)
710
710
711 #if serve
711 #if serve
712
712
713 check hgweb does not explode
713 check hgweb does not explode
714 ====================================
714 ====================================
715
715
716 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
716 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
717 adding changesets
717 adding changesets
718 adding manifests
718 adding manifests
719 adding file changes
719 adding file changes
720 added 62 changesets with 63 changes to 9 files (+60 heads)
720 added 62 changesets with 63 changes to 9 files (+60 heads)
721 (run 'hg heads .' to see heads, 'hg merge' to merge)
721 (run 'hg heads .' to see heads, 'hg merge' to merge)
722 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
722 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
723 > do
723 > do
724 > hg debugobsolete $node
724 > hg debugobsolete $node
725 > done
725 > done
726 $ hg up tip
726 $ hg up tip
727 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
727 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
728
728
729 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
729 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
730 $ cat hg.pid >> $DAEMON_PIDS
730 $ cat hg.pid >> $DAEMON_PIDS
731
731
732 check changelog view
732 check changelog view
733
733
734 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'shortlog/'
734 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'shortlog/'
735 200 Script output follows
735 200 Script output follows
736
736
737 check graph view
737 check graph view
738
738
739 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'graph'
739 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'graph'
740 200 Script output follows
740 200 Script output follows
741
741
742 check filelog view
742 check filelog view
743
743
744 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'log/'`hg id --debug --id`/'babar'
744 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'log/'`hg id --debug --id`/'babar'
745 200 Script output follows
745 200 Script output follows
746
746
747 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/68'
747 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/68'
748 200 Script output follows
748 200 Script output follows
749 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
749 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
750 404 Not Found
750 404 Not Found
751 [1]
751 [1]
752
752
753 check that web.view config option:
753 check that web.view config option:
754
754
755 $ kill `cat hg.pid`
755 $ kill `cat hg.pid`
756 $ cat >> .hg/hgrc << EOF
756 $ cat >> .hg/hgrc << EOF
757 > [web]
757 > [web]
758 > view=all
758 > view=all
759 > EOF
759 > EOF
760 $ wait
760 $ wait
761 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
761 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
762 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
762 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
763 200 Script output follows
763 200 Script output follows
764 $ kill `cat hg.pid`
764 $ kill `cat hg.pid`
765
765
766 Checking _enable=False warning if obsolete marker exists
766 Checking _enable=False warning if obsolete marker exists
767
767
768 $ echo '[extensions]' >> $HGRCPATH
768 $ echo '[extensions]' >> $HGRCPATH
769 $ echo "obs=!" >> $HGRCPATH
769 $ echo "obs=!" >> $HGRCPATH
770 $ hg log -r tip
770 $ hg log -r tip
771 obsolete feature not enabled but 68 markers found!
771 obsolete feature not enabled but 68 markers found!
772 changeset: 68:c15e9edfca13
772 changeset: 68:c15e9edfca13
773 tag: tip
773 tag: tip
774 parent: 7:50c51b361e60
774 parent: 7:50c51b361e60
775 user: test
775 user: test
776 date: Thu Jan 01 00:00:00 1970 +0000
776 date: Thu Jan 01 00:00:00 1970 +0000
777 summary: add celestine
777 summary: add celestine
778
778
779
779
780 reenable for later test
780 reenable for later test
781
781
782 $ echo '[extensions]' >> $HGRCPATH
782 $ echo '[extensions]' >> $HGRCPATH
783 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
783 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
784
784
785 #endif
785 #endif
786
786
787 Test incoming/outcoming with changesets obsoleted remotely, known locally
787 Test incoming/outcoming with changesets obsoleted remotely, known locally
788 ===============================================================================
788 ===============================================================================
789
789
790 This test issue 3805
790 This test issue 3805
791
791
792 $ hg init repo-issue3805
792 $ hg init repo-issue3805
793 $ cd repo-issue3805
793 $ cd repo-issue3805
794 $ echo "foo" > foo
794 $ echo "foo" > foo
795 $ hg ci -Am "A"
795 $ hg ci -Am "A"
796 adding foo
796 adding foo
797 $ hg clone . ../other-issue3805
797 $ hg clone . ../other-issue3805
798 updating to branch default
798 updating to branch default
799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
800 $ echo "bar" >> foo
800 $ echo "bar" >> foo
801 $ hg ci --amend
801 $ hg ci --amend
802 $ cd ../other-issue3805
802 $ cd ../other-issue3805
803 $ hg log -G
803 $ hg log -G
804 @ changeset: 0:193e9254ce7e
804 @ changeset: 0:193e9254ce7e
805 tag: tip
805 tag: tip
806 user: test
806 user: test
807 date: Thu Jan 01 00:00:00 1970 +0000
807 date: Thu Jan 01 00:00:00 1970 +0000
808 summary: A
808 summary: A
809
809
810 $ hg log -G -R ../repo-issue3805
810 $ hg log -G -R ../repo-issue3805
811 @ changeset: 2:3816541e5485
811 @ changeset: 2:3816541e5485
812 tag: tip
812 tag: tip
813 parent: -1:000000000000
813 parent: -1:000000000000
814 user: test
814 user: test
815 date: Thu Jan 01 00:00:00 1970 +0000
815 date: Thu Jan 01 00:00:00 1970 +0000
816 summary: A
816 summary: A
817
817
818 $ hg incoming
818 $ hg incoming
819 comparing with $TESTTMP/tmpe/repo-issue3805
819 comparing with $TESTTMP/tmpe/repo-issue3805
820 searching for changes
820 searching for changes
821 changeset: 2:3816541e5485
821 changeset: 2:3816541e5485
822 tag: tip
822 tag: tip
823 parent: -1:000000000000
823 parent: -1:000000000000
824 user: test
824 user: test
825 date: Thu Jan 01 00:00:00 1970 +0000
825 date: Thu Jan 01 00:00:00 1970 +0000
826 summary: A
826 summary: A
827
827
828 $ hg incoming --bundle ../issue3805.hg
828 $ hg incoming --bundle ../issue3805.hg
829 comparing with $TESTTMP/tmpe/repo-issue3805
829 comparing with $TESTTMP/tmpe/repo-issue3805
830 searching for changes
830 searching for changes
831 changeset: 2:3816541e5485
831 changeset: 2:3816541e5485
832 tag: tip
832 tag: tip
833 parent: -1:000000000000
833 parent: -1:000000000000
834 user: test
834 user: test
835 date: Thu Jan 01 00:00:00 1970 +0000
835 date: Thu Jan 01 00:00:00 1970 +0000
836 summary: A
836 summary: A
837
837
838 $ hg outgoing
838 $ hg outgoing
839 comparing with $TESTTMP/tmpe/repo-issue3805
839 comparing with $TESTTMP/tmpe/repo-issue3805
840 searching for changes
840 searching for changes
841 no changes found
841 no changes found
842 [1]
842 [1]
843
843
844 #if serve
844 #if serve
845
845
846 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
846 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
847 $ cat hg.pid >> $DAEMON_PIDS
847 $ cat hg.pid >> $DAEMON_PIDS
848
848
849 $ hg incoming http://localhost:$HGPORT
849 $ hg incoming http://localhost:$HGPORT
850 comparing with http://localhost:$HGPORT/
850 comparing with http://localhost:$HGPORT/
851 searching for changes
851 searching for changes
852 changeset: 1:3816541e5485
852 changeset: 1:3816541e5485
853 tag: tip
853 tag: tip
854 parent: -1:000000000000
854 parent: -1:000000000000
855 user: test
855 user: test
856 date: Thu Jan 01 00:00:00 1970 +0000
856 date: Thu Jan 01 00:00:00 1970 +0000
857 summary: A
857 summary: A
858
858
859 $ hg outgoing http://localhost:$HGPORT
859 $ hg outgoing http://localhost:$HGPORT
860 comparing with http://localhost:$HGPORT/
860 comparing with http://localhost:$HGPORT/
861 searching for changes
861 searching for changes
862 no changes found
862 no changes found
863 [1]
863 [1]
864
864
865 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
865 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
866
866
867 #endif
867 #endif
868
869 This test issue 3814
870
871 (nothing to push but locally hidden changeset)
872
873 $ cd ..
874 $ hg init repo-issue3814
875 $ cd repo-issue3805
876 $ hg push -r 3816541e5485 ../repo-issue3814
877 pushing to ../repo-issue3814
878 searching for changes
879 adding changesets
880 adding manifests
881 adding file changes
882 added 1 changesets with 1 changes to 1 files
883 $ hg out ../repo-issue3814
884 comparing with ../repo-issue3814
885 searching for changes
886 no changes found
887 [1]
888
889
General Comments 0
You need to be logged in to leave comments. Login now