##// END OF EJS Templates
merge.
Vadim Gelfer -
r2996:79981108 merge default
parent child Browse files
Show More
@@ -0,0 +1,145 b''
1 # cmdutil.py - help for command processing in mercurial
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from demandload import demandload
9 from node import *
10 from i18n import gettext as _
11 demandload(globals(), 'mdiff util')
12 demandload(globals(), 'os sys')
13
14 def make_filename(repo, pat, node,
15 total=None, seqno=None, revwidth=None, pathname=None):
16 node_expander = {
17 'H': lambda: hex(node),
18 'R': lambda: str(repo.changelog.rev(node)),
19 'h': lambda: short(node),
20 }
21 expander = {
22 '%': lambda: '%',
23 'b': lambda: os.path.basename(repo.root),
24 }
25
26 try:
27 if node:
28 expander.update(node_expander)
29 if node and revwidth is not None:
30 expander['r'] = (lambda:
31 str(repo.changelog.rev(node)).zfill(revwidth))
32 if total is not None:
33 expander['N'] = lambda: str(total)
34 if seqno is not None:
35 expander['n'] = lambda: str(seqno)
36 if total is not None and seqno is not None:
37 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
38 if pathname is not None:
39 expander['s'] = lambda: os.path.basename(pathname)
40 expander['d'] = lambda: os.path.dirname(pathname) or '.'
41 expander['p'] = lambda: pathname
42
43 newname = []
44 patlen = len(pat)
45 i = 0
46 while i < patlen:
47 c = pat[i]
48 if c == '%':
49 i += 1
50 c = pat[i]
51 c = expander[c]()
52 newname.append(c)
53 i += 1
54 return ''.join(newname)
55 except KeyError, inst:
56 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
57 inst.args[0])
58
59 def make_file(repo, pat, node=None,
60 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
61 if not pat or pat == '-':
62 return 'w' in mode and sys.stdout or sys.stdin
63 if hasattr(pat, 'write') and 'w' in mode:
64 return pat
65 if hasattr(pat, 'read') and 'r' in mode:
66 return pat
67 return open(make_filename(repo, pat, node, total, seqno, revwidth,
68 pathname),
69 mode)
70
71 def matchpats(repo, pats=[], opts={}, head=''):
72 cwd = repo.getcwd()
73 if not pats and cwd:
74 opts['include'] = [os.path.join(cwd, i)
75 for i in opts.get('include', [])]
76 opts['exclude'] = [os.path.join(cwd, x)
77 for x in opts.get('exclude', [])]
78 cwd = ''
79 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
80 opts.get('exclude'), head)
81
82 def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
83 files, matchfn, anypats = matchpats(repo, pats, opts, head)
84 exact = dict(zip(files, files))
85 def walk():
86 for src, fn in repo.walk(node=node, files=files, match=matchfn,
87 badmatch=badmatch):
88 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
89 return files, matchfn, walk()
90
91 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
92 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
93 for r in results:
94 yield r
95
96 def findrenames(repo, added=None, removed=None, threshold=0.5):
97 if added is None or removed is None:
98 added, removed = repo.status()[1:3]
99 changes = repo.changelog.read(repo.dirstate.parents()[0])
100 mf = repo.manifest.read(changes[0])
101 for a in added:
102 aa = repo.wread(a)
103 bestscore, bestname = None, None
104 for r in removed:
105 rr = repo.file(r).read(mf[r])
106 delta = mdiff.textdiff(aa, rr)
107 if len(delta) < len(aa):
108 myscore = 1.0 - (float(len(delta)) / len(aa))
109 if bestscore is None or myscore > bestscore:
110 bestscore, bestname = myscore, r
111 if bestname and bestscore >= threshold:
112 yield bestname, a, bestscore
113
114 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
115 similarity=None):
116 if dry_run is None:
117 dry_run = opts.get('dry_run')
118 if similarity is None:
119 similarity = float(opts.get('similarity') or 0)
120 add, remove = [], []
121 mapping = {}
122 for src, abs, rel, exact in walk(repo, pats, opts):
123 if src == 'f' and repo.dirstate.state(abs) == '?':
124 add.append(abs)
125 mapping[abs] = rel, exact
126 if repo.ui.verbose or not exact:
127 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
128 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
129 remove.append(abs)
130 mapping[abs] = rel, exact
131 if repo.ui.verbose or not exact:
132 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
133 if not dry_run:
134 repo.add(add, wlock=wlock)
135 repo.remove(remove, wlock=wlock)
136 if similarity > 0:
137 for old, new, score in findrenames(repo, add, remove, similarity):
138 oldrel, oldexact = mapping[old]
139 newrel, newexact = mapping[new]
140 if repo.ui.verbose or not oldexact or not newexact:
141 repo.ui.status(_('recording removal of %s as rename to %s '
142 '(%d%% similar)\n') %
143 (oldrel, newrel, score * 100))
144 if not dry_run:
145 repo.copy(old, new, wlock=wlock)
@@ -0,0 +1,68 b''
1 # mail.py - mail sending bits for mercurial
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from i18n import gettext as _
9 from demandload import *
10 demandload(globals(), "os re smtplib templater util")
11
12 def _smtp(ui):
13 '''send mail using smtp.'''
14
15 local_hostname = ui.config('smtp', 'local_hostname')
16 s = smtplib.SMTP(local_hostname=local_hostname)
17 mailhost = ui.config('smtp', 'host')
18 if not mailhost:
19 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
20 mailport = int(ui.config('smtp', 'port', 25))
21 ui.note(_('sending mail: smtp host %s, port %s\n') %
22 (mailhost, mailport))
23 s.connect(host=mailhost, port=mailport)
24 if ui.configbool('smtp', 'tls'):
25 ui.note(_('(using tls)\n'))
26 s.ehlo()
27 s.starttls()
28 s.ehlo()
29 username = ui.config('smtp', 'username')
30 password = ui.config('smtp', 'password')
31 if username and password:
32 ui.note(_('(authenticating to mail server as %s)\n') %
33 (username))
34 s.login(username, password)
35 return s
36
37 class _sendmail(object):
38 '''send mail using sendmail.'''
39
40 def __init__(self, ui, program):
41 self.ui = ui
42 self.program = program
43
44 def sendmail(self, sender, recipients, msg):
45 cmdline = '%s -f %s %s' % (
46 self.program, templater.email(sender),
47 ' '.join(map(templater.email, recipients)))
48 self.ui.note(_('sending mail: %s\n') % cmdline)
49 fp = os.popen(cmdline, 'w')
50 fp.write(msg)
51 ret = fp.close()
52 if ret:
53 raise util.Abort('%s %s' % (
54 os.path.basename(self.program.split(None, 1)[0]),
55 util.explain_exit(ret)[0]))
56
57 def connect(ui):
58 '''make a mail connection. object returned has one method, sendmail.
59 call as sendmail(sender, list-of-recipients, msg).'''
60
61 method = ui.config('email', 'method', 'smtp')
62 if method == 'smtp':
63 return _smtp(ui)
64
65 return _sendmail(ui, method)
66
67 def sendmail(ui, sender, recipients, msg):
68 return connect(ui).sendmail(sender, recipients, msg)
This diff has been collapsed as it changes many lines, (539 lines changed) Show them Hide them
@@ -0,0 +1,539 b''
1 # patch.py - patch file parsing routines
2 #
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from demandload import demandload
9 from i18n import gettext as _
10 from node import *
11 demandload(globals(), "cmdutil mdiff util")
12 demandload(globals(), "cStringIO email.Parser errno os re shutil sys tempfile")
13
14 # helper functions
15
16 def copyfile(src, dst, basedir=None):
17 if not basedir:
18 basedir = os.getcwd()
19
20 abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
21 if os.path.exists(absdst):
22 raise util.Abort(_("cannot create %s: destination already exists") %
23 dst)
24
25 targetdir = os.path.dirname(absdst)
26 if not os.path.isdir(targetdir):
27 os.makedirs(targetdir)
28 try:
29 shutil.copyfile(abssrc, absdst)
30 shutil.copymode(abssrc, absdst)
31 except shutil.Error, inst:
32 raise util.Abort(str(inst))
33
34 # public functions
35
36 def extract(ui, fileobj):
37 '''extract patch from data read from fileobj.
38
39 patch can be normal patch or contained in email message.
40
41 return tuple (filename, message, user, date). any item in returned
42 tuple can be None. if filename is None, fileobj did not contain
43 patch. caller must unlink filename when done.'''
44
45 # attempt to detect the start of a patch
46 # (this heuristic is borrowed from quilt)
47 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
48 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
49 '(---|\*\*\*)[ \t])', re.MULTILINE)
50
51 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
52 tmpfp = os.fdopen(fd, 'w')
53 try:
54 hgpatch = False
55
56 msg = email.Parser.Parser().parse(fileobj)
57
58 message = msg['Subject']
59 user = msg['From']
60 # should try to parse msg['Date']
61 date = None
62
63 if message:
64 message = message.replace('\n\t', ' ')
65 ui.debug('Subject: %s\n' % message)
66 if user:
67 ui.debug('From: %s\n' % user)
68 diffs_seen = 0
69 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
70
71 for part in msg.walk():
72 content_type = part.get_content_type()
73 ui.debug('Content-Type: %s\n' % content_type)
74 if content_type not in ok_types:
75 continue
76 payload = part.get_payload(decode=True)
77 m = diffre.search(payload)
78 if m:
79 ui.debug(_('found patch at byte %d\n') % m.start(0))
80 diffs_seen += 1
81 cfp = cStringIO.StringIO()
82 if message:
83 cfp.write(message)
84 cfp.write('\n')
85 for line in payload[:m.start(0)].splitlines():
86 if line.startswith('# HG changeset patch'):
87 ui.debug(_('patch generated by hg export\n'))
88 hgpatch = True
89 # drop earlier commit message content
90 cfp.seek(0)
91 cfp.truncate()
92 elif hgpatch:
93 if line.startswith('# User '):
94 user = line[7:]
95 ui.debug('From: %s\n' % user)
96 elif line.startswith("# Date "):
97 date = line[7:]
98 if not line.startswith('# '):
99 cfp.write(line)
100 cfp.write('\n')
101 message = cfp.getvalue()
102 if tmpfp:
103 tmpfp.write(payload)
104 if not payload.endswith('\n'):
105 tmpfp.write('\n')
106 elif not diffs_seen and message and content_type == 'text/plain':
107 message += '\n' + payload
108 except:
109 tmpfp.close()
110 os.unlink(tmpname)
111 raise
112
113 tmpfp.close()
114 if not diffs_seen:
115 os.unlink(tmpname)
116 return None, message, user, date
117 return tmpname, message, user, date
118
119 def readgitpatch(patchname):
120 """extract git-style metadata about patches from <patchname>"""
121 class gitpatch:
122 "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
123 def __init__(self, path):
124 self.path = path
125 self.oldpath = None
126 self.mode = None
127 self.op = 'MODIFY'
128 self.copymod = False
129 self.lineno = 0
130
131 # Filter patch for git information
132 gitre = re.compile('diff --git a/(.*) b/(.*)')
133 pf = file(patchname)
134 gp = None
135 gitpatches = []
136 # Can have a git patch with only metadata, causing patch to complain
137 dopatch = False
138
139 lineno = 0
140 for line in pf:
141 lineno += 1
142 if line.startswith('diff --git'):
143 m = gitre.match(line)
144 if m:
145 if gp:
146 gitpatches.append(gp)
147 src, dst = m.group(1,2)
148 gp = gitpatch(dst)
149 gp.lineno = lineno
150 elif gp:
151 if line.startswith('--- '):
152 if gp.op in ('COPY', 'RENAME'):
153 gp.copymod = True
154 dopatch = 'filter'
155 gitpatches.append(gp)
156 gp = None
157 if not dopatch:
158 dopatch = True
159 continue
160 if line.startswith('rename from '):
161 gp.op = 'RENAME'
162 gp.oldpath = line[12:].rstrip()
163 elif line.startswith('rename to '):
164 gp.path = line[10:].rstrip()
165 elif line.startswith('copy from '):
166 gp.op = 'COPY'
167 gp.oldpath = line[10:].rstrip()
168 elif line.startswith('copy to '):
169 gp.path = line[8:].rstrip()
170 elif line.startswith('deleted file'):
171 gp.op = 'DELETE'
172 elif line.startswith('new file mode '):
173 gp.op = 'ADD'
174 gp.mode = int(line.rstrip()[-3:], 8)
175 elif line.startswith('new mode '):
176 gp.mode = int(line.rstrip()[-3:], 8)
177 if gp:
178 gitpatches.append(gp)
179
180 if not gitpatches:
181 dopatch = True
182
183 return (dopatch, gitpatches)
184
185 def dogitpatch(patchname, gitpatches):
186 """Preprocess git patch so that vanilla patch can handle it"""
187 pf = file(patchname)
188 pfline = 1
189
190 fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
191 tmpfp = os.fdopen(fd, 'w')
192
193 try:
194 for i in range(len(gitpatches)):
195 p = gitpatches[i]
196 if not p.copymod:
197 continue
198
199 copyfile(p.oldpath, p.path)
200
201 # rewrite patch hunk
202 while pfline < p.lineno:
203 tmpfp.write(pf.readline())
204 pfline += 1
205 tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
206 line = pf.readline()
207 pfline += 1
208 while not line.startswith('--- a/'):
209 tmpfp.write(line)
210 line = pf.readline()
211 pfline += 1
212 tmpfp.write('--- a/%s\n' % p.path)
213
214 line = pf.readline()
215 while line:
216 tmpfp.write(line)
217 line = pf.readline()
218 except:
219 tmpfp.close()
220 os.unlink(patchname)
221 raise
222
223 tmpfp.close()
224 return patchname
225
226 def patch(patchname, ui, strip=1, cwd=None):
227 """apply the patch <patchname> to the working directory.
228 a list of patched files is returned"""
229
230 (dopatch, gitpatches) = readgitpatch(patchname)
231
232 files = {}
233 fuzz = False
234 if dopatch:
235 if dopatch == 'filter':
236 patchname = dogitpatch(patchname, gitpatches)
237 patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
238 args = []
239 if cwd:
240 args.append('-d %s' % util.shellquote(cwd))
241 fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
242 util.shellquote(patchname)))
243
244 if dopatch == 'filter':
245 False and os.unlink(patchname)
246
247 for line in fp:
248 line = line.rstrip()
249 ui.note(line + '\n')
250 if line.startswith('patching file '):
251 pf = util.parse_patch_output(line)
252 printed_file = False
253 files.setdefault(pf, (None, None))
254 elif line.find('with fuzz') >= 0:
255 fuzz = True
256 if not printed_file:
257 ui.warn(pf + '\n')
258 printed_file = True
259 ui.warn(line + '\n')
260 elif line.find('saving rejects to file') >= 0:
261 ui.warn(line + '\n')
262 elif line.find('FAILED') >= 0:
263 if not printed_file:
264 ui.warn(pf + '\n')
265 printed_file = True
266 ui.warn(line + '\n')
267
268 code = fp.close()
269 if code:
270 raise util.Abort(_("patch command failed: %s") %
271 util.explain_exit(code)[0])
272
273 for gp in gitpatches:
274 files[gp.path] = (gp.op, gp)
275
276 return (files, fuzz)
277
278 def diffopts(ui, opts={}):
279 return mdiff.diffopts(
280 text=opts.get('text'),
281 git=(opts.get('git') or
282 ui.configbool('diff', 'git', None)),
283 showfunc=(opts.get('show_function') or
284 ui.configbool('diff', 'showfunc', None)),
285 ignorews=(opts.get('ignore_all_space') or
286 ui.configbool('diff', 'ignorews', None)),
287 ignorewsamount=(opts.get('ignore_space_change') or
288 ui.configbool('diff', 'ignorewsamount', None)),
289 ignoreblanklines=(opts.get('ignore_blank_lines') or
290 ui.configbool('diff', 'ignoreblanklines', None)))
291
292 def updatedir(ui, repo, patches, wlock=None):
293 '''Update dirstate after patch application according to metadata'''
294 if not patches:
295 return
296 copies = []
297 removes = []
298 cfiles = patches.keys()
299 copts = {'after': False, 'force': False}
300 cwd = repo.getcwd()
301 if cwd:
302 cfiles = [util.pathto(cwd, f) for f in patches.keys()]
303 for f in patches:
304 ctype, gp = patches[f]
305 if ctype == 'RENAME':
306 copies.append((gp.oldpath, gp.path, gp.copymod))
307 removes.append(gp.oldpath)
308 elif ctype == 'COPY':
309 copies.append((gp.oldpath, gp.path, gp.copymod))
310 elif ctype == 'DELETE':
311 removes.append(gp.path)
312 for src, dst, after in copies:
313 if not after:
314 copyfile(src, dst, repo.root)
315 repo.copy(src, dst, wlock=wlock)
316 if removes:
317 repo.remove(removes, True, wlock=wlock)
318 for f in patches:
319 ctype, gp = patches[f]
320 if gp and gp.mode:
321 x = gp.mode & 0100 != 0
322 dst = os.path.join(repo.root, gp.path)
323 util.set_exec(dst, x)
324 cmdutil.addremove(repo, cfiles, wlock=wlock)
325 files = patches.keys()
326 files.extend([r for r in removes if r not in files])
327 files.sort()
328
329 return files
330
331 def diff(repo, node1=None, node2=None, files=None, match=util.always,
332 fp=None, changes=None, opts=None):
333 '''print diff of changes to files between two nodes, or node and
334 working directory.
335
336 if node1 is None, use first dirstate parent instead.
337 if node2 is None, compare node1 with working directory.'''
338
339 if opts is None:
340 opts = mdiff.defaultopts
341 if fp is None:
342 fp = repo.ui
343
344 if not node1:
345 node1 = repo.dirstate.parents()[0]
346
347 clcache = {}
348 def getchangelog(n):
349 if n not in clcache:
350 clcache[n] = repo.changelog.read(n)
351 return clcache[n]
352 mcache = {}
353 def getmanifest(n):
354 if n not in mcache:
355 mcache[n] = repo.manifest.read(n)
356 return mcache[n]
357 fcache = {}
358 def getfile(f):
359 if f not in fcache:
360 fcache[f] = repo.file(f)
361 return fcache[f]
362
363 # reading the data for node1 early allows it to play nicely
364 # with repo.status and the revlog cache.
365 change = getchangelog(node1)
366 mmap = getmanifest(change[0])
367 date1 = util.datestr(change[2])
368
369 if not changes:
370 changes = repo.status(node1, node2, files, match=match)[:5]
371 modified, added, removed, deleted, unknown = changes
372 if files:
373 def filterfiles(filters):
374 l = [x for x in filters if x in files]
375
376 for t in files:
377 if not t.endswith("/"):
378 t += "/"
379 l += [x for x in filters if x.startswith(t)]
380 return l
381
382 modified, added, removed = map(filterfiles, (modified, added, removed))
383
384 if not modified and not added and not removed:
385 return
386
387 def renamedbetween(f, n1, n2):
388 r1, r2 = map(repo.changelog.rev, (n1, n2))
389 src = None
390 while r2 > r1:
391 cl = getchangelog(n2)[0]
392 m = getmanifest(cl)
393 try:
394 src = getfile(f).renamed(m[f])
395 except KeyError:
396 return None
397 if src:
398 f = src[0]
399 n2 = repo.changelog.parents(n2)[0]
400 r2 = repo.changelog.rev(n2)
401 return src
402
403 if node2:
404 change = getchangelog(node2)
405 mmap2 = getmanifest(change[0])
406 _date2 = util.datestr(change[2])
407 def date2(f):
408 return _date2
409 def read(f):
410 return getfile(f).read(mmap2[f])
411 def renamed(f):
412 return renamedbetween(f, node1, node2)
413 else:
414 tz = util.makedate()[1]
415 _date2 = util.datestr()
416 def date2(f):
417 try:
418 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
419 except OSError, err:
420 if err.errno != errno.ENOENT: raise
421 return _date2
422 def read(f):
423 return repo.wread(f)
424 def renamed(f):
425 src = repo.dirstate.copies.get(f)
426 parent = repo.dirstate.parents()[0]
427 if src:
428 f = src[0]
429 of = renamedbetween(f, node1, parent)
430 if of:
431 return of
432 elif src:
433 cl = getchangelog(parent)[0]
434 return (src, getmanifest(cl)[src])
435 else:
436 return None
437
438 if repo.ui.quiet:
439 r = None
440 else:
441 hexfunc = repo.ui.verbose and hex or short
442 r = [hexfunc(node) for node in [node1, node2] if node]
443
444 if opts.git:
445 copied = {}
446 for f in added:
447 src = renamed(f)
448 if src:
449 copied[f] = src
450 srcs = [x[1][0] for x in copied.items()]
451
452 all = modified + added + removed
453 all.sort()
454 for f in all:
455 to = None
456 tn = None
457 dodiff = True
458 if f in mmap:
459 to = getfile(f).read(mmap[f])
460 if f not in removed:
461 tn = read(f)
462 if opts.git:
463 def gitmode(x):
464 return x and '100755' or '100644'
465 def addmodehdr(header, omode, nmode):
466 if omode != nmode:
467 header.append('old mode %s\n' % omode)
468 header.append('new mode %s\n' % nmode)
469
470 a, b = f, f
471 header = []
472 if f in added:
473 if node2:
474 mode = gitmode(mmap2.execf(f))
475 else:
476 mode = gitmode(util.is_exec(repo.wjoin(f), None))
477 if f in copied:
478 a, arev = copied[f]
479 omode = gitmode(mmap.execf(a))
480 addmodehdr(header, omode, mode)
481 op = a in removed and 'rename' or 'copy'
482 header.append('%s from %s\n' % (op, a))
483 header.append('%s to %s\n' % (op, f))
484 to = getfile(a).read(arev)
485 else:
486 header.append('new file mode %s\n' % mode)
487 elif f in removed:
488 if f in srcs:
489 dodiff = False
490 else:
491 mode = gitmode(mmap.execf(f))
492 header.append('deleted file mode %s\n' % mode)
493 else:
494 omode = gitmode(mmap.execf(f))
495 nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
496 addmodehdr(header, omode, nmode)
497 r = None
498 if dodiff:
499 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
500 fp.write(''.join(header))
501 if dodiff:
502 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts))
503
504 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
505 opts=None):
506 '''export changesets as hg patches.'''
507
508 total = len(revs)
509 revwidth = max(map(len, revs))
510
511 def single(node, seqno, fp):
512 parents = [p for p in repo.changelog.parents(node) if p != nullid]
513 if switch_parent:
514 parents.reverse()
515 prev = (parents and parents[0]) or nullid
516 change = repo.changelog.read(node)
517
518 if not fp:
519 fp = cmdutil.make_file(repo, template, node, total=total,
520 seqno=seqno, revwidth=revwidth)
521 if fp not in (sys.stdout, repo.ui):
522 repo.ui.note("%s\n" % fp.name)
523
524 fp.write("# HG changeset patch\n")
525 fp.write("# User %s\n" % change[1])
526 fp.write("# Date %d %d\n" % change[2])
527 fp.write("# Node ID %s\n" % hex(node))
528 fp.write("# Parent %s\n" % hex(prev))
529 if len(parents) > 1:
530 fp.write("# Parent %s\n" % hex(parents[1]))
531 fp.write(change[4].rstrip())
532 fp.write("\n\n")
533
534 diff(repo, prev, node, fp=fp, opts=opts)
535 if fp not in (sys.stdout, repo.ui):
536 fp.close()
537
538 for seqno, cset in enumerate(revs):
539 single(cset, seqno, fp)
@@ -0,0 +1,34 b''
1 # strutil.py - string utilities for Mercurial
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 def findall(haystack, needle, start=0, end=None):
9 if end is None:
10 end = len(haystack)
11 if end < 0:
12 end += len(haystack)
13 if start < 0:
14 start += len(haystack)
15 while start < end:
16 c = haystack.find(needle, start, end)
17 if c == -1:
18 break
19 yield c
20 start = c + 1
21
22 def rfindall(haystack, needle, start=0, end=None):
23 if end is None:
24 end = len(haystack)
25 if end < 0:
26 end += len(haystack)
27 if start < 0:
28 start += len(haystack)
29 while end >= 0:
30 c = haystack.rfind(needle, start, end)
31 if c == -1:
32 break
33 yield c
34 end = c - 1
@@ -0,0 +1,23 b''
1 #!/bin/sh
2
3 echo % init
4 hg init
5
6 echo % commit
7 echo 'a' > a
8 hg ci -A -m test -u nobody -d '1 0'
9
10 echo % annotate -c
11 hg annotate -c a
12
13 echo % annotate -d
14 hg annotate -d a
15
16 echo % annotate -n
17 hg annotate -n a
18
19 echo % annotate -u
20 hg annotate -u a
21
22 echo % annotate -cdnu
23 hg annotate -cdnu a
@@ -0,0 +1,13 b''
1 % init
2 % commit
3 adding a
4 % annotate -c
5 8435f90966e4: a
6 % annotate -d
7 Thu Jan 01 00:00:01 1970 +0000: a
8 % annotate -n
9 0: a
10 % annotate -u
11 nobody: a
12 % annotate -cdnu
13 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
@@ -0,0 +1,36 b''
1 #!/bin/sh
2
3 set -e
4
5 echo "[extensions]" >> $HGRCPATH
6 echo "hbisect=" >> $HGRCPATH
7
8 echo % init
9 hg init
10
11 echo % committing changes
12 count=0
13 echo > a
14 while test $count -lt 32 ; do
15 echo 'a' >> a
16 test $count -eq 0 && hg add
17 hg ci -m "msg $count" -d "$count 0"
18 echo % committed changeset $count
19 count=`expr $count + 1`
20 done
21
22 echo % log
23 hg log
24
25 echo % hg up -C
26 hg up -C
27
28 echo % bisect test
29 hg bisect init
30 hg bisect bad
31 hg bisect good 1
32 hg bisect good
33 hg bisect good
34 hg bisect good
35 hg bisect bad
36 hg bisect good
@@ -0,0 +1,216 b''
1 % init
2 % committing changes
3 adding a
4 % committed changeset 0
5 % committed changeset 1
6 % committed changeset 2
7 % committed changeset 3
8 % committed changeset 4
9 % committed changeset 5
10 % committed changeset 6
11 % committed changeset 7
12 % committed changeset 8
13 % committed changeset 9
14 % committed changeset 10
15 % committed changeset 11
16 % committed changeset 12
17 % committed changeset 13
18 % committed changeset 14
19 % committed changeset 15
20 % committed changeset 16
21 % committed changeset 17
22 % committed changeset 18
23 % committed changeset 19
24 % committed changeset 20
25 % committed changeset 21
26 % committed changeset 22
27 % committed changeset 23
28 % committed changeset 24
29 % committed changeset 25
30 % committed changeset 26
31 % committed changeset 27
32 % committed changeset 28
33 % committed changeset 29
34 % committed changeset 30
35 % committed changeset 31
36 % log
37 changeset: 31:58c80a7c8a40
38 tag: tip
39 user: test
40 date: Thu Jan 01 00:00:31 1970 +0000
41 summary: msg 31
42
43 changeset: 30:ed2d2f24b11c
44 user: test
45 date: Thu Jan 01 00:00:30 1970 +0000
46 summary: msg 30
47
48 changeset: 29:b5bd63375ab9
49 user: test
50 date: Thu Jan 01 00:00:29 1970 +0000
51 summary: msg 29
52
53 changeset: 28:8e0c2264c8af
54 user: test
55 date: Thu Jan 01 00:00:28 1970 +0000
56 summary: msg 28
57
58 changeset: 27:288867a866e9
59 user: test
60 date: Thu Jan 01 00:00:27 1970 +0000
61 summary: msg 27
62
63 changeset: 26:3efc6fd51aeb
64 user: test
65 date: Thu Jan 01 00:00:26 1970 +0000
66 summary: msg 26
67
68 changeset: 25:02a84173a97a
69 user: test
70 date: Thu Jan 01 00:00:25 1970 +0000
71 summary: msg 25
72
73 changeset: 24:10e0acd3809e
74 user: test
75 date: Thu Jan 01 00:00:24 1970 +0000
76 summary: msg 24
77
78 changeset: 23:5ec79163bff4
79 user: test
80 date: Thu Jan 01 00:00:23 1970 +0000
81 summary: msg 23
82
83 changeset: 22:06c7993750ce
84 user: test
85 date: Thu Jan 01 00:00:22 1970 +0000
86 summary: msg 22
87
88 changeset: 21:e5db6aa3fe2a
89 user: test
90 date: Thu Jan 01 00:00:21 1970 +0000
91 summary: msg 21
92
93 changeset: 20:7128fb4fdbc9
94 user: test
95 date: Thu Jan 01 00:00:20 1970 +0000
96 summary: msg 20
97
98 changeset: 19:52798545b482
99 user: test
100 date: Thu Jan 01 00:00:19 1970 +0000
101 summary: msg 19
102
103 changeset: 18:86977a90077e
104 user: test
105 date: Thu Jan 01 00:00:18 1970 +0000
106 summary: msg 18
107
108 changeset: 17:03515f4a9080
109 user: test
110 date: Thu Jan 01 00:00:17 1970 +0000
111 summary: msg 17
112
113 changeset: 16:a2e6ea4973e9
114 user: test
115 date: Thu Jan 01 00:00:16 1970 +0000
116 summary: msg 16
117
118 changeset: 15:e7fa0811edb0
119 user: test
120 date: Thu Jan 01 00:00:15 1970 +0000
121 summary: msg 15
122
123 changeset: 14:ce8f0998e922
124 user: test
125 date: Thu Jan 01 00:00:14 1970 +0000
126 summary: msg 14
127
128 changeset: 13:9d7d07bc967c
129 user: test
130 date: Thu Jan 01 00:00:13 1970 +0000
131 summary: msg 13
132
133 changeset: 12:1941b52820a5
134 user: test
135 date: Thu Jan 01 00:00:12 1970 +0000
136 summary: msg 12
137
138 changeset: 11:7b4cd9578619
139 user: test
140 date: Thu Jan 01 00:00:11 1970 +0000
141 summary: msg 11
142
143 changeset: 10:7c5eff49a6b6
144 user: test
145 date: Thu Jan 01 00:00:10 1970 +0000
146 summary: msg 10
147
148 changeset: 9:eb44510ef29a
149 user: test
150 date: Thu Jan 01 00:00:09 1970 +0000
151 summary: msg 9
152
153 changeset: 8:453eb4dba229
154 user: test
155 date: Thu Jan 01 00:00:08 1970 +0000
156 summary: msg 8
157
158 changeset: 7:03750880c6b5
159 user: test
160 date: Thu Jan 01 00:00:07 1970 +0000
161 summary: msg 7
162
163 changeset: 6:a3d5c6fdf0d3
164 user: test
165 date: Thu Jan 01 00:00:06 1970 +0000
166 summary: msg 6
167
168 changeset: 5:7874a09ea728
169 user: test
170 date: Thu Jan 01 00:00:05 1970 +0000
171 summary: msg 5
172
173 changeset: 4:9b2ba8336a65
174 user: test
175 date: Thu Jan 01 00:00:04 1970 +0000
176 summary: msg 4
177
178 changeset: 3:b53bea5e2fcb
179 user: test
180 date: Thu Jan 01 00:00:03 1970 +0000
181 summary: msg 3
182
183 changeset: 2:db07c04beaca
184 user: test
185 date: Thu Jan 01 00:00:02 1970 +0000
186 summary: msg 2
187
188 changeset: 1:5cd978ea5149
189 user: test
190 date: Thu Jan 01 00:00:01 1970 +0000
191 summary: msg 1
192
193 changeset: 0:b99c7b9c8e11
194 user: test
195 date: Thu Jan 01 00:00:00 1970 +0000
196 summary: msg 0
197
198 % hg up -C
199 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 % bisect test
201 Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
202 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
204 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 Testing changeset 27:288867a866e9 (8 changesets remaining, ~3 tests)
206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
208 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
210 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 The first bad revision is:
212 changeset: 29:b5bd63375ab9
213 user: test
214 date: Thu Jan 01 00:00:29 1970 +0000
215 summary: msg 29
216
@@ -0,0 +1,27 b''
1 #!/bin/sh
2
3 hg init
4
5 mkdir alpha
6 touch alpha/one
7 mkdir beta
8 touch beta/two
9
10 hg add alpha/one beta/two
11 hg ci -m "start" -d "1000000 0"
12
13 echo 1 > alpha/one
14 echo 2 > beta/two
15
16 echo EVERYTHING
17 hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
18 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
19
20 echo BETA ONLY
21 hg diff beta | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
22 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
23
24 echo INSIDE BETA
25 cd beta
26 hg diff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
27 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
@@ -0,0 +1,23 b''
1 EVERYTHING
2 diff -r ec612a6291f1 alpha/one
3 --- a/alpha/one
4 +++ b/alpha/one
5 @@ -0,0 +1,1 @@
6 +1
7 diff -r ec612a6291f1 beta/two
8 --- a/beta/two
9 +++ b/beta/two
10 @@ -0,0 +1,1 @@
11 +2
12 BETA ONLY
13 diff -r ec612a6291f1 beta/two
14 --- a/beta/two
15 +++ b/beta/two
16 @@ -0,0 +1,1 @@
17 +2
18 INSIDE BETA
19 diff -r ec612a6291f1 beta/two
20 --- a/beta/two
21 +++ b/beta/two
22 @@ -0,0 +1,1 @@
23 +2
@@ -0,0 +1,29 b''
1 #!/bin/sh
2
3 echo "[extensions]" >> $HGRCPATH
4 echo "extdiff=" >> $HGRCPATH
5
6 hg init a
7 cd a
8 echo a > a
9 hg add
10 diff -N /dev/null /dev/null 2> /dev/null
11 if [ $? -ne 0 ]; then
12 opt="-p gdiff"
13 fi
14 hg extdiff -o -Nr $opt
15
16 echo "[extdiff]" >> $HGRCPATH
17 echo "cmd.falabala=echo" >> $HGRCPATH
18 echo "opts.falabala=diffing" >> $HGRCPATH
19
20 hg falabala
21
22 hg help falabala
23
24 hg ci -d '0 0' -mtest1
25
26 echo b >> a
27 hg ci -d '1 0' -mtest2
28
29 hg falabala -r 0:1 || echo "diff-like tools yield a non-zero exit code"
@@ -0,0 +1,32 b''
1 adding a
2 making snapshot of 0 files from rev 000000000000
3 making snapshot of 1 files from working dir
4 diff -Nr a.000000000000/a a/a
5 0a1
6 > a
7 making snapshot of 0 files from rev 000000000000
8 making snapshot of 1 files from working dir
9 diffing a.000000000000 a
10 hg falabala [OPT]... [FILE]...
11
12 use 'echo' to diff repository (or selected files)
13
14 Show differences between revisions for the specified
15 files, using the 'echo' program.
16
17 When two revision arguments are given, then changes are
18 shown between those revisions. If only one revision is
19 specified then that revision is compared to the working
20 directory, and, when no revisions are specified, the
21 working directory files are compared to its parent.
22
23 options:
24
25 -o --option pass option to comparison program
26 -r --rev revision
27 -I --include include names matching the given patterns
28 -X --exclude exclude names matching the given patterns
29 making snapshot of 1 files from rev e27a2475d60a
30 making snapshot of 1 files from rev 5e49ec8d3f05
31 diffing a.e27a2475d60a a.5e49ec8d3f05
32 diff-like tools yield a non-zero exit code
@@ -0,0 +1,52 b''
1 #!/bin/sh
2
3 hg init a
4 cd a
5
6 echo start > start
7 hg ci -Amstart -d '0 0'
8 echo new > new
9 hg ci -Amnew -d '0 0'
10 echo '% new file'
11 hg diff --git -r 0 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
12 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
13
14 hg cp new copy
15 hg ci -mcopy -d '0 0'
16 echo '% copy'
17 hg diff --git -r 1:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
18 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
19
20 hg mv copy rename
21 hg ci -mrename -d '0 0'
22 echo '% rename'
23 hg diff --git -r 2:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
24 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
25
26 hg rm rename
27 hg ci -mdelete -d '0 0'
28 echo '% delete'
29 hg diff --git -r 3:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
30 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
31
32 cat > src <<EOF
33 1
34 2
35 3
36 4
37 5
38 EOF
39 hg ci -Amsrc -d '0 0'
40 chmod +x src
41 hg ci -munexec -d '0 0'
42 echo '% chmod 644'
43 hg diff --git -r 5:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
44 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
45
46 hg mv src dst
47 chmod -x dst
48 echo a >> dst
49 hg ci -mrenamemod -d '0 0'
50 echo '% rename+mod+chmod'
51 hg diff --git -r 6:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
52 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
@@ -0,0 +1,42 b''
1 adding start
2 adding new
3 % new file
4 diff --git a/new b/new
5 new file mode 100644
6 --- /dev/null
7 +++ b/new
8 @@ -0,0 +1,1 @@
9 +new
10 % copy
11 diff --git a/new b/copy
12 copy from new
13 copy to copy
14 % rename
15 diff --git a/copy b/rename
16 rename from copy
17 rename to rename
18 % delete
19 diff --git a/rename b/rename
20 deleted file mode 100644
21 --- a/rename
22 +++ /dev/null
23 @@ -1,1 +0,0 @@
24 -new
25 adding src
26 % chmod 644
27 diff --git a/src b/src
28 old mode 100644
29 new mode 100755
30 % rename+mod+chmod
31 diff --git a/src b/dst
32 old mode 100755
33 new mode 100644
34 rename from src
35 rename to dst
36 --- a/dst
37 +++ b/dst
38 @@ -3,3 +3,4 @@ 3
39 3
40 4
41 5
42 +a
@@ -0,0 +1,122 b''
1 #!/bin/sh
2
3 hg init a
4 cd a
5
6 echo % new file
7 hg import -mnew - <<EOF
8 diff --git a/new b/new
9 new file mode 100644
10 index 0000000..7898192
11 --- /dev/null
12 +++ b/new
13 @@ -0,0 +1 @@
14 +a
15 EOF
16
17 echo % chmod +x
18 hg import -msetx - <<EOF
19 diff --git a/new b/new
20 old mode 100644
21 new mode 100755
22 EOF
23
24 test -x new || echo failed
25
26 echo % copy
27 hg import -mcopy - <<EOF
28 diff --git a/new b/copy
29 old mode 100755
30 new mode 100644
31 similarity index 100%
32 copy from new
33 copy to copy
34 diff --git a/new b/copyx
35 similarity index 100%
36 copy from new
37 copy to copyx
38 EOF
39
40 test -f copy -a ! -x copy || echo failed
41 test -x copyx || echo failed
42 cat copy
43 hg cat copy
44
45 echo % rename
46 hg import -mrename - <<EOF
47 diff --git a/copy b/rename
48 similarity index 100%
49 rename from copy
50 rename to rename
51 EOF
52
53 hg locate
54
55 echo % delete
56 hg import -mdelete - <<EOF
57 diff --git a/copyx b/copyx
58 deleted file mode 100755
59 index 7898192..0000000
60 --- a/copyx
61 +++ /dev/null
62 @@ -1 +0,0 @@
63 -a
64 EOF
65
66 hg locate
67 test -f copyx && echo failed || true
68
69 echo % regular diff
70 hg import -mregular - <<EOF
71 diff --git a/rename b/rename
72 index 7898192..72e1fe3 100644
73 --- a/rename
74 +++ b/rename
75 @@ -1 +1,5 @@
76 a
77 +a
78 +a
79 +a
80 +a
81 EOF
82
83 echo % copy and modify
84 hg import -mcopymod - <<EOF
85 diff --git a/rename b/copy2
86 similarity index 80%
87 copy from rename
88 copy to copy2
89 index 72e1fe3..b53c148 100644
90 --- a/rename
91 +++ b/copy2
92 @@ -1,5 +1,5 @@
93 a
94 a
95 -a
96 +b
97 a
98 a
99 EOF
100
101 hg cat copy2
102
103 echo % rename and modify
104 hg import -mrenamemod - <<EOF
105 diff --git a/copy2 b/rename2
106 similarity index 80%
107 rename from copy2
108 rename to rename2
109 index b53c148..8f81e29 100644
110 --- a/copy2
111 +++ b/rename2
112 @@ -1,5 +1,5 @@
113 a
114 a
115 b
116 -a
117 +c
118 a
119 EOF
120
121 hg locate copy2
122 hg cat rename2
@@ -0,0 +1,34 b''
1 % new file
2 applying patch from stdin
3 % chmod +x
4 applying patch from stdin
5 % copy
6 applying patch from stdin
7 a
8 a
9 % rename
10 applying patch from stdin
11 copyx
12 new
13 rename
14 % delete
15 applying patch from stdin
16 new
17 rename
18 % regular diff
19 applying patch from stdin
20 % copy and modify
21 applying patch from stdin
22 a
23 a
24 b
25 a
26 a
27 % rename and modify
28 applying patch from stdin
29 copy2: No such file or directory
30 a
31 a
32 b
33 c
34 a
@@ -0,0 +1,49 b''
1 #!/bin/sh
2 # http://www.selenic.com/mercurial/bts/issue322
3
4 echo % file replaced with directory
5
6 hg init a
7 cd a
8 echo a > a
9 hg commit -Ama
10 rm a
11 mkdir a
12 echo a > a/a
13
14 echo % should fail - would corrupt dirstate
15 hg add a/a
16
17 cd ..
18
19 echo % directory replaced with file
20
21 hg init c
22 cd c
23 mkdir a
24 echo a > a/a
25 hg commit -Ama
26
27 rm -rf a
28 echo a > a
29
30 echo % should fail - would corrupt dirstate
31 hg add a
32
33 cd ..
34
35 echo % directory replaced with file
36
37 hg init d
38 cd d
39 mkdir b
40 mkdir b/c
41 echo a > b/c/d
42 hg commit -Ama
43 rm -rf b
44 echo a > b
45
46 echo % should fail - would corrupt dirstate
47 hg add b
48
49 exit 0
@@ -0,0 +1,12 b''
1 % file replaced with directory
2 adding a
3 % should fail - would corrupt dirstate
4 abort: file named 'a' already in dirstate
5 % directory replaced with file
6 adding a/a
7 % should fail - would corrupt dirstate
8 abort: directory named 'a' already in dirstate
9 % directory replaced with file
10 adding b/c/d
11 % should fail - would corrupt dirstate
12 abort: directory named 'b' already in dirstate
@@ -0,0 +1,40 b''
1 #!/bin/sh
2
3 hg init
4 echo a > a
5 hg commit -A -ma
6
7 echo a >> a
8 hg commit -mb
9
10 echo a >> a
11 hg commit -mc
12
13 hg up 1
14 echo a >> a
15 hg commit -md
16
17 hg up 1
18 echo a >> a
19 hg commit -me
20
21 hg up 1
22 echo % should fail because not at a head
23 hg merge
24
25 hg up
26 echo % should fail because \> 2 heads
27 hg merge
28
29 echo % should succeed
30 hg merge 2
31 hg commit -mm1
32
33 echo % should succeed - 2 heads
34 hg merge
35 hg commit -mm2
36
37 echo % should fail because 1 head
38 hg merge
39
40 true
@@ -0,0 +1,17 b''
1 adding a
2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
5 % should fail because not at a head
6 abort: repo has 3 heads - please merge with an explicit rev
7 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
8 % should fail because > 2 heads
9 abort: repo has 3 heads - please merge with an explicit rev
10 % should succeed
11 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 (branch merge, don't forget to commit)
13 % should succeed - 2 heads
14 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 (branch merge, don't forget to commit)
16 % should fail because 1 head
17 abort: there is nothing to merge - use "hg update" instead
@@ -0,0 +1,27 b''
1 #!/bin/sh
2
3 echo "[extensions]" >> $HGRCPATH
4 echo "mq=" >> $HGRCPATH
5
6 echo % init
7 hg init a
8 cd a
9
10 echo % commit
11 echo 'base' > base
12 hg ci -Ambase -d '1 0'
13
14 echo % qnew mqbase
15 hg qnew -mmqbase mqbase
16
17 echo % qrefresh
18 echo 'patched' > base
19 hg qrefresh
20
21 echo % qdiff
22 hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
23 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
24
25 echo % qdiff dirname
26 hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
27 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
@@ -0,0 +1,19 b''
1 % init
2 % commit
3 adding base
4 % qnew mqbase
5 % qrefresh
6 % qdiff
7 diff -r 67e992f2c4f3 base
8 --- a/base
9 +++ b/base
10 @@ -1,1 +1,1 @@ base
11 -base
12 +patched
13 % qdiff dirname
14 diff -r 67e992f2c4f3 base
15 --- a/base
16 +++ b/base
17 @@ -1,1 +1,1 @@ base
18 -base
19 +patched
@@ -0,0 +1,18 b''
1 #!/bin/sh
2
3 hg init
4
5 echo a > a
6 hg ci -d '0 0' -Ama
7
8 hg an a
9
10 echo "[ui]" >> $HGRCPATH
11 echo "strict=True" >> $HGRCPATH
12
13 hg an a
14 hg annotate a
15
16 echo % should succeed - up is an alias, not an abbreviation
17
18 hg up
@@ -0,0 +1,26 b''
1 adding a
2 0: a
3 hg: unknown command 'an'
4 Mercurial Distributed SCM
5
6 basic commands (use "hg help" for the full list or option "-v" for details):
7
8 add add the specified files on the next commit
9 annotate show changeset information per file line
10 clone make a copy of an existing repository
11 commit commit the specified files or all outstanding changes
12 diff diff repository (or selected files)
13 export dump the header and diffs for one or more changesets
14 init create a new repository in the given directory
15 log show revision history of entire repository or files
16 parents show the parents of the working dir or revision
17 pull pull changes from the specified source
18 push push changes to the specified destination
19 remove remove the specified files on the next commit
20 revert revert files or dirs to their states as of some revision
21 serve export the repository via HTTP
22 status show changed files in the working directory
23 update update or merge working directory
24 0: a
25 % should succeed - up is an alias, not an abbreviation
26 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -21,6 +21,7 b' doc/*.[0-9].{x,ht}ml'
21 MANIFEST
21 MANIFEST
22 patches
22 patches
23 mercurial/__version__.py
23 mercurial/__version__.py
24 .DS_Store
24
25
25 syntax: regexp
26 syntax: regexp
26 ^\.pc/
27 ^\.pc/
@@ -4,6 +4,7 b' Goffredo Baroncelli <kreijack at libero.'
4 Muli Ben-Yehuda <mulix at mulix.org>
4 Muli Ben-Yehuda <mulix at mulix.org>
5 Mikael Berthe <mikael at lilotux.net>
5 Mikael Berthe <mikael at lilotux.net>
6 Benoit Boissinot <bboissin at gmail.com>
6 Benoit Boissinot <bboissin at gmail.com>
7 Brendan Cully <brendan at kublai.com>
7 Vincent Danjean <vdanjean.ml at free.fr>
8 Vincent Danjean <vdanjean.ml at free.fr>
8 Jake Edge <jake at edge2.net>
9 Jake Edge <jake at edge2.net>
9 Michael Fetterman <michael.fetterman at intel.com>
10 Michael Fetterman <michael.fetterman at intel.com>
@@ -722,7 +722,7 b' code by typing `M-x find-library mercuri'
722 (if (not hg-root-dir)
722 (if (not hg-root-dir)
723 (error "error: %s: directory is not part of a Mercurial repository."
723 (error "error: %s: directory is not part of a Mercurial repository."
724 default-directory)
724 default-directory)
725 (cd (hg-root))))))
725 (cd hg-root-dir)))))
726
726
727 (defun hg-add (path)
727 (defun hg-add (path)
728 "Add PATH to the Mercurial repository on the next commit.
728 "Add PATH to the Mercurial repository on the next commit.
@@ -216,6 +216,6 b' http://selenic.com/mailman/listinfo/merc'
216
216
217 COPYING
217 COPYING
218 -------
218 -------
219 Copyright \(C) 2005 Matt Mackall.
219 Copyright \(C) 2005, 2006 Matt Mackall.
220 Free use of this software is granted under the terms of the GNU General
220 Free use of this software is granted under the terms of the GNU General
221 Public License (GPL).
221 Public License (GPL).
@@ -30,6 +30,6 b' hg(1) - the command line interface to Me'
30
30
31 COPYING
31 COPYING
32 -------
32 -------
33 Copyright \(C) 2005 Matt Mackall.
33 Copyright \(C) 2005, 2006 Matt Mackall.
34 Free use of this software is granted under the terms of the GNU General
34 Free use of this software is granted under the terms of the GNU General
35 Public License (GPL).
35 Public License (GPL).
@@ -306,7 +306,7 b' http_proxy::'
306 smtp::
306 smtp::
307 Configuration for extensions that need to send email messages.
307 Configuration for extensions that need to send email messages.
308 host;;
308 host;;
309 Optional. Host name of mail server. Default: "mail".
309 Host name of mail server, e.g. "mail.example.com".
310 port;;
310 port;;
311 Optional. Port to connect to on mail server. Default: 25.
311 Optional. Port to connect to on mail server. Default: 25.
312 tls;;
312 tls;;
@@ -377,6 +377,9 b' ui::'
377 remote command to use for clone/push/pull operations. Default is 'hg'.
377 remote command to use for clone/push/pull operations. Default is 'hg'.
378 ssh;;
378 ssh;;
379 command to use for SSH connections. Default is 'ssh'.
379 command to use for SSH connections. Default is 'ssh'.
380 strict;;
381 Require exact command names, instead of allowing unambiguous
382 abbreviations. True or False. Default is False.
380 timeout;;
383 timeout;;
381 The timeout used when a lock is held (in seconds), a negative value
384 The timeout used when a lock is held (in seconds), a negative value
382 means no timeout. Default is 600.
385 means no timeout. Default is 600.
@@ -862,6 +862,6 b' http://selenic.com/mailman/listinfo/mercurial[\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xaa\xe3\x83\xb3\xe3\x82\xb0\xe3\x83\xaa\xe3\x82\xb9\xe3\x83\x88]'
862
862
863 著作権情報
863 著作権情報
864 -----
864 -----
865 Copyright (C) 2005 Matt Mackall.
865 Copyright (C) 2005, 2006 Matt Mackall.
866 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
866 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
867 認められます。
867 認められます。
@@ -32,6 +32,6 b' hg(1) - Mercurial \xe3\x82\xb7\xe3\x82\xb9\xe3\x83\x86\xe3\x83\xa0\xe3\x81\xb8\xe3\x81\xae\xe3\x82\xb3\xe3\x83\x9e\xe3\x83\xb3\xe3\x83\x89\xe3\x83\xa9\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x95\xe3\x82\xa7\xe3\x82\xa4\xe3\x82\xb9'
32
32
33 著作権情報
33 著作権情報
34 ----
34 ----
35 Copyright (C) 2005 Matt Mackall.
35 Copyright (C) 2005, 2006 Matt Mackall.
36 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
36 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
37 認められます。
37 認められます。
@@ -5,19 +5,24 b''
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7 #
7 #
8 # allow to use external programs to compare revisions, or revision
8 # The `extdiff' Mercurial extension allows you to use external programs
9 # with working dir. program is called with two arguments: paths to
9 # to compare revisions, or revision with working dir. The external diff
10 # directories containing snapshots of files to compare.
10 # programs are called with a configurable set of options and two
11 # non-option arguments: paths to directories containing snapshots of
12 # files to compare.
11 #
13 #
12 # to enable:
14 # To enable this extension:
13 #
15 #
14 # [extensions]
16 # [extensions]
15 # hgext.extdiff =
17 # hgext.extdiff =
16 #
18 #
17 # also allows to configure new diff commands, so you do not need to
19 # The `extdiff' extension also allows to configure new diff commands, so
18 # type "hg extdiff -p kdiff3" always.
20 # you do not need to type "hg extdiff -p kdiff3" always.
19 #
21 #
20 # [extdiff]
22 # [extdiff]
23 # # add new command that runs GNU diff(1) in 'context diff' mode
24 # cmd.cdiff = gdiff
25 # opts.cdiff = -Nprc5
21 # # add new command called vdiff, runs kdiff3
26 # # add new command called vdiff, runs kdiff3
22 # cmd.vdiff = kdiff3
27 # cmd.vdiff = kdiff3
23 # # add new command called meld, runs meld (no need to name twice)
28 # # add new command called meld, runs meld (no need to name twice)
@@ -26,16 +31,23 b''
26 # #(see http://www.vim.org/scripts/script.php?script_id=102)
31 # #(see http://www.vim.org/scripts/script.php?script_id=102)
27 # cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)'
32 # cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)'
28 #
33 #
29 # you can use -I/-X and list of file or directory names like normal
34 # Each custom diff commands can have two parts: a `cmd' and an `opts'
30 # "hg diff" command. extdiff makes snapshots of only needed files, so
35 # part. The cmd.xxx option defines the name of an executable program
31 # compare program will be fast.
36 # that will be run, and opts.xxx defines a set of command-line options
37 # which will be inserted to the command between the program name and
38 # the files/directories to diff (i.e. the cdiff example above).
39 #
40 # You can use -I/-X and list of file or directory names like normal
41 # "hg diff" command. The `extdiff' extension makes snapshots of only
42 # needed files, so running the external diff program will actually be
43 # pretty fast (at least faster than having to compare the entire tree).
32
44
33 from mercurial.demandload import demandload
45 from mercurial.demandload import demandload
34 from mercurial.i18n import gettext as _
46 from mercurial.i18n import gettext as _
35 from mercurial.node import *
47 from mercurial.node import *
36 demandload(globals(), 'mercurial:commands,util os shutil tempfile')
48 demandload(globals(), 'mercurial:commands,cmdutil,util os shutil tempfile')
37
49
38 def dodiff(ui, repo, diffcmd, pats, opts):
50 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
39 def snapshot_node(files, node):
51 def snapshot_node(files, node):
40 '''snapshot files as of some revision'''
52 '''snapshot files as of some revision'''
41 changes = repo.changelog.read(node)
53 changes = repo.changelog.read(node)
@@ -79,9 +91,9 b' def dodiff(ui, repo, diffcmd, pats, opts'
79 return dirname
91 return dirname
80
92
81 node1, node2 = commands.revpair(ui, repo, opts['rev'])
93 node1, node2 = commands.revpair(ui, repo, opts['rev'])
82 files, matchfn, anypats = commands.matchpats(repo, pats, opts)
94 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
83 modified, added, removed, deleted, unknown = repo.changes(
95 modified, added, removed, deleted, unknown = repo.status(
84 node1, node2, files, match=matchfn)
96 node1, node2, files, match=matchfn)[:5]
85 if not (modified or added or removed):
97 if not (modified or added or removed):
86 return 0
98 return 0
87
99
@@ -92,9 +104,12 b' def dodiff(ui, repo, diffcmd, pats, opts'
92 dir2 = snapshot_node(modified + added, node2)
104 dir2 = snapshot_node(modified + added, node2)
93 else:
105 else:
94 dir2 = snapshot_wdir(modified + added)
106 dir2 = snapshot_wdir(modified + added)
95 util.system('%s %s "%s" "%s"' %
107 cmdline = ('%s %s %s %s' %
96 (diffcmd, ' '.join(opts['option']), dir1, dir2),
108 (util.shellquote(diffcmd),
97 cwd=tmproot)
109 ' '.join(map(util.shellquote, diffopts)),
110 util.shellquote(dir1), util.shellquote(dir2)))
111 ui.debug('running %r in %s\n' % (cmdline, tmproot))
112 util.system(cmdline, cwd=tmproot)
98 return 1
113 return 1
99 finally:
114 finally:
100 ui.note(_('cleaning up temp directory\n'))
115 ui.note(_('cleaning up temp directory\n'))
@@ -104,7 +119,9 b' def extdiff(ui, repo, *pats, **opts):'
104 '''use external program to diff repository (or selected files)
119 '''use external program to diff repository (or selected files)
105
120
106 Show differences between revisions for the specified files, using
121 Show differences between revisions for the specified files, using
107 an external program. The default program used is "diff -Npru".
122 an external program. The default program used is diff, with
123 default options "-Npru".
124
108 To select a different program, use the -p option. The program
125 To select a different program, use the -p option. The program
109 will be passed the names of two directories to compare. To pass
126 will be passed the names of two directories to compare. To pass
110 additional options to the program, use the -o option. These will
127 additional options to the program, use the -o option. These will
@@ -115,7 +132,8 b' def extdiff(ui, repo, *pats, **opts):'
115 specified then that revision is compared to the working
132 specified then that revision is compared to the working
116 directory, and, when no revisions are specified, the
133 directory, and, when no revisions are specified, the
117 working directory files are compared to its parent.'''
134 working directory files are compared to its parent.'''
118 return dodiff(ui, repo, opts['program'] or 'diff -Npru', pats, opts)
135 return dodiff(ui, repo, opts['program'] or 'diff',
136 opts['option'] or ['-Npru'], pats, opts)
119
137
120 cmdtable = {
138 cmdtable = {
121 "extdiff":
139 "extdiff":
@@ -133,21 +151,25 b' def uisetup(ui):'
133 if not cmd.startswith('cmd.'): continue
151 if not cmd.startswith('cmd.'): continue
134 cmd = cmd[4:]
152 cmd = cmd[4:]
135 if not path: path = cmd
153 if not path: path = cmd
136 def save(cmd, path):
154 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
155 diffopts = diffopts and [diffopts] or []
156 def save(cmd, path, diffopts):
137 '''use closure to save diff command to use'''
157 '''use closure to save diff command to use'''
138 def mydiff(ui, repo, *pats, **opts):
158 def mydiff(ui, repo, *pats, **opts):
139 return dodiff(ui, repo, path, pats, opts)
159 return dodiff(ui, repo, path, diffopts, pats, opts)
140 mydiff.__doc__ = '''use %s to diff repository (or selected files)
160 mydiff.__doc__ = '''use %(path)r to diff repository (or selected files)
141
161
142 Show differences between revisions for the specified
162 Show differences between revisions for the specified
143 files, using the %s program.
163 files, using the %(path)r program.
144
164
145 When two revision arguments are given, then changes are
165 When two revision arguments are given, then changes are
146 shown between those revisions. If only one revision is
166 shown between those revisions. If only one revision is
147 specified then that revision is compared to the working
167 specified then that revision is compared to the working
148 directory, and, when no revisions are specified, the
168 directory, and, when no revisions are specified, the
149 working directory files are compared to its parent.''' % (cmd, cmd)
169 working directory files are compared to its parent.''' % {
170 'path': path,
171 }
150 return mydiff
172 return mydiff
151 cmdtable[cmd] = (save(cmd, path),
173 cmdtable[cmd] = (save(cmd, path, diffopts),
152 cmdtable['extdiff'][1][1:],
174 cmdtable['extdiff'][1][1:],
153 _('hg %s [OPT]... [FILE]...') % cmd)
175 _('hg %s [OPT]... [FILE]...') % cmd)
@@ -24,13 +24,13 b" def fetch(ui, repo, source='default', **"
24 if modheads == 0:
24 if modheads == 0:
25 return 0
25 return 0
26 if modheads == 1:
26 if modheads == 1:
27 return hg.update(repo, repo.changelog.tip(), wlock=wlock)
27 return hg.clean(repo, repo.changelog.tip(), wlock=wlock)
28 newheads = repo.heads(parent)
28 newheads = repo.heads(parent)
29 newchildren = [n for n in repo.heads(parent) if n != parent]
29 newchildren = [n for n in repo.heads(parent) if n != parent]
30 newparent = parent
30 newparent = parent
31 if newchildren:
31 if newchildren:
32 newparent = newchildren[0]
32 newparent = newchildren[0]
33 hg.update(repo, newparent, wlock=wlock)
33 hg.clean(repo, newparent, wlock=wlock)
34 newheads = [n for n in repo.heads() if n != newparent]
34 newheads = [n for n in repo.heads() if n != newparent]
35 err = False
35 err = False
36 if newheads:
36 if newheads:
@@ -221,7 +221,7 b' def sign(ui, repo, *revs, **opts):'
221 repo.opener("localsigs", "ab").write(sigmessage)
221 repo.opener("localsigs", "ab").write(sigmessage)
222 return
222 return
223
223
224 for x in repo.changes():
224 for x in repo.status()[:5]:
225 if ".hgsigs" in x and not opts["force"]:
225 if ".hgsigs" in x and not opts["force"]:
226 raise util.Abort(_("working copy of .hgsigs is changed "
226 raise util.Abort(_("working copy of .hgsigs is changed "
227 "(please commit .hgsigs manually "
227 "(please commit .hgsigs manually "
@@ -23,10 +23,10 b' def lookup_rev(ui, repo, rev=None):'
23 return parents.pop()
23 return parents.pop()
24
24
25 def check_clean(ui, repo):
25 def check_clean(ui, repo):
26 modified, added, removed, deleted, unknown = repo.changes()
26 modified, added, removed, deleted, unknown = repo.status()[:5]
27 if modified or added or removed:
27 if modified or added or removed:
28 ui.warn("Repository is not clean, please commit or revert\n")
28 ui.warn("Repository is not clean, please commit or revert\n")
29 sys.exit(1)
29 sys.exit(1)
30
30
31 class bisect(object):
31 class bisect(object):
32 """dichotomic search in the DAG of changesets"""
32 """dichotomic search in the DAG of changesets"""
@@ -1,12 +1,13 b''
1 # Minimal support for git commands on an hg repository
1 # Minimal support for git commands on an hg repository
2 #
2 #
3 # Copyright 2005 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import time, sys, signal, os
8 from mercurial.demandload import *
9 from mercurial import hg, mdiff, fancyopts, commands, ui, util
9 demandload(globals(), 'time sys signal os')
10 demandload(globals(), 'mercurial:hg,mdiff,fancyopts,commands,ui,util')
10
11
11 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
12 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
12 changes=None, text=False):
13 changes=None, text=False):
@@ -14,7 +15,7 b' def dodiff(fp, ui, repo, node1, node2, f'
14 return time.asctime(time.gmtime(c[2][0]))
15 return time.asctime(time.gmtime(c[2][0]))
15
16
16 if not changes:
17 if not changes:
17 changes = repo.changes(node1, node2, files, match=match)
18 changes = repo.status(node1, node2, files, match=match)[:5]
18 modified, added, removed, deleted, unknown = changes
19 modified, added, removed, deleted, unknown = changes
19 if files:
20 if files:
20 modified, added, removed = map(lambda x: filterfiles(files, x),
21 modified, added, removed = map(lambda x: filterfiles(files, x),
@@ -67,12 +68,12 b' def difftree(ui, repo, node1=None, node2'
67 if node2:
68 if node2:
68 change = repo.changelog.read(node2)
69 change = repo.changelog.read(node2)
69 mmap2 = repo.manifest.read(change[0])
70 mmap2 = repo.manifest.read(change[0])
70 modified, added, removed, deleted, unknown = repo.changes(node1, node2)
71 modified, added, removed, deleted, unknown = repo.status(node1, node2)[:5]
71 def read(f): return repo.file(f).read(mmap2[f])
72 def read(f): return repo.file(f).read(mmap2[f])
72 date2 = date(change)
73 date2 = date(change)
73 else:
74 else:
74 date2 = time.asctime()
75 date2 = time.asctime()
75 modified, added, removed, deleted, unknown = repo.changes(node1)
76 modified, added, removed, deleted, unknown = repo.status(node1)[:5]
76 if not node1:
77 if not node1:
77 node1 = repo.dirstate.parents()[0]
78 node1 = repo.dirstate.parents()[0]
78 def read(f): return file(os.path.join(repo.root, f)).read()
79 def read(f): return file(os.path.join(repo.root, f)).read()
@@ -1,7 +1,6 b''
1
2 # queue.py - patch queues for mercurial
1 # queue.py - patch queues for mercurial
3 #
2 #
4 # Copyright 2005 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
5 #
4 #
6 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -31,9 +30,10 b' refresh contents of top applied patch '
31 '''
30 '''
32
31
33 from mercurial.demandload import *
32 from mercurial.demandload import *
33 from mercurial.i18n import gettext as _
34 from mercurial import commands
34 demandload(globals(), "os sys re struct traceback errno bz2")
35 demandload(globals(), "os sys re struct traceback errno bz2")
35 from mercurial.i18n import gettext as _
36 demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,ui,util")
36 from mercurial import ui, hg, revlog, commands, util
37
37
38 commands.norepo += " qclone qversion"
38 commands.norepo += " qclone qversion"
39
39
@@ -66,6 +66,7 b' class queue:'
66 self.guards_path = "guards"
66 self.guards_path = "guards"
67 self.active_guards = None
67 self.active_guards = None
68 self.guards_dirty = False
68 self.guards_dirty = False
69 self._diffopts = None
69
70
70 if os.path.exists(self.join(self.series_path)):
71 if os.path.exists(self.join(self.series_path)):
71 self.full_series = self.opener(self.series_path).read().splitlines()
72 self.full_series = self.opener(self.series_path).read().splitlines()
@@ -75,6 +76,11 b' class queue:'
75 lines = self.opener(self.status_path).read().splitlines()
76 lines = self.opener(self.status_path).read().splitlines()
76 self.applied = [statusentry(l) for l in lines]
77 self.applied = [statusentry(l) for l in lines]
77
78
79 def diffopts(self):
80 if self._diffopts is None:
81 self._diffopts = patch.diffopts(self.ui)
82 return self._diffopts
83
78 def join(self, *p):
84 def join(self, *p):
79 return os.path.join(self.path, *p)
85 return os.path.join(self.path, *p)
80
86
@@ -176,11 +182,11 b' class queue:'
176 if exactneg:
182 if exactneg:
177 return False, exactneg[0]
183 return False, exactneg[0]
178 pos = [g for g in patchguards if g[0] == '+']
184 pos = [g for g in patchguards if g[0] == '+']
179 nonpos = [g for g in pos if g[1:] not in guards]
185 exactpos = [g for g in pos if g[1:] in guards]
180 if pos:
186 if pos:
181 if not nonpos:
187 if exactpos:
182 return True, ''
188 return True, exactpos[0]
183 return False, nonpos
189 return False, pos
184 return True, ''
190 return True, ''
185
191
186 def explain_pushable(self, idx, all_patches=False):
192 def explain_pushable(self, idx, all_patches=False):
@@ -247,6 +253,9 b' class queue:'
247
253
248 for line in file(pf):
254 for line in file(pf):
249 line = line.rstrip()
255 line = line.rstrip()
256 if line.startswith('diff --git'):
257 diffstart = 2
258 break
250 if diffstart:
259 if diffstart:
251 if line.startswith('+++ '):
260 if line.startswith('+++ '):
252 diffstart = 2
261 diffstart = 2
@@ -292,6 +301,13 b' class queue:'
292 message.insert(0, subject)
301 message.insert(0, subject)
293 return (message, comments, user, date, diffstart > 1)
302 return (message, comments, user, date, diffstart > 1)
294
303
304 def printdiff(self, repo, node1, node2=None, files=None,
305 fp=None, changes=None, opts={}):
306 fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts)
307
308 patch.diff(repo, node1, node2, fns, match=matchfn,
309 fp=fp, changes=changes, opts=self.diffopts())
310
295 def mergeone(self, repo, mergeq, head, patch, rev, wlock):
311 def mergeone(self, repo, mergeq, head, patch, rev, wlock):
296 # first try just applying the patch
312 # first try just applying the patch
297 (err, n) = self.apply(repo, [ patch ], update_status=False,
313 (err, n) = self.apply(repo, [ patch ], update_status=False,
@@ -325,7 +341,7 b' class queue:'
325 if comments:
341 if comments:
326 comments = "\n".join(comments) + '\n\n'
342 comments = "\n".join(comments) + '\n\n'
327 patchf.write(comments)
343 patchf.write(comments)
328 commands.dodiff(patchf, self.ui, repo, head, n)
344 self.printdiff(repo, head, n, fp=patchf)
329 patchf.close()
345 patchf.close()
330 return (0, n)
346 return (0, n)
331
347
@@ -390,39 +406,15 b' class queue:'
390 '''Apply patchfile to the working directory.
406 '''Apply patchfile to the working directory.
391 patchfile: file name of patch'''
407 patchfile: file name of patch'''
392 try:
408 try:
393 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
409 (files, fuzz) = patch.patch(patchfile, self.ui, strip=1,
394 f = os.popen("%s -d %s -p1 --no-backup-if-mismatch < %s" %
410 cwd=repo.root)
395 (pp, util.shellquote(repo.root), util.shellquote(patchfile)))
411 except Exception, inst:
396 except:
412 self.ui.note(str(inst) + '\n')
397 self.ui.warn("patch failed, unable to continue (try -v)\n")
413 if not self.ui.verbose:
398 return (None, [], False)
414 self.ui.warn("patch failed, unable to continue (try -v)\n")
399 files = []
415 return (False, [], False)
400 fuzz = False
401 for l in f:
402 l = l.rstrip('\r\n');
403 if self.ui.verbose:
404 self.ui.warn(l + "\n")
405 if l[:14] == 'patching file ':
406 pf = os.path.normpath(util.parse_patch_output(l))
407 if pf not in files:
408 files.append(pf)
409 printed_file = False
410 file_str = l
411 elif l.find('with fuzz') >= 0:
412 if not printed_file:
413 self.ui.warn(file_str + '\n')
414 printed_file = True
415 self.ui.warn(l + '\n')
416 fuzz = True
417 elif l.find('saving rejects to file') >= 0:
418 self.ui.warn(l + '\n')
419 elif l.find('FAILED') >= 0:
420 if not printed_file:
421 self.ui.warn(file_str + '\n')
422 printed_file = True
423 self.ui.warn(l + '\n')
424
416
425 return (not f.close(), files, fuzz)
417 return (True, files, fuzz)
426
418
427 def apply(self, repo, series, list=False, update_status=True,
419 def apply(self, repo, series, list=False, update_status=True,
428 strict=False, patchdir=None, merge=None, wlock=None):
420 strict=False, patchdir=None, merge=None, wlock=None):
@@ -435,43 +427,37 b' class queue:'
435 lock = repo.lock()
427 lock = repo.lock()
436 tr = repo.transaction()
428 tr = repo.transaction()
437 n = None
429 n = None
438 for patch in series:
430 for patchname in series:
439 pushable, reason = self.pushable(patch)
431 pushable, reason = self.pushable(patchname)
440 if not pushable:
432 if not pushable:
441 self.explain_pushable(patch, all_patches=True)
433 self.explain_pushable(patchname, all_patches=True)
442 continue
434 continue
443 self.ui.warn("applying %s\n" % patch)
435 self.ui.warn("applying %s\n" % patchname)
444 pf = os.path.join(patchdir, patch)
436 pf = os.path.join(patchdir, patchname)
445
437
446 try:
438 try:
447 message, comments, user, date, patchfound = self.readheaders(patch)
439 message, comments, user, date, patchfound = self.readheaders(patchname)
448 except:
440 except:
449 self.ui.warn("Unable to read %s\n" % pf)
441 self.ui.warn("Unable to read %s\n" % patchname)
450 err = 1
442 err = 1
451 break
443 break
452
444
453 if not message:
445 if not message:
454 message = "imported patch %s\n" % patch
446 message = "imported patch %s\n" % patchname
455 else:
447 else:
456 if list:
448 if list:
457 message.append("\nimported patch %s" % patch)
449 message.append("\nimported patch %s" % patchname)
458 message = '\n'.join(message)
450 message = '\n'.join(message)
459
451
460 (patcherr, files, fuzz) = self.patch(repo, pf)
452 (patcherr, files, fuzz) = self.patch(repo, pf)
461 patcherr = not patcherr
453 patcherr = not patcherr
462
454
463 if merge and len(files) > 0:
455 if merge and files:
464 # Mark as merged and update dirstate parent info
456 # Mark as merged and update dirstate parent info
465 repo.dirstate.update(repo.dirstate.filterfiles(files), 'm')
457 repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm')
466 p1, p2 = repo.dirstate.parents()
458 p1, p2 = repo.dirstate.parents()
467 repo.dirstate.setparents(p1, merge)
459 repo.dirstate.setparents(p1, merge)
468 if len(files) > 0:
460 files = patch.updatedir(self.ui, repo, files, wlock=wlock)
469 cwd = repo.getcwd()
470 cfiles = files
471 if cwd:
472 cfiles = [util.pathto(cwd, f) for f in files]
473 commands.addremove_lock(self.ui, repo, cfiles,
474 opts={}, wlock=wlock)
475 n = repo.commit(files, message, user, date, force=1, lock=lock,
461 n = repo.commit(files, message, user, date, force=1, lock=lock,
476 wlock=wlock)
462 wlock=wlock)
477
463
@@ -479,11 +465,11 b' class queue:'
479 raise util.Abort(_("repo commit failed"))
465 raise util.Abort(_("repo commit failed"))
480
466
481 if update_status:
467 if update_status:
482 self.applied.append(statusentry(revlog.hex(n), patch))
468 self.applied.append(statusentry(revlog.hex(n), patchname))
483
469
484 if patcherr:
470 if patcherr:
485 if not patchfound:
471 if not patchfound:
486 self.ui.warn("patch %s is empty\n" % patch)
472 self.ui.warn("patch %s is empty\n" % patchname)
487 err = 0
473 err = 0
488 else:
474 else:
489 self.ui.warn("patch failed, rejects left in working dir\n")
475 self.ui.warn("patch failed, rejects left in working dir\n")
@@ -497,21 +483,28 b' class queue:'
497 tr.close()
483 tr.close()
498 return (err, n)
484 return (err, n)
499
485
500 def delete(self, repo, patch, force=False):
486 def delete(self, repo, patches, keep=False):
501 patch = self.lookup(patch, strict=True)
487 realpatches = []
502 info = self.isapplied(patch)
488 for patch in patches:
503 if info:
489 patch = self.lookup(patch, strict=True)
504 raise util.Abort(_("cannot delete applied patch %s") % patch)
490 info = self.isapplied(patch)
505 if patch not in self.series:
491 if info:
506 raise util.Abort(_("patch %s not in series file") % patch)
492 raise util.Abort(_("cannot delete applied patch %s") % patch)
507 if force:
493 if patch not in self.series:
494 raise util.Abort(_("patch %s not in series file") % patch)
495 realpatches.append(patch)
496
497 if not keep:
508 r = self.qrepo()
498 r = self.qrepo()
509 if r:
499 if r:
510 r.remove([patch], True)
500 r.remove(realpatches, True)
511 else:
501 else:
512 os.unlink(self.join(patch))
502 os.unlink(self.join(patch))
513 i = self.find_series(patch)
503
514 del self.full_series[i]
504 indices = [self.find_series(p) for p in realpatches]
505 indices.sort()
506 for i in indices[-1::-1]:
507 del self.full_series[i]
515 self.parse_series()
508 self.parse_series()
516 self.series_dirty = 1
509 self.series_dirty = 1
517
510
@@ -523,19 +516,20 b' class queue:'
523 raise util.Abort(_("queue top not at same revision as working directory"))
516 raise util.Abort(_("queue top not at same revision as working directory"))
524 return top
517 return top
525 return None
518 return None
526 def check_localchanges(self, repo):
519 def check_localchanges(self, repo, force=False, refresh=True):
527 (c, a, r, d, u) = repo.changes(None, None)
520 m, a, r, d = repo.status()[:4]
528 if c or a or d or r:
521 if m or a or r or d:
529 raise util.Abort(_("local changes found, refresh first"))
522 if not force:
523 if refresh:
524 raise util.Abort(_("local changes found, refresh first"))
525 else:
526 raise util.Abort(_("local changes found"))
527 return m, a, r, d
530 def new(self, repo, patch, msg=None, force=None):
528 def new(self, repo, patch, msg=None, force=None):
531 if os.path.exists(self.join(patch)):
529 if os.path.exists(self.join(patch)):
532 raise util.Abort(_('patch "%s" already exists') % patch)
530 raise util.Abort(_('patch "%s" already exists') % patch)
533 commitfiles = []
531 m, a, r, d = self.check_localchanges(repo, force)
534 (c, a, r, d, u) = repo.changes(None, None)
532 commitfiles = m + a + r
535 if c or a or d or r:
536 if not force:
537 raise util.Abort(_("local changes found, refresh first"))
538 commitfiles = c + a + r
539 self.check_toppatch(repo)
533 self.check_toppatch(repo)
540 wlock = repo.wlock()
534 wlock = repo.wlock()
541 insert = self.full_series_end()
535 insert = self.full_series_end()
@@ -561,7 +555,7 b' class queue:'
561 r = self.qrepo()
555 r = self.qrepo()
562 if r: r.add([patch])
556 if r: r.add([patch])
563 if commitfiles:
557 if commitfiles:
564 self.refresh(repo, msg=None, short=True)
558 self.refresh(repo, short=True)
565
559
566 def strip(self, repo, rev, update=True, backup="all", wlock=None):
560 def strip(self, repo, rev, update=True, backup="all", wlock=None):
567 def limitheads(chlog, stop):
561 def limitheads(chlog, stop):
@@ -649,9 +643,7 b' class queue:'
649 revnum = chlog.rev(rev)
643 revnum = chlog.rev(rev)
650
644
651 if update:
645 if update:
652 (c, a, r, d, u) = repo.changes(None, None)
646 self.check_localchanges(repo, refresh=False)
653 if c or a or d or r:
654 raise util.Abort(_("local changes found"))
655 urev = self.qparents(repo, rev)
647 urev = self.qparents(repo, rev)
656 hg.clean(repo, urev, wlock=wlock)
648 hg.clean(repo, urev, wlock=wlock)
657 repo.dirstate.write()
649 repo.dirstate.write()
@@ -725,6 +717,8 b' class queue:'
725 # 2) a unique substring of the patch name was given
717 # 2) a unique substring of the patch name was given
726 # 3) patchname[-+]num to indicate an offset in the series file
718 # 3) patchname[-+]num to indicate an offset in the series file
727 def lookup(self, patch, strict=False):
719 def lookup(self, patch, strict=False):
720 patch = patch and str(patch)
721
728 def partial_name(s):
722 def partial_name(s):
729 if s in self.series:
723 if s in self.series:
730 return s
724 return s
@@ -886,17 +880,16 b' class queue:'
886 top = self.check_toppatch(repo)
880 top = self.check_toppatch(repo)
887 qp = self.qparents(repo, rev)
881 qp = self.qparents(repo, rev)
888 changes = repo.changelog.read(qp)
882 changes = repo.changelog.read(qp)
889 mf1 = repo.manifest.readflags(changes[0])
890 mmap = repo.manifest.read(changes[0])
883 mmap = repo.manifest.read(changes[0])
891 (c, a, r, d, u) = repo.changes(qp, top)
884 m, a, r, d, u = repo.status(qp, top)[:5]
892 if d:
885 if d:
893 raise util.Abort("deletions found between repo revs")
886 raise util.Abort("deletions found between repo revs")
894 for f in c:
887 for f in m:
895 getfile(f, mmap[f])
888 getfile(f, mmap[f])
896 for f in r:
889 for f in r:
897 getfile(f, mmap[f])
890 getfile(f, mmap[f])
898 util.set_exec(repo.wjoin(f), mf1[f])
891 util.set_exec(repo.wjoin(f), mmap.execf(f))
899 repo.dirstate.update(c + r, 'n')
892 repo.dirstate.update(m + r, 'n')
900 for f in a:
893 for f in a:
901 try: os.unlink(repo.wjoin(f))
894 try: os.unlink(repo.wjoin(f))
902 except: raise
895 except: raise
@@ -912,15 +905,15 b' class queue:'
912 else:
905 else:
913 self.ui.write("Patch queue now empty\n")
906 self.ui.write("Patch queue now empty\n")
914
907
915 def diff(self, repo, files):
908 def diff(self, repo, pats, opts):
916 top = self.check_toppatch(repo)
909 top = self.check_toppatch(repo)
917 if not top:
910 if not top:
918 self.ui.write("No patches applied\n")
911 self.ui.write("No patches applied\n")
919 return
912 return
920 qp = self.qparents(repo, top)
913 qp = self.qparents(repo, top)
921 commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
914 self.printdiff(repo, qp, files=pats, opts=opts)
922
915
923 def refresh(self, repo, msg=None, short=False):
916 def refresh(self, repo, pats=None, **opts):
924 if len(self.applied) == 0:
917 if len(self.applied) == 0:
925 self.ui.write("No patches applied\n")
918 self.ui.write("No patches applied\n")
926 return
919 return
@@ -933,7 +926,7 b' class queue:'
933 message, comments, user, date, patchfound = self.readheaders(patch)
926 message, comments, user, date, patchfound = self.readheaders(patch)
934
927
935 patchf = self.opener(patch, "w")
928 patchf = self.opener(patch, "w")
936 msg = msg.rstrip()
929 msg = opts.get('msg', '').rstrip()
937 if msg:
930 if msg:
938 if comments:
931 if comments:
939 # Remove existing message.
932 # Remove existing message.
@@ -947,6 +940,7 b' class queue:'
947 comments = "\n".join(comments) + '\n\n'
940 comments = "\n".join(comments) + '\n\n'
948 patchf.write(comments)
941 patchf.write(comments)
949
942
943 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
950 tip = repo.changelog.tip()
944 tip = repo.changelog.tip()
951 if top == tip:
945 if top == tip:
952 # if the top of our patch queue is also the tip, there is an
946 # if the top of our patch queue is also the tip, there is an
@@ -959,30 +953,30 b' class queue:'
959 # patch already
953 # patch already
960 #
954 #
961 # this should really read:
955 # this should really read:
962 #(cc, dd, aa, aa2, uu) = repo.changes(tip, patchparent)
956 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
963 # but we do it backwards to take advantage of manifest/chlog
957 # but we do it backwards to take advantage of manifest/chlog
964 # caching against the next repo.changes call
958 # caching against the next repo.status call
965 #
959 #
966 (cc, aa, dd, aa2, uu) = repo.changes(patchparent, tip)
960 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
967 if short:
961 if opts.get('short'):
968 filelist = cc + aa + dd
962 filelist = mm + aa + dd
969 else:
963 else:
970 filelist = None
964 filelist = None
971 (c, a, r, d, u) = repo.changes(None, None, filelist)
965 m, a, r, d, u = repo.status(files=filelist)[:5]
972
966
973 # we might end up with files that were added between tip and
967 # we might end up with files that were added between tip and
974 # the dirstate parent, but then changed in the local dirstate.
968 # the dirstate parent, but then changed in the local dirstate.
975 # in this case, we want them to only show up in the added section
969 # in this case, we want them to only show up in the added section
976 for x in c:
970 for x in m:
977 if x not in aa:
971 if x not in aa:
978 cc.append(x)
972 mm.append(x)
979 # we might end up with files added by the local dirstate that
973 # we might end up with files added by the local dirstate that
980 # were deleted by the patch. In this case, they should only
974 # were deleted by the patch. In this case, they should only
981 # show up in the changed section.
975 # show up in the changed section.
982 for x in a:
976 for x in a:
983 if x in dd:
977 if x in dd:
984 del dd[dd.index(x)]
978 del dd[dd.index(x)]
985 cc.append(x)
979 mm.append(x)
986 else:
980 else:
987 aa.append(x)
981 aa.append(x)
988 # make sure any files deleted in the local dirstate
982 # make sure any files deleted in the local dirstate
@@ -993,23 +987,34 b' class queue:'
993 del aa[aa.index(x)]
987 del aa[aa.index(x)]
994 forget.append(x)
988 forget.append(x)
995 continue
989 continue
996 elif x in cc:
990 elif x in mm:
997 del cc[cc.index(x)]
991 del mm[mm.index(x)]
998 dd.append(x)
992 dd.append(x)
999
993
1000 c = list(util.unique(cc))
994 m = list(util.unique(mm))
1001 r = list(util.unique(dd))
995 r = list(util.unique(dd))
1002 a = list(util.unique(aa))
996 a = list(util.unique(aa))
1003 filelist = list(util.unique(c + r + a ))
997 filelist = filter(matchfn, util.unique(m + r + a))
1004 commands.dodiff(patchf, self.ui, repo, patchparent, None,
998 self.printdiff(repo, patchparent, files=filelist,
1005 filelist, changes=(c, a, r, [], u))
999 changes=(m, a, r, [], u), fp=patchf)
1006 patchf.close()
1000 patchf.close()
1007
1001
1008 changes = repo.changelog.read(tip)
1002 changes = repo.changelog.read(tip)
1009 repo.dirstate.setparents(*cparents)
1003 repo.dirstate.setparents(*cparents)
1004 copies = [(f, repo.dirstate.copied(f)) for f in a]
1010 repo.dirstate.update(a, 'a')
1005 repo.dirstate.update(a, 'a')
1006 for dst, src in copies:
1007 repo.dirstate.copy(src, dst)
1011 repo.dirstate.update(r, 'r')
1008 repo.dirstate.update(r, 'r')
1012 repo.dirstate.update(c, 'n')
1009 # if the patch excludes a modified file, mark that file with mtime=0
1010 # so status can see it.
1011 mm = []
1012 for i in range(len(m)-1, -1, -1):
1013 if not matchfn(m[i]):
1014 mm.append(m[i])
1015 del m[i]
1016 repo.dirstate.update(m, 'n')
1017 repo.dirstate.update(mm, 'n', st_mtime=0)
1013 repo.dirstate.forget(forget)
1018 repo.dirstate.forget(forget)
1014
1019
1015 if not msg:
1020 if not msg:
@@ -1025,7 +1030,7 b' class queue:'
1025 self.applied[-1] = statusentry(revlog.hex(n), patch)
1030 self.applied[-1] = statusentry(revlog.hex(n), patch)
1026 self.applied_dirty = 1
1031 self.applied_dirty = 1
1027 else:
1032 else:
1028 commands.dodiff(patchf, self.ui, repo, patchparent, None)
1033 self.printdiff(repo, patchparent, fp=patchf)
1029 patchf.close()
1034 patchf.close()
1030 self.pop(repo, force=True, wlock=wlock)
1035 self.pop(repo, force=True, wlock=wlock)
1031 self.push(repo, force=True, wlock=wlock)
1036 self.push(repo, force=True, wlock=wlock)
@@ -1224,7 +1229,7 b' class queue:'
1224 if not self.ui.verbose:
1229 if not self.ui.verbose:
1225 p = pname
1230 p = pname
1226 else:
1231 else:
1227 p = str(self.series.index(pname)) + " " + p
1232 p = str(self.series.index(pname)) + " " + pname
1228 return p
1233 return p
1229
1234
1230 def top(self, repo):
1235 def top(self, repo):
@@ -1291,13 +1296,13 b' class queue:'
1291 if qrepo:
1296 if qrepo:
1292 qrepo.add(added)
1297 qrepo.add(added)
1293
1298
1294 def delete(ui, repo, patch, **opts):
1299 def delete(ui, repo, patch, *patches, **opts):
1295 """remove a patch from the series file
1300 """remove patches from queue
1296
1301
1297 The patch must not be applied.
1302 The patches must not be applied.
1298 With -f, deletes the patch file as well as the series entry."""
1303 With -k, the patch files are preserved in the patch directory."""
1299 q = repo.mq
1304 q = repo.mq
1300 q.delete(repo, patch, force=opts.get('force'))
1305 q.delete(repo, (patch,) + patches, keep=opts.get('keep'))
1301 q.save_dirty()
1306 q.save_dirty()
1302 return 0
1307 return 0
1303
1308
@@ -1419,17 +1424,24 b' def new(ui, repo, patch, **opts):'
1419 changes unless -f is specified, in which case the patch will
1424 changes unless -f is specified, in which case the patch will
1420 be initialised with them.
1425 be initialised with them.
1421
1426
1422 -m or -l set the patch header as well as the commit message.
1427 -e, -m or -l set the patch header as well as the commit message.
1423 If neither is specified, the patch header is empty and the
1428 If none is specified, the patch header is empty and the
1424 commit message is 'New patch: PATCH'"""
1429 commit message is 'New patch: PATCH'"""
1425 q = repo.mq
1430 q = repo.mq
1426 message = commands.logmessage(opts)
1431 message = commands.logmessage(opts)
1432 if opts['edit']:
1433 message = ui.edit(message, ui.username())
1427 q.new(repo, patch, msg=message, force=opts['force'])
1434 q.new(repo, patch, msg=message, force=opts['force'])
1428 q.save_dirty()
1435 q.save_dirty()
1429 return 0
1436 return 0
1430
1437
1431 def refresh(ui, repo, **opts):
1438 def refresh(ui, repo, *pats, **opts):
1432 """update the current patch"""
1439 """update the current patch
1440
1441 If any file patterns are provided, the refreshed patch will contain only
1442 the modifications that match those patterns; the remaining modifications
1443 will remain in the working directory.
1444 """
1433 q = repo.mq
1445 q = repo.mq
1434 message = commands.logmessage(opts)
1446 message = commands.logmessage(opts)
1435 if opts['edit']:
1447 if opts['edit']:
@@ -1438,14 +1450,13 b' def refresh(ui, repo, **opts):'
1438 patch = q.applied[-1].name
1450 patch = q.applied[-1].name
1439 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1451 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1440 message = ui.edit('\n'.join(message), user or ui.username())
1452 message = ui.edit('\n'.join(message), user or ui.username())
1441 q.refresh(repo, msg=message, short=opts['short'])
1453 q.refresh(repo, pats, msg=message, **opts)
1442 q.save_dirty()
1454 q.save_dirty()
1443 return 0
1455 return 0
1444
1456
1445 def diff(ui, repo, *files, **opts):
1457 def diff(ui, repo, *pats, **opts):
1446 """diff of the current patch"""
1458 """diff of the current patch"""
1447 # deep in the dirstate code, the walkhelper method wants a list, not a tuple
1459 repo.mq.diff(repo, pats, opts)
1448 repo.mq.diff(repo, list(files))
1449 return 0
1460 return 0
1450
1461
1451 def fold(ui, repo, *files, **opts):
1462 def fold(ui, repo, *files, **opts):
@@ -1455,7 +1466,7 b' def fold(ui, repo, *files, **opts):'
1455 applied to the current patch in the order given. If all the
1466 applied to the current patch in the order given. If all the
1456 patches apply successfully, the current patch will be refreshed
1467 patches apply successfully, the current patch will be refreshed
1457 with the new cumulative patch, and the folded patches will
1468 with the new cumulative patch, and the folded patches will
1458 be deleted. With -f/--force, the folded patch files will
1469 be deleted. With -k/--keep, the folded patch files will not
1459 be removed afterwards.
1470 be removed afterwards.
1460
1471
1461 The header for each folded patch will be concatenated with
1472 The header for each folded patch will be concatenated with
@@ -1477,20 +1488,21 b' def fold(ui, repo, *files, **opts):'
1477 patches = []
1488 patches = []
1478 messages = []
1489 messages = []
1479 for f in files:
1490 for f in files:
1480 patch = q.lookup(f)
1491 p = q.lookup(f)
1481 if patch in patches or patch == parent:
1492 if p in patches or p == parent:
1482 ui.warn(_('Skipping already folded patch %s') % patch)
1493 ui.warn(_('Skipping already folded patch %s') % p)
1483 if q.isapplied(patch):
1494 if q.isapplied(p):
1484 raise util.Abort(_('qfold cannot fold already applied patch %s') % patch)
1495 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1485 patches.append(patch)
1496 patches.append(p)
1486
1497
1487 for patch in patches:
1498 for p in patches:
1488 if not message:
1499 if not message:
1489 messages.append(q.readheaders(patch)[0])
1500 messages.append(q.readheaders(p)[0])
1490 pf = q.join(patch)
1501 pf = q.join(p)
1491 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1502 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1492 if not patchsuccess:
1503 if not patchsuccess:
1493 raise util.Abort(_('Error folding patch %s') % patch)
1504 raise util.Abort(_('Error folding patch %s') % p)
1505 patch.updatedir(ui, repo, files)
1494
1506
1495 if not message:
1507 if not message:
1496 message, comments, user = q.readheaders(parent)[0:3]
1508 message, comments, user = q.readheaders(parent)[0:3]
@@ -1503,29 +1515,26 b' def fold(ui, repo, *files, **opts):'
1503 message = ui.edit(message, user or ui.username())
1515 message = ui.edit(message, user or ui.username())
1504
1516
1505 q.refresh(repo, msg=message)
1517 q.refresh(repo, msg=message)
1506
1518 q.delete(repo, patches, keep=opts['keep'])
1507 for patch in patches:
1508 q.delete(repo, patch, force=opts['force'])
1509
1510 q.save_dirty()
1519 q.save_dirty()
1511
1520
1512 def guard(ui, repo, *args, **opts):
1521 def guard(ui, repo, *args, **opts):
1513 '''set or print guards for a patch
1522 '''set or print guards for a patch
1514
1523
1515 guards control whether a patch can be pushed. a patch with no
1524 Guards control whether a patch can be pushed. A patch with no
1516 guards is aways pushed. a patch with posative guard ("+foo") is
1525 guards is always pushed. A patch with a positive guard ("+foo") is
1517 pushed only if qselect command enables guard "foo". a patch with
1526 pushed only if the qselect command has activated it. A patch with
1518 nagative guard ("-foo") is never pushed if qselect command enables
1527 a negative guard ("-foo") is never pushed if the qselect command
1519 guard "foo".
1528 has activated it.
1520
1529
1521 with no arguments, default is to print current active guards.
1530 With no arguments, print the currently active guards.
1522 with arguments, set active guards for patch.
1531 With arguments, set guards for the named patch.
1523
1532
1524 to set nagative guard "-foo" on topmost patch ("--" is needed so
1533 To set a negative guard "-foo" on topmost patch ("--" is needed so
1525 hg will not interpret "-foo" as argument):
1534 hg will not interpret "-foo" as an option):
1526 hg qguard -- -foo
1535 hg qguard -- -foo
1527
1536
1528 to set guards on other patch:
1537 To set guards on another patch:
1529 hg qguard other.patch +2.6.17 -stable
1538 hg qguard other.patch +2.6.17 -stable
1530 '''
1539 '''
1531 def status(idx):
1540 def status(idx):
@@ -1731,38 +1740,57 b' def strip(ui, repo, rev, **opts):'
1731 def select(ui, repo, *args, **opts):
1740 def select(ui, repo, *args, **opts):
1732 '''set or print guarded patches to push
1741 '''set or print guarded patches to push
1733
1742
1734 use qguard command to set or print guards on patch. then use
1743 Use the qguard command to set or print guards on patch, then use
1735 qselect to tell mq which guards to use. example:
1744 qselect to tell mq which guards to use. A patch will be pushed if it
1745 has no guards or any positive guards match the currently selected guard,
1746 but will not be pushed if any negative guards match the current guard.
1747 For example:
1736
1748
1737 qguard foo.patch -stable (nagative guard)
1749 qguard foo.patch -stable (negative guard)
1738 qguard bar.patch +stable (posative guard)
1750 qguard bar.patch +stable (positive guard)
1739 qselect stable
1751 qselect stable
1740
1752
1741 this sets "stable" guard. mq will skip foo.patch (because it has
1753 This activates the "stable" guard. mq will skip foo.patch (because
1742 nagative match) but push bar.patch (because it has posative
1754 it has a negative match) but push bar.patch (because it
1743 match). patch is pushed only if all posative guards match and no
1755 has a positive match).
1744 nagative guards match.
1745
1756
1746 with no arguments, default is to print current active guards.
1757 With no arguments, prints the currently active guards.
1747 with arguments, set active guards as given.
1758 With one argument, sets the active guard.
1748
1759
1749 use -n/--none to deactivate guards (no other arguments needed).
1760 Use -n/--none to deactivate guards (no other arguments needed).
1750 when no guards active, patches with posative guards are skipped,
1761 When no guards are active, patches with positive guards are skipped
1751 patches with nagative guards are pushed.
1762 and patches with negative guards are pushed.
1752
1763
1753 use -s/--series to print list of all guards in series file (no
1764 qselect can change the guards on applied patches. It does not pop
1754 other arguments needed). use -v for more information.'''
1765 guarded patches by default. Use --pop to pop back to the last applied
1766 patch that is not guarded. Use --reapply (which implies --pop) to push
1767 back to the current patch afterwards, but skip guarded patches.
1768
1769 Use -s/--series to print a list of all guards in the series file (no
1770 other arguments needed). Use -v for more information.'''
1755
1771
1756 q = repo.mq
1772 q = repo.mq
1757 guards = q.active()
1773 guards = q.active()
1758 if args or opts['none']:
1774 if args or opts['none']:
1775 old_unapplied = q.unapplied(repo)
1776 old_guarded = [i for i in xrange(len(q.applied)) if
1777 not q.pushable(i)[0]]
1759 q.set_active(args)
1778 q.set_active(args)
1760 q.save_dirty()
1779 q.save_dirty()
1761 if not args:
1780 if not args:
1762 ui.status(_('guards deactivated\n'))
1781 ui.status(_('guards deactivated\n'))
1763 if q.series:
1782 if not opts['pop'] and not opts['reapply']:
1764 ui.status(_('%d of %d unapplied patches active\n') %
1783 unapplied = q.unapplied(repo)
1765 (len(q.unapplied(repo)), len(q.series)))
1784 guarded = [i for i in xrange(len(q.applied))
1785 if not q.pushable(i)[0]]
1786 if len(unapplied) != len(old_unapplied):
1787 ui.status(_('number of unguarded, unapplied patches has '
1788 'changed from %d to %d\n') %
1789 (len(old_unapplied), len(unapplied)))
1790 if len(guarded) != len(old_guarded):
1791 ui.status(_('number of guarded, applied patches has changed '
1792 'from %d to %d\n') %
1793 (len(old_guarded), len(guarded)))
1766 elif opts['series']:
1794 elif opts['series']:
1767 guards = {}
1795 guards = {}
1768 noguards = 0
1796 noguards = 0
@@ -1790,9 +1818,51 b' def select(ui, repo, *args, **opts):'
1790 ui.write(g, '\n')
1818 ui.write(g, '\n')
1791 else:
1819 else:
1792 ui.write(_('no active guards\n'))
1820 ui.write(_('no active guards\n'))
1821 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
1822 popped = False
1823 if opts['pop'] or opts['reapply']:
1824 for i in xrange(len(q.applied)):
1825 pushable, reason = q.pushable(i)
1826 if not pushable:
1827 ui.status(_('popping guarded patches\n'))
1828 popped = True
1829 if i == 0:
1830 q.pop(repo, all=True)
1831 else:
1832 q.pop(repo, i-1)
1833 break
1834 if popped:
1835 try:
1836 if reapply:
1837 ui.status(_('reapplying unguarded patches\n'))
1838 q.push(repo, reapply)
1839 finally:
1840 q.save_dirty()
1793
1841
1794 def reposetup(ui, repo):
1842 def reposetup(ui, repo):
1795 class mqrepo(repo.__class__):
1843 class mqrepo(repo.__class__):
1844 def abort_if_wdir_patched(self, errmsg, force=False):
1845 if self.mq.applied and not force:
1846 parent = revlog.hex(self.dirstate.parents()[0])
1847 if parent in [s.rev for s in self.mq.applied]:
1848 raise util.Abort(errmsg)
1849
1850 def commit(self, *args, **opts):
1851 if len(args) >= 6:
1852 force = args[5]
1853 else:
1854 force = opts.get('force')
1855 self.abort_if_wdir_patched(
1856 _('cannot commit over an applied mq patch'),
1857 force)
1858
1859 return super(mqrepo, self).commit(*args, **opts)
1860
1861 def push(self, remote, force=False, revs=None):
1862 if self.mq.applied and not force:
1863 raise util.Abort(_('source has mq patches applied'))
1864 return super(mqrepo, self).push(remote, force, revs)
1865
1796 def tags(self):
1866 def tags(self):
1797 if self.tagscache:
1867 if self.tagscache:
1798 return self.tagscache
1868 return self.tagscache
@@ -1814,8 +1884,9 b' def reposetup(ui, repo):'
1814
1884
1815 return tagscache
1885 return tagscache
1816
1886
1817 repo.__class__ = mqrepo
1887 if repo.local():
1818 repo.mq = queue(ui, repo.join(""))
1888 repo.__class__ = mqrepo
1889 repo.mq = queue(ui, repo.join(""))
1819
1890
1820 cmdtable = {
1891 cmdtable = {
1821 "qapplied": (applied, [], 'hg qapplied [PATCH]'),
1892 "qapplied": (applied, [], 'hg qapplied [PATCH]'),
@@ -1833,15 +1904,18 b' cmdtable = {'
1833 (commit,
1904 (commit,
1834 commands.table["^commit|ci"][1],
1905 commands.table["^commit|ci"][1],
1835 'hg qcommit [OPTION]... [FILE]...'),
1906 'hg qcommit [OPTION]... [FILE]...'),
1836 "^qdiff": (diff, [], 'hg qdiff [FILE]...'),
1907 "^qdiff": (diff,
1837 "qdelete":
1908 [('I', 'include', [], _('include names matching the given patterns')),
1909 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
1910 'hg qdiff [-I] [-X] [FILE]...'),
1911 "qdelete|qremove|qrm":
1838 (delete,
1912 (delete,
1839 [('f', 'force', None, _('delete patch file'))],
1913 [('k', 'keep', None, _('keep patch file'))],
1840 'hg qdelete [-f] PATCH'),
1914 'hg qdelete [-k] PATCH'),
1841 'qfold':
1915 'qfold':
1842 (fold,
1916 (fold,
1843 [('e', 'edit', None, _('edit patch header')),
1917 [('e', 'edit', None, _('edit patch header')),
1844 ('f', 'force', None, _('delete folded patch files')),
1918 ('k', 'keep', None, _('keep folded patch files')),
1845 ('m', 'message', '', _('set patch header to <text>')),
1919 ('m', 'message', '', _('set patch header to <text>')),
1846 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1920 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1847 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
1921 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
@@ -1862,10 +1936,11 b' cmdtable = {'
1862 'hg qinit [-c]'),
1936 'hg qinit [-c]'),
1863 "qnew":
1937 "qnew":
1864 (new,
1938 (new,
1865 [('m', 'message', '', _('use <text> as commit message')),
1939 [('e', 'edit', None, _('edit commit message')),
1940 ('m', 'message', '', _('use <text> as commit message')),
1866 ('l', 'logfile', '', _('read the commit message from <file>')),
1941 ('l', 'logfile', '', _('read the commit message from <file>')),
1867 ('f', 'force', None, _('import uncommitted changes into patch'))],
1942 ('f', 'force', None, _('import uncommitted changes into patch'))],
1868 'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'),
1943 'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'),
1869 "qnext": (next, [], 'hg qnext'),
1944 "qnext": (next, [], 'hg qnext'),
1870 "qprev": (prev, [], 'hg qprev'),
1945 "qprev": (prev, [], 'hg qprev'),
1871 "^qpop":
1946 "^qpop":
@@ -1887,8 +1962,10 b' cmdtable = {'
1887 [('e', 'edit', None, _('edit commit message')),
1962 [('e', 'edit', None, _('edit commit message')),
1888 ('m', 'message', '', _('change commit message with <text>')),
1963 ('m', 'message', '', _('change commit message with <text>')),
1889 ('l', 'logfile', '', _('change commit message with <file> content')),
1964 ('l', 'logfile', '', _('change commit message with <file> content')),
1890 ('s', 'short', None, 'short refresh')],
1965 ('s', 'short', None, 'short refresh'),
1891 'hg qrefresh [-e] [-m TEXT] [-l FILE] [-s]'),
1966 ('I', 'include', [], _('include names matching the given patterns')),
1967 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
1968 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'),
1892 'qrename|qmv':
1969 'qrename|qmv':
1893 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
1970 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
1894 "qrestore":
1971 "qrestore":
@@ -1907,8 +1984,11 b' cmdtable = {'
1907 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
1984 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
1908 "qselect": (select,
1985 "qselect": (select,
1909 [('n', 'none', None, _('disable all guards')),
1986 [('n', 'none', None, _('disable all guards')),
1910 ('s', 'series', None, _('list all guards in series file'))],
1987 ('s', 'series', None, _('list all guards in series file')),
1911 'hg qselect [GUARDS]'),
1988 ('', 'pop', None,
1989 _('pop to before first guarded applied patch')),
1990 ('', 'reapply', None, _('pop, then reapply patches'))],
1991 'hg qselect [OPTION...] [GUARD...]'),
1912 "qseries":
1992 "qseries":
1913 (series,
1993 (series,
1914 [('m', 'missing', None, 'print patches not in series'),
1994 [('m', 'missing', None, 'print patches not in series'),
@@ -1923,4 +2003,3 b' cmdtable = {'
1923 "qtop": (top, [], 'hg qtop'),
2003 "qtop": (top, [], 'hg qtop'),
1924 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
2004 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1925 }
2005 }
1926
@@ -67,8 +67,8 b''
67 from mercurial.demandload import *
67 from mercurial.demandload import *
68 from mercurial.i18n import gettext as _
68 from mercurial.i18n import gettext as _
69 from mercurial.node import *
69 from mercurial.node import *
70 demandload(globals(), 'email.Parser mercurial:commands,templater,util')
70 demandload(globals(), 'mercurial:commands,patch,templater,util,mail')
71 demandload(globals(), 'fnmatch socket time')
71 demandload(globals(), 'email.Parser fnmatch socket time')
72
72
73 # template for single changeset can include email headers.
73 # template for single changeset can include email headers.
74 single_template = '''
74 single_template = '''
@@ -229,8 +229,8 b' class notifier(object):'
229 else:
229 else:
230 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
230 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
231 (len(self.subs), count))
231 (len(self.subs), count))
232 mail = self.ui.sendmail()
232 mail.sendmail(self.ui, templater.email(msg['From']),
233 mail.sendmail(templater.email(msg['From']), self.subs, msgtext)
233 self.subs, msgtext)
234
234
235 def diff(self, node, ref):
235 def diff(self, node, ref):
236 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
236 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
@@ -238,7 +238,7 b' class notifier(object):'
238 return
238 return
239 fp = templater.stringio()
239 fp = templater.stringio()
240 prev = self.repo.changelog.parents(node)[0]
240 prev = self.repo.changelog.parents(node)[0]
241 commands.dodiff(fp, self.ui, self.repo, prev, ref)
241 patch.diff(self.repo, fp, prev, ref)
242 difflines = fp.getvalue().splitlines(1)
242 difflines = fp.getvalue().splitlines(1)
243 if maxdiff > 0 and len(difflines) > maxdiff:
243 if maxdiff > 0 and len(difflines) > maxdiff:
244 self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') %
244 self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') %
@@ -23,26 +23,49 b''
23 # the changeset summary, so you can be sure you are sending the right
23 # the changeset summary, so you can be sure you are sending the right
24 # changes.
24 # changes.
25 #
25 #
26 # It is best to run this script with the "-n" (test only) flag before
26 # To enable this extension:
27 # firing it up "for real", in which case it will use your pager to
28 # display each of the messages that it would send.
29 #
27 #
30 # The "-m" (mbox) option will create an mbox file instead of sending
28 # [extensions]
31 # the messages directly. This can be reviewed e.g. with "mutt -R -f mbox",
29 # hgext.patchbomb =
32 # and finally sent with "formail -s sendmail -bm -t < mbox".
33 #
30 #
34 # To configure other defaults, add a section like this to your hgrc
31 # To configure other defaults, add a section like this to your hgrc
35 # file:
32 # file:
36 #
33 #
37 # [email]
34 # [email]
38 # from = My Name <my@email>
35 # from = My Name <my@email>
39 # to = recipient1, recipient2, ...
36 # to = recipient1, recipient2, ...
40 # cc = cc1, cc2, ...
37 # cc = cc1, cc2, ...
41 # bcc = bcc1, bcc2, ...
38 # bcc = bcc1, bcc2, ...
39 #
40 # Then you can use the "hg email" command to mail a series of changesets
41 # as a patchbomb.
42 #
43 # To avoid sending patches prematurely, it is a good idea to first run
44 # the "email" command with the "-n" option (test only). You will be
45 # prompted for an email recipient address, a subject an an introductory
46 # message describing the patches of your patchbomb. Then when all is
47 # done, your pager will be fired up once for each patchbomb message, so
48 # you can verify everything is alright.
49 #
50 # The "-m" (mbox) option is also very useful. Instead of previewing
51 # each patchbomb message in a pager or sending the messages directly,
52 # it will create a UNIX mailbox file with the patch emails. This
53 # mailbox file can be previewed with any mail user agent which supports
54 # UNIX mbox files, i.e. with mutt:
55 #
56 # % mutt -R -f mbox
57 #
58 # When you are previewing the patchbomb messages, you can use `formail'
59 # (a utility that is commonly installed as part of the procmail package),
60 # to send each message out:
61 #
62 # % formail -s sendmail -bm -t < mbox
63 #
64 # That should be all. Now your patchbomb is on its way out.
42
65
43 from mercurial.demandload import *
66 from mercurial.demandload import *
44 demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
67 demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
45 mercurial:commands,hg,ui
68 mercurial:commands,hg,mail,ui
46 os errno popen2 socket sys tempfile time''')
69 os errno popen2 socket sys tempfile time''')
47 from mercurial.i18n import gettext as _
70 from mercurial.i18n import gettext as _
48 from mercurial.node import *
71 from mercurial.node import *
@@ -241,7 +264,7 b' def patchbomb(ui, repo, *revs, **opts):'
241 ui.write('\n')
264 ui.write('\n')
242
265
243 if not opts['test'] and not opts['mbox']:
266 if not opts['test'] and not opts['mbox']:
244 mail = ui.sendmail()
267 mailer = mail.connect(ui)
245 parent = None
268 parent = None
246
269
247 # Calculate UTC offset
270 # Calculate UTC offset
@@ -290,7 +313,7 b' def patchbomb(ui, repo, *revs, **opts):'
290 ui.status('Sending ', m['Subject'], ' ...\n')
313 ui.status('Sending ', m['Subject'], ' ...\n')
291 # Exim does not remove the Bcc field
314 # Exim does not remove the Bcc field
292 del m['Bcc']
315 del m['Bcc']
293 mail.sendmail(sender, to + bcc + cc, m.as_string(0))
316 mailer.sendmail(sender, to + bcc + cc, m.as_string(0))
294
317
295 cmdtable = {
318 cmdtable = {
296 'email':
319 'email':
@@ -163,12 +163,12 b' def archive(repo, dest, node, kind, deco'
163 change = repo.changelog.read(node)
163 change = repo.changelog.read(node)
164 mn = change[0]
164 mn = change[0]
165 archiver = archivers[kind](dest, prefix, mtime or change[2][0])
165 archiver = archivers[kind](dest, prefix, mtime or change[2][0])
166 mf = repo.manifest.read(mn).items()
166 m = repo.manifest.read(mn)
167 mff = repo.manifest.readflags(mn)
167 items = m.items()
168 mf.sort()
168 items.sort()
169 write('.hg_archival.txt', 0644,
169 write('.hg_archival.txt', 0644,
170 'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node)))
170 'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node)))
171 for filename, filenode in mf:
171 for filename, filenode in items:
172 write(filename, mff[filename] and 0755 or 0644,
172 write(filename, m.execf(filename) and 0755 or 0644,
173 repo.file(filename).read(filenode))
173 repo.file(filename).read(filenode))
174 archiver.done()
174 archiver.done()
@@ -1,7 +1,7 b''
1 /*
1 /*
2 bdiff.c - efficient binary diff extension for Mercurial
2 bdiff.c - efficient binary diff extension for Mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # changelog.py - changelog class for mercurial
1 # changelog.py - changelog class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
This diff has been collapsed as it changes many lines, (697 lines changed) Show them Hide them
@@ -1,6 +1,6 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -10,10 +10,10 b' from node import *'
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
13 demandload(globals(), "fnmatch mdiff random signal tempfile time")
13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
15 demandload(globals(), "archival cStringIO changegroup email.Parser")
15 demandload(globals(), "archival cStringIO changegroup")
16 demandload(globals(), "hgweb.server sshserver")
16 demandload(globals(), "cmdutil hgweb.server sshserver")
17
17
18 class UnknownCommand(Exception):
18 class UnknownCommand(Exception):
19 """Exception raised if command is not in the command table."""
19 """Exception raised if command is not in the command table."""
@@ -21,19 +21,10 b' class AmbiguousCommand(Exception):'
21 """Exception raised if command shortcut matches more than one command."""
21 """Exception raised if command shortcut matches more than one command."""
22
22
23 def bail_if_changed(repo):
23 def bail_if_changed(repo):
24 modified, added, removed, deleted, unknown = repo.changes()
24 modified, added, removed, deleted = repo.status()[:4]
25 if modified or added or removed or deleted:
25 if modified or added or removed or deleted:
26 raise util.Abort(_("outstanding uncommitted changes"))
26 raise util.Abort(_("outstanding uncommitted changes"))
27
27
28 def filterfiles(filters, files):
29 l = [x for x in files if x in filters]
30
31 for t in filters:
32 if t and t[-1] != "/":
33 t += "/"
34 l += [x for x in files if x.startswith(t)]
35 return l
36
37 def relpath(repo, args):
28 def relpath(repo, args):
38 cwd = repo.getcwd()
29 cwd = repo.getcwd()
39 if cwd:
30 if cwd:
@@ -59,29 +50,6 b' def logmessage(opts):'
59 (logfile, inst.strerror))
50 (logfile, inst.strerror))
60 return message
51 return message
61
52
62 def matchpats(repo, pats=[], opts={}, head=''):
63 cwd = repo.getcwd()
64 if not pats and cwd:
65 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
66 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
67 cwd = ''
68 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
69 opts.get('exclude'), head)
70
71 def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
72 files, matchfn, anypats = matchpats(repo, pats, opts, head)
73 exact = dict(zip(files, files))
74 def walk():
75 for src, fn in repo.walk(node=node, files=files, match=matchfn,
76 badmatch=badmatch):
77 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
78 return files, matchfn, walk()
79
80 def walk(repo, pats, opts, node=None, head='', badmatch=None):
81 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
82 for r in results:
83 yield r
84
85 def walkchangerevs(ui, repo, pats, opts):
53 def walkchangerevs(ui, repo, pats, opts):
86 '''Iterate over files and the revs they changed in.
54 '''Iterate over files and the revs they changed in.
87
55
@@ -124,7 +92,7 b' def walkchangerevs(ui, repo, pats, opts)'
124 windowsize *= 2
92 windowsize *= 2
125
93
126
94
127 files, matchfn, anypats = matchpats(repo, pats, opts)
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
128 follow = opts.get('follow') or opts.get('follow_first')
96 follow = opts.get('follow') or opts.get('follow_first')
129
97
130 if repo.changelog.count() == 0:
98 if repo.changelog.count() == 0:
@@ -215,49 +183,59 b' def walkchangerevs(ui, repo, pats, opts)'
215 fncache[rev] = matches
183 fncache[rev] = matches
216 wanted[rev] = 1
184 wanted[rev] = 1
217
185
218 def iterate():
186 class followfilter:
219 class followfilter:
187 def __init__(self, onlyfirst=False):
220 def __init__(self, onlyfirst=False):
188 self.startrev = -1
221 self.startrev = -1
189 self.roots = []
222 self.roots = []
190 self.onlyfirst = onlyfirst
223 self.onlyfirst = onlyfirst
191
224
192 def match(self, rev):
225 def match(self, rev):
193 def realparents(rev):
226 def realparents(rev):
194 if self.onlyfirst:
227 if self.onlyfirst:
195 return repo.changelog.parentrevs(rev)[0:1]
228 return repo.changelog.parentrevs(rev)[0:1]
196 else:
229 else:
197 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
230 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
198
231
199 if self.startrev == -1:
232 if self.startrev == -1:
200 self.startrev = rev
233 self.startrev = rev
201 return True
202
203 if rev > self.startrev:
204 # forward: all descendants
205 if not self.roots:
206 self.roots.append(self.startrev)
207 for parent in realparents(rev):
208 if parent in self.roots:
209 self.roots.append(rev)
210 return True
211 else:
212 # backwards: all parents
213 if not self.roots:
214 self.roots.extend(realparents(self.startrev))
215 if rev in self.roots:
216 self.roots.remove(rev)
217 self.roots.extend(realparents(rev))
234 return True
218 return True
235
219
236 if rev > self.startrev:
220 return False
237 # forward: all descendants
221
238 if not self.roots:
222 # it might be worthwhile to do this in the iterator if the rev range
239 self.roots.append(self.startrev)
223 # is descending and the prune args are all within that range
240 for parent in realparents(rev):
224 for rev in opts.get('prune', ()):
241 if parent in self.roots:
225 rev = repo.changelog.rev(repo.lookup(rev))
242 self.roots.append(rev)
226 ff = followfilter()
243 return True
227 stop = min(revs[0], revs[-1])
244 else:
228 for x in range(rev, stop-1, -1):
245 # backwards: all parents
229 if ff.match(x) and wanted.has_key(x):
246 if not self.roots:
230 del wanted[x]
247 self.roots.extend(realparents(self.startrev))
231
248 if rev in self.roots:
232 def iterate():
249 self.roots.remove(rev)
250 self.roots.extend(realparents(rev))
251 return True
252
253 return False
254
255 if follow and not files:
233 if follow and not files:
256 ff = followfilter(onlyfirst=opts.get('follow_first'))
234 ff = followfilter(onlyfirst=opts.get('follow_first'))
257 def want(rev):
235 def want(rev):
258 if rev not in wanted:
236 if ff.match(rev) and rev in wanted:
259 return False
237 return True
260 return ff.match(rev)
238 return False
261 else:
239 else:
262 def want(rev):
240 def want(rev):
263 return rev in wanted
241 return rev in wanted
@@ -344,63 +322,6 b' def revrange(ui, repo, revs):'
344 seen[rev] = 1
322 seen[rev] = 1
345 yield str(rev)
323 yield str(rev)
346
324
347 def make_filename(repo, pat, node,
348 total=None, seqno=None, revwidth=None, pathname=None):
349 node_expander = {
350 'H': lambda: hex(node),
351 'R': lambda: str(repo.changelog.rev(node)),
352 'h': lambda: short(node),
353 }
354 expander = {
355 '%': lambda: '%',
356 'b': lambda: os.path.basename(repo.root),
357 }
358
359 try:
360 if node:
361 expander.update(node_expander)
362 if node and revwidth is not None:
363 expander['r'] = (lambda:
364 str(repo.changelog.rev(node)).zfill(revwidth))
365 if total is not None:
366 expander['N'] = lambda: str(total)
367 if seqno is not None:
368 expander['n'] = lambda: str(seqno)
369 if total is not None and seqno is not None:
370 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
371 if pathname is not None:
372 expander['s'] = lambda: os.path.basename(pathname)
373 expander['d'] = lambda: os.path.dirname(pathname) or '.'
374 expander['p'] = lambda: pathname
375
376 newname = []
377 patlen = len(pat)
378 i = 0
379 while i < patlen:
380 c = pat[i]
381 if c == '%':
382 i += 1
383 c = pat[i]
384 c = expander[c]()
385 newname.append(c)
386 i += 1
387 return ''.join(newname)
388 except KeyError, inst:
389 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
390 inst.args[0])
391
392 def make_file(repo, pat, node=None,
393 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
394 if not pat or pat == '-':
395 return 'w' in mode and sys.stdout or sys.stdin
396 if hasattr(pat, 'write') and 'w' in mode:
397 return pat
398 if hasattr(pat, 'read') and 'r' in mode:
399 return pat
400 return open(make_filename(repo, pat, node, total, seqno, revwidth,
401 pathname),
402 mode)
403
404 def write_bundle(cg, filename=None, compress=True):
325 def write_bundle(cg, filename=None, compress=True):
405 """Write a bundle file and return its filename.
326 """Write a bundle file and return its filename.
406
327
@@ -453,74 +374,6 b' def write_bundle(cg, filename=None, comp'
453 if cleanup is not None:
374 if cleanup is not None:
454 os.unlink(cleanup)
375 os.unlink(cleanup)
455
376
456 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
457 changes=None, text=False, opts={}):
458 if not node1:
459 node1 = repo.dirstate.parents()[0]
460 # reading the data for node1 early allows it to play nicely
461 # with repo.changes and the revlog cache.
462 change = repo.changelog.read(node1)
463 mmap = repo.manifest.read(change[0])
464 date1 = util.datestr(change[2])
465
466 if not changes:
467 changes = repo.changes(node1, node2, files, match=match)
468 modified, added, removed, deleted, unknown = changes
469 if files:
470 modified, added, removed = map(lambda x: filterfiles(files, x),
471 (modified, added, removed))
472
473 if not modified and not added and not removed:
474 return
475
476 if node2:
477 change = repo.changelog.read(node2)
478 mmap2 = repo.manifest.read(change[0])
479 _date2 = util.datestr(change[2])
480 def date2(f):
481 return _date2
482 def read(f):
483 return repo.file(f).read(mmap2[f])
484 else:
485 tz = util.makedate()[1]
486 _date2 = util.datestr()
487 def date2(f):
488 try:
489 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
490 except OSError, err:
491 if err.errno != errno.ENOENT: raise
492 return _date2
493 def read(f):
494 return repo.wread(f)
495
496 if ui.quiet:
497 r = None
498 else:
499 hexfunc = ui.verbose and hex or short
500 r = [hexfunc(node) for node in [node1, node2] if node]
501
502 diffopts = ui.diffopts()
503 showfunc = opts.get('show_function') or diffopts['showfunc']
504 ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
505 ignorewsamount = opts.get('ignore_space_change') or \
506 diffopts['ignorewsamount']
507 ignoreblanklines = opts.get('ignore_blank_lines') or \
508 diffopts['ignoreblanklines']
509
510 all = modified + added + removed
511 all.sort()
512 for f in all:
513 to = None
514 tn = None
515 if f in mmap:
516 to = repo.file(f).read(mmap[f])
517 if f not in removed:
518 tn = read(f)
519 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
520 showfunc=showfunc, ignorews=ignorews,
521 ignorewsamount=ignorewsamount,
522 ignoreblanklines=ignoreblanklines))
523
524 def trimuser(ui, name, rev, revcache):
377 def trimuser(ui, name, rev, revcache):
525 """trim the name of the user who committed a change"""
378 """trim the name of the user who committed a change"""
526 user = revcache.get(rev)
379 user = revcache.get(rev)
@@ -550,17 +403,15 b' class changeset_printer(object):'
550 changes = log.read(changenode)
403 changes = log.read(changenode)
551 date = util.datestr(changes[2])
404 date = util.datestr(changes[2])
552
405
553 parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
406 hexfunc = self.ui.debugflag and hex or short
554 for p in log.parents(changenode)
407
408 parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode)
555 if self.ui.debugflag or p != nullid]
409 if self.ui.debugflag or p != nullid]
556 if (not self.ui.debugflag and len(parents) == 1 and
410 if (not self.ui.debugflag and len(parents) == 1 and
557 parents[0][0] == rev-1):
411 parents[0][0] == rev-1):
558 parents = []
412 parents = []
559
413
560 if self.ui.verbose:
414 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
561 self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
562 else:
563 self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
564
415
565 for tag in self.repo.nodetags(changenode):
416 for tag in self.repo.nodetags(changenode):
566 self.ui.status(_("tag: %s\n") % tag)
417 self.ui.status(_("tag: %s\n") % tag)
@@ -577,7 +428,7 b' class changeset_printer(object):'
577 self.ui.status(_("date: %s\n") % date)
428 self.ui.status(_("date: %s\n") % date)
578
429
579 if self.ui.debugflag:
430 if self.ui.debugflag:
580 files = self.repo.changes(log.parents(changenode)[0], changenode)
431 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
581 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
432 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
582 files):
433 files):
583 if value:
434 if value:
@@ -633,7 +484,7 b' def show_version(ui):'
633 ui.write(_("Mercurial Distributed SCM (version %s)\n")
484 ui.write(_("Mercurial Distributed SCM (version %s)\n")
634 % version.get_version())
485 % version.get_version())
635 ui.status(_(
486 ui.status(_(
636 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
487 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
637 "This is free software; see the source for copying conditions. "
488 "This is free software; see the source for copying conditions. "
638 "There is NO\nwarranty; "
489 "There is NO\nwarranty; "
639 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
490 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
@@ -654,7 +505,7 b' def help_(ui, name=None, with_version=Fa'
654 if with_version:
505 if with_version:
655 show_version(ui)
506 show_version(ui)
656 ui.write('\n')
507 ui.write('\n')
657 aliases, i = findcmd(name)
508 aliases, i = findcmd(ui, name)
658 # synopsis
509 # synopsis
659 ui.write("%s\n\n" % i[2])
510 ui.write("%s\n\n" % i[2])
660
511
@@ -787,7 +638,7 b' def add(ui, repo, *pats, **opts):'
787 """
638 """
788
639
789 names = []
640 names = []
790 for src, abs, rel, exact in walk(repo, pats, opts):
641 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
791 if exact:
642 if exact:
792 if ui.verbose:
643 if ui.verbose:
793 ui.status(_('adding %s\n') % rel)
644 ui.status(_('adding %s\n') % rel)
@@ -801,33 +652,21 b' def add(ui, repo, *pats, **opts):'
801 def addremove(ui, repo, *pats, **opts):
652 def addremove(ui, repo, *pats, **opts):
802 """add all new files, delete all missing files (DEPRECATED)
653 """add all new files, delete all missing files (DEPRECATED)
803
654
804 (DEPRECATED)
805 Add all new files and remove all missing files from the repository.
655 Add all new files and remove all missing files from the repository.
806
656
807 New files are ignored if they match any of the patterns in .hgignore. As
657 New files are ignored if they match any of the patterns in .hgignore. As
808 with add, these changes take effect at the next commit.
658 with add, these changes take effect at the next commit.
809
659
810 This command is now deprecated and will be removed in a future
660 Use the -s option to detect renamed files. With a parameter > 0,
811 release. Please use add and remove --after instead.
661 this compares every removed file with every added file and records
662 those similar enough as renames. This option takes a percentage
663 between 0 (disabled) and 100 (files must be identical) as its
664 parameter. Detecting renamed files this way can be expensive.
812 """
665 """
813 ui.warn(_('(the addremove command is deprecated; use add and remove '
666 sim = float(opts.get('similarity') or 0)
814 '--after instead)\n'))
667 if sim < 0 or sim > 100:
815 return addremove_lock(ui, repo, pats, opts)
668 raise util.Abort(_('similarity must be between 0 and 100'))
816
669 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
817 def addremove_lock(ui, repo, pats, opts, wlock=None):
818 add, remove = [], []
819 for src, abs, rel, exact in walk(repo, pats, opts):
820 if src == 'f' and repo.dirstate.state(abs) == '?':
821 add.append(abs)
822 if ui.verbose or not exact:
823 ui.status(_('adding %s\n') % ((pats and rel) or abs))
824 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
825 remove.append(abs)
826 if ui.verbose or not exact:
827 ui.status(_('removing %s\n') % ((pats and rel) or abs))
828 if not opts.get('dry_run'):
829 repo.add(add, wlock=wlock)
830 repo.remove(remove, wlock=wlock)
831
670
832 def annotate(ui, repo, *pats, **opts):
671 def annotate(ui, repo, *pats, **opts):
833 """show changeset information per file line
672 """show changeset information per file line
@@ -870,7 +709,8 b' def annotate(ui, repo, *pats, **opts):'
870
709
871 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
710 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
872
711
873 for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()):
712 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
713 node=ctx.node()):
874 fctx = ctx.filectx(abs)
714 fctx = ctx.filectx(abs)
875 if not opts['text'] and util.binary(fctx.data()):
715 if not opts['text'] and util.binary(fctx.data()):
876 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
716 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
@@ -922,10 +762,10 b' def archive(ui, repo, dest, **opts):'
922 raise util.Abort(_('uncommitted merge - please provide a '
762 raise util.Abort(_('uncommitted merge - please provide a '
923 'specific revision'))
763 'specific revision'))
924
764
925 dest = make_filename(repo, dest, node)
765 dest = cmdutil.make_filename(repo, dest, node)
926 if os.path.realpath(dest) == repo.root:
766 if os.path.realpath(dest) == repo.root:
927 raise util.Abort(_('repository root cannot be destination'))
767 raise util.Abort(_('repository root cannot be destination'))
928 dummy, matchfn, dummy = matchpats(repo, [], opts)
768 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
929 kind = opts.get('type') or 'files'
769 kind = opts.get('type') or 'files'
930 prefix = opts['prefix']
770 prefix = opts['prefix']
931 if dest == '-':
771 if dest == '-':
@@ -933,7 +773,7 b' def archive(ui, repo, dest, **opts):'
933 raise util.Abort(_('cannot archive plain files to stdout'))
773 raise util.Abort(_('cannot archive plain files to stdout'))
934 dest = sys.stdout
774 dest = sys.stdout
935 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
775 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
936 prefix = make_filename(repo, prefix, node)
776 prefix = cmdutil.make_filename(repo, prefix, node)
937 archival.archive(repo, dest, node, kind, not opts['no_decode'],
777 archival.archive(repo, dest, node, kind, not opts['no_decode'],
938 matchfn, prefix)
778 matchfn, prefix)
939
779
@@ -978,6 +818,7 b' def backout(ui, repo, rev, **opts):'
978 parent = p1
818 parent = p1
979 hg.clean(repo, node, show_stats=False)
819 hg.clean(repo, node, show_stats=False)
980 revert_opts = opts.copy()
820 revert_opts = opts.copy()
821 revert_opts['all'] = True
981 revert_opts['rev'] = hex(parent)
822 revert_opts['rev'] = hex(parent)
982 revert(ui, repo, **revert_opts)
823 revert(ui, repo, **revert_opts)
983 commit_opts = opts.copy()
824 commit_opts = opts.copy()
@@ -1037,8 +878,9 b' def cat(ui, repo, file1, *pats, **opts):'
1037 %p root-relative path name of file being printed
878 %p root-relative path name of file being printed
1038 """
879 """
1039 ctx = repo.changectx(opts['rev'] or "-1")
880 ctx = repo.changectx(opts['rev'] or "-1")
1040 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()):
881 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
1041 fp = make_file(repo, opts['output'], ctx.node(), pathname=abs)
882 ctx.node()):
883 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
1042 fp.write(ctx.filectx(abs).data())
884 fp.write(ctx.filectx(abs).data())
1043
885
1044 def clone(ui, source, dest=None, **opts):
886 def clone(ui, source, dest=None, **opts):
@@ -1100,11 +942,10 b' def commit(ui, repo, *pats, **opts):'
1100 message = logmessage(opts)
942 message = logmessage(opts)
1101
943
1102 if opts['addremove']:
944 if opts['addremove']:
1103 addremove_lock(ui, repo, pats, opts)
945 cmdutil.addremove(repo, pats, opts)
1104 fns, match, anypats = matchpats(repo, pats, opts)
946 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
1105 if pats:
947 if pats:
1106 modified, added, removed, deleted, unknown = (
948 modified, added, removed = repo.status(files=fns, match=match)[:3]
1107 repo.changes(files=fns, match=match))
1108 files = modified + added + removed
949 files = modified + added + removed
1109 else:
950 else:
1110 files = []
951 files = []
@@ -1259,7 +1100,7 b' def docopy(ui, repo, pats, opts, wlock):'
1259 copylist = []
1100 copylist = []
1260 for pat in pats:
1101 for pat in pats:
1261 srcs = []
1102 srcs = []
1262 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
1103 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
1263 origsrc = okaytocopy(abssrc, relsrc, exact)
1104 origsrc = okaytocopy(abssrc, relsrc, exact)
1264 if origsrc:
1105 if origsrc:
1265 srcs.append((origsrc, abssrc, relsrc, exact))
1106 srcs.append((origsrc, abssrc, relsrc, exact))
@@ -1311,7 +1152,7 b" def debugcomplete(ui, cmd='', **opts):"
1311 options = []
1152 options = []
1312 otables = [globalopts]
1153 otables = [globalopts]
1313 if cmd:
1154 if cmd:
1314 aliases, entry = findcmd(cmd)
1155 aliases, entry = findcmd(ui, cmd)
1315 otables.append(entry[1])
1156 otables.append(entry[1])
1316 for t in otables:
1157 for t in otables:
1317 for o in t:
1158 for o in t:
@@ -1321,7 +1162,7 b" def debugcomplete(ui, cmd='', **opts):"
1321 ui.write("%s\n" % "\n".join(options))
1162 ui.write("%s\n" % "\n".join(options))
1322 return
1163 return
1323
1164
1324 clist = findpossible(cmd).keys()
1165 clist = findpossible(ui, cmd).keys()
1325 clist.sort()
1166 clist.sort()
1326 ui.write("%s\n" % "\n".join(clist))
1167 ui.write("%s\n" % "\n".join(clist))
1327
1168
@@ -1333,9 +1174,9 b' def debugrebuildstate(ui, repo, rev=None'
1333 rev = repo.lookup(rev)
1174 rev = repo.lookup(rev)
1334 change = repo.changelog.read(rev)
1175 change = repo.changelog.read(rev)
1335 n = change[0]
1176 n = change[0]
1336 files = repo.manifest.readflags(n)
1177 files = repo.manifest.read(n)
1337 wlock = repo.wlock()
1178 wlock = repo.wlock()
1338 repo.dirstate.rebuild(rev, files.iteritems())
1179 repo.dirstate.rebuild(rev, files)
1339
1180
1340 def debugcheckstate(ui, repo):
1181 def debugcheckstate(ui, repo):
1341 """validate the correctness of the current dirstate"""
1182 """validate the correctness of the current dirstate"""
@@ -1476,7 +1317,7 b' def debugrename(ui, repo, file, rev=None'
1476
1317
1477 def debugwalk(ui, repo, *pats, **opts):
1318 def debugwalk(ui, repo, *pats, **opts):
1478 """show how files match on given patterns"""
1319 """show how files match on given patterns"""
1479 items = list(walk(repo, pats, opts))
1320 items = list(cmdutil.walk(repo, pats, opts))
1480 if not items:
1321 if not items:
1481 return
1322 return
1482 fmt = '%%s %%-%ds %%-%ds %%s' % (
1323 fmt = '%%s %%-%ds %%-%ds %%s' % (
@@ -1505,37 +1346,10 b' def diff(ui, repo, *pats, **opts):'
1505 """
1346 """
1506 node1, node2 = revpair(ui, repo, opts['rev'])
1347 node1, node2 = revpair(ui, repo, opts['rev'])
1507
1348
1508 fns, matchfn, anypats = matchpats(repo, pats, opts)
1349 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1509
1350
1510 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1351 patch.diff(repo, node1, node2, fns, match=matchfn,
1511 text=opts['text'], opts=opts)
1352 opts=patch.diffopts(ui, opts))
1512
1513 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1514 node = repo.lookup(changeset)
1515 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1516 if opts['switch_parent']:
1517 parents.reverse()
1518 prev = (parents and parents[0]) or nullid
1519 change = repo.changelog.read(node)
1520
1521 fp = make_file(repo, opts['output'], node, total=total, seqno=seqno,
1522 revwidth=revwidth)
1523 if fp != sys.stdout:
1524 ui.note("%s\n" % fp.name)
1525
1526 fp.write("# HG changeset patch\n")
1527 fp.write("# User %s\n" % change[1])
1528 fp.write("# Date %d %d\n" % change[2])
1529 fp.write("# Node ID %s\n" % hex(node))
1530 fp.write("# Parent %s\n" % hex(prev))
1531 if len(parents) > 1:
1532 fp.write("# Parent %s\n" % hex(parents[1]))
1533 fp.write(change[4].rstrip())
1534 fp.write("\n\n")
1535
1536 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1537 if fp != sys.stdout:
1538 fp.close()
1539
1353
1540 def export(ui, repo, *changesets, **opts):
1354 def export(ui, repo, *changesets, **opts):
1541 """dump the header and diffs for one or more changesets
1355 """dump the header and diffs for one or more changesets
@@ -1566,15 +1380,14 b' def export(ui, repo, *changesets, **opts'
1566 """
1380 """
1567 if not changesets:
1381 if not changesets:
1568 raise util.Abort(_("export requires at least one changeset"))
1382 raise util.Abort(_("export requires at least one changeset"))
1569 seqno = 0
1570 revs = list(revrange(ui, repo, changesets))
1383 revs = list(revrange(ui, repo, changesets))
1571 total = len(revs)
1384 if len(revs) > 1:
1572 revwidth = max(map(len, revs))
1385 ui.note(_('exporting patches:\n'))
1573 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1386 else:
1574 ui.note(msg)
1387 ui.note(_('exporting patch:\n'))
1575 for cset in revs:
1388 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1576 seqno += 1
1389 switch_parent=opts['switch_parent'],
1577 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1390 opts=patch.diffopts(ui, opts))
1578
1391
1579 def forget(ui, repo, *pats, **opts):
1392 def forget(ui, repo, *pats, **opts):
1580 """don't add the specified files on the next commit (DEPRECATED)
1393 """don't add the specified files on the next commit (DEPRECATED)
@@ -1587,7 +1400,7 b' def forget(ui, repo, *pats, **opts):'
1587 """
1400 """
1588 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1401 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1589 forget = []
1402 forget = []
1590 for src, abs, rel, exact in walk(repo, pats, opts):
1403 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1591 if repo.dirstate.state(abs) == 'a':
1404 if repo.dirstate.state(abs) == 'a':
1592 forget.append(abs)
1405 forget.append(abs)
1593 if ui.verbose or not exact:
1406 if ui.verbose or not exact:
@@ -1644,42 +1457,56 b' def grep(ui, repo, pattern, *pats, **opt'
1644 self.linenum = linenum
1457 self.linenum = linenum
1645 self.colstart = colstart
1458 self.colstart = colstart
1646 self.colend = colend
1459 self.colend = colend
1460
1647 def __eq__(self, other):
1461 def __eq__(self, other):
1648 return self.line == other.line
1462 return self.line == other.line
1649 def __hash__(self):
1650 return hash(self.line)
1651
1463
1652 matches = {}
1464 matches = {}
1465 copies = {}
1653 def grepbody(fn, rev, body):
1466 def grepbody(fn, rev, body):
1654 matches[rev].setdefault(fn, {})
1467 matches[rev].setdefault(fn, [])
1655 m = matches[rev][fn]
1468 m = matches[rev][fn]
1656 for lnum, cstart, cend, line in matchlines(body):
1469 for lnum, cstart, cend, line in matchlines(body):
1657 s = linestate(line, lnum, cstart, cend)
1470 s = linestate(line, lnum, cstart, cend)
1658 m[s] = s
1471 m.append(s)
1659
1472
1660 # FIXME: prev isn't used, why ?
1473 def difflinestates(a, b):
1474 sm = difflib.SequenceMatcher(None, a, b)
1475 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1476 if tag == 'insert':
1477 for i in range(blo, bhi):
1478 yield ('+', b[i])
1479 elif tag == 'delete':
1480 for i in range(alo, ahi):
1481 yield ('-', a[i])
1482 elif tag == 'replace':
1483 for i in range(alo, ahi):
1484 yield ('-', a[i])
1485 for i in range(blo, bhi):
1486 yield ('+', b[i])
1487
1661 prev = {}
1488 prev = {}
1662 ucache = {}
1489 ucache = {}
1663 def display(fn, rev, states, prevstates):
1490 def display(fn, rev, states, prevstates):
1664 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1665 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1666 counts = {'-': 0, '+': 0}
1491 counts = {'-': 0, '+': 0}
1667 filerevmatches = {}
1492 filerevmatches = {}
1668 for l in diff:
1493 if incrementing or not opts['all']:
1494 a, b = prevstates, states
1495 else:
1496 a, b = states, prevstates
1497 for change, l in difflinestates(a, b):
1669 if incrementing or not opts['all']:
1498 if incrementing or not opts['all']:
1670 change = ((l in prevstates) and '-') or '+'
1671 r = rev
1499 r = rev
1672 else:
1500 else:
1673 change = ((l in states) and '-') or '+'
1674 r = prev[fn]
1501 r = prev[fn]
1675 cols = [fn, str(rev)]
1502 cols = [fn, str(r)]
1676 if opts['line_number']:
1503 if opts['line_number']:
1677 cols.append(str(l.linenum))
1504 cols.append(str(l.linenum))
1678 if opts['all']:
1505 if opts['all']:
1679 cols.append(change)
1506 cols.append(change)
1680 if opts['user']:
1507 if opts['user']:
1681 cols.append(trimuser(ui, getchange(rev)[1], rev,
1508 cols.append(trimuser(ui, getchange(r)[1], rev,
1682 ucache))
1509 ucache))
1683 if opts['files_with_matches']:
1510 if opts['files_with_matches']:
1684 c = (fn, rev)
1511 c = (fn, rev)
1685 if c in filerevmatches:
1512 if c in filerevmatches:
@@ -1696,6 +1523,7 b' def grep(ui, repo, pattern, *pats, **opt'
1696 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1523 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1697 count = 0
1524 count = 0
1698 incrementing = False
1525 incrementing = False
1526 follow = opts.get('follow')
1699 for st, rev, fns in changeiter:
1527 for st, rev, fns in changeiter:
1700 if st == 'window':
1528 if st == 'window':
1701 incrementing = rev
1529 incrementing = rev
@@ -1710,20 +1538,31 b' def grep(ui, repo, pattern, *pats, **opt'
1710 fstate.setdefault(fn, {})
1538 fstate.setdefault(fn, {})
1711 try:
1539 try:
1712 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1540 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1541 if follow:
1542 copied = getfile(fn).renamed(mf[fn])
1543 if copied:
1544 copies.setdefault(rev, {})[fn] = copied[0]
1713 except KeyError:
1545 except KeyError:
1714 pass
1546 pass
1715 elif st == 'iter':
1547 elif st == 'iter':
1716 states = matches[rev].items()
1548 states = matches[rev].items()
1717 states.sort()
1549 states.sort()
1718 for fn, m in states:
1550 for fn, m in states:
1551 copy = copies.get(rev, {}).get(fn)
1719 if fn in skip:
1552 if fn in skip:
1553 if copy:
1554 skip[copy] = True
1720 continue
1555 continue
1721 if incrementing or not opts['all'] or fstate[fn]:
1556 if incrementing or not opts['all'] or fstate[fn]:
1722 pos, neg = display(fn, rev, m, fstate[fn])
1557 pos, neg = display(fn, rev, m, fstate[fn])
1723 count += pos + neg
1558 count += pos + neg
1724 if pos and not opts['all']:
1559 if pos and not opts['all']:
1725 skip[fn] = True
1560 skip[fn] = True
1561 if copy:
1562 skip[copy] = True
1726 fstate[fn] = m
1563 fstate[fn] = m
1564 if copy:
1565 fstate[copy] = m
1727 prev[fn] = rev
1566 prev[fn] = rev
1728
1567
1729 if not incrementing:
1568 if not incrementing:
@@ -1732,7 +1571,8 b' def grep(ui, repo, pattern, *pats, **opt'
1732 for fn, state in fstate:
1571 for fn, state in fstate:
1733 if fn in skip:
1572 if fn in skip:
1734 continue
1573 continue
1735 display(fn, rev, {}, state)
1574 if fn not in copies.get(prev[fn], {}):
1575 display(fn, rev, {}, state)
1736 return (count == 0 and 1) or 0
1576 return (count == 0 and 1) or 0
1737
1577
1738 def heads(ui, repo, **opts):
1578 def heads(ui, repo, **opts):
@@ -1769,8 +1609,8 b' def identify(ui, repo):'
1769 ui.write(_("unknown\n"))
1609 ui.write(_("unknown\n"))
1770 return
1610 return
1771
1611
1772 hexfunc = ui.verbose and hex or short
1612 hexfunc = ui.debugflag and hex or short
1773 modified, added, removed, deleted, unknown = repo.changes()
1613 modified, added, removed, deleted = repo.status()[:4]
1774 output = ["%s%s" %
1614 output = ["%s%s" %
1775 ('+'.join([hexfunc(parent) for parent in parents]),
1615 ('+'.join([hexfunc(parent) for parent in parents]),
1776 (modified or added or removed or deleted) and "+" or "")]
1616 (modified or added or removed or deleted) and "+" or "")]
@@ -1814,81 +1654,23 b' def import_(ui, repo, patch1, *patches, '
1814 d = opts["base"]
1654 d = opts["base"]
1815 strip = opts["strip"]
1655 strip = opts["strip"]
1816
1656
1817 mailre = re.compile(r'(?:From |[\w-]+:)')
1657 wlock = repo.wlock()
1818
1658 lock = repo.lock()
1819 # attempt to detect the start of a patch
1659
1820 # (this heuristic is borrowed from quilt)
1660 for p in patches:
1821 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1661 pf = os.path.join(d, p)
1822 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1662
1823 '(---|\*\*\*)[ \t])', re.MULTILINE)
1824
1825 for patch in patches:
1826 pf = os.path.join(d, patch)
1827
1828 message = None
1829 user = None
1830 date = None
1831 hgpatch = False
1832
1833 p = email.Parser.Parser()
1834 if pf == '-':
1663 if pf == '-':
1835 msg = p.parse(sys.stdin)
1836 ui.status(_("applying patch from stdin\n"))
1664 ui.status(_("applying patch from stdin\n"))
1665 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1837 else:
1666 else:
1838 msg = p.parse(file(pf))
1667 ui.status(_("applying %s\n") % p)
1839 ui.status(_("applying %s\n") % patch)
1668 tmpname, message, user, date = patch.extract(ui, file(pf))
1840
1669
1841 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
1670 if tmpname is None:
1842 tmpfp = os.fdopen(fd, 'w')
1671 raise util.Abort(_('no diffs found'))
1672
1843 try:
1673 try:
1844 message = msg['Subject']
1845 if message:
1846 message = message.replace('\n\t', ' ')
1847 ui.debug('Subject: %s\n' % message)
1848 user = msg['From']
1849 if user:
1850 ui.debug('From: %s\n' % user)
1851 diffs_seen = 0
1852 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
1853 for part in msg.walk():
1854 content_type = part.get_content_type()
1855 ui.debug('Content-Type: %s\n' % content_type)
1856 if content_type not in ok_types:
1857 continue
1858 payload = part.get_payload(decode=True)
1859 m = diffre.search(payload)
1860 if m:
1861 ui.debug(_('found patch at byte %d\n') % m.start(0))
1862 diffs_seen += 1
1863 hgpatch = False
1864 fp = cStringIO.StringIO()
1865 if message:
1866 fp.write(message)
1867 fp.write('\n')
1868 for line in payload[:m.start(0)].splitlines():
1869 if line.startswith('# HG changeset patch'):
1870 ui.debug(_('patch generated by hg export\n'))
1871 hgpatch = True
1872 # drop earlier commit message content
1873 fp.seek(0)
1874 fp.truncate()
1875 elif hgpatch:
1876 if line.startswith('# User '):
1877 user = line[7:]
1878 ui.debug('From: %s\n' % user)
1879 elif line.startswith("# Date "):
1880 date = line[7:]
1881 if not line.startswith('# '):
1882 fp.write(line)
1883 fp.write('\n')
1884 message = fp.getvalue()
1885 if tmpfp:
1886 tmpfp.write(payload)
1887 if not payload.endswith('\n'):
1888 tmpfp.write('\n')
1889 elif not diffs_seen and message and content_type == 'text/plain':
1890 message += '\n' + payload
1891
1892 if opts['message']:
1674 if opts['message']:
1893 # pickup the cmdline msg
1675 # pickup the cmdline msg
1894 message = opts['message']
1676 message = opts['message']
@@ -1900,18 +1682,9 b' def import_(ui, repo, patch1, *patches, '
1900 message = None
1682 message = None
1901 ui.debug(_('message:\n%s\n') % message)
1683 ui.debug(_('message:\n%s\n') % message)
1902
1684
1903 tmpfp.close()
1685 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
1904 if not diffs_seen:
1686 files = patch.updatedir(ui, repo, files, wlock=wlock)
1905 raise util.Abort(_('no diffs found'))
1687 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1906
1907 files = util.patch(strip, tmpname, ui, cwd=repo.root)
1908 if len(files) > 0:
1909 cfiles = files
1910 cwd = repo.getcwd()
1911 if cwd:
1912 cfiles = [util.pathto(cwd, f) for f in files]
1913 addremove_lock(ui, repo, cfiles, {})
1914 repo.commit(files, message, user, date)
1915 finally:
1688 finally:
1916 os.unlink(tmpname)
1689 os.unlink(tmpname)
1917
1690
@@ -1964,7 +1737,7 b' def incoming(ui, repo, source="default",'
1964 displayer.show(changenode=n)
1737 displayer.show(changenode=n)
1965 if opts['patch']:
1738 if opts['patch']:
1966 prev = (parents and parents[0]) or nullid
1739 prev = (parents and parents[0]) or nullid
1967 dodiff(ui, ui, other, prev, n)
1740 patch.diff(other, prev, n, fp=repo.ui)
1968 ui.write("\n")
1741 ui.write("\n")
1969 finally:
1742 finally:
1970 if hasattr(other, 'close'):
1743 if hasattr(other, 'close'):
@@ -2012,8 +1785,8 b' def locate(ui, repo, *pats, **opts):'
2012 else:
1785 else:
2013 node = None
1786 node = None
2014
1787
2015 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1788 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2016 head='(?:.*/|)'):
1789 head='(?:.*/|)'):
2017 if not node and repo.dirstate.state(abs) == '?':
1790 if not node and repo.dirstate.state(abs) == '?':
2018 continue
1791 continue
2019 if opts['fullpath']:
1792 if opts['fullpath']:
@@ -2115,7 +1888,7 b' def log(ui, repo, *pats, **opts):'
2115 displayer.show(rev, brinfo=br)
1888 displayer.show(rev, brinfo=br)
2116 if opts['patch']:
1889 if opts['patch']:
2117 prev = (parents and parents[0]) or nullid
1890 prev = (parents and parents[0]) or nullid
2118 dodiff(du, du, repo, prev, changenode, match=matchfn)
1891 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
2119 du.write("\n\n")
1892 du.write("\n\n")
2120 elif st == 'iter':
1893 elif st == 'iter':
2121 if count == limit: break
1894 if count == limit: break
@@ -2146,12 +1919,12 b' def manifest(ui, repo, rev=None):'
2146 else:
1919 else:
2147 n = repo.manifest.tip()
1920 n = repo.manifest.tip()
2148 m = repo.manifest.read(n)
1921 m = repo.manifest.read(n)
2149 mf = repo.manifest.readflags(n)
2150 files = m.keys()
1922 files = m.keys()
2151 files.sort()
1923 files.sort()
2152
1924
2153 for f in files:
1925 for f in files:
2154 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1926 ui.write("%40s %3s %s\n" % (hex(m[f]),
1927 m.execf(f) and "755" or "644", f))
2155
1928
2156 def merge(ui, repo, node=None, force=None, branch=None):
1929 def merge(ui, repo, node=None, force=None, branch=None):
2157 """Merge working directory with another revision
1930 """Merge working directory with another revision
@@ -2160,9 +1933,29 b' def merge(ui, repo, node=None, force=Non'
2160 requested revision. Files that changed between either parent are
1933 requested revision. Files that changed between either parent are
2161 marked as changed for the next commit and a commit must be
1934 marked as changed for the next commit and a commit must be
2162 performed before any further updates are allowed.
1935 performed before any further updates are allowed.
1936
1937 If no revision is specified, the working directory's parent is a
1938 head revision, and the repository contains exactly one other head,
1939 the other head is merged with by default. Otherwise, an explicit
1940 revision to merge with must be provided.
2163 """
1941 """
2164
1942
2165 node = _lookup(repo, node, branch)
1943 if node:
1944 node = _lookup(repo, node, branch)
1945 else:
1946 heads = repo.heads()
1947 if len(heads) > 2:
1948 raise util.Abort(_('repo has %d heads - '
1949 'please merge with an explicit rev') %
1950 len(heads))
1951 if len(heads) == 1:
1952 raise util.Abort(_('there is nothing to merge - '
1953 'use "hg update" instead'))
1954 parent = repo.dirstate.parents()[0]
1955 if parent not in heads:
1956 raise util.Abort(_('working dir not at a head rev - '
1957 'use "hg update" or merge with an explicit rev'))
1958 node = parent == heads[0] and heads[-1] or heads[0]
2166 return hg.merge(repo, node, force=force)
1959 return hg.merge(repo, node, force=force)
2167
1960
2168 def outgoing(ui, repo, dest=None, **opts):
1961 def outgoing(ui, repo, dest=None, **opts):
@@ -2196,7 +1989,7 b' def outgoing(ui, repo, dest=None, **opts'
2196 displayer.show(changenode=n)
1989 displayer.show(changenode=n)
2197 if opts['patch']:
1990 if opts['patch']:
2198 prev = (parents and parents[0]) or nullid
1991 prev = (parents and parents[0]) or nullid
2199 dodiff(ui, ui, repo, prev, n)
1992 patch.diff(repo, prev, n)
2200 ui.write("\n")
1993 ui.write("\n")
2201
1994
2202 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1995 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
@@ -2409,12 +2202,12 b' def remove(ui, repo, *pats, **opts):'
2409 names = []
2202 names = []
2410 if not opts['after'] and not pats:
2203 if not opts['after'] and not pats:
2411 raise util.Abort(_('no files specified'))
2204 raise util.Abort(_('no files specified'))
2412 files, matchfn, anypats = matchpats(repo, pats, opts)
2205 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2413 exact = dict.fromkeys(files)
2206 exact = dict.fromkeys(files)
2414 mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn))
2207 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2415 modified, added, removed, deleted, unknown = mardu
2208 modified, added, removed, deleted, unknown = mardu
2416 remove, forget = [], []
2209 remove, forget = [], []
2417 for src, abs, rel, exact in walk(repo, pats, opts):
2210 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2418 reason = None
2211 reason = None
2419 if abs not in deleted and opts['after']:
2212 if abs not in deleted and opts['after']:
2420 reason = _('is still present')
2213 reason = _('is still present')
@@ -2494,8 +2287,12 b' def revert(ui, repo, *pats, **opts):'
2494
2287
2495 If names are given, all files matching the names are reverted.
2288 If names are given, all files matching the names are reverted.
2496
2289
2497 If no arguments are given, all files in the repository are reverted.
2290 If no arguments are given, no files are reverted.
2498 """
2291 """
2292
2293 if not pats and not opts['all']:
2294 raise util.Abort(_('no files or directories specified'))
2295
2499 parent, p2 = repo.dirstate.parents()
2296 parent, p2 = repo.dirstate.parents()
2500 if opts['rev']:
2297 if opts['rev']:
2501 node = repo.lookup(opts['rev'])
2298 node = repo.lookup(opts['rev'])
@@ -2521,20 +2318,21 b' def revert(ui, repo, *pats, **opts):'
2521
2318
2522 # walk dirstate.
2319 # walk dirstate.
2523
2320
2524 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
2321 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2322 badmatch=mf.has_key):
2525 names[abs] = (rel, exact)
2323 names[abs] = (rel, exact)
2526 if src == 'b':
2324 if src == 'b':
2527 target_only[abs] = True
2325 target_only[abs] = True
2528
2326
2529 # walk target manifest.
2327 # walk target manifest.
2530
2328
2531 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
2329 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2532 badmatch=names.has_key):
2330 badmatch=names.has_key):
2533 if abs in names: continue
2331 if abs in names: continue
2534 names[abs] = (rel, exact)
2332 names[abs] = (rel, exact)
2535 target_only[abs] = True
2333 target_only[abs] = True
2536
2334
2537 changes = repo.changes(match=names.has_key, wlock=wlock)
2335 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2538 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2336 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2539
2337
2540 revert = ([], _('reverting %s\n'))
2338 revert = ([], _('reverting %s\n'))
@@ -2741,7 +2539,7 b' def status(ui, repo, *pats, **opts):'
2741
2539
2742 all = opts['all']
2540 all = opts['all']
2743
2541
2744 files, matchfn, anypats = matchpats(repo, pats, opts)
2542 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2745 cwd = (pats and repo.getcwd()) or ''
2543 cwd = (pats and repo.getcwd()) or ''
2746 modified, added, removed, deleted, unknown, ignored, clean = [
2544 modified, added, removed, deleted, unknown, ignored, clean = [
2747 [util.pathto(cwd, x) for x in n]
2545 [util.pathto(cwd, x) for x in n]
@@ -2801,17 +2599,20 b' def tag(ui, repo, name, rev_=None, **opt'
2801 if opts['rev']:
2599 if opts['rev']:
2802 rev_ = opts['rev']
2600 rev_ = opts['rev']
2803 if rev_:
2601 if rev_:
2804 r = hex(repo.lookup(rev_))
2602 r = repo.lookup(rev_)
2805 else:
2603 else:
2806 p1, p2 = repo.dirstate.parents()
2604 p1, p2 = repo.dirstate.parents()
2807 if p1 == nullid:
2605 if p1 == nullid:
2808 raise util.Abort(_('no revision to tag'))
2606 raise util.Abort(_('no revision to tag'))
2809 if p2 != nullid:
2607 if p2 != nullid:
2810 raise util.Abort(_('outstanding uncommitted merges'))
2608 raise util.Abort(_('outstanding uncommitted merges'))
2811 r = hex(p1)
2609 r = p1
2812
2610
2813 repo.tag(name, r, opts['local'], opts['message'], opts['user'],
2611 message = opts['message']
2814 opts['date'])
2612 if not message:
2613 message = _('Added tag %s for changeset %s') % (name, short(r))
2614
2615 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2815
2616
2816 def tags(ui, repo):
2617 def tags(ui, repo):
2817 """list repository tags
2618 """list repository tags
@@ -2823,9 +2624,10 b' def tags(ui, repo):'
2823
2624
2824 l = repo.tagslist()
2625 l = repo.tagslist()
2825 l.reverse()
2626 l.reverse()
2627 hexfunc = ui.debugflag and hex or short
2826 for t, n in l:
2628 for t, n in l:
2827 try:
2629 try:
2828 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2630 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2829 except KeyError:
2631 except KeyError:
2830 r = " ?:?"
2632 r = " ?:?"
2831 if ui.quiet:
2633 if ui.quiet:
@@ -2844,7 +2646,7 b' def tip(ui, repo, **opts):'
2844 br = repo.branchlookup([n])
2646 br = repo.branchlookup([n])
2845 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2647 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2846 if opts['patch']:
2648 if opts['patch']:
2847 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2649 patch.diff(repo, repo.changelog.parents(n)[0], n)
2848
2650
2849 def unbundle(ui, repo, fname, **opts):
2651 def unbundle(ui, repo, fname, **opts):
2850 """apply a changegroup file
2652 """apply a changegroup file
@@ -2957,11 +2759,14 b' table = {'
2957 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2759 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2958 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2760 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2959 _('hg add [OPTION]... [FILE]...')),
2761 _('hg add [OPTION]... [FILE]...')),
2960 "debugaddremove|addremove":
2762 "addremove":
2961 (addremove,
2763 (addremove,
2962 [('I', 'include', [], _('include names matching the given patterns')),
2764 [('I', 'include', [], _('include names matching the given patterns')),
2963 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2765 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2964 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2766 ('n', 'dry-run', None,
2767 _('do not perform actions, just print output')),
2768 ('s', 'similarity', '',
2769 _('guess renamed files by similarity (0<=s<=1)'))],
2965 _('hg addremove [OPTION]... [FILE]...')),
2770 _('hg addremove [OPTION]... [FILE]...')),
2966 "^annotate":
2771 "^annotate":
2967 (annotate,
2772 (annotate,
@@ -3067,6 +2872,7 b' table = {'
3067 ('a', 'text', None, _('treat all files as text')),
2872 ('a', 'text', None, _('treat all files as text')),
3068 ('p', 'show-function', None,
2873 ('p', 'show-function', None,
3069 _('show which function each change is in')),
2874 _('show which function each change is in')),
2875 ('g', 'git', None, _('use git extended diff format')),
3070 ('w', 'ignore-all-space', None,
2876 ('w', 'ignore-all-space', None,
3071 _('ignore white space when comparing lines')),
2877 _('ignore white space when comparing lines')),
3072 ('b', 'ignore-space-change', None,
2878 ('b', 'ignore-space-change', None,
@@ -3091,6 +2897,8 b' table = {'
3091 (grep,
2897 (grep,
3092 [('0', 'print0', None, _('end fields with NUL')),
2898 [('0', 'print0', None, _('end fields with NUL')),
3093 ('', 'all', None, _('print all revisions that match')),
2899 ('', 'all', None, _('print all revisions that match')),
2900 ('f', 'follow', None,
2901 _('follow changeset history, or file history across copies and renames')),
3094 ('i', 'ignore-case', None, _('ignore case when matching')),
2902 ('i', 'ignore-case', None, _('ignore case when matching')),
3095 ('l', 'files-with-matches', None,
2903 ('l', 'files-with-matches', None,
3096 _('print only filenames and revs that match')),
2904 _('print only filenames and revs that match')),
@@ -3127,7 +2935,7 b' table = {'
3127 ('n', 'newest-first', None, _('show newest record first')),
2935 ('n', 'newest-first', None, _('show newest record first')),
3128 ('', 'bundle', '', _('file to store the bundles into')),
2936 ('', 'bundle', '', _('file to store the bundles into')),
3129 ('p', 'patch', None, _('show patch')),
2937 ('p', 'patch', None, _('show patch')),
3130 ('r', 'rev', [], _('a specific revision you would like to pull')),
2938 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
3131 ('', 'template', '', _('display with template')),
2939 ('', 'template', '', _('display with template')),
3132 ('e', 'ssh', '', _('specify ssh command to use')),
2940 ('e', 'ssh', '', _('specify ssh command to use')),
3133 ('', 'remotecmd', '',
2941 ('', 'remotecmd', '',
@@ -3164,6 +2972,7 b' table = {'
3164 ('', 'style', '', _('display using template map file')),
2972 ('', 'style', '', _('display using template map file')),
3165 ('m', 'only-merges', None, _('show only merges')),
2973 ('m', 'only-merges', None, _('show only merges')),
3166 ('p', 'patch', None, _('show patch')),
2974 ('p', 'patch', None, _('show patch')),
2975 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3167 ('', 'template', '', _('display with template')),
2976 ('', 'template', '', _('display with template')),
3168 ('I', 'include', [], _('include names matching the given patterns')),
2977 ('I', 'include', [], _('include names matching the given patterns')),
3169 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2978 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
@@ -3202,7 +3011,7 b' table = {'
3202 ('e', 'ssh', '', _('specify ssh command to use')),
3011 ('e', 'ssh', '', _('specify ssh command to use')),
3203 ('f', 'force', None,
3012 ('f', 'force', None,
3204 _('run even when remote repository is unrelated')),
3013 _('run even when remote repository is unrelated')),
3205 ('r', 'rev', [], _('a specific revision you would like to pull')),
3014 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
3206 ('', 'remotecmd', '',
3015 ('', 'remotecmd', '',
3207 _('specify hg command to run on the remote side'))],
3016 _('specify hg command to run on the remote side'))],
3208 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
3017 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
@@ -3242,7 +3051,8 b' table = {'
3242 _('hg rename [OPTION]... SOURCE... DEST')),
3051 _('hg rename [OPTION]... SOURCE... DEST')),
3243 "^revert":
3052 "^revert":
3244 (revert,
3053 (revert,
3245 [('r', 'rev', '', _('revision to revert to')),
3054 [('a', 'all', None, _('revert all changes when no arguments given')),
3055 ('r', 'rev', '', _('revision to revert to')),
3246 ('', 'no-backup', None, _('do not save backup copies of files')),
3056 ('', 'no-backup', None, _('do not save backup copies of files')),
3247 ('I', 'include', [], _('include names matching given patterns')),
3057 ('I', 'include', [], _('include names matching given patterns')),
3248 ('X', 'exclude', [], _('exclude names matching given patterns')),
3058 ('X', 'exclude', [], _('exclude names matching given patterns')),
@@ -3341,7 +3151,7 b' norepo = ("clone init version help debug'
3341 " debugindex debugindexdot")
3151 " debugindex debugindexdot")
3342 optionalrepo = ("paths serve debugconfig")
3152 optionalrepo = ("paths serve debugconfig")
3343
3153
3344 def findpossible(cmd):
3154 def findpossible(ui, cmd):
3345 """
3155 """
3346 Return cmd -> (aliases, command table entry)
3156 Return cmd -> (aliases, command table entry)
3347 for each matching command.
3157 for each matching command.
@@ -3354,7 +3164,7 b' def findpossible(cmd):'
3354 found = None
3164 found = None
3355 if cmd in aliases:
3165 if cmd in aliases:
3356 found = cmd
3166 found = cmd
3357 else:
3167 elif not ui.config("ui", "strict"):
3358 for a in aliases:
3168 for a in aliases:
3359 if a.startswith(cmd):
3169 if a.startswith(cmd):
3360 found = a
3170 found = a
@@ -3370,9 +3180,9 b' def findpossible(cmd):'
3370
3180
3371 return choice
3181 return choice
3372
3182
3373 def findcmd(cmd):
3183 def findcmd(ui, cmd):
3374 """Return (aliases, command table entry) for command string."""
3184 """Return (aliases, command table entry) for command string."""
3375 choice = findpossible(cmd)
3185 choice = findpossible(ui, cmd)
3376
3186
3377 if choice.has_key(cmd):
3187 if choice.has_key(cmd):
3378 return choice[cmd]
3188 return choice[cmd]
@@ -3407,7 +3217,7 b' def parse(ui, args):'
3407
3217
3408 if args:
3218 if args:
3409 cmd, args = args[0], args[1:]
3219 cmd, args = args[0], args[1:]
3410 aliases, i = findcmd(cmd)
3220 aliases, i = findcmd(ui, cmd)
3411 cmd = aliases[0]
3221 cmd = aliases[0]
3412 defaults = ui.config("defaults", cmd)
3222 defaults = ui.config("defaults", cmd)
3413 if defaults:
3223 if defaults:
@@ -3446,18 +3256,11 b' def findext(name):'
3446 return sys.modules[v]
3256 return sys.modules[v]
3447 raise KeyError(name)
3257 raise KeyError(name)
3448
3258
3449 def dispatch(args):
3259 def load_extensions(ui):
3450 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3260 added = []
3451 num = getattr(signal, name, None)
3261 for ext_name, load_from_name in ui.extensions():
3452 if num: signal.signal(num, catchterm)
3262 if ext_name in external:
3453
3263 continue
3454 try:
3455 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3456 except util.Abort, inst:
3457 sys.stderr.write(_("abort: %s\n") % inst)
3458 return -1
3459
3460 for ext_name, load_from_name in u.extensions():
3461 try:
3264 try:
3462 if load_from_name:
3265 if load_from_name:
3463 # the module will be loaded in sys.modules
3266 # the module will be loaded in sys.modules
@@ -3477,23 +3280,36 b' def dispatch(args):'
3477 except ImportError:
3280 except ImportError:
3478 mod = importh(ext_name)
3281 mod = importh(ext_name)
3479 external[ext_name] = mod.__name__
3282 external[ext_name] = mod.__name__
3283 added.append((mod, ext_name))
3480 except (util.SignalInterrupt, KeyboardInterrupt):
3284 except (util.SignalInterrupt, KeyboardInterrupt):
3481 raise
3285 raise
3482 except Exception, inst:
3286 except Exception, inst:
3483 u.warn(_("*** failed to import extension %s: %s\n") % (ext_name, inst))
3287 ui.warn(_("*** failed to import extension %s: %s\n") %
3484 if u.print_exc():
3288 (ext_name, inst))
3289 if ui.print_exc():
3485 return 1
3290 return 1
3486
3291
3487 for name in external.itervalues():
3292 for mod, name in added:
3488 mod = sys.modules[name]
3489 uisetup = getattr(mod, 'uisetup', None)
3293 uisetup = getattr(mod, 'uisetup', None)
3490 if uisetup:
3294 if uisetup:
3491 uisetup(u)
3295 uisetup(ui)
3492 cmdtable = getattr(mod, 'cmdtable', {})
3296 cmdtable = getattr(mod, 'cmdtable', {})
3493 for t in cmdtable:
3297 for t in cmdtable:
3494 if t in table:
3298 if t in table:
3495 u.warn(_("module %s overrides %s\n") % (name, t))
3299 ui.warn(_("module %s overrides %s\n") % (name, t))
3496 table.update(cmdtable)
3300 table.update(cmdtable)
3301
3302 def dispatch(args):
3303 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3304 num = getattr(signal, name, None)
3305 if num: signal.signal(num, catchterm)
3306
3307 try:
3308 u = ui.ui(traceback='--traceback' in sys.argv[1:],
3309 readhooks=[load_extensions])
3310 except util.Abort, inst:
3311 sys.stderr.write(_("abort: %s\n") % inst)
3312 return -1
3497
3313
3498 try:
3314 try:
3499 cmd, func, args, options, cmdoptions = parse(u, args)
3315 cmd, func, args, options, cmdoptions = parse(u, args)
@@ -3545,6 +3361,7 b' def dispatch(args):'
3545 mod = sys.modules[name]
3361 mod = sys.modules[name]
3546 if hasattr(mod, 'reposetup'):
3362 if hasattr(mod, 'reposetup'):
3547 mod.reposetup(u, repo)
3363 mod.reposetup(u, repo)
3364 hg.repo_setup_hooks.append(mod.reposetup)
3548 except hg.RepoError:
3365 except hg.RepoError:
3549 if cmd not in optionalrepo.split():
3366 if cmd not in optionalrepo.split():
3550 raise
3367 raise
@@ -1,6 +1,6 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -109,9 +109,9 b' def demandload(scope, modules):'
109 mod = mod[:col]
109 mod = mod[:col]
110 else:
110 else:
111 fromlist = []
111 fromlist = []
112 as = None
112 as_ = None
113 if '@' in mod:
113 if '@' in mod:
114 mod, as = mod.split("@")
114 mod, as_ = mod.split("@")
115 importer = _importer(scope, mod, fromlist)
115 importer = _importer(scope, mod, fromlist)
116 if fromlist:
116 if fromlist:
117 for name in fromlist:
117 for name in fromlist:
@@ -130,6 +130,6 b' def demandload(scope, modules):'
130 continue
130 continue
131 else:
131 else:
132 basemod = mod
132 basemod = mod
133 if not as:
133 if not as_:
134 as = basemod
134 as_ = basemod
135 scope[as] = _replacer(importer, as)
135 scope[as_] = _replacer(importer, as_)
@@ -1,7 +1,7 b''
1 """
1 """
2 dirstate.py - working directory tracking for mercurial
2 dirstate.py - working directory tracking for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
@@ -10,7 +10,7 b' of the GNU General Public License, incor'
10 from node import *
10 from node import *
11 from i18n import gettext as _
11 from i18n import gettext as _
12 from demandload import *
12 from demandload import *
13 demandload(globals(), "struct os time bisect stat util re errno")
13 demandload(globals(), "struct os time bisect stat strutil util re errno")
14
14
15 class dirstate(object):
15 class dirstate(object):
16 format = ">cllll"
16 format = ">cllll"
@@ -22,6 +22,7 b' class dirstate(object):'
22 self.ui = ui
22 self.ui = ui
23 self.map = None
23 self.map = None
24 self.pl = None
24 self.pl = None
25 self.dirs = None
25 self.copies = {}
26 self.copies = {}
26 self.ignorefunc = None
27 self.ignorefunc = None
27 self.blockignore = False
28 self.blockignore = False
@@ -197,6 +198,38 b' class dirstate(object):'
197 def copied(self, file):
198 def copied(self, file):
198 return self.copies.get(file, None)
199 return self.copies.get(file, None)
199
200
201 def initdirs(self):
202 if self.dirs is None:
203 self.dirs = {}
204 for f in self.map:
205 self.updatedirs(f, 1)
206
207 def updatedirs(self, path, delta):
208 if self.dirs is not None:
209 for c in strutil.findall(path, '/'):
210 pc = path[:c]
211 self.dirs.setdefault(pc, 0)
212 self.dirs[pc] += delta
213
214 def checkshadows(self, files):
215 def prefixes(f):
216 for c in strutil.rfindall(f, '/'):
217 yield f[:c]
218 self.lazyread()
219 self.initdirs()
220 seendirs = {}
221 for f in files:
222 if self.dirs.get(f):
223 raise util.Abort(_('directory named %r already in dirstate') %
224 f)
225 for d in prefixes(f):
226 if d in seendirs:
227 break
228 if d in self.map:
229 raise util.Abort(_('file named %r already in dirstate') %
230 d)
231 seendirs[d] = True
232
200 def update(self, files, state, **kw):
233 def update(self, files, state, **kw):
201 ''' current states:
234 ''' current states:
202 n normal
235 n normal
@@ -207,10 +240,16 b' class dirstate(object):'
207 if not files: return
240 if not files: return
208 self.lazyread()
241 self.lazyread()
209 self.markdirty()
242 self.markdirty()
243 if state == "a":
244 self.initdirs()
245 self.checkshadows(files)
210 for f in files:
246 for f in files:
211 if state == "r":
247 if state == "r":
212 self.map[f] = ('r', 0, 0, 0)
248 self.map[f] = ('r', 0, 0, 0)
249 self.updatedirs(f, -1)
213 else:
250 else:
251 if state == "a":
252 self.updatedirs(f, 1)
214 s = os.lstat(self.wjoin(f))
253 s = os.lstat(self.wjoin(f))
215 st_size = kw.get('st_size', s.st_size)
254 st_size = kw.get('st_size', s.st_size)
216 st_mtime = kw.get('st_mtime', s.st_mtime)
255 st_mtime = kw.get('st_mtime', s.st_mtime)
@@ -222,9 +261,11 b' class dirstate(object):'
222 if not files: return
261 if not files: return
223 self.lazyread()
262 self.lazyread()
224 self.markdirty()
263 self.markdirty()
264 self.initdirs()
225 for f in files:
265 for f in files:
226 try:
266 try:
227 del self.map[f]
267 del self.map[f]
268 self.updatedirs(f, -1)
228 except KeyError:
269 except KeyError:
229 self.ui.warn(_("not in dirstate: %s!\n") % f)
270 self.ui.warn(_("not in dirstate: %s!\n") % f)
230 pass
271 pass
@@ -232,14 +273,15 b' class dirstate(object):'
232 def clear(self):
273 def clear(self):
233 self.map = {}
274 self.map = {}
234 self.copies = {}
275 self.copies = {}
276 self.dirs = None
235 self.markdirty()
277 self.markdirty()
236
278
237 def rebuild(self, parent, files):
279 def rebuild(self, parent, files):
238 self.clear()
280 self.clear()
239 umask = os.umask(0)
281 umask = os.umask(0)
240 os.umask(umask)
282 os.umask(umask)
241 for f, mode in files:
283 for f in files:
242 if mode:
284 if files.execf(f):
243 self.map[f] = ('n', ~umask, -1, 0)
285 self.map[f] = ('n', ~umask, -1, 0)
244 else:
286 else:
245 self.map[f] = ('n', ~umask & 0666, -1, 0)
287 self.map[f] = ('n', ~umask & 0666, -1, 0)
@@ -476,7 +518,7 b' class dirstate(object):'
476 if size >= 0 and (size != st.st_size
518 if size >= 0 and (size != st.st_size
477 or (mode ^ st.st_mode) & 0100):
519 or (mode ^ st.st_mode) & 0100):
478 modified.append(fn)
520 modified.append(fn)
479 elif time != st.st_mtime:
521 elif time != int(st.st_mtime):
480 lookup.append(fn)
522 lookup.append(fn)
481 elif list_clean:
523 elif list_clean:
482 clean.append(fn)
524 clean.append(fn)
@@ -1,6 +1,6 b''
1 # filelog.py - file history class for mercurial
1 # filelog.py - file history class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -65,6 +65,26 b' class filelog(revlog):'
65 return (m["copy"], bin(m["copyrev"]))
65 return (m["copy"], bin(m["copyrev"]))
66 return False
66 return False
67
67
68 def size(self, rev):
69 """return the size of a given revision"""
70
71 # for revisions with renames, we have to go the slow way
72 node = self.node(rev)
73 if self.renamed(node):
74 return len(self.read(node))
75
76 return revlog.size(self, rev)
77
78 def cmp(self, node, text):
79 """compare text with a given file revision"""
80
81 # for renames, we have to go the slow way
82 if self.renamed(node):
83 t2 = self.read(node)
84 return t2 != text
85
86 return revlog.cmp(self, node, text)
87
68 def annotate(self, node):
88 def annotate(self, node):
69
89
70 def decorate(text, rev):
90 def decorate(text, rev):
@@ -76,31 +96,59 b' class filelog(revlog):'
76 return child
96 return child
77
97
78 # find all ancestors
98 # find all ancestors
79 needed = {node:1}
99 needed = {(self, node):1}
80 visit = [node]
100 files = [self]
101 visit = [(self, node)]
81 while visit:
102 while visit:
82 n = visit.pop(0)
103 f, n = visit.pop(0)
83 for p in self.parents(n):
104 rn = f.renamed(n)
84 if p not in needed:
105 if rn:
85 needed[p] = 1
106 f, n = rn
86 visit.append(p)
107 f = filelog(self.opener, f, self.defversion)
108 files.insert(0, f)
109 if (f, n) not in needed:
110 needed[(f, n)] = 1
111 else:
112 needed[(f, n)] += 1
113 for p in f.parents(n):
114 if p == nullid:
115 continue
116 if (f, p) not in needed:
117 needed[(f, p)] = 1
118 visit.append((f, p))
87 else:
119 else:
88 # count how many times we'll use this
120 # count how many times we'll use this
89 needed[p] += 1
121 needed[(f, p)] += 1
90
122
91 # sort by revision which is a topological order
123 # sort by revision (per file) which is a topological order
92 visit = [ (self.rev(n), n) for n in needed.keys() ]
124 visit = []
93 visit.sort()
125 for f in files:
126 fn = [(f.rev(n[1]), f, n[1]) for n in needed.keys() if n[0] == f]
127 fn.sort()
128 visit.extend(fn)
94 hist = {}
129 hist = {}
95
130
96 for r,n in visit:
131 for i in range(len(visit)):
97 curr = decorate(self.read(n), self.linkrev(n))
132 r, f, n = visit[i]
98 for p in self.parents(n):
133 curr = decorate(f.read(n), f.linkrev(n))
134 if r == -1:
135 continue
136 parents = f.parents(n)
137 # follow parents across renames
138 if r < 1 and i > 0:
139 j = i
140 while j > 0 and visit[j][1] == f:
141 j -= 1
142 parents = (visit[j][2],)
143 f = visit[j][1]
144 else:
145 parents = f.parents(n)
146 for p in parents:
99 if p != nullid:
147 if p != nullid:
100 curr = pair(hist[p], curr)
148 curr = pair(hist[p], curr)
101 # trim the history of unneeded revs
149 # trim the history of unneeded revs
102 needed[p] -= 1
150 needed[(f, p)] -= 1
103 if not needed[p]:
151 if not needed[(f, p)]:
104 del hist[p]
152 del hist[p]
105 hist[n] = curr
153 hist[n] = curr
106
154
@@ -1,6 +1,7 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 #
5 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -48,9 +49,14 b' def islocal(repo):'
48 return False
49 return False
49 return repo.local()
50 return repo.local()
50
51
52 repo_setup_hooks = []
53
51 def repository(ui, path=None, create=False):
54 def repository(ui, path=None, create=False):
52 """return a repository object for the specified path"""
55 """return a repository object for the specified path"""
53 return _lookup(path).instance(ui, path, create)
56 repo = _lookup(path).instance(ui, path, create)
57 for hook in repo_setup_hooks:
58 hook(ui, repo)
59 return repo
54
60
55 def defaultdest(source):
61 def defaultdest(source):
56 '''return default destination of clone if none is given'''
62 '''return default destination of clone if none is given'''
@@ -1,7 +1,7 b''
1 # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
1 # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 # hgweb/hgweb_mod.py - Web interface for a repository.
1 # hgweb/hgweb_mod.py - Web interface for a repository.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -11,7 +11,7 b' import os.path'
11 import mimetypes
11 import mimetypes
12 from mercurial.demandload import demandload
12 from mercurial.demandload import demandload
13 demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
13 demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
14 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone")
14 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
15 demandload(globals(), "mercurial:templater")
15 demandload(globals(), "mercurial:templater")
16 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
16 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
17 from mercurial.node import *
17 from mercurial.node import *
@@ -129,37 +129,27 b' class hgweb(object):'
129 date1 = util.datestr(change1[2])
129 date1 = util.datestr(change1[2])
130 date2 = util.datestr(change2[2])
130 date2 = util.datestr(change2[2])
131
131
132 modified, added, removed, deleted, unknown = r.changes(node1, node2)
132 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
133 if files:
133 if files:
134 modified, added, removed = map(lambda x: filterfiles(files, x),
134 modified, added, removed = map(lambda x: filterfiles(files, x),
135 (modified, added, removed))
135 (modified, added, removed))
136
136
137 diffopts = self.repo.ui.diffopts()
137 diffopts = patch.diffopts(self.repo.ui)
138 showfunc = diffopts['showfunc']
139 ignorews = diffopts['ignorews']
140 ignorewsamount = diffopts['ignorewsamount']
141 ignoreblanklines = diffopts['ignoreblanklines']
142 for f in modified:
138 for f in modified:
143 to = r.file(f).read(mmap1[f])
139 to = r.file(f).read(mmap1[f])
144 tn = r.file(f).read(mmap2[f])
140 tn = r.file(f).read(mmap2[f])
145 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
141 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
146 showfunc=showfunc, ignorews=ignorews,
142 opts=diffopts), f, tn)
147 ignorewsamount=ignorewsamount,
148 ignoreblanklines=ignoreblanklines), f, tn)
149 for f in added:
143 for f in added:
150 to = None
144 to = None
151 tn = r.file(f).read(mmap2[f])
145 tn = r.file(f).read(mmap2[f])
152 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
146 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
153 showfunc=showfunc, ignorews=ignorews,
147 opts=diffopts), f, tn)
154 ignorewsamount=ignorewsamount,
155 ignoreblanklines=ignoreblanklines), f, tn)
156 for f in removed:
148 for f in removed:
157 to = r.file(f).read(mmap1[f])
149 to = r.file(f).read(mmap1[f])
158 tn = None
150 tn = None
159 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
151 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
160 showfunc=showfunc, ignorews=ignorews,
152 opts=diffopts), f, tn)
161 ignorewsamount=ignorewsamount,
162 ignoreblanklines=ignoreblanklines), f, tn)
163
153
164 def changelog(self, pos, shortlog=False):
154 def changelog(self, pos, shortlog=False):
165 def changenav(**map):
155 def changenav(**map):
@@ -398,7 +388,7 b' class hgweb(object):'
398 parent=self.siblings(fl.parents(n), fl.rev, file=f),
388 parent=self.siblings(fl.parents(n), fl.rev, file=f),
399 child=self.siblings(fl.children(n), fl.rev, file=f),
389 child=self.siblings(fl.children(n), fl.rev, file=f),
400 rename=self.renamelink(fl, n),
390 rename=self.renamelink(fl, n),
401 permissions=self.repo.manifest.readflags(mfn)[f])
391 permissions=self.repo.manifest.read(mfn).execf(f))
402
392
403 def fileannotate(self, f, node):
393 def fileannotate(self, f, node):
404 bcache = {}
394 bcache = {}
@@ -452,7 +442,7 b' class hgweb(object):'
452 rename=self.renamelink(fl, n),
442 rename=self.renamelink(fl, n),
453 parent=self.siblings(fl.parents(n), fl.rev, file=f),
443 parent=self.siblings(fl.parents(n), fl.rev, file=f),
454 child=self.siblings(fl.children(n), fl.rev, file=f),
444 child=self.siblings(fl.children(n), fl.rev, file=f),
455 permissions=self.repo.manifest.readflags(mfn)[f])
445 permissions=self.repo.manifest.read(mfn).execf(f))
456
446
457 def manifest(self, mnode, path):
447 def manifest(self, mnode, path):
458 man = self.repo.manifest
448 man = self.repo.manifest
@@ -462,7 +452,6 b' class hgweb(object):'
462 rev = man.rev(mn)
452 rev = man.rev(mn)
463 changerev = man.linkrev(mn)
453 changerev = man.linkrev(mn)
464 node = self.repo.changelog.node(changerev)
454 node = self.repo.changelog.node(changerev)
465 mff = man.readflags(mn)
466
455
467 files = {}
456 files = {}
468
457
@@ -496,7 +485,7 b' class hgweb(object):'
496 "filenode": hex(fnode),
485 "filenode": hex(fnode),
497 "parity": self.stripes(parity),
486 "parity": self.stripes(parity),
498 "basename": f,
487 "basename": f,
499 "permissions": mff[full]}
488 "permissions": mf.execf(full)}
500 parity += 1
489 parity += 1
501
490
502 def dirlist(**map):
491 def dirlist(**map):
@@ -1,7 +1,7 b''
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 # hgweb/request.py - An http request from either CGI or the standalone server.
1 # hgweb/request.py - An http request from either CGI or the standalone server.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 # hgweb/server.py - The standalone hg web server.
1 # hgweb/server.py - The standalone hg web server.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # httprangereader.py - just what it says
1 # httprangereader.py - just what it says
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,7 b''
1 # httprepo.py - HTTP repository proxy classes for mercurial
1 # httprepo.py - HTTP repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 #
5 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 """
1 """
2 i18n.py - internationalization support for mercurial
2 i18n.py - internationalization support for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # localrepo.py - read/write repository class for mercurial
1 # localrepo.py - read/write repository class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -169,7 +169,7 b' class localrepository(repo.repository):'
169
169
170 tag_disallowed = ':\r\n'
170 tag_disallowed = ':\r\n'
171
171
172 def tag(self, name, node, local=False, message=None, user=None, date=None):
172 def tag(self, name, node, message, local, user, date):
173 '''tag a revision with a symbolic name.
173 '''tag a revision with a symbolic name.
174
174
175 if local is True, the tag is stored in a per-repository file.
175 if local is True, the tag is stored in a per-repository file.
@@ -191,27 +191,24 b' class localrepository(repo.repository):'
191 if c in name:
191 if c in name:
192 raise util.Abort(_('%r cannot be used in a tag name') % c)
192 raise util.Abort(_('%r cannot be used in a tag name') % c)
193
193
194 self.hook('pretag', throw=True, node=node, tag=name, local=local)
194 self.hook('pretag', throw=True, node=hex(node), tag=name, local=local)
195
195
196 if local:
196 if local:
197 self.opener('localtags', 'a').write('%s %s\n' % (node, name))
197 self.opener('localtags', 'a').write('%s %s\n' % (hex(node), name))
198 self.hook('tag', node=node, tag=name, local=local)
198 self.hook('tag', node=hex(node), tag=name, local=local)
199 return
199 return
200
200
201 for x in self.changes():
201 for x in self.status()[:5]:
202 if '.hgtags' in x:
202 if '.hgtags' in x:
203 raise util.Abort(_('working copy of .hgtags is changed '
203 raise util.Abort(_('working copy of .hgtags is changed '
204 '(please commit .hgtags manually)'))
204 '(please commit .hgtags manually)'))
205
205
206 self.wfile('.hgtags', 'ab').write('%s %s\n' % (node, name))
206 self.wfile('.hgtags', 'ab').write('%s %s\n' % (hex(node), name))
207 if self.dirstate.state('.hgtags') == '?':
207 if self.dirstate.state('.hgtags') == '?':
208 self.add(['.hgtags'])
208 self.add(['.hgtags'])
209
209
210 if not message:
211 message = _('Added tag %s for changeset %s') % (name, node)
212
213 self.commit(['.hgtags'], message, user, date)
210 self.commit(['.hgtags'], message, user, date)
214 self.hook('tag', node=node, tag=name, local=local)
211 self.hook('tag', node=hex(node), tag=name, local=local)
215
212
216 def tags(self):
213 def tags(self):
217 '''return a mapping of tag to node'''
214 '''return a mapping of tag to node'''
@@ -470,8 +467,7 b' class localrepository(repo.repository):'
470 p2 = p2 or self.dirstate.parents()[1] or nullid
467 p2 = p2 or self.dirstate.parents()[1] or nullid
471 c1 = self.changelog.read(p1)
468 c1 = self.changelog.read(p1)
472 c2 = self.changelog.read(p2)
469 c2 = self.changelog.read(p2)
473 m1 = self.manifest.read(c1[0])
470 m1 = self.manifest.read(c1[0]).copy()
474 mf1 = self.manifest.readflags(c1[0])
475 m2 = self.manifest.read(c2[0])
471 m2 = self.manifest.read(c2[0])
476 changed = []
472 changed = []
477
473
@@ -484,36 +480,32 b' class localrepository(repo.repository):'
484 wlock = self.wlock()
480 wlock = self.wlock()
485 l = self.lock()
481 l = self.lock()
486 tr = self.transaction()
482 tr = self.transaction()
487 mm = m1.copy()
488 mfm = mf1.copy()
489 linkrev = self.changelog.count()
483 linkrev = self.changelog.count()
490 for f in files:
484 for f in files:
491 try:
485 try:
492 t = self.wread(f)
486 t = self.wread(f)
493 tm = util.is_exec(self.wjoin(f), mfm.get(f, False))
487 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
494 r = self.file(f)
488 r = self.file(f)
495 mfm[f] = tm
496
489
497 (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
490 (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
498 if entry:
491 if entry:
499 mm[f] = entry
492 m1[f] = entry
500 continue
493 continue
501
494
502 mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
495 m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
503 changed.append(f)
496 changed.append(f)
504 if update_dirstate:
497 if update_dirstate:
505 self.dirstate.update([f], "n")
498 self.dirstate.update([f], "n")
506 except IOError:
499 except IOError:
507 try:
500 try:
508 del mm[f]
501 del m1[f]
509 del mfm[f]
510 if update_dirstate:
502 if update_dirstate:
511 self.dirstate.forget([f])
503 self.dirstate.forget([f])
512 except:
504 except:
513 # deleted from p2?
505 # deleted from p2?
514 pass
506 pass
515
507
516 mnode = self.manifest.add(mm, mfm, tr, linkrev, c1[0], c2[0])
508 mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
517 user = user or self.ui.username()
509 user = user or self.ui.username()
518 n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
510 n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
519 tr.close()
511 tr.close()
@@ -537,15 +529,14 b' class localrepository(repo.repository):'
537 else:
529 else:
538 self.ui.warn(_("%s not tracked!\n") % f)
530 self.ui.warn(_("%s not tracked!\n") % f)
539 else:
531 else:
540 modified, added, removed, deleted, unknown = self.changes(match=match)
532 modified, added, removed, deleted, unknown = self.status(match=match)[:5]
541 commit = modified + added
533 commit = modified + added
542 remove = removed
534 remove = removed
543
535
544 p1, p2 = self.dirstate.parents()
536 p1, p2 = self.dirstate.parents()
545 c1 = self.changelog.read(p1)
537 c1 = self.changelog.read(p1)
546 c2 = self.changelog.read(p2)
538 c2 = self.changelog.read(p2)
547 m1 = self.manifest.read(c1[0])
539 m1 = self.manifest.read(c1[0]).copy()
548 mf1 = self.manifest.readflags(c1[0])
549 m2 = self.manifest.read(c2[0])
540 m2 = self.manifest.read(c2[0])
550
541
551 if not commit and not remove and not force and p2 == nullid:
542 if not commit and not remove and not force and p2 == nullid:
@@ -571,7 +562,7 b' class localrepository(repo.repository):'
571 for f in commit:
562 for f in commit:
572 self.ui.note(f + "\n")
563 self.ui.note(f + "\n")
573 try:
564 try:
574 mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False))
565 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
575 t = self.wread(f)
566 t = self.wread(f)
576 except IOError:
567 except IOError:
577 self.ui.warn(_("trouble committing %s!\n") % f)
568 self.ui.warn(_("trouble committing %s!\n") % f)
@@ -598,12 +589,11 b' class localrepository(repo.repository):'
598 changed.append(f)
589 changed.append(f)
599
590
600 # update manifest
591 # update manifest
601 m1 = m1.copy()
602 m1.update(new)
592 m1.update(new)
603 for f in remove:
593 for f in remove:
604 if f in m1:
594 if f in m1:
605 del m1[f]
595 del m1[f]
606 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0],
596 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
607 (new, remove))
597 (new, remove))
608
598
609 # add changeset
599 # add changeset
@@ -675,8 +665,7 b' class localrepository(repo.repository):'
675
665
676 def fcmp(fn, mf):
666 def fcmp(fn, mf):
677 t1 = self.wread(fn)
667 t1 = self.wread(fn)
678 t2 = self.file(fn).read(mf.get(fn, nullid))
668 return self.file(fn).cmp(mf.get(fn, nullid), t1)
679 return cmp(t1, t2)
680
669
681 def mfmatches(node):
670 def mfmatches(node):
682 change = self.changelog.read(node)
671 change = self.changelog.read(node)
@@ -718,8 +707,10 b' class localrepository(repo.repository):'
718 for f in lookup:
707 for f in lookup:
719 if fcmp(f, mf2):
708 if fcmp(f, mf2):
720 modified.append(f)
709 modified.append(f)
721 elif wlock is not None:
710 else:
722 self.dirstate.update([f], "n")
711 clean.append(f)
712 if wlock is not None:
713 self.dirstate.update([f], "n")
723 else:
714 else:
724 # we are comparing working dir against non-parent
715 # we are comparing working dir against non-parent
725 # generate a pseudo-manifest for the working dir
716 # generate a pseudo-manifest for the working dir
@@ -758,16 +749,6 b' class localrepository(repo.repository):'
758 l.sort()
749 l.sort()
759 return (modified, added, removed, deleted, unknown, ignored, clean)
750 return (modified, added, removed, deleted, unknown, ignored, clean)
760
751
761 def changes(self, node1=None, node2=None, files=[], match=util.always,
762 wlock=None, list_ignored=False, list_clean=False):
763 '''DEPRECATED - use status instead'''
764 marduit = self.status(node1, node2, files, match, wlock,
765 list_ignored, list_clean)
766 if list_ignored:
767 return marduit[:-1]
768 else:
769 return marduit[:-2]
770
771 def add(self, list, wlock=None):
752 def add(self, list, wlock=None):
772 if not wlock:
753 if not wlock:
773 wlock = self.wlock()
754 wlock = self.wlock()
@@ -816,7 +797,6 b' class localrepository(repo.repository):'
816 def undelete(self, list, wlock=None):
797 def undelete(self, list, wlock=None):
817 p = self.dirstate.parents()[0]
798 p = self.dirstate.parents()[0]
818 mn = self.changelog.read(p)[0]
799 mn = self.changelog.read(p)[0]
819 mf = self.manifest.readflags(mn)
820 m = self.manifest.read(mn)
800 m = self.manifest.read(mn)
821 if not wlock:
801 if not wlock:
822 wlock = self.wlock()
802 wlock = self.wlock()
@@ -826,7 +806,7 b' class localrepository(repo.repository):'
826 else:
806 else:
827 t = self.file(f).read(m[f])
807 t = self.file(f).read(m[f])
828 self.wwrite(f, t)
808 self.wwrite(f, t)
829 util.set_exec(self.wjoin(f), mf[f])
809 util.set_exec(self.wjoin(f), m.execf(f))
830 self.dirstate.update([f], "n")
810 self.dirstate.update([f], "n")
831
811
832 def copy(self, source, dest, wlock=None):
812 def copy(self, source, dest, wlock=None):
@@ -1122,7 +1102,7 b' class localrepository(repo.repository):'
1122 else:
1102 else:
1123 raise util.Abort(_("repository is unrelated"))
1103 raise util.Abort(_("repository is unrelated"))
1124
1104
1125 self.ui.note(_("found new changesets starting at ") +
1105 self.ui.debug(_("found new changesets starting at ") +
1126 " ".join([short(f) for f in fetch]) + "\n")
1106 " ".join([short(f) for f in fetch]) + "\n")
1127
1107
1128 self.ui.debug(_("%d total queries\n") % reqcnt)
1108 self.ui.debug(_("%d total queries\n") % reqcnt)
@@ -1,6 +1,6 b''
1 # lock.py - simple locking scheme for mercurial
1 # lock.py - simple locking scheme for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # manifest.py - manifest revision class for mercurial
1 # manifest.py - manifest revision class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -10,6 +10,31 b' from i18n import gettext as _'
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "array bisect struct")
11 demandload(globals(), "array bisect struct")
12
12
13 class manifestdict(dict):
14 def __init__(self, mapping=None, flags=None):
15 if mapping is None: mapping = {}
16 if flags is None: flags = {}
17 dict.__init__(self, mapping)
18 self._flags = flags
19 def flags(self, f):
20 return self._flags.get(f, "")
21 def execf(self, f):
22 "test for executable in manifest flags"
23 return "x" in self.flags(f)
24 def linkf(self, f):
25 "test for symlink in manifest flags"
26 return "l" in self.flags(f)
27 def rawset(self, f, entry):
28 self[f] = bin(entry[:40])
29 fl = entry[40:-1]
30 if fl: self._flags[f] = fl
31 def set(self, f, execf=False, linkf=False):
32 if linkf: self._flags[f] = "l"
33 elif execf: self._flags[f] = "x"
34 else: self._flags[f] = ""
35 def copy(self):
36 return manifestdict(dict.copy(self), dict.copy(self._flags))
37
13 class manifest(revlog):
38 class manifest(revlog):
14 def __init__(self, opener, defversion=REVLOGV0):
39 def __init__(self, opener, defversion=REVLOGV0):
15 self.mapcache = None
40 self.mapcache = None
@@ -18,26 +43,18 b' class manifest(revlog):'
18 defversion)
43 defversion)
19
44
20 def read(self, node):
45 def read(self, node):
21 if node == nullid: return {} # don't upset local cache
46 if node == nullid: return manifestdict() # don't upset local cache
22 if self.mapcache and self.mapcache[0] == node:
47 if self.mapcache and self.mapcache[0] == node:
23 return self.mapcache[1]
48 return self.mapcache[1]
24 text = self.revision(node)
49 text = self.revision(node)
25 map = {}
26 flag = {}
27 self.listcache = array.array('c', text)
50 self.listcache = array.array('c', text)
28 lines = text.splitlines(1)
51 lines = text.splitlines(1)
52 mapping = manifestdict()
29 for l in lines:
53 for l in lines:
30 (f, n) = l.split('\0')
54 (f, n) = l.split('\0')
31 map[f] = bin(n[:40])
55 mapping.rawset(f, n)
32 flag[f] = (n[40:-1] == "x")
56 self.mapcache = (node, mapping)
33 self.mapcache = (node, map, flag)
57 return mapping
34 return map
35
36 def readflags(self, node):
37 if node == nullid: return {} # don't upset local cache
38 if not self.mapcache or self.mapcache[0] != node:
39 self.read(node)
40 return self.mapcache[2]
41
58
42 def diff(self, a, b):
59 def diff(self, a, b):
43 return mdiff.textdiff(str(a), str(b))
60 return mdiff.textdiff(str(a), str(b))
@@ -86,7 +103,7 b' class manifest(revlog):'
86 '''look up entry for a single file efficiently.
103 '''look up entry for a single file efficiently.
87 return (node, flag) pair if found, (None, None) if not.'''
104 return (node, flag) pair if found, (None, None) if not.'''
88 if self.mapcache and node == self.mapcache[0]:
105 if self.mapcache and node == self.mapcache[0]:
89 return self.mapcache[1].get(f), self.mapcache[2].get(f)
106 return self.mapcache[1].get(f), self.mapcache[1].flags(f)
90 text = self.revision(node)
107 text = self.revision(node)
91 start, end = self._search(text, f)
108 start, end = self._search(text, f)
92 if start == end:
109 if start == end:
@@ -95,7 +112,7 b' class manifest(revlog):'
95 f, n = l.split('\0')
112 f, n = l.split('\0')
96 return bin(n[:40]), n[40:-1] == 'x'
113 return bin(n[:40]), n[40:-1] == 'x'
97
114
98 def add(self, map, flags, transaction, link, p1=None, p2=None,
115 def add(self, map, transaction, link, p1=None, p2=None,
99 changed=None):
116 changed=None):
100 # apply the changes collected during the bisect loop to our addlist
117 # apply the changes collected during the bisect loop to our addlist
101 # return a delta suitable for addrevision
118 # return a delta suitable for addrevision
@@ -123,9 +140,7 b' class manifest(revlog):'
123
140
124 # if this is changed to support newlines in filenames,
141 # if this is changed to support newlines in filenames,
125 # be sure to check the templates/ dir again (especially *-raw.tmpl)
142 # be sure to check the templates/ dir again (especially *-raw.tmpl)
126 text = ["%s\000%s%s\n" %
143 text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) for f in files]
127 (f, hex(map[f]), flags[f] and "x" or '')
128 for f in files]
129 self.listcache = array.array('c', "".join(text))
144 self.listcache = array.array('c', "".join(text))
130 cachedelta = None
145 cachedelta = None
131 else:
146 else:
@@ -151,8 +166,7 b' class manifest(revlog):'
151 # bs will either be the index of the item or the insert point
166 # bs will either be the index of the item or the insert point
152 start, end = self._search(addbuf, f, start)
167 start, end = self._search(addbuf, f, start)
153 if w[1] == 0:
168 if w[1] == 0:
154 l = "%s\000%s%s\n" % (f, hex(map[f]),
169 l = "%s\000%s%s\n" % (f, hex(map[f]), map.flags(f))
155 flags[f] and "x" or '')
156 else:
170 else:
157 l = ""
171 l = ""
158 if start == end and w[1] == 1:
172 if start == end and w[1] == 1:
@@ -183,6 +197,6 b' class manifest(revlog):'
183
197
184 n = self.addrevision(buffer(self.listcache), transaction, link, p1, \
198 n = self.addrevision(buffer(self.listcache), transaction, link, p1, \
185 p2, cachedelta)
199 p2, cachedelta)
186 self.mapcache = (n, map, flags)
200 self.mapcache = (n, map)
187
201
188 return n
202 return n
@@ -1,6 +1,6 b''
1 # mdiff.py - diff and patch routines for mercurial
1 # mdiff.py - diff and patch routines for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -19,14 +19,41 b' def splitnewlines(text):'
19 lines[-1] = lines[-1][:-1]
19 lines[-1] = lines[-1][:-1]
20 return lines
20 return lines
21
21
22 def unidiff(a, ad, b, bd, fn, r=None, text=False,
22 class diffopts(object):
23 showfunc=False, ignorews=False, ignorewsamount=False,
23 '''context is the number of context lines
24 ignoreblanklines=False):
24 text treats all files as text
25 showfunc enables diff -p output
26 git enables the git extended patch format
27 ignorews ignores all whitespace changes in the diff
28 ignorewsamount ignores changes in the amount of whitespace
29 ignoreblanklines ignores changes whose lines are all blank'''
25
30
31 defaults = {
32 'context': 3,
33 'text': False,
34 'showfunc': True,
35 'git': False,
36 'ignorews': False,
37 'ignorewsamount': False,
38 'ignoreblanklines': False,
39 }
40
41 __slots__ = defaults.keys()
42
43 def __init__(self, **opts):
44 for k in self.__slots__:
45 v = opts.get(k)
46 if v is None:
47 v = self.defaults[k]
48 setattr(self, k, v)
49
50 defaultopts = diffopts()
51
52 def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts):
26 if not a and not b: return ""
53 if not a and not b: return ""
27 epoch = util.datestr((0, 0))
54 epoch = util.datestr((0, 0))
28
55
29 if not text and (util.binary(a) or util.binary(b)):
56 if not opts.text and (util.binary(a) or util.binary(b)):
30 l = ['Binary file %s has changed\n' % fn]
57 l = ['Binary file %s has changed\n' % fn]
31 elif not a:
58 elif not a:
32 b = splitnewlines(b)
59 b = splitnewlines(b)
@@ -49,10 +76,7 b' def unidiff(a, ad, b, bd, fn, r=None, te'
49 else:
76 else:
50 al = splitnewlines(a)
77 al = splitnewlines(a)
51 bl = splitnewlines(b)
78 bl = splitnewlines(b)
52 l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn,
79 l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts))
53 showfunc=showfunc, ignorews=ignorews,
54 ignorewsamount=ignorewsamount,
55 ignoreblanklines=ignoreblanklines))
56 if not l: return ""
80 if not l: return ""
57 # difflib uses a space, rather than a tab
81 # difflib uses a space, rather than a tab
58 l[0] = "%s\t%s\n" % (l[0][:-2], ad)
82 l[0] = "%s\t%s\n" % (l[0][:-2], ad)
@@ -72,21 +96,15 b' def unidiff(a, ad, b, bd, fn, r=None, te'
72 # t1 and t2 are the text to be diffed
96 # t1 and t2 are the text to be diffed
73 # l1 and l2 are the text broken up into lines
97 # l1 and l2 are the text broken up into lines
74 # header1 and header2 are the filenames for the diff output
98 # header1 and header2 are the filenames for the diff output
75 # context is the number of context lines
99 def bunidiff(t1, t2, l1, l2, header1, header2, opts=defaultopts):
76 # showfunc enables diff -p output
77 # ignorews ignores all whitespace changes in the diff
78 # ignorewsamount ignores changes in the amount of whitespace
79 # ignoreblanklines ignores changes whose lines are all blank
80 def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False,
81 ignorews=False, ignorewsamount=False, ignoreblanklines=False):
82 def contextend(l, len):
100 def contextend(l, len):
83 ret = l + context
101 ret = l + opts.context
84 if ret > len:
102 if ret > len:
85 ret = len
103 ret = len
86 return ret
104 return ret
87
105
88 def contextstart(l):
106 def contextstart(l):
89 ret = l - context
107 ret = l - opts.context
90 if ret < 0:
108 if ret < 0:
91 return 0
109 return 0
92 return ret
110 return ret
@@ -101,7 +119,7 b' def bunidiff(t1, t2, l1, l2, header1, he'
101 blen = b2 - bstart + aend - a2
119 blen = b2 - bstart + aend - a2
102
120
103 func = ""
121 func = ""
104 if showfunc:
122 if opts.showfunc:
105 # walk backwards from the start of the context
123 # walk backwards from the start of the context
106 # to find a line starting with an alphanumeric char.
124 # to find a line starting with an alphanumeric char.
107 for x in xrange(astart, -1, -1):
125 for x in xrange(astart, -1, -1):
@@ -119,14 +137,14 b' def bunidiff(t1, t2, l1, l2, header1, he'
119
137
120 header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ]
138 header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ]
121
139
122 if showfunc:
140 if opts.showfunc:
123 funcre = re.compile('\w')
141 funcre = re.compile('\w')
124 if ignorewsamount:
142 if opts.ignorewsamount:
125 wsamountre = re.compile('[ \t]+')
143 wsamountre = re.compile('[ \t]+')
126 wsappendedre = re.compile(' \n')
144 wsappendedre = re.compile(' \n')
127 if ignoreblanklines:
145 if opts.ignoreblanklines:
128 wsblanklinesre = re.compile('\n')
146 wsblanklinesre = re.compile('\n')
129 if ignorews:
147 if opts.ignorews:
130 wsre = re.compile('[ \t]')
148 wsre = re.compile('[ \t]')
131
149
132 # bdiff.blocks gives us the matching sequences in the files. The loop
150 # bdiff.blocks gives us the matching sequences in the files. The loop
@@ -159,13 +177,13 b' def bunidiff(t1, t2, l1, l2, header1, he'
159 if not old and not new:
177 if not old and not new:
160 continue
178 continue
161
179
162 if ignoreblanklines:
180 if opts.ignoreblanklines:
163 wsold = wsblanklinesre.sub('', "".join(old))
181 wsold = wsblanklinesre.sub('', "".join(old))
164 wsnew = wsblanklinesre.sub('', "".join(new))
182 wsnew = wsblanklinesre.sub('', "".join(new))
165 if wsold == wsnew:
183 if wsold == wsnew:
166 continue
184 continue
167
185
168 if ignorewsamount:
186 if opts.ignorewsamount:
169 wsold = wsamountre.sub(' ', "".join(old))
187 wsold = wsamountre.sub(' ', "".join(old))
170 wsold = wsappendedre.sub('\n', wsold)
188 wsold = wsappendedre.sub('\n', wsold)
171 wsnew = wsamountre.sub(' ', "".join(new))
189 wsnew = wsamountre.sub(' ', "".join(new))
@@ -173,7 +191,7 b' def bunidiff(t1, t2, l1, l2, header1, he'
173 if wsold == wsnew:
191 if wsold == wsnew:
174 continue
192 continue
175
193
176 if ignorews:
194 if opts.ignorews:
177 wsold = wsre.sub('', "".join(old))
195 wsold = wsre.sub('', "".join(old))
178 wsnew = wsre.sub('', "".join(new))
196 wsnew = wsre.sub('', "".join(new))
179 if wsold == wsnew:
197 if wsold == wsnew:
@@ -184,7 +202,7 b' def bunidiff(t1, t2, l1, l2, header1, he'
184 prev = None
202 prev = None
185 if hunk:
203 if hunk:
186 # join with the previous hunk if it falls inside the context
204 # join with the previous hunk if it falls inside the context
187 if astart < hunk[1] + context + 1:
205 if astart < hunk[1] + opts.context + 1:
188 prev = hunk
206 prev = hunk
189 astart = hunk[1]
207 astart = hunk[1]
190 bstart = hunk[3]
208 bstart = hunk[3]
@@ -10,6 +10,11 b' from i18n import gettext as _'
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "util os tempfile")
11 demandload(globals(), "util os tempfile")
12
12
13 def fmerge(f, local, other, ancestor):
14 """merge executable flags"""
15 a, b, c = ancestor.execf(f), local.execf(f), other.execf(f)
16 return ((a^b) | (a^c)) ^ a
17
13 def merge3(repo, fn, my, other, p1, p2):
18 def merge3(repo, fn, my, other, p1, p2):
14 """perform a 3-way merge in the working directory"""
19 """perform a 3-way merge in the working directory"""
15
20
@@ -75,7 +80,7 b' def update(repo, node, branchmerge=False'
75 raise util.Abort(_("update spans branches, use 'hg merge' "
80 raise util.Abort(_("update spans branches, use 'hg merge' "
76 "or 'hg update -C' to lose changes"))
81 "or 'hg update -C' to lose changes"))
77
82
78 modified, added, removed, deleted, unknown = repo.changes()
83 modified, added, removed, deleted, unknown = repo.status()[:5]
79 if branchmerge and not forcemerge:
84 if branchmerge and not forcemerge:
80 if modified or added or removed:
85 if modified or added or removed:
81 raise util.Abort(_("outstanding uncommitted changes"))
86 raise util.Abort(_("outstanding uncommitted changes"))
@@ -84,18 +89,13 b' def update(repo, node, branchmerge=False'
84 m2n = repo.changelog.read(p2)[0]
89 m2n = repo.changelog.read(p2)[0]
85 man = repo.manifest.ancestor(m1n, m2n)
90 man = repo.manifest.ancestor(m1n, m2n)
86 m1 = repo.manifest.read(m1n)
91 m1 = repo.manifest.read(m1n)
87 mf1 = repo.manifest.readflags(m1n)
88 m2 = repo.manifest.read(m2n).copy()
92 m2 = repo.manifest.read(m2n).copy()
89 mf2 = repo.manifest.readflags(m2n)
90 ma = repo.manifest.read(man)
93 ma = repo.manifest.read(man)
91 mfa = repo.manifest.readflags(man)
92
94
93 if not forcemerge and not overwrite:
95 if not force:
94 for f in unknown:
96 for f in unknown:
95 if f in m2:
97 if f in m2:
96 t1 = repo.wread(f)
98 if repo.file(f).cmp(m2[f], repo.wread(f)):
97 t2 = repo.file(f).read(m2[f])
98 if cmp(t1, t2) != 0:
99 raise util.Abort(_("'%s' already exists in the working"
99 raise util.Abort(_("'%s' already exists in the working"
100 " dir and differs from remote") % f)
100 " dir and differs from remote") % f)
101
101
@@ -103,22 +103,27 b' def update(repo, node, branchmerge=False'
103 # we care about merging
103 # we care about merging
104 repo.ui.note(_("resolving manifests\n"))
104 repo.ui.note(_("resolving manifests\n"))
105 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
105 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
106 (overwrite, branchmerge, partial and True or False, linear_path))
106 (overwrite, branchmerge, bool(partial), linear_path))
107 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
107 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
108 (short(man), short(m1n), short(m2n)))
108 (short(man), short(m1n), short(m2n)))
109
109
110 merge = {}
110 merge = {}
111 get = {}
111 get = {}
112 remove = []
112 remove = []
113 forget = []
113
114
114 # construct a working dir manifest
115 # construct a working dir manifest
115 mw = m1.copy()
116 mw = m1.copy()
116 mfw = mf1.copy()
117 umap = dict.fromkeys(unknown)
117 umap = dict.fromkeys(unknown)
118
118
119 for f in added + modified + unknown:
119 for f in added + modified + unknown:
120 mw[f] = ""
120 mw[f] = ""
121 mfw[f] = util.is_exec(repo.wjoin(f), mfw.get(f, False))
121 # is the wfile new and matches m2?
122 if (f not in m1 and f in m2 and
123 not repo.file(f).cmp(m2[f], repo.wread(f))):
124 mw[f] = m2[f]
125
126 mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f)))
122
127
123 for f in deleted + removed:
128 for f in deleted + removed:
124 if f in mw:
129 if f in mw:
@@ -129,8 +134,8 b' def update(repo, node, branchmerge=False'
129 # the file, then we need to remove it from the dirstate, to
134 # the file, then we need to remove it from the dirstate, to
130 # prevent the dirstate from listing the file when it is no
135 # prevent the dirstate from listing the file when it is no
131 # longer in the manifest.
136 # longer in the manifest.
132 if not partial and linear_path and f not in m2:
137 if linear_path and f not in m2:
133 repo.dirstate.forget((f,))
138 forget.append(f)
134
139
135 # Compare manifests
140 # Compare manifests
136 for f, n in mw.iteritems():
141 for f, n in mw.iteritems():
@@ -139,46 +144,32 b' def update(repo, node, branchmerge=False'
139 if f in m2:
144 if f in m2:
140 s = 0
145 s = 0
141
146
142 # is the wfile new since m1, and match m2?
143 if f not in m1:
144 t1 = repo.wread(f)
145 t2 = repo.file(f).read(m2[f])
146 if cmp(t1, t2) == 0:
147 n = m2[f]
148 del t1, t2
149
150 # are files different?
147 # are files different?
151 if n != m2[f]:
148 if n != m2[f]:
152 a = ma.get(f, nullid)
149 a = ma.get(f, nullid)
153 # are both different from the ancestor?
150 # are both different from the ancestor?
154 if n != a and m2[f] != a:
151 if n != a and m2[f] != a:
155 repo.ui.debug(_(" %s versions differ, resolve\n") % f)
152 repo.ui.debug(_(" %s versions differ, resolve\n") % f)
156 # merge executable bits
153 merge[f] = (fmerge(f, mw, m2, ma), m1.get(f, nullid), m2[f])
157 # "if we changed or they changed, change in merge"
158 a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
159 mode = ((a^b) | (a^c)) ^ a
160 merge[f] = (m1.get(f, nullid), m2[f], mode)
161 s = 1
154 s = 1
162 # are we clobbering?
155 # are we clobbering?
163 # is remote's version newer?
156 # is remote's version newer?
164 # or are we going back in time?
157 # or are we going back in time?
165 elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
158 elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
166 repo.ui.debug(_(" remote %s is newer, get\n") % f)
159 repo.ui.debug(_(" remote %s is newer, get\n") % f)
167 get[f] = m2[f]
160 get[f] = (m2.execf(f), m2[f])
168 s = 1
161 s = 1
169 elif f in umap or f in added:
162 elif f in umap or f in added:
170 # this unknown file is the same as the checkout
163 # this unknown file is the same as the checkout
171 # we need to reset the dirstate if the file was added
164 # we need to reset the dirstate if the file was added
172 get[f] = m2[f]
165 get[f] = (m2.execf(f), m2[f])
173
166
174 if not s and mfw[f] != mf2[f]:
167 if not s and mw.execf(f) != m2.execf(f):
175 if overwrite:
168 if overwrite:
176 repo.ui.debug(_(" updating permissions for %s\n") % f)
169 repo.ui.debug(_(" updating permissions for %s\n") % f)
177 util.set_exec(repo.wjoin(f), mf2[f])
170 util.set_exec(repo.wjoin(f), m2.execf(f))
178 else:
171 else:
179 a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
172 if fmerge(f, mw, m2, ma) != mw.execf(f):
180 mode = ((a^b) | (a^c)) ^ a
181 if mode != b:
182 repo.ui.debug(_(" updating permissions for %s\n")
173 repo.ui.debug(_(" updating permissions for %s\n")
183 % f)
174 % f)
184 util.set_exec(repo.wjoin(f), mode)
175 util.set_exec(repo.wjoin(f), mode)
@@ -221,22 +212,24 b' def update(repo, node, branchmerge=False'
221 (_("remote changed %s which local deleted\n") % f) +
212 (_("remote changed %s which local deleted\n") % f) +
222 _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
213 _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
223 if r == _("k"):
214 if r == _("k"):
224 get[f] = n
215 get[f] = (m2.execf(f), n)
225 elif f not in ma:
216 elif f not in ma:
226 repo.ui.debug(_("remote created %s\n") % f)
217 repo.ui.debug(_("remote created %s\n") % f)
227 get[f] = n
218 get[f] = (m2.execf(f), n)
228 else:
219 else:
229 if overwrite or p2 == pa: # going backwards?
220 if overwrite or p2 == pa: # going backwards?
230 repo.ui.debug(_("local deleted %s, recreating\n") % f)
221 repo.ui.debug(_("local deleted %s, recreating\n") % f)
231 get[f] = n
222 get[f] = (m2.execf(f), n)
232 else:
223 else:
233 repo.ui.debug(_("local deleted %s\n") % f)
224 repo.ui.debug(_("local deleted %s\n") % f)
234
225
235 del mw, m1, m2, ma
226 del mw, m1, m2, ma
236
227
228 ### apply phase
229
237 if overwrite:
230 if overwrite:
238 for f in merge:
231 for f in merge:
239 get[f] = merge[f][1]
232 get[f] = merge[f][:2]
240 merge = {}
233 merge = {}
241
234
242 if linear_path or overwrite:
235 if linear_path or overwrite:
@@ -254,17 +247,13 b' def update(repo, node, branchmerge=False'
254 files = get.keys()
247 files = get.keys()
255 files.sort()
248 files.sort()
256 for f in files:
249 for f in files:
250 flag, node = get[f]
257 if f[0] == "/":
251 if f[0] == "/":
258 continue
252 continue
259 repo.ui.note(_("getting %s\n") % f)
253 repo.ui.note(_("getting %s\n") % f)
260 t = repo.file(f).read(get[f])
254 t = repo.file(f).read(node)
261 repo.wwrite(f, t)
255 repo.wwrite(f, t)
262 util.set_exec(repo.wjoin(f), mf2[f])
256 util.set_exec(repo.wjoin(f), flag)
263 if not partial:
264 if branchmerge:
265 repo.dirstate.update([f], 'n', st_mtime=-1)
266 else:
267 repo.dirstate.update([f], 'n')
268
257
269 # merge the tricky bits
258 # merge the tricky bits
270 unresolved = []
259 unresolved = []
@@ -272,24 +261,11 b' def update(repo, node, branchmerge=False'
272 files.sort()
261 files.sort()
273 for f in files:
262 for f in files:
274 repo.ui.status(_("merging %s\n") % f)
263 repo.ui.status(_("merging %s\n") % f)
275 my, other, flag = merge[f]
264 flag, my, other = merge[f]
276 ret = merge3(repo, f, my, other, xp1, xp2)
265 ret = merge3(repo, f, my, other, xp1, xp2)
277 if ret:
266 if ret:
278 unresolved.append(f)
267 unresolved.append(f)
279 util.set_exec(repo.wjoin(f), flag)
268 util.set_exec(repo.wjoin(f), flag)
280 if not partial:
281 if branchmerge:
282 # We've done a branch merge, mark this file as merged
283 # so that we properly record the merger later
284 repo.dirstate.update([f], 'm')
285 else:
286 # We've update-merged a locally modified file, so
287 # we set the dirstate to emulate a normal checkout
288 # of that file some time in the past. Thus our
289 # merge will appear as a normal local file
290 # modification.
291 f_len = len(repo.file(f).read(other))
292 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
293
269
294 remove.sort()
270 remove.sort()
295 for f in remove:
271 for f in remove:
@@ -301,14 +277,40 b' def update(repo, node, branchmerge=False'
301 if inst.errno != errno.ENOENT:
277 if inst.errno != errno.ENOENT:
302 repo.ui.warn(_("update failed to remove %s: %s!\n") %
278 repo.ui.warn(_("update failed to remove %s: %s!\n") %
303 (f, inst.strerror))
279 (f, inst.strerror))
280
281 # update dirstate
304 if not partial:
282 if not partial:
283 repo.dirstate.setparents(p1, p2)
284 repo.dirstate.forget(forget)
305 if branchmerge:
285 if branchmerge:
306 repo.dirstate.update(remove, 'r')
286 repo.dirstate.update(remove, 'r')
307 else:
287 else:
308 repo.dirstate.forget(remove)
288 repo.dirstate.forget(remove)
309
289
310 if not partial:
290 files = get.keys()
311 repo.dirstate.setparents(p1, p2)
291 files.sort()
292 for f in files:
293 if branchmerge:
294 repo.dirstate.update([f], 'n', st_mtime=-1)
295 else:
296 repo.dirstate.update([f], 'n')
297
298 files = merge.keys()
299 files.sort()
300 for f in files:
301 if branchmerge:
302 # We've done a branch merge, mark this file as merged
303 # so that we properly record the merger later
304 repo.dirstate.update([f], 'm')
305 else:
306 # We've update-merged a locally modified file, so
307 # we set the dirstate to emulate a normal checkout
308 # of that file some time in the past. Thus our
309 # merge will appear as a normal local file
310 # modification.
311 fl = repo.file(f)
312 f_len = fl.size(fl.rev(other))
313 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
312
314
313 if show_stats:
315 if show_stats:
314 stats = ((len(get), _("updated")),
316 stats = ((len(get), _("updated")),
@@ -14,7 +14,7 b''
14 allocation of intermediate Python objects. Working memory is about 2x
14 allocation of intermediate Python objects. Working memory is about 2x
15 the total number of hunks.
15 the total number of hunks.
16
16
17 Copyright 2005 Matt Mackall <mpm@selenic.com>
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
18
18
19 This software may be used and distributed according to the terms
19 This software may be used and distributed according to the terms
20 of the GNU General Public License, incorporated herein by reference.
20 of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 """
1 """
2 node.py - basic nodeid manipulation for mercurial
2 node.py - basic nodeid manipulation for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
@@ -2,7 +2,7 b''
2 # Used for the py2exe distutil.
2 # Used for the py2exe distutil.
3 # This module must be the first mercurial module imported in setup.py
3 # This module must be the first mercurial module imported in setup.py
4 #
4 #
5 # Copyright 2005 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
5 # Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
@@ -39,9 +39,9 b' def demandload(scope, modules):'
39 except:
39 except:
40 module = m
40 module = m
41 fromlist = []
41 fromlist = []
42 as = None
42 as_ = None
43 if '@' in module:
43 if '@' in module:
44 module, as = module.split("@")
44 module, as_ = module.split('@')
45 mod = __import__(module, scope, scope, fromlist)
45 mod = __import__(module, scope, scope, fromlist)
46 if fromlist == []:
46 if fromlist == []:
47 # mod is only the top package, but we need all packages
47 # mod is only the top package, but we need all packages
@@ -50,9 +50,9 b' def demandload(scope, modules):'
50 mn = comp[0]
50 mn = comp[0]
51 while True:
51 while True:
52 # mn and mod.__name__ might not be the same
52 # mn and mod.__name__ might not be the same
53 if not as:
53 if not as_:
54 as = mn
54 as_ = mn
55 scope[as] = mod
55 scope[as_] = mod
56 requiredmodules[mod.__name__] = 1
56 requiredmodules[mod.__name__] = 1
57 if len(comp) == i: break
57 if len(comp) == i: break
58 mod = getattr(mod,comp[i])
58 mod = getattr(mod,comp[i])
@@ -1,6 +1,6 b''
1 # remoterepo - remote repositort proxy classes for mercurial
1 # remoterepo - remote repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,7 b''
1 # repo.py - repository base classes for mercurial
1 # repo.py - repository base classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 #
5 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -4,7 +4,7 b' revlog.py - storage back-end for mercuri'
4 This provides efficient delta storage with O(1) retrieve and append
4 This provides efficient delta storage with O(1) retrieve and append
5 and O(changes) merge between branches
5 and O(changes) merge between branches
6
6
7 Copyright 2005 Matt Mackall <mpm@selenic.com>
7 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
8
8
9 This software may be used and distributed according to the terms
9 This software may be used and distributed according to the terms
10 of the GNU General Public License, incorporated herein by reference.
10 of the GNU General Public License, incorporated herein by reference.
@@ -766,6 +766,19 b' class revlog(object):'
766
766
767 raise RevlogError(_("No match found"))
767 raise RevlogError(_("No match found"))
768
768
769 def cmp(self, node, text):
770 """compare text with a given file revision"""
771 p1, p2 = self.parents(node)
772 return hash(text, p1, p2) != node
773
774 def makenode(self, node, text):
775 """calculate a file nodeid for text, descended or possibly
776 unchanged from node"""
777
778 if self.cmp(node, text):
779 return hash(text, node, nullid)
780 return node
781
769 def diff(self, a, b):
782 def diff(self, a, b):
770 """return a delta between two revisions"""
783 """return a delta between two revisions"""
771 return mdiff.textdiff(a, b)
784 return mdiff.textdiff(a, b)
@@ -1,6 +1,6 b''
1 # sshrepo.py - ssh repository proxy class for mercurial
1 # sshrepo.py - ssh repository proxy class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,7 b''
1 # sshserver.py - ssh protocol server support for mercurial
1 # sshserver.py - ssh protocol server support for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 #
5 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -2,7 +2,7 b''
2 #
2 #
3 # This provides read-only repo access to repositories exported via static http
3 # This provides read-only repo access to repositories exported via static http
4 #
4 #
5 # Copyright 2005 Matt Mackall <mpm@selenic.com>
5 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
@@ -459,7 +459,7 b' class changeset_templater(object):'
459 yield x
459 yield x
460
460
461 if self.ui.debugflag:
461 if self.ui.debugflag:
462 files = self.repo.changes(log.parents(changenode)[0], changenode)
462 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
463 def showfiles(**args):
463 def showfiles(**args):
464 for x in showlist('file', files[0], **args): yield x
464 for x in showlist('file', files[0], **args): yield x
465 def showadds(**args):
465 def showadds(**args):
@@ -6,7 +6,7 b''
6 # effectively log-structured, this should amount to simply truncating
6 # effectively log-structured, this should amount to simply truncating
7 # anything that isn't referenced in the changelog.
7 # anything that isn't referenced in the changelog.
8 #
8 #
9 # Copyright 2005 Matt Mackall <mpm@selenic.com>
9 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
10 #
10 #
11 # This software may be used and distributed according to the terms
11 # This software may be used and distributed according to the terms
12 # of the GNU General Public License, incorporated herein by reference.
12 # of the GNU General Public License, incorporated herein by reference.
@@ -1,22 +1,24 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import gettext as _
8 from i18n import gettext as _
9 from demandload import *
9 from demandload import *
10 demandload(globals(), "errno getpass os re smtplib socket sys tempfile")
10 demandload(globals(), "errno getpass os re socket sys tempfile")
11 demandload(globals(), "ConfigParser templater traceback util")
11 demandload(globals(), "ConfigParser mdiff templater traceback util")
12
12
13 class ui(object):
13 class ui(object):
14 def __init__(self, verbose=False, debug=False, quiet=False,
14 def __init__(self, verbose=False, debug=False, quiet=False,
15 interactive=True, traceback=False, parentui=None):
15 interactive=True, traceback=False, parentui=None,
16 readhooks=[]):
16 self.overlay = {}
17 self.overlay = {}
17 if parentui is None:
18 if parentui is None:
18 # this is the parent of all ui children
19 # this is the parent of all ui children
19 self.parentui = None
20 self.parentui = None
21 self.readhooks = list(readhooks)
20 self.cdata = ConfigParser.SafeConfigParser()
22 self.cdata = ConfigParser.SafeConfigParser()
21 self.readconfig(util.rcpath())
23 self.readconfig(util.rcpath())
22
24
@@ -34,6 +36,7 b' class ui(object):'
34 else:
36 else:
35 # parentui may point to an ui object which is already a child
37 # parentui may point to an ui object which is already a child
36 self.parentui = parentui.parentui or parentui
38 self.parentui = parentui.parentui or parentui
39 self.readhooks = list(parentui.readhooks or readhooks)
37 parent_cdata = self.parentui.cdata
40 parent_cdata = self.parentui.cdata
38 self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
41 self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
39 # make interpolation work
42 # make interpolation work
@@ -78,6 +81,8 b' class ui(object):'
78 for name, path in self.configitems("paths"):
81 for name, path in self.configitems("paths"):
79 if path and "://" not in path and not os.path.isabs(path):
82 if path and "://" not in path and not os.path.isabs(path):
80 self.cdata.set("paths", name, os.path.join(root, path))
83 self.cdata.set("paths", name, os.path.join(root, path))
84 for hook in self.readhooks:
85 hook(self)
81
86
82 def setconfig(self, section, name, val):
87 def setconfig(self, section, name, val):
83 self.overlay[(section, name)] = val
88 self.overlay[(section, name)] = val
@@ -169,17 +174,6 b' class ui(object):'
169 result[key.lower()] = value
174 result[key.lower()] = value
170 return result
175 return result
171
176
172 def diffopts(self):
173 if self.diffcache:
174 return self.diffcache
175 result = {'showfunc': True, 'ignorews': False,
176 'ignorewsamount': False, 'ignoreblanklines': False}
177 for key, value in self.configitems("diff"):
178 if value:
179 result[key.lower()] = (value.lower() == 'true')
180 self.diffcache = result
181 return result
182
183 def username(self):
177 def username(self):
184 """Return default username to be used in commits.
178 """Return default username to be used in commits.
185
179
@@ -292,62 +286,6 b' class ui(object):'
292
286
293 return t
287 return t
294
288
295 def sendmail(self):
296 '''send mail message. object returned has one method, sendmail.
297 call as sendmail(sender, list-of-recipients, msg).'''
298
299 def smtp():
300 '''send mail using smtp.'''
301
302 local_hostname = self.config('smtp', 'local_hostname')
303 s = smtplib.SMTP(local_hostname=local_hostname)
304 mailhost = self.config('smtp', 'host')
305 if not mailhost:
306 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
307 mailport = int(self.config('smtp', 'port', 25))
308 self.note(_('sending mail: smtp host %s, port %s\n') %
309 (mailhost, mailport))
310 s.connect(host=mailhost, port=mailport)
311 if self.configbool('smtp', 'tls'):
312 self.note(_('(using tls)\n'))
313 s.ehlo()
314 s.starttls()
315 s.ehlo()
316 username = self.config('smtp', 'username')
317 password = self.config('smtp', 'password')
318 if username and password:
319 self.note(_('(authenticating to mail server as %s)\n') %
320 (username))
321 s.login(username, password)
322 return s
323
324 class sendmail(object):
325 '''send mail using sendmail.'''
326
327 def __init__(self, ui, program):
328 self.ui = ui
329 self.program = program
330
331 def sendmail(self, sender, recipients, msg):
332 cmdline = '%s -f %s %s' % (
333 self.program, templater.email(sender),
334 ' '.join(map(templater.email, recipients)))
335 self.ui.note(_('sending mail: %s\n') % cmdline)
336 fp = os.popen(cmdline, 'w')
337 fp.write(msg)
338 ret = fp.close()
339 if ret:
340 raise util.Abort('%s %s' % (
341 os.path.basename(self.program.split(None, 1)[0]),
342 util.explain_exit(ret)[0]))
343
344 method = self.config('email', 'method', 'smtp')
345 if method == 'smtp':
346 mail = smtp()
347 else:
348 mail = sendmail(self, method)
349 return mail
350
351 def print_exc(self):
289 def print_exc(self):
352 '''print exception traceback if traceback printing enabled.
290 '''print exception traceback if traceback printing enabled.
353 only to call in exception handler. returns true if traceback
291 only to call in exception handler. returns true if traceback
@@ -2,6 +2,8 b''
2 util.py - Mercurial utility functions and platform specfic implementations
2 util.py - Mercurial utility functions and platform specfic implementations
3
3
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
5 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5
7
6 This software may be used and distributed according to the terms
8 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
9 of the GNU General Public License, incorporated herein by reference.
@@ -93,27 +95,6 b' def find_in_path(name, path, default=Non'
93 return p_name
95 return p_name
94 return default
96 return default
95
97
96 def patch(strip, patchname, ui, cwd=None):
97 """apply the patch <patchname> to the working directory.
98 a list of patched files is returned"""
99 patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
100 args = []
101 if cwd:
102 args.append('-d %s' % shellquote(cwd))
103 fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
104 shellquote(patchname)))
105 files = {}
106 for line in fp:
107 line = line.rstrip()
108 ui.status("%s\n" % line)
109 if line.startswith('patching file '):
110 pf = parse_patch_output(line)
111 files.setdefault(pf, 1)
112 code = fp.close()
113 if code:
114 raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
115 return files.keys()
116
117 def binary(s):
98 def binary(s):
118 """return true if a string is binary data using diff's heuristic"""
99 """return true if a string is binary data using diff's heuristic"""
119 if s and '\0' in s[:4096]:
100 if s and '\0' in s[:4096]:
@@ -1,4 +1,4 b''
1 # Copyright (C) 2005 by Intevation GmbH
1 # Copyright (C) 2005, 2006 by Intevation GmbH
2 # Author(s):
2 # Author(s):
3 # Thomas Arendsen Hein <thomas@intevation.de>
3 # Thomas Arendsen Hein <thomas@intevation.de>
4 #
4 #
@@ -28,6 +28,68 b' writing tests:'
28
28
29 - diff will show the current time
29 - diff will show the current time
30
30
31 use hg diff | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" to strip
31 use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
32 dates
32 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
33 to strip dates
34
35 - You can append your own hgrc settings to the file that the environment
36 variable HGRCPATH points to. This file is cleared before running a test.
37
38 You also need to be careful that the tests are portable from one platform
39 to another. You're probably working on Linux, where the GNU toolchain has
40 more (or different) functionality than on MacOS, *BSD, Solaris, AIX, etc.
41 While testing on all platforms is the only sure-fire way to make sure that
42 you've written portable code, here's a list of problems that have been
43 found and fixed in the tests. Another, more comprehensive list may be
44 found in the GNU Autoconf manual, online here:
45
46 http://www.gnu.org/software/autoconf/manual/html_node/Portable-Shell.html
47
48 sh:
49
50 The Bourne shell is a very basic shell. /bin/sh on Linux is typically
51 bash, which even in Bourne-shell mode has many features that Bourne shells
52 on other Unix systems don't have (and even on Linux /bin/sh isn't
53 guaranteed to be bash). You'll need to be careful about constructs that
54 seem ubiquitous, but are actually not available in the least common
55 denominator. While using another shell (ksh, bash explicitly, posix shell,
56 etc.) explicitly may seem like another option, these may not exist in a
57 portable location, and so are generally probably not a good idea. You may
58 find that rewriting the test in python will be easier.
59
60 - don't use pushd/popd; save the output of "pwd" and use "cd" in place of
61 the pushd, and cd back to the saved pwd instead of popd.
33
62
63 - don't use math expressions like let, (( ... )), or $(( ... )); use "expr"
64 instead.
65
66 grep:
67
68 - don't use the -q option; redirect stdout to /dev/null instead.
69
70 - don't use extended regular expressions with grep; use egrep instead, and
71 don't escape any regex operators.
72
73 sed:
74
75 - make sure that the beginning-of-line matcher ("^") is at the very
76 beginning of the expression -- it may not be supported inside parens.
77
78 echo:
79
80 - echo may interpret "\n" and print a newline; use printf instead if you
81 want a literal "\n" (backslash + n).
82
83 false:
84
85 - false is guaranteed only to return a non-zero value; you cannot depend on
86 it being 1. On Solaris in particular, /bin/false returns 255. Rewrite
87 your test to not depend on a particular return value, or create a
88 temporary "false" executable, and call that instead.
89
90 diff:
91
92 - don't use the -N option. There's no particularly good workaround short
93 of writing a reasonably complicated replacement script, but substituting
94 gdiff for diff if you can't rewrite the test not to need -N will probably
95 do.
@@ -211,6 +211,10 b' def run_one(test):'
211 sys.stdout.write('.')
211 sys.stdout.write('.')
212 sys.stdout.flush()
212 sys.stdout.flush()
213
213
214 # create a fresh hgrc
215 hgrc = file(HGRCPATH, 'w+')
216 hgrc.close()
217
214 err = os.path.join(TESTDIR, test+".err")
218 err = os.path.join(TESTDIR, test+".err")
215 ref = os.path.join(TESTDIR, test+".out")
219 ref = os.path.join(TESTDIR, test+".out")
216
220
@@ -319,11 +323,11 b" os.environ['TZ'] = 'GMT'"
319 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
323 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
320 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
324 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
321 os.environ["HGUSER"] = "test"
325 os.environ["HGUSER"] = "test"
322 os.environ["HGRCPATH"] = ""
323
326
324 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
327 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
325 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
328 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
326 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
329 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
330 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
327
331
328 vlog("# Using TESTDIR", TESTDIR)
332 vlog("# Using TESTDIR", TESTDIR)
329 vlog("# Using HGTMP", HGTMP)
333 vlog("# Using HGTMP", HGTMP)
@@ -1,8 +1,12 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
5 cat > $HGTMP/false <<EOF
6 #!/bin/sh
7 exit 1
8 EOF
9 chmod +x $HGTMP/false
6
10
7 hg init foo
11 hg init foo
8 cd foo
12 cd foo
@@ -11,7 +15,7 b' hg add foo'
11
15
12 # mq may keep a reference to the repository so __del__ will not be called
16 # mq may keep a reference to the repository so __del__ will not be called
13 # and .hg/journal.dirstate will not be deleted:
17 # and .hg/journal.dirstate will not be deleted:
14 HGEDITOR=false hg ci
18 HGEDITOR=$HGTMP/false hg ci
15 HGEDITOR=false hg ci
19 HGEDITOR=$HGTMP/false hg ci
16
20
17 exit 0
21 exit 0
@@ -10,3 +10,17 b' cd dir/'
10 touch ../foo_2 bar_2
10 touch ../foo_2 bar_2
11 hg -v addremove
11 hg -v addremove
12 hg -v commit -m "add 2" -d "1000000 0"
12 hg -v commit -m "add 2" -d "1000000 0"
13
14 cd ..
15 hg init sim
16 cd sim
17 echo a > a
18 echo a >> a
19 echo a >> a
20 echo c > c
21 hg commit -Ama
22 mv a b
23 rm c
24 echo d > d
25 hg addremove -s 0.5
26 hg commit -mb
@@ -1,10 +1,15 b''
1 (the addremove command is deprecated; use add and remove --after instead)
2 adding dir/bar
1 adding dir/bar
3 adding foo
2 adding foo
4 dir/bar
3 dir/bar
5 foo
4 foo
6 (the addremove command is deprecated; use add and remove --after instead)
7 adding dir/bar_2
5 adding dir/bar_2
8 adding foo_2
6 adding foo_2
9 dir/bar_2
7 dir/bar_2
10 foo_2
8 foo_2
9 adding a
10 adding c
11 adding b
12 adding d
13 removing a
14 removing c
15 recording removal of a as rename to b (100% similar)
@@ -1,8 +1,5 b''
1 (the addremove command is deprecated; use add and remove --after instead)
2 adding foo
1 adding foo
3 (the addremove command is deprecated; use add and remove --after instead)
4 adding bar
2 adding bar
5 (the addremove command is deprecated; use add and remove --after instead)
6 adding baz/bletch
3 adding baz/bletch
7 test-archive-TIP/.hg_archival.txt
4 test-archive-TIP/.hg_archival.txt
8 test-archive-TIP/bar
5 test-archive-TIP/bar
@@ -1,4 +1,20 b''
1 # default style is like normal output
1 # default style is like normal output
2 1c1
3 < changeset: 3:10e46f2dcbf4
4 ---
5 > changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
6 10c10
7 < changeset: 2:97054abb4ab8
8 ---
9 > changeset: 2:97054abb4ab824450e9164180baf491ae0078465
10 18c18
11 < changeset: 1:b608e9d1a3f0
12 ---
13 > changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
14 29c29
15 < changeset: 0:1e4e1b8f71e0
16 ---
17 > changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2 18a19
18 18a19
3 > files:
19 > files:
4 29a31
20 29a31
@@ -13,7 +13,7 b' echo "%%% should show a removed and b ad'
13 hg status
13 hg status
14
14
15 echo "reverting..."
15 echo "reverting..."
16 hg revert
16 hg revert --all
17
17
18 echo "%%% should show b unknown and a back to normal"
18 echo "%%% should show b unknown and a back to normal"
19 hg status
19 hg status
@@ -42,10 +42,10 b' echo "%%% should show a removed and b ad'
42 hg status
42 hg status
43
43
44 echo "%%% revert should fail"
44 echo "%%% revert should fail"
45 hg revert
45 hg revert --all
46
46
47 echo "%%% revert should be ok now"
47 echo "%%% revert should be ok now"
48 hg revert -r2
48 hg revert -r2 --all
49
49
50 echo "%%% should show b unknown and a marked modified (merged)"
50 echo "%%% should show b unknown and a marked modified (merged)"
51 hg status
51 hg status
@@ -2,7 +2,7 b' A b'
2 b
2 b
3 b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
3 b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
4 we should see two history entries
4 we should see two history entries
5 changeset: 1:386a3cc01532710ca78aed9a54fa2f459c04f29c
5 changeset: 1:386a3cc01532
6 tag: tip
6 tag: tip
7 user: test
7 user: test
8 date: Mon Jan 12 13:46:40 1970 +0000
8 date: Mon Jan 12 13:46:40 1970 +0000
@@ -11,7 +11,7 b' description:'
11 2
11 2
12
12
13
13
14 changeset: 0:33aaa84a386bd609094aeb21a97c09436c482ef1
14 changeset: 0:33aaa84a386b
15 user: test
15 user: test
16 date: Mon Jan 12 13:46:40 1970 +0000
16 date: Mon Jan 12 13:46:40 1970 +0000
17 files: a
17 files: a
@@ -1,8 +1,7 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "fetch=" >> $HGRCPATH
5 echo "fetch=" >> $HGTMP/.hgrc
6
5
7 hg init a
6 hg init a
8 echo a > a/a
7 echo a > a/a
@@ -31,10 +31,10 b' main: we should have a merge here'
31 2 150 71 2 2 a6aef98656b7 c36078bec30d 000000000000
31 2 150 71 2 2 a6aef98656b7 c36078bec30d 000000000000
32 3 221 72 3 3 0c2cc6fc80e2 182b283965f1 a6aef98656b7
32 3 221 72 3 3 0c2cc6fc80e2 182b283965f1 a6aef98656b7
33 log should show foo and quux changed
33 log should show foo and quux changed
34 changeset: 3:0c2cc6fc80e2d4ee289bb658dbbe9ad932380fe9
34 changeset: 3:0c2cc6fc80e2
35 tag: tip
35 tag: tip
36 parent: 1:182b283965f1069c0112784e30e7755ad1c0dd52
36 parent: 1:182b283965f1
37 parent: 2:a6aef98656b71154cae9d87408abe6d0218c8045
37 parent: 2:a6aef98656b7
38 user: test
38 user: test
39 date: Mon Jan 12 13:46:40 1970 +0000
39 date: Mon Jan 12 13:46:40 1970 +0000
40 files: foo quux
40 files: foo quux
@@ -45,7 +45,7 b' hg --cwd c head -v'
45 hg --cwd b tip --verbose
45 hg --cwd b tip --verbose
46
46
47 echo %% --config
47 echo %% --config
48 hg --cwd c --config paths.quuxfoo=bar paths | grep -q quuxfoo && echo quuxfoo
48 hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /dev/null && echo quuxfoo
49 hg --cwd c --config '' tip -q
49 hg --cwd c --config '' tip -q
50 hg --cwd c --config a.b tip -q
50 hg --cwd c --config a.b tip -q
51 hg --cwd c --config a tip -q
51 hg --cwd c --config a tip -q
@@ -47,7 +47,7 b' 0:b6c483daf290'
47 0:8580ff50825a
47 0:8580ff50825a
48 1:b6c483daf290
48 1:b6c483daf290
49 %% -v/--verbose
49 %% -v/--verbose
50 changeset: 1:b6c483daf2907ce5825c0bb50f5716226281cc1a
50 changeset: 1:b6c483daf290
51 tag: tip
51 tag: tip
52 user: test
52 user: test
53 date: Thu Jan 01 00:00:01 1970 +0000
53 date: Thu Jan 01 00:00:01 1970 +0000
@@ -56,7 +56,7 b' description:'
56 b
56 b
57
57
58
58
59 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
59 changeset: 0:8580ff50825a
60 user: test
60 user: test
61 date: Thu Jan 01 00:00:01 1970 +0000
61 date: Thu Jan 01 00:00:01 1970 +0000
62 files: a
62 files: a
@@ -64,7 +64,7 b' description:'
64 a
64 a
65
65
66
66
67 changeset: 0:b6c483daf2907ce5825c0bb50f5716226281cc1a
67 changeset: 0:b6c483daf290
68 tag: tip
68 tag: tip
69 user: test
69 user: test
70 date: Thu Jan 01 00:00:01 1970 +0000
70 date: Thu Jan 01 00:00:01 1970 +0000
@@ -114,92 +114,94 b' Mercurial Distributed SCM'
114
114
115 list of commands (use "hg help -v" to show aliases and global options):
115 list of commands (use "hg help -v" to show aliases and global options):
116
116
117 add add the specified files on the next commit
117 add add the specified files on the next commit
118 annotate show changeset information per file line
118 addremove add all new files, delete all missing files (DEPRECATED)
119 archive create unversioned archive of a repository revision
119 annotate show changeset information per file line
120 backout reverse effect of earlier changeset
120 archive create unversioned archive of a repository revision
121 bundle create a changegroup file
121 backout reverse effect of earlier changeset
122 cat output the latest or given revisions of files
122 bundle create a changegroup file
123 clone make a copy of an existing repository
123 cat output the latest or given revisions of files
124 commit commit the specified files or all outstanding changes
124 clone make a copy of an existing repository
125 copy mark files as copied for the next commit
125 commit commit the specified files or all outstanding changes
126 diff diff repository (or selected files)
126 copy mark files as copied for the next commit
127 export dump the header and diffs for one or more changesets
127 diff diff repository (or selected files)
128 grep search for a pattern in specified files and revisions
128 export dump the header and diffs for one or more changesets
129 heads show current repository heads
129 grep search for a pattern in specified files and revisions
130 help show help for a command, extension, or list of commands
130 heads show current repository heads
131 identify print information about the working copy
131 help show help for a command, extension, or list of commands
132 import import an ordered set of patches
132 identify print information about the working copy
133 incoming show new changesets found in source
133 import import an ordered set of patches
134 init create a new repository in the given directory
134 incoming show new changesets found in source
135 locate locate files matching specific patterns
135 init create a new repository in the given directory
136 log show revision history of entire repository or files
136 locate locate files matching specific patterns
137 manifest output the latest or given revision of the project manifest
137 log show revision history of entire repository or files
138 merge Merge working directory with another revision
138 manifest output the latest or given revision of the project manifest
139 outgoing show changesets not found in destination
139 merge Merge working directory with another revision
140 parents show the parents of the working dir or revision
140 outgoing show changesets not found in destination
141 paths show definition of symbolic path names
141 parents show the parents of the working dir or revision
142 pull pull changes from the specified source
142 paths show definition of symbolic path names
143 push push changes to the specified destination
143 pull pull changes from the specified source
144 recover roll back an interrupted transaction
144 push push changes to the specified destination
145 remove remove the specified files on the next commit
145 recover roll back an interrupted transaction
146 rename rename files; equivalent of copy + remove
146 remove remove the specified files on the next commit
147 revert revert files or dirs to their states as of some revision
147 rename rename files; equivalent of copy + remove
148 rollback roll back the last transaction in this repository
148 revert revert files or dirs to their states as of some revision
149 root print the root (top) of the current working dir
149 rollback roll back the last transaction in this repository
150 serve export the repository via HTTP
150 root print the root (top) of the current working dir
151 status show changed files in the working directory
151 serve export the repository via HTTP
152 tag add a tag for the current tip or a given revision
152 status show changed files in the working directory
153 tags list repository tags
153 tag add a tag for the current tip or a given revision
154 tip show the tip revision
154 tags list repository tags
155 unbundle apply a changegroup file
155 tip show the tip revision
156 update update or merge working directory
156 unbundle apply a changegroup file
157 verify verify the integrity of the repository
157 update update or merge working directory
158 version output version and copyright information
158 verify verify the integrity of the repository
159 version output version and copyright information
159 Mercurial Distributed SCM
160 Mercurial Distributed SCM
160
161
161 list of commands (use "hg help -v" to show aliases and global options):
162 list of commands (use "hg help -v" to show aliases and global options):
162
163
163 add add the specified files on the next commit
164 add add the specified files on the next commit
164 annotate show changeset information per file line
165 addremove add all new files, delete all missing files (DEPRECATED)
165 archive create unversioned archive of a repository revision
166 annotate show changeset information per file line
166 backout reverse effect of earlier changeset
167 archive create unversioned archive of a repository revision
167 bundle create a changegroup file
168 backout reverse effect of earlier changeset
168 cat output the latest or given revisions of files
169 bundle create a changegroup file
169 clone make a copy of an existing repository
170 cat output the latest or given revisions of files
170 commit commit the specified files or all outstanding changes
171 clone make a copy of an existing repository
171 copy mark files as copied for the next commit
172 commit commit the specified files or all outstanding changes
172 diff diff repository (or selected files)
173 copy mark files as copied for the next commit
173 export dump the header and diffs for one or more changesets
174 diff diff repository (or selected files)
174 grep search for a pattern in specified files and revisions
175 export dump the header and diffs for one or more changesets
175 heads show current repository heads
176 grep search for a pattern in specified files and revisions
176 help show help for a command, extension, or list of commands
177 heads show current repository heads
177 identify print information about the working copy
178 help show help for a command, extension, or list of commands
178 import import an ordered set of patches
179 identify print information about the working copy
179 incoming show new changesets found in source
180 import import an ordered set of patches
180 init create a new repository in the given directory
181 incoming show new changesets found in source
181 locate locate files matching specific patterns
182 init create a new repository in the given directory
182 log show revision history of entire repository or files
183 locate locate files matching specific patterns
183 manifest output the latest or given revision of the project manifest
184 log show revision history of entire repository or files
184 merge Merge working directory with another revision
185 manifest output the latest or given revision of the project manifest
185 outgoing show changesets not found in destination
186 merge Merge working directory with another revision
186 parents show the parents of the working dir or revision
187 outgoing show changesets not found in destination
187 paths show definition of symbolic path names
188 parents show the parents of the working dir or revision
188 pull pull changes from the specified source
189 paths show definition of symbolic path names
189 push push changes to the specified destination
190 pull pull changes from the specified source
190 recover roll back an interrupted transaction
191 push push changes to the specified destination
191 remove remove the specified files on the next commit
192 recover roll back an interrupted transaction
192 rename rename files; equivalent of copy + remove
193 remove remove the specified files on the next commit
193 revert revert files or dirs to their states as of some revision
194 rename rename files; equivalent of copy + remove
194 rollback roll back the last transaction in this repository
195 revert revert files or dirs to their states as of some revision
195 root print the root (top) of the current working dir
196 rollback roll back the last transaction in this repository
196 serve export the repository via HTTP
197 root print the root (top) of the current working dir
197 status show changed files in the working directory
198 serve export the repository via HTTP
198 tag add a tag for the current tip or a given revision
199 status show changed files in the working directory
199 tags list repository tags
200 tag add a tag for the current tip or a given revision
200 tip show the tip revision
201 tags list repository tags
201 unbundle apply a changegroup file
202 tip show the tip revision
202 update update or merge working directory
203 unbundle apply a changegroup file
203 verify verify the integrity of the repository
204 update update or merge working directory
204 version output version and copyright information
205 verify verify the integrity of the repository
206 version output version and copyright information
205 %% not tested: --debugger
207 %% not tested: --debugger
@@ -18,6 +18,13 b' head -n 3 port > port1'
18 mv port1 port
18 mv port1 port
19 hg commit -m 4 -u spam -d '4 0'
19 hg commit -m 4 -u spam -d '4 0'
20 hg grep port port
20 hg grep port port
21 echo 'FIXME: history is wrong here'
22 hg grep --all -nu port port
21 hg grep --all -nu port port
23 hg grep import port
22 hg grep import port
23
24 hg cp port port2
25 hg commit -m 4 -u spam -d '5 0'
26 echo '% follow'
27 hg grep -f 'import$' port2
28 echo deport >> port2
29 hg commit -m 5 -u eggs -d '6 0'
30 hg grep -f --all -nu port port2
@@ -1,10 +1,25 b''
1 port:4:export
1 port:4:export
2 port:4:vaportight
2 port:4:vaportight
3 port:4:import/export
3 port:4:import/export
4 FIXME: history is wrong here
4 port:4:4:-:spam:import/export
5 port:1:1:-:eggs:import
5 port:3:4:+:eggs:import/export
6 port:1:2:+:eggs:vaportight
6 port:2:1:-:spam:import
7 port:1:3:+:eggs:import/export
7 port:2:2:-:spam:export
8 port:0:2:+:spam:export
8 port:2:1:+:spam:export
9 port:0:1:+:spam:import
9 port:2:2:+:spam:vaportight
10 port:2:3:+:spam:import/export
11 port:1:2:+:eggs:export
12 port:0:1:+:eggs:import
10 port:4:import/export
13 port:4:import/export
14 % follow
15 port:0:import
16 port2:6:4:+:eggs:deport
17 port:4:4:-:spam:import/export
18 port:3:4:+:eggs:import/export
19 port:2:1:-:spam:import
20 port:2:2:-:spam:export
21 port:2:1:+:spam:export
22 port:2:2:+:spam:vaportight
23 port:2:3:+:spam:import/export
24 port:1:2:+:eggs:export
25 port:0:1:+:eggs:import
@@ -38,90 +38,92 b' Mercurial Distributed SCM'
38
38
39 list of commands (use "hg help -v" to show aliases and global options):
39 list of commands (use "hg help -v" to show aliases and global options):
40
40
41 add add the specified files on the next commit
41 add add the specified files on the next commit
42 annotate show changeset information per file line
42 addremove add all new files, delete all missing files (DEPRECATED)
43 archive create unversioned archive of a repository revision
43 annotate show changeset information per file line
44 backout reverse effect of earlier changeset
44 archive create unversioned archive of a repository revision
45 bundle create a changegroup file
45 backout reverse effect of earlier changeset
46 cat output the latest or given revisions of files
46 bundle create a changegroup file
47 clone make a copy of an existing repository
47 cat output the latest or given revisions of files
48 commit commit the specified files or all outstanding changes
48 clone make a copy of an existing repository
49 copy mark files as copied for the next commit
49 commit commit the specified files or all outstanding changes
50 diff diff repository (or selected files)
50 copy mark files as copied for the next commit
51 export dump the header and diffs for one or more changesets
51 diff diff repository (or selected files)
52 grep search for a pattern in specified files and revisions
52 export dump the header and diffs for one or more changesets
53 heads show current repository heads
53 grep search for a pattern in specified files and revisions
54 help show help for a command, extension, or list of commands
54 heads show current repository heads
55 identify print information about the working copy
55 help show help for a command, extension, or list of commands
56 import import an ordered set of patches
56 identify print information about the working copy
57 incoming show new changesets found in source
57 import import an ordered set of patches
58 init create a new repository in the given directory
58 incoming show new changesets found in source
59 locate locate files matching specific patterns
59 init create a new repository in the given directory
60 log show revision history of entire repository or files
60 locate locate files matching specific patterns
61 manifest output the latest or given revision of the project manifest
61 log show revision history of entire repository or files
62 merge Merge working directory with another revision
62 manifest output the latest or given revision of the project manifest
63 outgoing show changesets not found in destination
63 merge Merge working directory with another revision
64 parents show the parents of the working dir or revision
64 outgoing show changesets not found in destination
65 paths show definition of symbolic path names
65 parents show the parents of the working dir or revision
66 pull pull changes from the specified source
66 paths show definition of symbolic path names
67 push push changes to the specified destination
67 pull pull changes from the specified source
68 recover roll back an interrupted transaction
68 push push changes to the specified destination
69 remove remove the specified files on the next commit
69 recover roll back an interrupted transaction
70 rename rename files; equivalent of copy + remove
70 remove remove the specified files on the next commit
71 revert revert files or dirs to their states as of some revision
71 rename rename files; equivalent of copy + remove
72 rollback roll back the last transaction in this repository
72 revert revert files or dirs to their states as of some revision
73 root print the root (top) of the current working dir
73 rollback roll back the last transaction in this repository
74 serve export the repository via HTTP
74 root print the root (top) of the current working dir
75 status show changed files in the working directory
75 serve export the repository via HTTP
76 tag add a tag for the current tip or a given revision
76 status show changed files in the working directory
77 tags list repository tags
77 tag add a tag for the current tip or a given revision
78 tip show the tip revision
78 tags list repository tags
79 unbundle apply a changegroup file
79 tip show the tip revision
80 update update or merge working directory
80 unbundle apply a changegroup file
81 verify verify the integrity of the repository
81 update update or merge working directory
82 version output version and copyright information
82 verify verify the integrity of the repository
83 add add the specified files on the next commit
83 version output version and copyright information
84 annotate show changeset information per file line
84 add add the specified files on the next commit
85 archive create unversioned archive of a repository revision
85 addremove add all new files, delete all missing files (DEPRECATED)
86 backout reverse effect of earlier changeset
86 annotate show changeset information per file line
87 bundle create a changegroup file
87 archive create unversioned archive of a repository revision
88 cat output the latest or given revisions of files
88 backout reverse effect of earlier changeset
89 clone make a copy of an existing repository
89 bundle create a changegroup file
90 commit commit the specified files or all outstanding changes
90 cat output the latest or given revisions of files
91 copy mark files as copied for the next commit
91 clone make a copy of an existing repository
92 diff diff repository (or selected files)
92 commit commit the specified files or all outstanding changes
93 export dump the header and diffs for one or more changesets
93 copy mark files as copied for the next commit
94 grep search for a pattern in specified files and revisions
94 diff diff repository (or selected files)
95 heads show current repository heads
95 export dump the header and diffs for one or more changesets
96 help show help for a command, extension, or list of commands
96 grep search for a pattern in specified files and revisions
97 identify print information about the working copy
97 heads show current repository heads
98 import import an ordered set of patches
98 help show help for a command, extension, or list of commands
99 incoming show new changesets found in source
99 identify print information about the working copy
100 init create a new repository in the given directory
100 import import an ordered set of patches
101 locate locate files matching specific patterns
101 incoming show new changesets found in source
102 log show revision history of entire repository or files
102 init create a new repository in the given directory
103 manifest output the latest or given revision of the project manifest
103 locate locate files matching specific patterns
104 merge Merge working directory with another revision
104 log show revision history of entire repository or files
105 outgoing show changesets not found in destination
105 manifest output the latest or given revision of the project manifest
106 parents show the parents of the working dir or revision
106 merge Merge working directory with another revision
107 paths show definition of symbolic path names
107 outgoing show changesets not found in destination
108 pull pull changes from the specified source
108 parents show the parents of the working dir or revision
109 push push changes to the specified destination
109 paths show definition of symbolic path names
110 recover roll back an interrupted transaction
110 pull pull changes from the specified source
111 remove remove the specified files on the next commit
111 push push changes to the specified destination
112 rename rename files; equivalent of copy + remove
112 recover roll back an interrupted transaction
113 revert revert files or dirs to their states as of some revision
113 remove remove the specified files on the next commit
114 rollback roll back the last transaction in this repository
114 rename rename files; equivalent of copy + remove
115 root print the root (top) of the current working dir
115 revert revert files or dirs to their states as of some revision
116 serve export the repository via HTTP
116 rollback roll back the last transaction in this repository
117 status show changed files in the working directory
117 root print the root (top) of the current working dir
118 tag add a tag for the current tip or a given revision
118 serve export the repository via HTTP
119 tags list repository tags
119 status show changed files in the working directory
120 tip show the tip revision
120 tag add a tag for the current tip or a given revision
121 unbundle apply a changegroup file
121 tags list repository tags
122 update update or merge working directory
122 tip show the tip revision
123 verify verify the integrity of the repository
123 unbundle apply a changegroup file
124 version output version and copyright information
124 update update or merge working directory
125 verify verify the integrity of the repository
126 version output version and copyright information
125 hg add [OPTION]... [FILE]...
127 hg add [OPTION]... [FILE]...
126
128
127 add the specified files on the next commit
129 add the specified files on the next commit
@@ -176,6 +178,7 b' options:'
176 -r --rev revision
178 -r --rev revision
177 -a --text treat all files as text
179 -a --text treat all files as text
178 -p --show-function show which function each change is in
180 -p --show-function show which function each change is in
181 -g --git use git extended diff format
179 -w --ignore-all-space ignore white space when comparing lines
182 -w --ignore-all-space ignore white space when comparing lines
180 -b --ignore-space-change ignore changes in the amount of white space
183 -b --ignore-space-change ignore changes in the amount of white space
181 -B --ignore-blank-lines ignore changes whose lines are all blank
184 -B --ignore-blank-lines ignore changes whose lines are all blank
@@ -36,43 +36,43 b' added 3 changesets with 2 changes to 2 f'
36 (run 'hg update' to get a working copy)
36 (run 'hg update' to get a working copy)
37 pretag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
37 pretag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
38 precommit hook: p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
38 precommit hook: p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
39 pretxncommit hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
39 pretxncommit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
40 4:4f92e785b90a
40 4:8ea2ef7ad3e8
41 commit hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
41 commit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
42 commit hook b
42 commit hook b
43 tag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
43 tag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
44 pretag hook: t=la n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
44 pretag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
45 tag hook: t=la n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
45 tag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
46 pretag hook: t=fa n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=0
46 pretag hook: t=fa n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=0
47 pretag.forbid hook
47 pretag.forbid hook
48 abort: pretag.forbid hook exited with status 1
48 abort: pretag.forbid hook exited with status 1
49 pretag hook: t=fla n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
49 pretag hook: t=fla n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
50 pretag.forbid hook
50 pretag.forbid hook
51 abort: pretag.forbid hook exited with status 1
51 abort: pretag.forbid hook exited with status 1
52 4:4f92e785b90a
52 4:8ea2ef7ad3e8
53 precommit hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
53 precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
54 pretxncommit hook: n=7792358308a2026661cea44f9d47c072813004cb p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
54 pretxncommit hook: n=fad284daf8c032148abaffcd745dafeceefceb61 p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
55 5:7792358308a2
55 5:fad284daf8c0
56 pretxncommit.forbid hook: tip=5:7792358308a2
56 pretxncommit.forbid hook: tip=5:fad284daf8c0
57 abort: pretxncommit.forbid hook exited with status 1
57 abort: pretxncommit.forbid hook exited with status 1
58 transaction abort!
58 transaction abort!
59 rollback completed
59 rollback completed
60 4:4f92e785b90a
60 4:8ea2ef7ad3e8
61 precommit hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
61 precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
62 precommit.forbid hook
62 precommit.forbid hook
63 abort: precommit.forbid hook exited with status 1
63 abort: precommit.forbid hook exited with status 1
64 4:4f92e785b90a
64 4:8ea2ef7ad3e8
65 preupdate hook: p1=b702efe9688826e3a91283852b328b84dbf37bc2 p2=
65 preupdate hook: p1=b702efe9688826e3a91283852b328b84dbf37bc2 p2=
66 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
66 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
67 preupdate hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
67 preupdate hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
68 update hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2= err=0
68 update hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2= err=0
69 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 3:4c52fb2e4022
70 3:4c52fb2e4022
71 prechangegroup.forbid hook
71 prechangegroup.forbid hook
72 pulling from ../a
72 pulling from ../a
73 searching for changes
73 searching for changes
74 abort: prechangegroup.forbid hook exited with status 1
74 abort: prechangegroup.forbid hook exited with status 1
75 pretxnchangegroup.forbid hook: tip=4:4f92e785b90a
75 pretxnchangegroup.forbid hook: tip=4:8ea2ef7ad3e8
76 pulling from ../a
76 pulling from ../a
77 searching for changes
77 searching for changes
78 adding changesets
78 adding changesets
@@ -84,7 +84,7 b' transaction abort!'
84 rollback completed
84 rollback completed
85 3:4c52fb2e4022
85 3:4c52fb2e4022
86 preoutgoing hook: s=pull
86 preoutgoing hook: s=pull
87 outgoing hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 s=pull
87 outgoing hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 s=pull
88 pulling from ../a
88 pulling from ../a
89 searching for changes
89 searching for changes
90 adding changesets
90 adding changesets
@@ -11,7 +11,7 b' cat hg1.pid hg2.pid >> $DAEMON_PIDS'
11
11
12 echo % clone via stream
12 echo % clone via stream
13 http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \
13 http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \
14 sed -e 's/[0-9][0-9.]*/XXX/g'
14 sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/.\(B\/sec\)/X\1/'
15 hg verify -R copy
15 hg verify -R copy
16
16
17 echo % try to clone via stream, should use pull instead
17 echo % try to clone via stream, should use pull instead
@@ -2,7 +2,7 b' adding foo'
2 % clone via stream
2 % clone via stream
3 streaming all changes
3 streaming all changes
4 XXX files to transfer, XXX bytes of data
4 XXX files to transfer, XXX bytes of data
5 transferred XXX bytes in XXX seconds (XXX KB/sec)
5 transferred XXX bytes in XXX seconds (XXX XB/sec)
6 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
6 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
7 checking changesets
7 checking changesets
8 checking manifests
8 checking manifests
@@ -72,7 +72,7 b' rm -rf b'
72
72
73 echo % plain diff in email, no subject, no message body, should fail
73 echo % plain diff in email, no subject, no message body, should fail
74 hg clone -r0 a b
74 hg clone -r0 a b
75 grep -v '^\(Subject\|email\)' msg.patch | hg --cwd b import -
75 egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
76 rm -rf b
76 rm -rf b
77
77
78 echo % hg export in email, should use patch header
78 echo % hg export in email, should use patch header
@@ -89,9 +89,10 b" hg --cwd a ci -u someoneelse -d '1 0' -m"
89 echo % hg import in a subdirectory
89 echo % hg import in a subdirectory
90 hg clone -r0 a b
90 hg clone -r0 a b
91 hg --cwd a export tip | sed -e 's/d1\/d2\///' > tip.patch
91 hg --cwd a export tip | sed -e 's/d1\/d2\///' > tip.patch
92 pushd b/d1/d2 2>&1 > /dev/null
92 dir=`pwd`
93 cd b/d1/d2 2>&1 > /dev/null
93 hg import ../../../tip.patch
94 hg import ../../../tip.patch
94 popd 2>&1 > /dev/null
95 cd $dir
95 echo "% message should be 'subdir change'"
96 echo "% message should be 'subdir change'"
96 hg --cwd b tip | grep 'subdir change'
97 hg --cwd b tip | grep 'subdir change'
97 echo "% committer should be 'someoneelse'"
98 echo "% committer should be 'someoneelse'"
@@ -8,7 +8,6 b' adding file changes'
8 added 1 changesets with 2 changes to 2 files
8 added 1 changesets with 2 changes to 2 files
9 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
9 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
10 applying ../tip.patch
10 applying ../tip.patch
11 patching file a
12 % message should be same
11 % message should be same
13 summary: second change
12 summary: second change
14 % committer should be same
13 % committer should be same
@@ -21,7 +20,6 b' adding file changes'
21 added 1 changesets with 2 changes to 2 files
20 added 1 changesets with 2 changes to 2 files
22 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 applying ../tip.patch
22 applying ../tip.patch
24 patching file a
25 transaction abort!
23 transaction abort!
26 rollback completed
24 rollback completed
27 % import of plain diff should be ok with message
25 % import of plain diff should be ok with message
@@ -32,7 +30,6 b' adding file changes'
32 added 1 changesets with 2 changes to 2 files
30 added 1 changesets with 2 changes to 2 files
33 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 applying ../tip.patch
32 applying ../tip.patch
35 patching file a
36 % import from stdin
33 % import from stdin
37 requesting all changes
34 requesting all changes
38 adding changesets
35 adding changesets
@@ -41,7 +38,6 b' adding file changes'
41 added 1 changesets with 2 changes to 2 files
38 added 1 changesets with 2 changes to 2 files
42 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
39 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 applying patch from stdin
40 applying patch from stdin
44 patching file a
45 % override commit message
41 % override commit message
46 requesting all changes
42 requesting all changes
47 adding changesets
43 adding changesets
@@ -50,7 +46,6 b' adding file changes'
50 added 1 changesets with 2 changes to 2 files
46 added 1 changesets with 2 changes to 2 files
51 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
47 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 applying patch from stdin
48 applying patch from stdin
53 patching file a
54 summary: override
49 summary: override
55 % plain diff in email, subject, message body
50 % plain diff in email, subject, message body
56 requesting all changes
51 requesting all changes
@@ -60,7 +55,6 b' adding file changes'
60 added 1 changesets with 2 changes to 2 files
55 added 1 changesets with 2 changes to 2 files
61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 applying ../msg.patch
57 applying ../msg.patch
63 patching file a
64 user: email patcher
58 user: email patcher
65 summary: email patch
59 summary: email patch
66 % plain diff in email, no subject, message body
60 % plain diff in email, no subject, message body
@@ -71,7 +65,6 b' adding file changes'
71 added 1 changesets with 2 changes to 2 files
65 added 1 changesets with 2 changes to 2 files
72 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
73 applying patch from stdin
67 applying patch from stdin
74 patching file a
75 % plain diff in email, subject, no message body
68 % plain diff in email, subject, no message body
76 requesting all changes
69 requesting all changes
77 adding changesets
70 adding changesets
@@ -80,7 +73,6 b' adding file changes'
80 added 1 changesets with 2 changes to 2 files
73 added 1 changesets with 2 changes to 2 files
81 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
74 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 applying patch from stdin
75 applying patch from stdin
83 patching file a
84 % plain diff in email, no subject, no message body, should fail
76 % plain diff in email, no subject, no message body, should fail
85 requesting all changes
77 requesting all changes
86 adding changesets
78 adding changesets
@@ -89,7 +81,6 b' adding file changes'
89 added 1 changesets with 2 changes to 2 files
81 added 1 changesets with 2 changes to 2 files
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 applying patch from stdin
83 applying patch from stdin
92 patching file a
93 transaction abort!
84 transaction abort!
94 rollback completed
85 rollback completed
95 % hg export in email, should use patch header
86 % hg export in email, should use patch header
@@ -100,7 +91,6 b' adding file changes'
100 added 1 changesets with 2 changes to 2 files
91 added 1 changesets with 2 changes to 2 files
101 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 applying patch from stdin
93 applying patch from stdin
103 patching file a
104 summary: second change
94 summary: second change
105 % hg import in a subdirectory
95 % hg import in a subdirectory
106 requesting all changes
96 requesting all changes
@@ -110,7 +100,6 b' adding file changes'
110 added 1 changesets with 2 changes to 2 files
100 added 1 changesets with 2 changes to 2 files
111 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
112 applying ../../../tip.patch
102 applying ../../../tip.patch
113 patching file a
114 % message should be 'subdir change'
103 % message should be 'subdir change'
115 summary: subdir change
104 summary: subdir change
116 % committer should be 'someoneelse'
105 % committer should be 'someoneelse'
@@ -63,3 +63,6 b" hg ci -Amb1.1 -d'1 0'"
63
63
64 echo % log --follow-first
64 echo % log --follow-first
65 hg log --follow-first
65 hg log --follow-first
66
67 echo % log -P 2
68 hg log -P 2
@@ -34,7 +34,7 b' date: Thu Jan 01 00:00:01 1970 +0'
34 summary: a
34 summary: a
35
35
36 % one rename
36 % one rename
37 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
37 changeset: 0:8580ff50825a
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:01 1970 +0000
39 date: Thu Jan 01 00:00:01 1970 +0000
40 files: a
40 files: a
@@ -43,7 +43,7 b' a'
43
43
44
44
45 % many renames
45 % many renames
46 changeset: 4:8c1c8408f7371319750ea2d4fa7969828effbcf4
46 changeset: 4:8c1c8408f737
47 tag: tip
47 tag: tip
48 user: test
48 user: test
49 date: Thu Jan 01 00:00:05 1970 +0000
49 date: Thu Jan 01 00:00:05 1970 +0000
@@ -52,7 +52,7 b' description:'
52 e
52 e
53
53
54
54
55 changeset: 2:21fba396af4c801f9717de6c415b6cc9620437e8
55 changeset: 2:21fba396af4c
56 user: test
56 user: test
57 date: Thu Jan 01 00:00:03 1970 +0000
57 date: Thu Jan 01 00:00:03 1970 +0000
58 files: b dir/b
58 files: b dir/b
@@ -60,7 +60,7 b' description:'
60 c
60 c
61
61
62
62
63 changeset: 1:c0296dabce9bf0cd3fdd608de26693c91cd6bbf4
63 changeset: 1:c0296dabce9b
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:02 1970 +0000
65 date: Thu Jan 01 00:00:02 1970 +0000
66 files: b
66 files: b
@@ -68,7 +68,7 b' description:'
68 b
68 b
69
69
70
70
71 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
71 changeset: 0:8580ff50825a
72 user: test
72 user: test
73 date: Thu Jan 01 00:00:01 1970 +0000
73 date: Thu Jan 01 00:00:01 1970 +0000
74 files: a
74 files: a
@@ -149,3 +149,29 b' user: test'
149 date: Thu Jan 01 00:00:01 1970 +0000
149 date: Thu Jan 01 00:00:01 1970 +0000
150 summary: base
150 summary: base
151
151
152 % log -P 2
153 changeset: 6:2404bbcab562
154 tag: tip
155 user: test
156 date: Thu Jan 01 00:00:01 1970 +0000
157 summary: b1.1
158
159 changeset: 5:302e9dd6890d
160 parent: 3:e62f78d544b4
161 parent: 4:ddb82e70d1a1
162 user: test
163 date: Thu Jan 01 00:00:01 1970 +0000
164 summary: m12
165
166 changeset: 4:ddb82e70d1a1
167 parent: 0:67e992f2c4f3
168 user: test
169 date: Thu Jan 01 00:00:01 1970 +0000
170 summary: b2
171
172 changeset: 3:e62f78d544b4
173 parent: 1:3d5bf5654eda
174 user: test
175 date: Thu Jan 01 00:00:01 1970 +0000
176 summary: b1
177
@@ -15,7 +15,7 b' hg update -C 0'
15 hg id
15 hg id
16 echo "changed file1" >> file1
16 echo "changed file1" >> file1
17 hg id
17 hg id
18 hg revert
18 hg revert --all
19 hg diff
19 hg diff
20 hg status
20 hg status
21 hg id
21 hg id
@@ -29,11 +29,11 b' HGMERGE=merge hg update'
29 hg diff
29 hg diff
30 hg status
30 hg status
31 hg id
31 hg id
32 hg revert
32 hg revert --all
33 hg diff
33 hg diff
34 hg status
34 hg status
35 hg id
35 hg id
36 hg revert -r tip
36 hg revert -r tip --all
37 hg diff
37 hg diff
38 hg status
38 hg status
39 hg id
39 hg id
@@ -16,7 +16,7 b' hg update -C 0'
16 hg id
16 hg id
17 echo "changed file1" >> file1
17 echo "changed file1" >> file1
18 hg id
18 hg id
19 hg revert --no-backup
19 hg revert --no-backup --all
20 hg diff
20 hg diff
21 hg status
21 hg status
22 hg id
22 hg id
@@ -31,11 +31,11 b' hg diff | sed -e "s/\\(+++ [a-zA-Z0-9_/.-'
31 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(>>>>>>>\) .*/\1/"
31 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(>>>>>>>\) .*/\1/"
32 hg status
32 hg status
33 hg id
33 hg id
34 hg revert --no-backup
34 hg revert --no-backup --all
35 hg diff
35 hg diff
36 hg status
36 hg status
37 hg id
37 hg id
38 hg revert -r tip --no-backup
38 hg revert -r tip --no-backup --all
39 hg diff
39 hg diff
40 hg status
40 hg status
41 hg id
41 hg id
@@ -1,8 +1,7 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 echo % help
6 echo % help
8 hg help mq
7 hg help mq
@@ -10,6 +9,10 b' hg help mq'
10 hg init a
9 hg init a
11 cd a
10 cd a
12 echo a > a
11 echo a > a
12 hg ci -Ama
13
14 hg clone . ../k
15
13 mkdir b
16 mkdir b
14 echo z > b/z
17 echo z > b/z
15 hg ci -Ama
18 hg ci -Ama
@@ -48,7 +51,7 b' echo % qrefresh'
48
51
49 echo a >> a
52 echo a >> a
50 hg qrefresh
53 hg qrefresh
51 sed -e "s/\(^diff -r \)\([a-f0-9]* \)/\1 x/" \
54 sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \
52 -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
55 -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
53 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch
56 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch
54
57
@@ -103,12 +106,49 b' hg qnext'
103 hg qprev
106 hg qprev
104 hg qapplied
107 hg qapplied
105
108
109 echo % commit should fail
110 hg commit
111
112 echo % push should fail
113 hg push ../../k
114
106 echo % qunapplied
115 echo % qunapplied
107 hg qunapplied
116 hg qunapplied
108
117
118 echo % push should succeed
119 hg qpop -a
120 hg push ../../k
121
109 echo % strip
122 echo % strip
110 cd ../../b
123 cd ../../b
111 echo x>x
124 echo x>x
112 hg ci -Ama
125 hg ci -Ama
113 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
126 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
114 hg unbundle .hg/strip-backup/*
127 hg unbundle .hg/strip-backup/*
128
129 cat >>$HGRCPATH <<EOF
130 [diff]
131 git = True
132 EOF
133 cd ..
134 hg init git
135 cd git
136 hg qinit
137
138 hg qnew -m'new file' new
139 echo foo > new
140 chmod +x new
141 hg add new
142 hg qrefresh
143 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
144 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new
145
146 hg qnew -m'copy file' copy
147 hg cp new copy
148 hg qrefresh
149 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
150 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy
151
152 hg qpop
153 hg qpush
154 hg qdiff
@@ -1,8 +1,7 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 hg init
6 hg init
8 hg qinit
7 hg qinit
@@ -63,22 +62,39 b' echo % should push all'
63 hg qpush -a
62 hg qpush -a
64
63
65 hg qpop -a
64 hg qpop -a
66 hg qguard a.patch +1 +2
65 hg qguard a.patch +1
66 hg qguard b.patch +2
67 hg qselect 1
67 hg qselect 1
68 echo % should push a.patch, not b.patch
69 hg qpush
70 hg qpush
71 hg qpop -a
72
73 hg qselect 2
68 echo % should push b.patch
74 echo % should push b.patch
69 hg qpush
75 hg qpush
70 hg qpop -a
76 hg qpop -a
71
77
72 hg qselect 2
78 hg qselect 1 2
79 echo % should push a.patch, b.patch
73 hg qpush
80 hg qpush
74 hg qpop -a
75
76 hg qselect 1 2
77 echo % should push a.patch
78 hg qpush
81 hg qpush
79 hg qpop -a
82 hg qpop -a
80
83
81 hg qguard a.patch +1 +2 -3
84 hg qguard a.patch +1 +2 -3
82 hg qselect 1 2 3
85 hg qselect 1 2 3
86 echo % list patches and guards
87 hg qguard -l
88 echo % list series
89 hg qseries -v
90 echo % list guards
91 hg qselect
83 echo % should push b.patch
92 echo % should push b.patch
84 hg qpush
93 hg qpush
94
95 hg qpush -a
96 hg qselect -n --reapply
97 echo % guards in series file: +1 +2 -3
98 hg qselect -s
99 echo % should show c.patch
100 hg qapplied
@@ -13,7 +13,7 b' a.patch: +a'
13 applying b.patch
13 applying b.patch
14 Now at: b.patch
14 Now at: b.patch
15 Patch queue now empty
15 Patch queue now empty
16 3 of 3 unapplied patches active
16 number of unguarded, unapplied patches has changed from 2 to 3
17 % should push a.patch
17 % should push a.patch
18 applying a.patch
18 applying a.patch
19 Now at: a.patch
19 Now at: a.patch
@@ -28,27 +28,57 b' applying c.patch'
28 Now at: c.patch
28 Now at: c.patch
29 Patch queue now empty
29 Patch queue now empty
30 guards deactivated
30 guards deactivated
31 2 of 3 unapplied patches active
31 number of unguarded, unapplied patches has changed from 3 to 2
32 % should push all
32 % should push all
33 applying b.patch
33 applying b.patch
34 applying c.patch
34 applying c.patch
35 Now at: c.patch
35 Now at: c.patch
36 Patch queue now empty
36 Patch queue now empty
37 2 of 3 unapplied patches active
37 number of unguarded, unapplied patches has changed from 1 to 2
38 % should push a.patch, not b.patch
39 applying a.patch
40 Now at: a.patch
41 applying c.patch
42 Now at: c.patch
43 Patch queue now empty
38 % should push b.patch
44 % should push b.patch
39 applying b.patch
45 applying b.patch
40 Now at: b.patch
46 Now at: b.patch
41 Patch queue now empty
47 Patch queue now empty
42 2 of 3 unapplied patches active
48 number of unguarded, unapplied patches has changed from 2 to 3
49 % should push a.patch, b.patch
50 applying a.patch
51 Now at: a.patch
43 applying b.patch
52 applying b.patch
44 Now at: b.patch
53 Now at: b.patch
45 Patch queue now empty
54 Patch queue now empty
46 3 of 3 unapplied patches active
55 number of unguarded, unapplied patches has changed from 3 to 2
47 % should push a.patch
56 % list patches and guards
48 applying a.patch
57 a.patch: +1 +2 -3
49 Now at: a.patch
58 b.patch: +2
50 Patch queue now empty
59 c.patch: unguarded
51 2 of 3 unapplied patches active
60 % list series
61 0 G a.patch
62 1 U b.patch
63 2 U c.patch
64 % list guards
65 1
66 2
67 3
52 % should push b.patch
68 % should push b.patch
53 applying b.patch
69 applying b.patch
54 Now at: b.patch
70 Now at: b.patch
71 applying c.patch
72 Now at: c.patch
73 guards deactivated
74 popping guarded patches
75 Patch queue now empty
76 reapplying unguarded patches
77 applying c.patch
78 Now at: c.patch
79 % guards in series file: +1 +2 -3
80 +1
81 +2
82 -3
83 % should show c.patch
84 c.patch
@@ -1,8 +1,7 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 hg init a
6 hg init a
8 cd a
7 cd a
@@ -1,9 +1,8 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 # Environement setup for MQ
3 # Environement setup for MQ
4 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
4 echo "[extensions]" >> $HGRCPATH
5 echo "[extensions]" >> $HGTMP/.hgrc
5 echo "mq=" >> $HGRCPATH
6 echo "mq=" >> $HGTMP/.hgrc
7
6
8 #Repo init
7 #Repo init
9 hg init
8 hg init
@@ -33,7 +32,7 b' echo " This is the 3rd log message" >> l'
33 echo bbbb > file
32 echo bbbb > file
34 hg qrefresh -l logfile
33 hg qrefresh -l logfile
35 echo =======================
34 echo =======================
36 echo "Should display 'Third commit message\n This is the 3rd log message'"
35 printf "Should display 'Third commit message\\\n This is the 3rd log message'\n"
37 hg log -l1 -v | sed -n '/description/,$p'
36 hg log -l1 -v | sed -n '/description/,$p'
38 echo
37 echo
39
38
@@ -46,6 +45,6 b' echo bbbb > file2'
46 echo " This is the 5th log message" >> logfile) |\
45 echo " This is the 5th log message" >> logfile) |\
47 hg qrefresh -l-
46 hg qrefresh -l-
48 echo =======================
47 echo =======================
49 echo "Should display 'Fifth commit message\n This is the 5th log message'"
48 printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n"
50 hg log -l1 -v | sed -n '/description/,$p'
49 hg log -l1 -v | sed -n '/description/,$p'
51 echo
50 echo
@@ -1,8 +1,7 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "[extensions]" >> $HGTMP/.hgrc
4 echo "mq=" >> $HGRCPATH
5 echo "mq=" >> $HGTMP/.hgrc
6
5
7 hg init a
6 hg init a
8 cd a
7 cd a
@@ -27,7 +27,7 b' list of commands (use "hg help -v mq" to'
27 qapplied print the patches already applied
27 qapplied print the patches already applied
28 qclone clone main and patch repository at same time
28 qclone clone main and patch repository at same time
29 qcommit commit changes in the queue repository
29 qcommit commit changes in the queue repository
30 qdelete remove a patch from the series file
30 qdelete remove patches from queue
31 qdiff diff of the current patch
31 qdiff diff of the current patch
32 qfold fold the named patches into the current patch
32 qfold fold the named patches into the current patch
33 qguard set or print guards for a patch
33 qguard set or print guards for a patch
@@ -49,6 +49,7 b' list of commands (use "hg help -v mq" to'
49 qunapplied print the patches not yet applied
49 qunapplied print the patches not yet applied
50 strip strip a revision and all later revs on the same branch
50 strip strip a revision and all later revs on the same branch
51 adding a
51 adding a
52 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 adding b/z
53 adding b/z
53 % qinit
54 % qinit
54 % -R qinit
55 % -R qinit
@@ -102,8 +103,21 b' Now at: test.patch'
102 test2.patch
103 test2.patch
103 Only one patch applied
104 Only one patch applied
104 test.patch
105 test.patch
106 % commit should fail
107 abort: cannot commit over an applied mq patch
108 % push should fail
109 pushing to ../../k
110 abort: source has mq patches applied
105 % qunapplied
111 % qunapplied
106 test2.patch
112 test2.patch
113 % push should succeed
114 Patch queue now empty
115 pushing to ../../k
116 searching for changes
117 adding changesets
118 adding manifests
119 adding file changes
120 added 1 changesets with 1 changes to 1 files
107 % strip
121 % strip
108 adding x
122 adding x
109 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
123 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -113,3 +127,22 b' adding manifests'
113 adding file changes
127 adding file changes
114 added 1 changesets with 1 changes to 1 files
128 added 1 changesets with 1 changes to 1 files
115 (run 'hg update' to get a working copy)
129 (run 'hg update' to get a working copy)
130 new file
131
132 diff --git a/new b/new
133 new file mode 100755
134 --- /dev/null
135 +++ b/new
136 @@ -0,0 +1,1 @@
137 +foo
138 copy file
139
140 diff --git a/new b/copy
141 copy from new
142 copy to copy
143 Now at: new
144 applying copy
145 Now at: copy
146 diff --git a/new b/copy
147 copy from new
148 copy to copy
@@ -14,6 +14,6 b' hg add b/x'
14 echo '# should print A b/x'
14 echo '# should print A b/x'
15 hg st
15 hg st
16 echo '# should forget b/x'
16 echo '# should forget b/x'
17 hg revert
17 hg revert --all
18 echo '# should print nothing'
18 echo '# should print nothing'
19 hg st b
19 hg st b
@@ -1,6 +1,6 b''
1 reverting a
1 reverting a
2 changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
2 changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
3 merging with changeset 2:99a1acecff55
3 merging with changeset 2:e6c3abc120e7
4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
5 (branch merge, don't forget to commit)
5 (branch merge, don't forget to commit)
6 abort: invalid date: 'should fail'
6 abort: invalid date: 'should fail'
@@ -1,4 +1,3 b''
1 (the addremove command is deprecated; use add and remove --after instead)
2 adding foo
1 adding foo
3 checking changesets
2 checking changesets
4 checking manifests
3 checking manifests
@@ -9,7 +9,7 b' hg commit -m 1 -d "1000000 0"'
9 hg remove
9 hg remove
10 rm foo
10 rm foo
11 hg remove foo
11 hg remove foo
12 hg revert
12 hg revert --all
13 rm foo
13 rm foo
14 hg remove --after
14 hg remove --after
15 hg commit -m 2 -d "1000000 0"
15 hg commit -m 2 -d "1000000 0"
@@ -31,7 +31,7 b' echo %% should show a b c e'
31 ls
31 ls
32 echo %% should verbosely save backup to e.orig
32 echo %% should verbosely save backup to e.orig
33 echo z > e
33 echo z > e
34 hg revert -v
34 hg revert --all -v
35 echo %% should say no changes needed
35 echo %% should say no changes needed
36 hg revert a
36 hg revert a
37 echo %% should say file not managed
37 echo %% should say file not managed
@@ -46,9 +46,9 b' echo z > z'
46 hg add z
46 hg add z
47 hg st
47 hg st
48 echo %% should add a, forget z
48 echo %% should add a, forget z
49 hg revert -r0
49 hg revert --all -r0
50 echo %% should forget a
50 echo %% should forget a
51 hg revert -rtip
51 hg revert --all -rtip
52 rm -f a *.orig
52 rm -f a *.orig
53 echo %% should silently add a
53 echo %% should silently add a
54 hg revert -r0 a
54 hg revert -r0 a
@@ -56,7 +56,7 b' hg st a'
56
56
57 hg update -C
57 hg update -C
58 chmod +x c
58 chmod +x c
59 hg revert
59 hg revert --all
60 echo %% should print non-executable
60 echo %% should print non-executable
61 test -x c || echo non-executable
61 test -x c || echo non-executable
62
62
@@ -64,7 +64,7 b' chmod +x c'
64 hg commit -d '1000001 0' -m exe
64 hg commit -d '1000001 0' -m exe
65
65
66 chmod -x c
66 chmod -x c
67 hg revert
67 hg revert --all
68 echo %% should print executable
68 echo %% should print executable
69 test -x c && echo executable
69 test -x c && echo executable
70
70
@@ -78,6 +78,11 b" hg commit -d '2 0' -m a"
78 hg update 0
78 hg update 0
79 mkdir b
79 mkdir b
80 echo b > b/b
80 echo b > b/b
81
82 echo % should fail - no arguments
81 hg revert -rtip
83 hg revert -rtip
82
84
85 echo % should succeed
86 hg revert --all -rtip
87
83 true
88 true
@@ -13,7 +13,7 b' hg ci -m "2" -d "1000000 0"'
13
13
14 echo %% Should show unknown
14 echo %% Should show unknown
15 hg status
15 hg status
16 hg revert -r 0
16 hg revert -r 0 --all
17 echo %% Should show unknown and b removed
17 echo %% Should show unknown and b removed
18 hg status
18 hg status
19 echo %% Should show a and unknown
19 echo %% Should show a and unknown
@@ -54,4 +54,7 b' executable'
54 %% issue 241
54 %% issue 241
55 adding a
55 adding a
56 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 % should fail - no arguments
58 abort: no files or directories specified
59 % should succeed
57 reverting a
60 reverting a
@@ -1,4 +1,3 b''
1 (the addremove command is deprecated; use add and remove --after instead)
2 adding foo
1 adding foo
3 checking changesets
2 checking changesets
4 checking manifests
3 checking manifests
@@ -1,6 +1,4 b''
1 (the addremove command is deprecated; use add and remove --after instead)
2 adding foo
1 adding foo
3 (the addremove command is deprecated; use add and remove --after instead)
4 adding bomb
2 adding bomb
5 adding a.c
3 adding a.c
6 adding dir/a.o
4 adding dir/a.o
@@ -4,11 +4,11 b' user: test'
4 date: Mon Jan 12 13:46:40 1970 +0000
4 date: Mon Jan 12 13:46:40 1970 +0000
5 summary: test
5 summary: test
6
6
7 changeset: 1:c5c60883086f
7 changeset: 1:3ecf002a1c57
8 tag: tip
8 tag: tip
9 user: test
9 user: test
10 date: Mon Jan 12 13:46:40 1970 +0000
10 date: Mon Jan 12 13:46:40 1970 +0000
11 summary: Added tag bleah for changeset 0acdaf8983679e0aac16e811534eb49d7ee1f2b4
11 summary: Added tag bleah for changeset 0acdaf898367
12
12
13 changeset: 0:0acdaf898367
13 changeset: 0:0acdaf898367
14 tag: bleah
14 tag: bleah
@@ -24,9 +24,9 b' failed'
24 use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
24 use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
25 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah
25 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah
26 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0
26 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0
27 c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1
27 3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
28 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
28 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
29 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar
29 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar
30 c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1
30 3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
31 abort: '\n' cannot be used in a tag name
31 abort: '\n' cannot be used in a tag name
32 abort: ':' cannot be used in a tag name
32 abort: ':' cannot be used in a tag name
@@ -9,7 +9,7 b' hg add a'
9 hg commit -m "test" -d "1000000 0"
9 hg commit -m "test" -d "1000000 0"
10 hg co
10 hg co
11 hg identify
11 hg identify
12 T=`hg tip -v | head -n 1 | cut -d : -f 3`
12 T=`hg tip --debug | head -n 1 | cut -d : -f 3`
13 echo "$T first" > .hgtags
13 echo "$T first" > .hgtags
14 cat .hgtags
14 cat .hgtags
15 hg add .hgtags
15 hg add .hgtags
@@ -2,35 +2,35 b' unknown'
2 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 0acdaf898367 tip
3 0acdaf898367 tip
4 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 first
4 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 first
5 tip 1:8a3ca90d111dc784e6575d373105be12570e8776
5 tip 1:8a3ca90d111d
6 first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
6 first 0:0acdaf898367
7 8a3ca90d111d tip
7 8a3ca90d111d tip
8 M a
8 M a
9 8a3ca90d111d+ tip
9 8a3ca90d111d+ tip
10 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
10 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
11 0acdaf898367+ first
11 0acdaf898367+ first
12 0acdaf8983679e0aac16e811534eb49d7ee1f2b4+ first
12 0acdaf898367+ first
13 M a
13 M a
14 8216907a933d tip
14 8216907a933d tip
15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 (branch merge, don't forget to commit)
16 (branch merge, don't forget to commit)
17 8216907a933d+8a3ca90d111d+ tip
17 8216907a933d+8a3ca90d111d+ tip
18 M .hgtags
18 M .hgtags
19 tip 6:c6af9d771a81bb9c7f267ec03491224a9f8ba1cd
19 tip 6:e2174d339386
20 first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
20 first 0:0acdaf898367
21 .hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
21 .hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
22 .hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
22 .hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
23 localtags, line 1: tag 'invalid' refers to unknown node
23 localtags, line 1: tag 'invalid' refers to unknown node
24 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
25 .hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
25 .hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
26 .hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
26 .hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
27 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
27 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
28 localtags, line 1: tag 'invalid' refers to unknown node
28 localtags, line 1: tag 'invalid' refers to unknown node
29 tip 8:4ca6f1b1a68c77be687a03aaeb1614671ba59b20
29 tip 8:4ca6f1b1a68c
30 first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
30 first 0:0acdaf898367
31 changeset: 8:4ca6f1b1a68c
31 changeset: 8:4ca6f1b1a68c
32 .hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
32 .hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
33 .hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
33 .hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
34 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
34 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
35 localtags, line 1: tag 'invalid' refers to unknown node
35 localtags, line 1: tag 'invalid' refers to unknown node
36 tag: tip
36 tag: tip
@@ -1,4 +1,3 b''
1 (the addremove command is deprecated; use add and remove --after instead)
2 adding a
1 adding a
3 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -8,7 +7,6 b' diff -r 33aaa84a386b a'
8 @@ -1,1 +1,1 @@ a
7 @@ -1,1 +1,1 @@ a
9 -a
8 -a
10 +abc
9 +abc
11 (the addremove command is deprecated; use add and remove --after instead)
12 adding b
10 adding b
13 M a
11 M a
14 changeset: 0:33aaa84a386b
12 changeset: 0:33aaa84a386b
@@ -43,7 +41,7 b' user: test'
43 date: Mon Jan 12 13:46:40 1970 +0000
41 date: Mon Jan 12 13:46:40 1970 +0000
44 summary: 1
42 summary: 1
45
43
46 abort: there is nothing to merge, just use 'hg update' or look at 'hg heads'
44 abort: there is nothing to merge - use "hg update" instead
47 failed
45 failed
48 changeset: 0:33aaa84a386b
46 changeset: 0:33aaa84a386b
49 user: test
47 user: test
@@ -66,7 +64,7 b' user: test'
66 date: Mon Jan 12 13:46:40 1970 +0000
64 date: Mon Jan 12 13:46:40 1970 +0000
67 summary: 2
65 summary: 2
68
66
69 changeset: 1:802f095af299cde27a85b2f056aef3829870956c
67 changeset: 1:802f095af299
70 tag: tip
68 tag: tip
71 user: test
69 user: test
72 date: Mon Jan 12 13:46:40 1970 +0000
70 date: Mon Jan 12 13:46:40 1970 +0000
@@ -75,7 +73,7 b' description:'
75 2
73 2
76
74
77
75
78 changeset: 0:33aaa84a386bd609094aeb21a97c09436c482ef1
76 changeset: 0:33aaa84a386b
79 user: test
77 user: test
80 date: Mon Jan 12 13:46:40 1970 +0000
78 date: Mon Jan 12 13:46:40 1970 +0000
81 files: a
79 files: a
@@ -90,7 +88,6 b' diff -r 802f095af299 a'
90 -a2
88 -a2
91 +abc
89 +abc
92 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
90 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
93 (the addremove command is deprecated; use add and remove --after instead)
94 adding b
91 adding b
95 M a
92 M a
96 changeset: 1:802f095af299
93 changeset: 1:802f095af299
@@ -1,4 +1,3 b''
1 (the addremove command is deprecated; use add and remove --after instead)
2 adding beans/black
1 adding beans/black
3 adding beans/borlotti
2 adding beans/borlotti
4 adding beans/kidney
3 adding beans/kidney
General Comments 0
You need to be logged in to leave comments. Login now